MCP Server
MCP Server
Sử dụng FourA từ bất kỳ client Model Context Protocol nào (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) dưới dạng 4 tool gốc và 6 workflow prompt. Không cần code tích hợp, không cần HTTP client tùy chỉnh.
Mã nguồn mở trên GitHub; trên npm dưới tên @fouradata/mcp. Bản phát hành hiện tại: 0.7.3.
Bắt đầu nhanh: stdio cục bộ (khuyên dùng cho Claude Desktop)
Lấy key tại foura.ai/dashboard#api-keys (một cú nhấp chuột, chỉ hiển thị một lần khi tạo, định dạng pk_live_...). Thêm nội dung này vào cấu hình MCP client của bạn:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": { "FOURA_API_KEY": "pk_live_..." }
}
}
}
Lưu ý với Claude Desktop: thoát hoàn toàn Claude Desktop (
Cmd+Qtrên macOS) trước khi chỉnh sửa tệp cấu hình. Nếu ứng dụng vẫn đang chạy, nó sẽ ghi đè cấu hình trong bộ nhớ lên các chỉnh sửa của bạn khi thoát.
Lệnh npx sẽ tải xuống @fouradata/mcp trong lần khởi chạy đầu tiên và chạy nó dưới dạng tiến trình con của MCP client. Không cần cài đặt toàn cục.
| Client | Vị trí tệp cấu hình |
|---|---|
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Code | claude mcp add foura -- npx -y @fouradata/mcp (đặt FOURA_API_KEY trong biến môi trường trước) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code (tiện ích mở rộng MCP) | .vscode/mcp.json |
Khởi động lại client. Các công cụ (foura_auto, foura_single, foura_proxy, foura_browser) và sáu prompt sẽ xuất hiện trong danh sách công cụ của bạn.
Bắt đầu nhanh: phiên bản hosted (Streamable HTTP)
Đối với các client hỗ trợ giao thức Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code với --transport http), hãy trỏ chúng đến endpoint được lưu trữ thay vì chạy tiến trình con cục bộ:
{
"mcpServers": {
"foura": {
"url": "https://mcp.foura.ai/mcp",
"headers": {
"Authorization": "Bearer pk_live_..."
}
}
}
}
Đối với Claude Desktop, sử dụng cấu hình stdio ở trên hoặc kết nối endpoint được lưu trữ qua mcp-remote:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
}
}
}
Hosted endpoint reference
| Thuộc tính | Giá trị |
|---|---|
| URL | https://mcp.foura.ai/mcp |
| Transport | Streamable HTTP (POST /mcp, SSE responses) |
| Xác thực | Authorization: Bearer pk_live_... mỗi request |
| MCP-Protocol-Version | Theo @modelcontextprotocol/sdk (hiện tại là 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07) |
| 401 challenge | WWW-Authenticate: Bearer realm="foura-mcp" |
Thử thách 401 cố ý không chứa tham số RFC 9728 resource_metadata. Việc khai báo tham số này khiến client hỗ trợ OAuth khởi chạy một quy trình mà server này không triển khai. Hãy gửi key pk_live_ của bạn dưới dạng Bearer token và lỗi 401 sẽ không còn.
Hosted server hoạt động theo cơ chế stateless. Mỗi request đều mang key riêng, và server sẽ chuyển tiếp key đó đến FourA API dưới dạng X-API-Key. Một key duy nhất mở khóa toàn bộ bốn công cụ.
Để bảo vệ chống lại tấn công DNS-rebinding (CVE-2025-66414), server sẽ xác thực header Host (phải là mcp.foura.ai hoặc localhost) và header Origin khi có mặt (danh sách cho phép: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Các bộ gọi server-to-server (curl, MCP client ở chế độ stdio bridge) không gửi Origin và được thông qua.
Tools
Cả bốn công cụ đều được gắn chú thích readOnlyHint: true và openWorldHint: true theo đặc tả MCP 2025-06-18. Những client tự động phê duyệt các công cụ chỉ đọc đáng tin cậy sẽ gọi chúng mà không hiển thị hộp thoại xác nhận cho từng request.
foura_auto là lựa chọn mặc định thông minh: cung cấp một URL và công cụ sẽ trả về nội dung, tự động chọn phương thức tìm nạp cho bạn. Ba công cụ còn lại là các thành phần cơ bản cấp thấp hơn mà nó điều phối; hãy sử dụng chúng khi bạn muốn kiểm soát rõ ràng.
foura_auto
Cung cấp một URL khi bạn muốn FourA tự chọn phương thức request. Công cụ thực hiện các lần thử có giới hạn qua các đường dẫn HTTP, proxy và trình duyệt hiện có. Truyền validate trên các mục tiêu được bảo vệ để response bắt buộc phải chứa nội dung xác thực trang thật. Nếu không có lần thử nào đáp ứng được việc xác thực, công cụ sẽ trả về lỗi thay vì coi trang thử thách là thành công.
Response bao gồm chi tiết hoàn thành trong meta và theo mặc định là một session có thể tái sử dụng chứa proxy, cookies và userAgent. Đối với request tiếp theo thông thường, hãy gọi foura_single với session.proxy dưới dạng proxy, tuần tự hóa cookie thành header Cookie, và gửi session.userAgent dưới dạng header User-Agent. Đối với render JavaScript, hãy truyền các giá trị session vào các trường foura_browser tương ứng.
foura_single
Một HTTP request, nhận lại response. Tương ứng trực tiếp một-một với POST /api/single/.
Sử dụng cho các trang tĩnh, JSON API, HTML được render phía server.
Chọn trình duyệt bạn muốn thể hiện
Một request sẽ mặc định thể hiện Google Chrome mới nhất. Khi một mục tiêu chấp nhận trình duyệt này nhưng từ chối trình duyệt khác, hãy đặt browser (Chrome, Edge, Safari, Firefox hoặc Tor), os (Windows, macOS, Android hoặc iOS), hoặc version, hoặc truyền chính xác id profile:
{
"method": "GET",
"url": "https://example.com",
"browser": "Firefox",
"os": "Windows"
}
Phiên bản mới nhất được ưu tiên khi có nhiều profile khớp. Một tổ hợp không tồn tại sẽ trả về lỗi liệt kê các tùy chọn khả dụng, vì vậy request không bao giờ được gửi dưới dạng một trình duyệt bạn không chọn. Việc chọn lựa cần unblocker, tính năng này được bật theo mặc định. Danh mục được xuất bản tại GET /api/profiles và không cần API key.
Bốn trường tương tự nằm bên trong đối tượng request của foura_proxy.
foura_proxy
Định tuyến một HTTP request qua proxy xoay vòng với tính năng tự động thử lại. Sử dụng khi foura_single bị chặn hoặc mục tiêu yêu cầu một quốc gia xuất phát cụ thể.
Đặt exitCountries thành một allowlist nghiêm ngặt gồm mã quốc gia hai chữ cái hiển thị cho mục tiêu, được cung cấp bởi người dùng hoặc yêu cầu từ mục tiêu:
{
"maxTries": 5,
"exitCountries": ["CZ", "GB"],
"request": {
"method": "GET",
"url": "https://example.com/pricing",
"browser": "Chrome",
"os": "Windows"
}
}
Các giá trị được cắt khoảng trắng, chuyển thành chữ hoa và loại bỏ trùng lặp. Các proxy không xác định được vị trí xuất sẽ bị loại trừ, và request không bao giờ tự động chuyển sang quốc gia không được yêu cầu. Quá trình chọn proxy sử dụng metadata quốc gia mới nhất hiển thị với mục tiêu, thông thường được cập nhật trong vòng mười phút; đây không phải là quá trình tra cứu vị trí địa lý theo thời gian thực khi gửi request. Không suy đoán quốc gia phục vụ từ địa chỉ proxy host.
Một kết quả thành công theo phạm vi trả về exitCountry và proxy ID có thể tái sử dụng. Kiểm tra để đảm bảo exitCountry thuộc về allowlist đã yêu cầu. Nếu pool hiện tại không có kết quả phù hợp, công cụ sẽ trả về code: "no_eligible_proxy" cùng phạm vi đã được chuẩn hóa trong details.exitCountries. Giữ nguyên phạm vi đó và thử lại sau. Chỉ thay đổi hoặc mở rộng phạm vi khi người dùng thay đổi yêu cầu một cách rõ ràng. Giới hạn phạm vi quốc gia khả dụng từ gói Startup trở lên. Trên gói không hỗ trợ, lệnh gọi gửi kèm exitCountries sẽ bị từ chối với 403 và X-FourA-Limit: plan_limit_feature.
Nếu trang đã chọn sau đó cần JavaScript, hãy truyền proxy ID nhận được sang foura_browser.proxy để trình duyệt tái sử dụng cùng vị trí xuất.
Đặt exitClass: "premium" cho mục tiêu mà standard pool không thể truy cập dù đã thử bao nhiêu vị trí xuất. Đây là một quyền cấp phép chứ không phải một chỉ thị: standard pool vẫn ưu tiên xử lý để phản hồi và thường thành công, và một request được xử lý trước khi thử bất kỳ premium exit nào sẽ không tính lưu lượng premium. Lượt thử premium sẽ tính lưu lượng đã dùng ngay cả khi thất bại. Response trả về exitClass, là premium hoặc standard, giúp bạn biết request được phục vụ bởi phân lớp nào. standard cũng là kết quả trả về khi dung lượng premium trong gói đã hết, và đây là kết quả bình thường chứ không phải lỗi. exitClass: "standard" nghiêm cấm hoàn toàn việc nâng cấp phân lớp. exitClass: "premium" trên gói không có premium exits sẽ bị từ chối với code: "plan_limit_premium". Xem exitClass.
Khi quá trình luân chuyển phải đổi sang dòng trình duyệt khác để nhận phản hồi, response thành công sẽ mang profile chứa dòng trình duyệt đã chọn. Hãy gửi lại với thông tin này, nếu không lệnh gọi tiếp theo sẽ lặp lại phiên bản đã thất bại.
Một lượt luân chuyển thất bại mang attemptReport bên cạnh lỗi: một câu summary, cùng các số đếm phân loại những exit không bao giờ phản hồi (noResponse), exit bị bot check từ chối (defense, cùng các nhà cung cấp trong vendors), các trang đã nhận được nhưng chỉ bị từ chối bởi chính validate.data của bạn (contentRejected), statusRejected, và other. profilesTried liệt kê các trình duyệt mà tác vụ đã gửi theo thứ tự sử dụng đầu tiên, với default nghĩa là request được gửi đi chính xác như ban đầu. Giá trị contentRejected cao nghĩa là FourA đã phân phối trang thực tế nhưng quy tắc của bạn đã loại bỏ chúng. Xem Why a Proxy Request Ran Out of Tries.
foura_browser
Phiên trình duyệt hoàn chỉnh. JavaScript chạy, DOM kết xuất, cookie được trả về. Tương đồng với POST /api/browser/.
Sử dụng cho các ứng dụng single-page, nội dung lazy-load hoặc các trang có quy trình kiểm tra yêu cầu trình duyệt thực để hoàn tất.
Để biết cấu trúc input, giá trị mặc định và các quy tắc xác thực cho từng tool, hãy tham khảo tài liệu tham chiếu endpoint REST. Schema của tool khớp từng trường với REST API, cùng với tùy chọn chỉ dành cho MCP là offload_large (xem bên dưới).
Khi mục tiêu thực hiện kiểm tra bot
foura_single và foura_proxy trả về defense khi mục tiêu chạy quy trình kiểm tra bot trước khi trả về body. defense.solved: true nghĩa là đã vượt qua kiểm tra và data là trang thực tế; false nghĩa là body có thể là trang challenge. Hãy thử lại với browser, os hoặc phiên bản khác, hoặc chuyển lên foura_proxy hoặc foura_browser, thay vì xử lý trang challenge như nội dung thông thường.
Response có kiểu dữ liệu (typed responses)
Mỗi response của tool đều bao gồm cả content (bản tóm tắt văn bản dễ đọc) và structuredContent (JSON có kiểu dữ liệu được xác thực theo outputSchema của tool). Mỗi tool có một cấu trúc riêng:
foura_auto: cấu trúc đơn{ status, headers, data }kèmmeta({ rung, solved, attempts, credits }, luôn xuất hiện, trong đórunglà một trongcache,probe,proxy,browser,warmup,fail) và theo mặc định làsession({ proxy, cookies, userAgent }) để replay qua các tool cấp thấp hơn. Không cótotal_time.foura_single:{ status, headers, data, total_time, ... }(headers là một mảng, mỗi phần tử tương ứng với một bước redirect)foura_proxy: tương tự single cộng thêm{ proxy, total }; yêu cầu thành công theo phạm vi (scoped success) sẽ bao gồmexitCountry, yêu cầu chỉ định class bao gồmexitClass, lượt xoay vòng thay đổi họ browser bao gồmprofile, và yêu cầu thất bại bao gồmattemptReportfoura_browser: cấu trúc riêng biệt{ status, headers: object, body, cookies, userAgent }(lưu ý:bodycó thể là chuỗi hoặc object tùy thuộc vào content-type)
Mỗi tool cũng báo cáo chi phí của lệnh gọi và cách truy vết lệnh gọi đó, được đọc từ response header của API:
credits: số credit đã dùng cho lệnh gọi này. Cũng xuất hiện khi thất bại, vì tác vụ vẫn được thực thi. Bạn chỉ bị tính phí cho lệnh gọi thành công, do đó lệnh gọi thất bại hiển thị credit tại đây nhưng không tốn phí của bạn.request_id: ID của FourA cho lệnh gọi. Hãy cung cấp ID này khi gửi yêu cầu hỗ trợ.exitClass:premiumkhi lệnh gọi được xử lý qua exit node premium. Trênfoura_singlevàfoura_browser, điều này xảy ra khiproxyreplay một exit màfoura_proxytìm thấy.
Các trường này sẽ không xuất hiện nếu API không trả về thông tin gì, do đó client được viết cho phiên bản cũ hơn vẫn hoạt động bình thường mà không cần thay đổi. Các giá trị tương tự được ghi chép tại Response Headers.
Các client hỗ trợ structuredContent có thể truyền trực tiếp typed object cho LLM thay vì yêu cầu nó phải phân tích cú pháp JSON từ văn bản thuần.
Response header đa giá trị
Các header xuất hiện nhiều lần (Set-Cookie, Link, WWW-Authenticate) được trả về dưới dạng mảng:
{
"headers": [
{
"result": { "version": "HTTP/2", "code": 200, "reason": "" },
"content-type": "text/html",
"set-cookie": ["a=1; Path=/", "b=2; Path=/"]
}
]
}
Điều này quan trọng đối với các trang web thiết lập cookie phiên + theo dõi + chấp thuận trong cùng một response (hầu hết các trang thương mại điện tử).
Response lớn: offload_large (mặc định: inline)
Theo mặc định (từ v0.2.0), toàn bộ response body được trả về dạng inline trong structuredContent bất kể kích thước. Cơ chế này hoạt động ngay trên mọi MCP client.
Nếu client của bạn hỗ trợ MCP resources/read VÀ bạn muốn tiết kiệm token trên các trang lớn, hãy truyền offload_large: true cho mỗi lệnh gọi tool. Khi đó, các response >= 50 KB sẽ được ghi vào đĩa, trả về dưới dạng resource_link, và client của bạn chỉ tìm nạp body khi thực sự cần. Trên máy chủ hosted, payload được lưu trong cache sẽ hết hạn sau 1 giờ. Trên instance riêng của bạn, hệ thống không tự xóa payload đã lưu: hãy tự xóa các tệp cũ hơn một giờ khỏi thư mục payload.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true
}
| Client | offload_large: true |
|---|---|
| Claude Desktop | chưa hỗ trợ, giữ mặc định false |
| Claude Code, Cursor, Windsurf | được hỗ trợ |
| VS Code MCP extension | được hỗ trợ |
Cô lập theo tenant: mỗi API key có một namespace riêng (sha256(apiKey)[:16]). Chỉ key đã lưu trữ payload mới có thể đọc lại payload đó. Các thao tác đọc cross-tenant trả về Payload not found mà không làm lộ sự tồn tại của dữ liệu.
Built-in Prompts
Sáu template quy trình hiển thị dưới /prompts trong bất kỳ MCP client nào. Mỗi template nhận các đối số có tên và trả về một user message theo mẫu nhằm điều phối một hoặc nhiều công cụ.
| Prompt | Đối số | Chức năng |
|---|---|---|
smart_fetch |
url, tùy chọn must_contain, extract |
Tự động fetch (tự chọn phương thức, xử lý bot protection), sau đó trả về hoặc trích xuất nội dung |
scrape_product_page |
url |
Fetch qua browser, sau đó trích xuất tiêu đề sản phẩm, giá, hình ảnh, tình trạng kho, SKU dưới dạng JSON |
extract_article |
url |
Single fetch với proxy fallback, sau đó loại bỏ điều hướng/quảng cáo và trả về JSON bài viết sạch |
monitor_pricing |
url, tùy chọn target_price |
Fetch qua proxy, trích xuất giá hiện tại, so sánh với giá mục tiêu |
check_endpoint_health |
url, tùy chọn expected_text |
Single fetch với xác thực nghiêm ngặt, trả về khả năng tiếp cận và thời gian phản hồi |
bulk_fetch_urls |
urls (phân tách bằng dấu phẩy) |
Single fetch song song, tự động fallback về proxy cho từng URL, chỉ trả về metadata |
Prompts không tốn token khi ở trạng thái nhàn rỗi. Chỉ các prompt được gọi mới được đưa vào context của LLM.
Toàn văn kèm các manual fallback prompt: MCP Recipes.
Error envelope
Mọi lỗi (isError: true) đều đi kèm một envelope structuredContent. Các trường tối thiểu trên mọi lỗi:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
Khi xảy ra lỗi upstream kèm HTTP status, status cũng xuất hiện. Với lỗi rate limit và dung lượng, envelope upstream sẽ bổ sung retryAfter, current.{concurrency, rpm} và limits.{maxConcurrency, maxRpm}. Xem Lỗi API để biết cấu trúc REST bên dưới.
Các giá trị code ổn định:
| Mã | HTTP | Ý nghĩa | Có thể thử lại an toàn? |
|---|---|---|---|
ssrf_blocked |
n/a | Mục tiêu là địa chỉ private hoặc reserved (RFC 5735, 6598, IPv6 reserved), URL không phải http(s), hoặc host name không phân giải được | Không, hãy kiểm tra URL. Có thể thử lại nếu lỗi tra cứu chỉ mang tính tạm thời |
upstream_non_json |
thay đổi | Upstream trả về body sai định dạng | Có thể, hãy kiểm tra |
output_validation_failed |
n/a | outputSchema của MCP server đã từ chối response từ upstream, hoặc công cụ không thể hoàn tất lệnh gọi (chưa cấu hình API key, API không thể truy cập) |
Có thể: kiểm tra cấu hình, sau đó báo cáo lỗi |
bad_request |
400 | Cấu trúc đầu vào bị từ chối | Không, hãy sửa các đối số |
auth_failed |
401 | Key bị thiếu, không hợp lệ hoặc đã bị vô hiệu hóa | Không, hãy sửa key |
forbidden |
403 | Mục tiêu phản hồi 403 và validate của bạn đã từ chối (kiểm tra trang web, giới hạn quốc gia) |
Không, hoặc chuyển sang foura_proxy |
not_found |
404 | Thiếu mục tiêu hoặc endpoint | Không |
rate_limited |
429 | Đã chạm giới hạn RPM | Có, đợi retryAfter |
at_capacity |
503 | Đã chạm giới hạn đồng thời | Có, đợi retryAfter |
service_disabled |
503 | Dịch vụ tạm ngưng để bảo trì. Công cụ không thuộc gói của bạn sẽ trả về plan_limit_feature |
Liên hệ hỗ trợ |
service_unavailable |
503 | Lỗi 503 chung | Có, backoff ngắn |
upstream_error |
500+ hoặc 0 | Mục tiêu phản hồi bằng lỗi máy chủ, hoặc trên foura_proxy, foura_browser và foura_auto không phản hồi |
Có, exponential backoff |
upstream_client_error |
4xx | Lỗi 4xx khác | Thường là không |
upstream_unknown |
khác | Request đã chạy nhưng không có phản hồi được chấp nhận: trên foura_single mục tiêu không phản hồi (timeout, từ chối kết nối), và trên bất kỳ công cụ nào validate của bạn đã từ chối response 2xx hoặc 3xx. Đọc status và error |
Điều tra |
no_eligible_proxy |
n/a | Không có proxy khớp với phạm vi nghiêm ngặt exitCountries |
Thử lại sau; chỉ thay đổi phạm vi một cách rõ ràng |
plan_limit_* |
403 hoặc 429 | Một trong các giới hạn của gói dịch vụ đã từ chối lệnh gọi: plan_limit_ theo sau bởi feature, premium, concurrency, rate, browser_daily, credits hoặc bandwidth. Xem Lỗi MCP Server |
Đợi retryAfter khi có mặt; nếu không, chỉ gọi lại khi giới hạn đặt lại hoặc gói thay đổi |
Các agent LLM có thể đọc trực tiếp code để xử lý logic retry mà không cần phân tích văn bản. Hướng dẫn xác thực: Xác thực.
Giới hạn
- Inline body theo mặc định. Với
offload_large: true, response >= 50 KB được ghi vào ổ đĩa +resource_link(theo từng tenant, TTL 1 giờ). - Các target nội bộ bị từ chối (RFC 5735, RFC 6598, các dải IPv6 dành riêng) ở tầng MCP. Chỉ chuyển tiếp các host công khai.
- Giới hạn request body tối đa 256 KB đối với các request
/mcpgửi đến (payload MCP thực tế < 4 KB). - Rate limit được FourA API thực thi cho từng dịch vụ. Xem Rate Limits.
Tự host
Toàn bộ mã nguồn server được công khai trên GitHub theo @fouradata/mcp. Clone repo, npm install, npm run build, và chạy node dist/http.js để khởi chạy instance của riêng bạn. Chạy stateless trong một container duy nhất phía sau bất kỳ load balancer nào.
Biến môi trường có thể cấu hình:
| Biến | Mặc định | Mục đích |
|---|---|---|
PORT |
3076 |
Cổng lắng nghe HTTP |
FOURA_API_BASE |
https://api.foura.ai/api |
Base URL của upstream FourA REST |
FOURA_MCP_PAYLOADS_DIR |
thư mục foura-mcp-payloads trong thư mục tạm của hệ thống (file Docker Compose đi kèm đặt là /data/payloads) |
Nơi lưu cache trên ổ đĩa cho response >= 50 KB (với offload_large: true) |
FOURA_MCP_ALLOWED_HOSTS |
mcp.foura.ai,localhost,127.0.0.1,[::1] |
Danh sách hostname cho phép cho header Host (phòng thủ DNS-rebinding) |
FOURA_MCP_ALLOWED_ORIGINS |
https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com |
Danh sách Origin cho phép cho các trình gọi từ trình duyệt |
Container chính thức chạy dưới uid 1001 (non-root). Thư mục bind mount /data/payloads trên host phải có quyền ghi cho uid đó.
Mở rộng theo chiều ngang phía sau bất kỳ load balancer nào. Client gửi kèm key trong mỗi request, do đó không cần sticky session.