سرور MCP Firecrawl بدون هیچ کلید API بالا میآید، اما روی نشانی میزبانیشده فقط سه ابزار firecrawl_search، firecrawl_scrape و firecrawl_parse ثبت میکند و همان بسته روی stdio بیستوپنج ابزار. در این نوشته هر دو حالت را با curl اندازه گرفتم و نشان دادم چرا پاسخ سرور باید از فیلتر data: رد شود.
سرور بدون کلید کار میکند، ولی فقط سه ابزار
مستندات رسمی میگوید نقطهی پایانی میزبانیشده بدون هیچ اعتبارنامهای کار میکند. لحظهی خواندن: ۳ اکتبر ۲۰۲۶. اولین درخواست با initialize این پاسخ را داد و نسخهی گزارششده با برچسب latest در رجیستری npm یکی بود؛ یعنی کدی که روی سرور میزبانیشده اجرا میشود همان بستهای است که مخزن رسمی منتشر میکند.
$ curl -s -X POST https://mcp.firecrawl.dev/v2/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" --data-binary @init.json \
| grep "^data: " | sed "s/^data: //" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['result']['serverInfo'])"
{'name': 'firecrawl-fastmcp', 'version': '3.27.3'}
همین رجیستری برای نسخهی 3.27.3 شرط node >=22.0.0 و پروانهی MIT را ثبت کرده است. اما «بدون کلید» با «همهچیز در دسترس» یکی نیست: همان tools/list روی همین نشانی و بدون هیچ کلیدی فقط سه ابزار برگرداند.
$ curl -s -X POST https://mcp.firecrawl.dev/v2/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" --data-binary @list.json \
| grep "^data: " | sed "s/^data: //" \
| python3 -c "import json,sys; t=json.load(sys.stdin)['result']['tools']; print(len(t),'tools')"
3 tools
این سهتایی بودن در جدول نرخمحدودیتها هم نوشته شده است: بدون کلید، جستوجو و اسکرپ و پارس رایگان و محدود به آیپی همان روزند، و ابزارهایی مثل crawl، map و agent هنوز کلید میخواهند.
| حالت اتصال | تعداد ابزار | آنچه واقعا کار میکند |
|---|---|---|
| میزبانیشده، بدون کلید | ۳ | جستوجو، اسکرپ، پارس |
| محلی روی stdio، بدون کلید | ۲۵ | همان سه، بقیه نیازمند کلید |
| پروفایل کامل طبق ادعای مخزن | ۲۶ | با ابزارهای بازخورد، خارج از حالت بدون کلید |
عدد ۲۵ را خودم شمردم و عدد ۲۶ از توضیح خود مخزن است، نه از اجرای من: آن عدد وقتی شمرده میشود که پروفایل کامل با تنظیمات پیشفرض بالا بیاید، و حذف ابزارهای بازخورد یا اجرای بدون کلید شمارش را پایین میآورد.
یک فراخوانی واقعی با curl
ابزارها با متد tools/call صدا زده میشوند و نام ابزار داخل params.name مینشیند. این فراخوانی واقعی است و خروجیاش همان چیزی است که در ادامه میبینید.
$ cat > call.json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"firecrawl_search","arguments":{"query":"model context protocol streamable http transport","limit":2}}}
$ curl -s -X POST https://mcp.firecrawl.dev/v2/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" --data-binary @call.json \
| grep "^data: " | sed "s/^data: //" \
| python3 -c "import json,sys; print(len(json.loads(json.load(sys.stdin)['result']['content'][0]['text'])['data']['web']),'results')"
2 results
1. Transports - What is the Model Context Protocol (MCP)?
https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
2. Streamable HTTP - What is the Model Context Protocol (MCP)?
https://modelcontextprotocol.io/specification/draft/basic/transports/streamable-http
معنادارترین بخش این خروجی خود نتیجهها نیست، بلکه دو لایهی تودرتوی رشته است: متن درون result.content[0].text خودش یک JSON دیگر است که باید دوباره باز شود. اگر مستقیم روی همان لایه صدا بزنید، رشتهی خام را میبینید و ساختاری که بتوانید روی آن کلید data را بخوانید در اختیارتان نیست.
گلوگاه واقعی: پاسخ سرور SSE است
وقتی خروجی curl را مستقیم به یک تجزیهگر JSON دادم، اولین تلاش با خطای JSONDecodeError: Expecting value: line 1 column 1 شکست خورد و هیچ چیزی چاپ نشد. علتش این است که سرور با content-type: text/event-stream جواب میدهد و هر پیام را در قالب data: میپیچد.
$ curl -s -D - -o /dev/null -X POST https://mcp.firecrawl.dev/v2/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" --data-binary @init.json
HTTP/2 200
cache-control: no-cache
content-type: text/event-stream
server: nginx/1.30.4
این سرآیند عیب نیست و قرارداد همین است. مشخصات ترابری MCP صریح مینویسد کلاینت باید هر دو نوع application/json و text/event-stream را در هدر Accept بفرستد و همین سند اجازه میدهد سرور با SSE پاسخ دهد. پس راهحل حذف هدر نیست؛ جدا کردن خط data: پیش از تجزیه است.
قاعدهی کاربردی این نوشته همینجاست: پاسخ هر سرور را پیش از تجزیه از قالب SSE بیرون بیاورید، وگرنه اولین تلاش با خطای تجزیهی JSON شکست میخورد و آدم فکر میکند سرور خراب است. اگر خروجی را در فایل نگه داشتهاید، همان فیلتر را روی فایل اجرا کنید.
# خط data: را جدا کنید تا خروجی تمیز JSON شود
grep '^data: ' reply.txt | sed 's/^data: //' > payload.json
python3 -m json.tool payload.json | head -5
اجرای محلی: بیستوپنج ابزار روی stdio
همان بستهی npm روی این ماشین با npx -y firecrawl-mcp بالا آمد و بیستوپنج ابزار ثبت کرد. در ترابری stdio هر پیام JSON-RPC با خط جدید از ورودی و خروجی عبور میکند، پس فرایند را با یک خط لوله میشود خواند.
$ node --version
v26.7.0
$ npx -y firecrawl-mcp
[firecrawl-mcp] Search feedback tool disabled by FIRECRAWL_NO_SEARCH_FEEDBACK
No FIRECRAWL_API_KEY or FIRECRAWL_API_URL set — running in keyless mode.
$ # پس از tools/list روی همان فرایند، ده ابزار اول از ۲۵:
LOCAL TOOL COUNT: 25
- firecrawl_scrape
- firecrawl_map
- firecrawl_search
- firecrawl_crawl
- firecrawl_agent
- firecrawl_interact
- firecrawl_parse
- firecrawl_research_search_papers
- firecrawl_developer_search
- firecrawl_credit_usage
پیام خطای خود سرور دو چیز را روشن میکند: در حالت بدون کلید، scrape و search رایگاناند و بقیهی ابزارها کلید میخواهند. ثبت شدن یک ابزار در فهرست تضمین نمیکند که بدون کلید جواب بدهد، پس فهرست را معیار دسترسی نخوانید.
وصل کردن به کدکس و کلاد کد
مستندات برای هر کلاینت یک خط آماده دارد. برای کدکس:
$ codex mcp add firecrawl --url https://mcp.firecrawl.dev/v2/mcp
و برای کلاد کد، با ترابری صریح http:
$ claude mcp add --transport http firecrawl https://mcp.firecrawl.dev/v2/mcp
برای هر کلاینتی که فقط JSON میخواند، همان نشانی با کلید url کافی است و بلوک command لازم نیست. برای سطح کامل ابزارها، کلید را هدر میگذارید نه بخشی از آدرس؛ مخزن رسمی هشدار میدهد که نگذارید کلید در URL بنشیند یا در گفتوگوی ایجنت لو برود. برای تست کلاینت محلی، تست سرور MCP با خط فرمان اینسپکتور مسیر دیگری برای دیدن همین فهرست ابزار است.
{"mcpServers": {"firecrawl": {"type": "http", "url": "https://mcp.firecrawl.dev/v2/mcp", "headers": {"Authorization": "Bearer <FIRECRAWL_API_KEY>"}}}}
سقف واقعی مصرف و یک ادعای نادرست
جدول صفحهی قیمت میگوید هر اعتبار برابر یک صفحهی اسکرپ است و هر ده نتیجهی جستوجو دو اعتبار میبرد. با این نسبت، پلن Hobby با ۵٬۰۰۰ اعتبار ماهانه یعنی ۵٬۰۰۰ صفحه یا ۲۵٬۰۰۰ نتیجهی جستوجو در ماه، چون ۵٬۰۰۰ تقسیم بر دو ضرب در ده همان ۲۵٬۰۰۰ میشود. سقف درخواست دقیقهای جداست و روی همزمانی مرورگر مینشیند.
| پلن | مرورگر همزمان | درخواست در دقیقه | اعتبار ماهانه |
|---|---|---|---|
| Free | ۲ | ۱۰ | ۱٬۰۰۰ |
| Hobby | ۵ | ۱۰۰ | ۵٬۰۰۰ |
| Standard | ۲۵ | ۵۰۰ | ۱۰۰٬۰۰۰ |
یک ریزهکاری که در همین جدول گم میشود: صفحهای که خطای ۴۰۳ یا ۴۰۴ بدهد باز هم تحویل داده میشود و یک اعتبار میبرد، ولی اسکرپی که هیچ نتیجهای نداشته باشد هزینهای ندارد. اگر کلید شما زودتر از انتظار تمام میشود، اول شمار خطاها را نگاه کنید نه تعداد درخواستها.
ادعای دومی هم هست که در تست نیفتاد. مخزن رسمی میگوید نشانی mcp-search مجموعهای ثابت از هشت ابزار جستوجو را جدا میکند. همان نشانی را بدون کلید صدا زدم و بهجای فهرست ابزار، خطای ۴۰۱ گرفتم.
$ curl -s -D - -X POST https://mcp.firecrawl.dev/v2/mcp-search \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" --data-binary @init.json
HTTP/2 401
www-authenticate: Bearer resource_metadata="...", error="invalid_token"
یعنی این مسیر دیگر بدون اعتبار باز نیست و توکن دسترسی OAuth میخواهد. اگر میخواهید بدون کلید شروع کنید، نشانی /v2/mcp را استفاده کنید و سراغ mcp-search نروید، وگرنه پیش از اولین ابزار به خطای ۴۰۱ میخورید. برای ساخت کلاینت بهجای دستازپا، SDK پایتون نسخهی 2 همین کار را با یک بستهی رسمی انجام میدهد.
جمعبندی عملی: اگر سه ابزار بدون کلید برایتان کافی است، همان نشانی میزبانیشده بس است و نیازی به نصب و حساب ندارد. فقط یادتان باشد خروجیاش SSE است و باید خط data: را جدا کنید، وگرنه اولین تلاش شکست میخورد.
دیدگاهها
۰ موردهنوز دیدگاهی ثبت نشده. اولین نفر باشید.