Dans mon setup opencode + Ollama sur RTX 3090, j’avais commencé avec SearXNG comme source web via MCP.
Ça fonctionnait, mais ce n’était pas exactement le bon outil pour mon usage. SearXNG est un métamoteur de recherche. Il trouve des pages. Firecrawl est plus proche d’une brique d’extraction : il cherche, scrape, nettoie, crawl et renvoie du contenu exploitable par un agent.
Pour un assistant local qui doit lire de la documentation, vérifier une API récente ou comparer plusieurs sources techniques, la différence se sent assez vite.
En bref#
- J’ai remplacé le MCP SearXNG par Firecrawl dans opencode.
- Le gain principal n’est pas la recherche elle-même, mais la qualité du contenu renvoyé au modèle.
- SearXNG reste très bien pour chercher. Firecrawl est plus adapté quand l’agent doit lire et exploiter les pages.
- Firecrawl peut fonctionner via API cloud ou instance self-hosted.
- Le self-hosted tourne avec 5 services actifs dans cette configuration (API, Playwright, Redis, RabbitMQ, PostgreSQL), plus FoundationDB si le profil dédié est activé. Compter ~4 CPUs et 8 Go RAM pour l’API, plus 2 CPUs et 4 Go pour Playwright.
- Dans cette configuration, le port 3002 est exposé sans authentification. L’API est ouverte à qui peut l’atteindre.
- Il faut traiter le MCP comme du code exécutable : il peut lancer des requêtes web, consommer des crédits API et exposer des données au fournisseur choisi.
Pourquoi SearXNG ne suffisait pas#
SearXNG a un avantage évident : c’est simple, léger et auto-hébergeable. Pour une recherche web classique, ça fait le job.
Le problème apparaît quand l’assistant IA doit aller plus loin que “trouve-moi une URL”.
Dans mon usage, les cas typiques sont :
- lire une documentation récente ;
- vérifier une option de configuration ;
- comparer une note de version avec un changelog ;
- récupérer le contenu réel d’une page, pas seulement son titre et son extrait ;
- extraire une information structurée depuis plusieurs sources.
Avec SearXNG, on récupère surtout des résultats de recherche. Il faut ensuite que le modèle décide quoi ouvrir, quoi ignorer, et parfois composer avec des pages mal extraites ou partielles.
Firecrawl déplace le problème : il ne se contente pas de trouver une page, il essaye de la transformer en contenu propre pour LLM. C’est exactement le format attendu par un assistant de code.
Ce que Firecrawl apporte#
Firecrawl expose plusieurs primitives utiles pour un agent. C’est le vrai intérêt du changement : on ne branche pas seulement un moteur de recherche à opencode, on lui donne une petite chaîne de collecte web.
| Fonction | Usage réel dans opencode |
|---|---|
| Search | Trouver des pages pertinentes sur une requête, avec possibilité de récupérer aussi le contenu |
| Scrape | Récupérer le contenu nettoyé d’une URL en markdown ou dans un format plus structuré |
| Crawl | Parcourir plusieurs pages d’un site ou d’une documentation, avec des limites explicites |
| Map | Lister les URLs disponibles avant de décider quoi scraper |
| Extract | Sortir des données structurées avec un schéma quand le contenu brut ne suffit pas |
| Interact | Manipuler une page avec navigateur quand le contenu dépend d’actions |
Pour un assistant local, scrape et search suffisent déjà à justifier le changement.
Exemple concret : quand je demande à opencode de vérifier une option récente dans une documentation, je veux qu’il lise la page officielle, pas qu’il s’appuie sur un extrait de moteur de recherche. Firecrawl renvoie généralement un markdown plus propre, avec moins de navigation parasite.
Les gains pratiques sont assez nets.
Moins de bruit dans le contexte. Une page web classique contient souvent du menu, du footer, des scripts, des blocs marketing, des liens de tracking et des éléments sans valeur technique. Avec SearXNG, l’agent reçoit surtout des résultats de recherche et doit ensuite se débrouiller. Avec Firecrawl, le contenu arrive déjà nettoyé. Pour un petit modèle local, c’est important : chaque token gaspillé dans du bruit réduit la place disponible pour la vraie question.
Des sources plus exploitables. Sur une documentation, Firecrawl peut renvoyer le markdown de la page plutôt qu’un simple titre et une description. opencode peut alors comparer une option de configuration, relire un exemple officiel, vérifier un endpoint ou repérer une note de compatibilité. Ça ne remplace pas une lecture humaine sur un sujet sensible, mais ça évite beaucoup d’aller-retour manuels.
Un workflow plus déterministe. map permet de découvrir les URLs d’un site sans tout aspirer. crawl permet de récupérer une section, mais avec des limites. C’est plus propre que demander à l’agent de chercher au hasard jusqu’à trouver quelque chose. Pour une doc technique, le bon enchaînement ressemble souvent à : chercher la page, scraper la page, éventuellement mapper la section si la réponse est répartie sur plusieurs URLs.
Une meilleure base pour l’extraction structurée. Quand il faut sortir une liste de versions, de paramètres, de prix, de flags ou de champs JSON, le mode extraction est plus adapté qu’un résumé libre. Dans mon usage, ça sert surtout à demander à l’agent de revenir avec une réponse vérifiable : nom de l’option, valeur par défaut, version concernée, URL source. Le résultat reste à contrôler, mais il est moins flou.
Un meilleur comportement sur les pages modernes. Le service Playwright donne une marge sur les sites qui nécessitent du rendu JavaScript. Ce n’est pas une garantie contre les protections anti-bot, mais c’est déjà plus réaliste qu’un simple fetch HTTP sur beaucoup de sites modernes.
Une séparation plus claire entre recherche et lecture. SearXNG est bon pour trouver. Firecrawl est meilleur quand il faut lire. Cette distinction aide à formuler les prompts : on ne demande pas seulement “cherche X”, on demande “trouve la source officielle, lis-la, puis réponds avec les éléments vérifiables”.
Le point à nuancer : Firecrawl n’est pas magique. Les sites protégés, les pages très dynamiques, les paywalls, les limites robots.txt et les protections anti-bot peuvent toujours bloquer ou dégrader le résultat. L’intérêt est d’avoir une brique plus spécialisée que SearXNG, pas un passe-droit universel.
Configuration opencode#
Dans mon article précédent, la configuration MCP SearXNG ressemblait à ceci :
"mcp": {
"searxng": {
"type": "local",
"command": ["npx", "-y", "mcp-searxng"],
"environment": {
"SEARXNG_URL": "http://localhost:8080"
},
"enabled": true
}
}Avec Firecrawl en self-hosted et sans authentification, le MCP pointe simplement vers l’instance locale :
"mcp": {
"firecrawl": {
"type": "local",
"command": ["npx", "-y", "firecrawl-mcp"],
"environment": {
"FIRECRAWL_API_URL": "http://localhost:3002"
},
"enabled": true
}
}Pas de clé API nécessaire ici : l’instance self-hosted est configurée sans authentification (USE_DB_AUTHENTICATION=false). C’est plus simple à intégrer, mais ça signifie aussi que toute machine pouvant accéder au port 3002 peut utiliser l’API.
Pour l’API cloud Firecrawl, on ajoute la clé et on retire l’URL :
"mcp": {
"firecrawl": {
"type": "local",
"command": ["npx", "-y", "firecrawl-mcp"],
"environment": {
"FIRECRAWL_API_KEY": "fc-REDACTED"
},
"enabled": true
}
}Je préfère garder la clé API hors du fichier de configuration quand c’est possible. Une variante plus propre consiste à exporter la variable dans le shell qui lance opencode :
export FIRECRAWL_API_KEY="fc-REDACTED"
opencodeAvec cette approche, la config MCP n’a pas besoin de la section environment :
"mcp": {
"firecrawl": {
"type": "local",
"command": ["npx", "-y", "firecrawl-mcp"],
"enabled": true
}
}Sur une machine personnelle, ça reste simple. Sur un poste partagé, un serveur ou une machine de travail, il faut traiter cette clé comme n’importe quel secret applicatif.
Installation Firecrawl en self-hosted#
La stack self-hosted se compose de cinq services Docker actifs dans cette configuration. FoundationDB est présent dans le compose, mais derrière un profil optionnel. Voici l’essentiel du fichier docker-compose.yml utilisé sur ma machine :
name: firecrawl
services:
# Navigateur headless pour le scraping de pages dynamiques
playwright-service:
image: ghcr.io/firecrawl/playwright-service:latest
environment:
PORT: 3000
networks:
- backend
cpus: 2.0
mem_limit: 4G
# API principale : scrape, search, crawl, extract
api:
image: ghcr.io/firecrawl/firecrawl
environment:
REDIS_URL: redis://redis:6379
REDIS_RATE_LIMIT_URL: redis://redis:6379
PLAYWRIGHT_MICROSERVICE_URL: http://playwright-service:3000/scrape
PORT: ${INTERNAL_PORT:-3002}
HOST: "0.0.0.0"
ENV: local
USE_DB_AUTHENTICATION: "false"
NUM_WORKERS_PER_QUEUE: 8
CRAWL_CONCURRENT_REQUESTS: 10
MAX_CONCURRENT_JOBS: 5
BROWSER_POOL_SIZE: 5
depends_on:
redis:
condition: service_started
playwright-service:
condition: service_started
rabbitmq:
condition: service_healthy
ports:
- "${PORT:-3002}:${INTERNAL_PORT:-3002}"
cpus: 4.0
mem_limit: 8G
extra_hosts:
- "host.docker.internal:host-gateway"
command: node dist/src/harness.js --start-docker
# Cache et files d'attente
redis:
image: redis:alpine
networks:
- backend
# Message broker
rabbitmq:
image: rabbitmq:3-management
networks:
- backend
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "check_running"]
interval: 5s
timeout: 5s
retries: 3
start_period: 5s
# Base de données pour la file de jobs
nuq-postgres:
image: ghcr.io/firecrawl/nuq-postgres:latest
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
networks:
- backend
# FoundationDB (optionnel, non utilisé par défaut)
foundationdb:
image: foundationdb/foundationdb:7.3.63
profiles:
- fdb
networks:
- backend
volumes:
- fdb-data:/var/fdb/data
- fdb-cluster-file:/var/fdb
networks:
backend:
driver: bridge
volumes:
fdb-data:
fdb-cluster-file:Quelques remarques sur cette configuration :
Ressources. L’API seule réclame 4 CPUs et 8 Go RAM, le service Playwright 2 CPUs et 4 Go RAM. Avec Redis, RabbitMQ et PostgreSQL, la stack consomme nettement plus qu’un simple métamoteur de recherche. C’est très loin de la légèreté de SearXNG.
Search backend. Par défaut, Firecrawl self-hosted utilise le moteur Google directement. Le .env permet de configurer un endpoint SearXNG si on préfère passer par son propre moteur de recherche, mais ce n’est pas obligatoire.
Fonctionnalités IA. Les fonctionnalités comme le format JSON dans le scrape ou l’API /extract nécessitent un fournisseur IA (OpenAI ou Ollama). Sans OPENAI_API_KEY ou OLLAMA_BASE_URL configuré, ces fonctionnalités ne sont pas disponibles. L’extraction non structurée (scrape en markdown) fonctionne sans.
BULL_AUTH_KEY. La variable d’environnement BULL_AUTH_KEY est positionnée à CHANGEME dans le .env. Si une interface d’administration ou un endpoint lié aux files de jobs est exposé, cette valeur doit être changée. En local isolé, c’est surtout un rappel : ne pas laisser une valeur par défaut dans une stack accessible depuis le réseau.
PostgreSQL. Les identifiants postgres/postgres sont ceux de la configuration locale. Ils ne doivent pas être repris tels quels sur une instance exposée ou partagée.
Fichier .env#
Le fichier .env minimal pour démarrer :
PORT=3002
HOST=0.0.0.0
USE_DB_AUTHENTICATION=false
BULL_AUTH_KEY=CHANGEMESi on veut activer les fonctionnalités IA avec Ollama :
OLLAMA_BASE_URL=http://host.docker.internal:11434/api
MODEL_NAME=qwen3.6:27b-q4_K_M
MODEL_EMBEDDING_NAME=nomic-embed-texthost.docker.internal est disponible grâce à extra_hosts dans le docker-compose, ce qui permet à l’API Firecrawl de joindre Ollama sur la machine hôte.
Démarrage#
cd /chemin/vers/firecrawl
docker compose up -dLa première exécution télécharge les images (plusieurs centaines de Mo chacune). Les conteneurs mettent environ 30 à 60 secondes à démarrer complètement, le temps que RabbitMQ soit healthy et que l’API initialise ses connexions.
Vérification#
# Lister les conteneurs
docker compose ps
# Vérifier que l'API répond (doit retourner un statut ou une erreur 404)
curl -s -o /dev/null -w "%{http_code}" http://localhost:3002/
# Test de scrape simple
curl -s http://localhost:3002/v2/scrape \
-H "Content-Type: application/json" \
-d '{"url":"https://docs.firecrawl.dev","formats":["markdown"],"onlyMainContent":true}' \
| jq '.data.markdown[0:200]'Self-hosted vs cloud#
La différence principale n’est pas le coût, mais les capacités :
- le cloud Firecrawl gère automatiquement les proxies, les rotations d’IP, les anti-bots et les pages complexes. Le self-hosted repose ici sur un seul nœud Playwright, sans rotation ni pool distribué.
- le cloud a accès aux modèles d’extraction gérés par Firecrawl. En self-hosted, la qualité de l’extraction JSON ou d’/extract dépend du modèle disponible localement.
- le self-hosted ne consomme pas de crédits Firecrawl, mais consomme des ressources machine et de la bande passante. Les limites (concurrent requests, rate limiting) sont configurées localement.
- le self-hosted conserve les URLs et contenus en local, ce qui peut être un critère pour du travail sur des données sensibles.
Pour un usage d’assistant de code qui scrape surtout de la documentation technique publique, le self-hosted suffit largement. Pour du scraping de sites protégés ou à grand volume, le cloud apporte des capacités que le self-hosted n’égalera pas sans infrastructure significative.
Vérifier côté opencode#
Une fois l’instance Firecrawl démarrée, vérification rapide depuis opencode :
opencode mcp listLe serveur Firecrawl doit apparaître comme actif. Si le serveur ne démarre pas, vérifier Node.js et les variables d’environnement :
node --version
npm --version
printenv FIRECRAWL_API_URLLe test le plus parlant reste une demande simple dans opencode :
Utilise Firecrawl pour lire la documentation officielle de Firecrawl sur MCP,
puis résume uniquement les variables d'environnement nécessaires.Si la réponse cite des éléments précis et cohérents avec la page officielle, l’intégration est utilisable. Si le modèle hallucine ou répond sans appeler l’outil, le problème vient souvent des permissions, de la config MCP ou du prompt.
Permissions et garde-fous#
Un MCP donne des outils supplémentaires à l’agent. C’est pratique, mais il faut éviter de lui donner un chéquier ouvert.
Dans opencode, les permissions peuvent être contraintes par outil. Pour Firecrawl, une posture raisonnable consiste à demander confirmation avant les appels MCP :
"permission": {
"firecrawl_*": "ask"
}Selon le workflow, on peut être plus permissif sur une machine personnelle. Mais je préfère voir passer les appels qui déclenchent une recherche, un crawl ou une extraction.
Les risques concrets :
- consommer des crédits API sans s’en rendre compte (version cloud) ;
- scraper une URL interne ou sensible par erreur ;
- envoyer à Firecrawl une page qui contient des informations privées ;
- lancer un crawl trop large ;
- faire confiance à du contenu web injecté dans le contexte du modèle.
Avec l’installation self-hosted, d’autres points méritent l’attention :
Absence d’authentification. Dans cette configuration, l’API Firecrawl est accessible sans clé sur le port 3002. Le point décisif est le mapping Docker ports: "${PORT:-3002}:${INTERNAL_PORT:-3002}" : sans préfixe 127.0.0.1, Docker publie généralement le port sur toutes les interfaces de la machine. Si l’accès LAN n’est pas voulu, il faut binder explicitement sur 127.0.0.1:3002:3002.
BULL_AUTH_KEY par défaut. La variable BULL_AUTH_KEY est initialisée à CHANGEME. Ce n’est pas forcément un problème si aucun endpoint d’administration n’est exposé hors du réseau Docker, mais c’est une mauvaise valeur par défaut à conserver dès que la stack devient accessible depuis un autre poste.
SSRF potentiel. Firecrawl peut accéder à des ressources internes via le conteneur Playwright. L’option extra_hosts mappe host.docker.internal vers la machine hôte. Sans restriction, un prompt bien conçu pourrait demander à l’agent de scraper http://host.docker.internal:8080 ou d’autres services internes.
Consommation de ressources externes. Même en self-hosted, le backend de recherche peut dépendre d’un moteur externe selon la configuration. Si Google Search ou un autre fournisseur est utilisé, les quotas et limites ne disparaissent pas : ils changent simplement d’endroit.
Le dernier point est sous-estimé. Une page web lue par un agent peut contenir des instructions malveillantes ou simplement absurdes. Le modèle peut les voir comme du contexte légitime. Pour de la documentation publique, le risque reste raisonnable. Pour des dépôts inconnus, des tickets publics ou des pages générées par utilisateurs, il faut garder une marge de méfiance.
Firecrawl vs SearXNG#
Le remplacement n’est pas une condamnation de SearXNG. Les deux outils ne répondent pas exactement au même besoin.
| Critère | SearXNG | Firecrawl |
|---|---|---|
| Recherche web | Très bon | Bon |
| Extraction de contenu | Basique selon intégration | Point fort |
| Markdown propre pour LLM | Variable | Meilleur en général |
| Lecture de documentation | Résultats à ouvrir ensuite | Page directement exploitable |
| Exploration d’un site | Recherche par requête | map, puis scrape ciblé |
| Extraction structurée | Pas le rôle principal | Possible avec schéma |
| Pages avec JavaScript | Limité | Playwright côté Firecrawl |
| Self-hosting léger | Oui | Plus lourd |
| Coût direct | Aucun hors infra | API payante en cloud |
| Maintenance | Faible | Plus élevée en self-hosted |
| Pages dynamiques | Limité | Mieux armé, sans garantie |
| Usage agent IA | Correct | Plus adapté |
Mon choix est simple : pour un assistant de code, je préfère moins de résultats mais un contenu mieux exploitable.
SearXNG reste pertinent si l’objectif est :
- garder un moteur de recherche local ;
- éviter une API externe ;
- faire des recherches rapides sans extraction poussée ;
- rester sur une stack très légère.
Firecrawl devient plus intéressant si l’objectif est :
- alimenter un LLM avec du markdown propre ;
- lire des documentations entières ;
- crawler une petite section de site ;
- extraire une information structurée ;
- réduire le bruit envoyé au modèle ;
- vérifier une source officielle sans quitter le terminal ;
- donner à un agent une vraie capacité de lecture web.
Impact sur le workflow#
Avec SearXNG, je formulais souvent mes demandes en deux temps :
- cherche les pages pertinentes ;
- ouvre telle source et résume ce qui compte.
Avec Firecrawl, je peux demander directement :
Vérifie dans la documentation officielle si l'option X existe encore,
cite la source utilisée, puis propose la modification minimale du fichier de config.Ce n’est pas une révolution. C’est surtout moins de friction, et moins de travail de plomberie autour du modèle.
Dans la pratique, ça change plusieurs choses.
Documentation vivante. Pour une librairie, un outil CLI ou une API cloud, je peux demander à opencode de relire la doc actuelle avant de proposer une configuration. C’est utile sur les sujets qui bougent vite : options renommées, flags dépréciés, exemples mis à jour, changements d’authentification.
Comparaison de sources. Quand une réponse dépend de plusieurs pages, Firecrawl rend le parcours plus propre. L’agent peut chercher, scraper deux ou trois sources, puis expliquer les divergences. Pour une CVE ou une annonce upstream, ça ne dispense pas de contrôler manuellement, mais ça accélère la collecte initiale.
Réponses plus faciles à auditer. Je peux demander explicitement : “liste les URLs consultées avant de répondre”. Avec des résultats Firecrawl propres, c’est plus simple de repérer si l’agent s’appuie sur la documentation officielle, un vieux billet de blog ou une page sans rapport.
Meilleure utilisation du modèle local. Un modèle 27b local n’a pas la même marge qu’un gros modèle cloud. Lui donner un contexte propre, court et directement exploitable améliore souvent plus la réponse que changer trois fois de prompt.
Moins de copier-coller manuel. Avant, je faisais souvent la recherche dans le navigateur, je copiais la partie utile, puis je revenais dans opencode. Maintenant l’agent peut récupérer la page lui-même, et je garde mon attention sur la validation technique.
Pour les sujets sécurité, ça ne remplace pas la vérification humaine. Quand il s’agit d’une CVE, d’un correctif ou d’une version affectée, je continue à contrôler les sources officielles : advisory upstream, NVD, tracker Debian/Ubuntu/Red Hat, commits, changelog signé si disponible.
Firecrawl aide à récupérer l’information. Il ne décide pas si elle est fiable.
Ce que je surveille#
Coût et quotas. Un crawl large peut consommer vite. Pour un usage opencode, je garde les demandes courtes et ciblées.
Traçabilité. Je veux savoir quelles URLs ont été consultées. Si l’agent donne une réponse technique sans source claire, je lui demande de lister les pages utilisées.
Isolation. Je ne donne pas à un agent un accès web libre quand je travaille sur des données sensibles. Local ne veut plus dire local dès qu’un MCP appelle une API externe.
Ressources self-hosted. La stack Firecrawl est lourde. L’API peut consommer 8 Go RAM et le service Playwright 4 Go. Sur une machine qui fait tourner Ollama (qui utilise déjà 17-19 Go VRAM pour un modèle 27b), l’ajout de ces conteneurs peut impacter les performances. Une commande rapide pour surveiller :
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"Si la machine commence à swaper ou que les réponses du modèle local ralentissent, arrêter Firecrawl temporairement libère les ressources nécessaires.
Conclusion#
Dans ce workflow, Firecrawl remplace mieux SearXNG parce que mon besoin n’est pas seulement de chercher le web. C’est de fournir à opencode un contenu propre, lisible et assez structuré pour qu’un modèle local puisse l’exploiter correctement.
SearXNG reste une bonne brique homelab. Mais pour un assistant IA qui doit lire de la documentation vivante, Firecrawl colle mieux au problème.
Le compromis est clair : plus de confort côté agent, plus d’attention côté secrets, coût, données envoyées et permissions MCP. Ça reste acceptable si on garde l’intégration bornée et vérifiable.
Sources#
- Dépôt Firecrawl : https://github.com/firecrawl/firecrawl
- Documentation self-hosted Firecrawl : https://github.com/firecrawl/firecrawl/blob/main/SELF_HOST.md
- Docker Compose Firecrawl : https://github.com/firecrawl/firecrawl/blob/main/docker-compose.yml
- Package NPM firecrawl-mcp : https://www.npmjs.com/package/firecrawl-mcp
- MCP Firecrawl officiel : https://github.com/firecrawl/firecrawl-mcp-server
- Documentation Firecrawl API v2 : https://docs.firecrawl.dev/api-reference/v2-introduction
- Documentation Firecrawl Search : https://docs.firecrawl.dev/api-reference/endpoint/search
- Documentation Firecrawl Scrape : https://docs.firecrawl.dev/api-reference/endpoint/scrape
- Documentation Firecrawl Interact : https://docs.firecrawl.dev/features/interact
- Documentation opencode CLI MCP : https://opencode.ai/docs/cli/
- Documentation opencode permissions : https://opencode.ai/docs/tools/
- Docker Compose Playwright image Firecrawl : https://github.com/firecrawl/firecrawl/pkgs/container/playwright-service
- FoundationDB : https://www.foundationdb.org/
- RabbitMQ : https://www.rabbitmq.com/




