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+Q trê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èm meta ({ rung, solved, attempts, credits }, luôn xuất hiện, trong đó rung là một trong cache, 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ồm exitCountry, yêu cầu chỉ định class bao gồm exitClass, lượt xoay vòng thay đổi họ browser bao gồm profile, và yêu cầu thất bại bao gồm attemptReport
  • foura_browser: cấu trúc riêng biệt { status, headers: object, body, cookies, userAgent } (lưu ý: body có 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: premium khi lệnh gọi được xử lý qua exit node premium. Trên foura_single và foura_browser, điều này xảy ra khi proxy replay một exit mà foura_proxy tì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 /mcp gử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.

Cập nhật: 27 tháng 9, 2026