MCP

Hosted Model Context Protocol endpoint exposing all five Gyrence primitives as MCP tools. JSON-RPC 2.0 in, JSON or Server-Sent Events out, bearer-token auth. Use this when your client is an MCP-aware agent runtime (Claude Desktop, Cursor, your own MCP SDK) and you want to skip writing per-primitive HTTP wrappers.

This page is the wire-level reference. For the conceptual model — why MCP, billing parity, client configuration — start with Concepts → MCP integration.

Use this when

  • Your runtime speaks MCP and you want the agent itself to pick which Gyrence primitive to call.
  • You want one transport for both discovery (Search, Map) and acquisition (Fetch, Gyre, Extract).
  • You want zero divergence between MCP and HTTP — same credits, same activity log, same error model.
MethodPOST
Path/api/mcp
AuthBearer
CreditsPer-tool — identical to the underlying HTTP primitive

Auth

Authorization: Bearer mc_<your-workspace-key>

The same key that authenticates /api/v1/* authenticates MCP. Header-only — keys are never accepted in the URL path or body. Missing/invalid keys return JSON-RPC error code -32001 with HTTP 401. Failed auth is never billed.

GET and DELETE return HTTP 405 (no standalone SSE channel).

The tools

Five tools, named gyrence_<primitive>. Each tool's input schema is the same Zod object that validates the corresponding /api/v1/* request — so request shapes match the HTTP docs verbatim.

ToolUnderlying handlerCredit cost
gyrence_searchPOST /api/v1/search1 base; +1 per HTTP sub-fetch, +3 per browser sub-fetch when fetch: true
gyrence_fetchPOST /api/v1/fetch1 (HTTP) or 3 (browser)
gyrence_gyrePOST /api/v1/gyreSum of per-page costs across pages[] (1 / 3 per page), minimum 1
gyrence_extractPOST /api/v1/extract5 (HTTP) or 7 (browser)
gyrence_mapPOST /api/v1/map1 flat

For full request/response shapes per tool, follow the link to the corresponding HTTP reference page — the schemas are identical.

JSON-RPC methods

The server speaks the standard MCP method set. Your client library handles this for you; the calls below are useful for sanity-checking with curl.

initialize

Negotiation handshake. Returns server name, version, and protocol capabilities.

curl -X POST https://www.gyrence.com/api/mcp \
  -H "Authorization: Bearer $GYRENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": {},
      "clientInfo": { "name": "my-client", "version": "0.0.1" }
    }
  }'

tools/list

Enumerate the five tools and their JSON Schemas. The schema for each tool is generated from the same Zod object as the HTTP route, so the input shape is canonical.

curl -X POST https://www.gyrence.com/api/mcp \
  -H "Authorization: Bearer $GYRENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'

Response (abbreviated):

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      { "name": "gyrence_search", "description": "Resolve a query into ranked, deduplicated URLs…", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" }, "limit": { "type": "number" }, "fetch": { "type": "boolean" }, "fetchFormats": { "type": "array" }, "tbs": { "type": "string" } }, "required": ["query"] } },
      { "name": "gyrence_fetch",   "description": "…", "inputSchema": { "...": "..." } },
      { "name": "gyrence_gyre",    "description": "…", "inputSchema": { "...": "..." } },
      { "name": "gyrence_extract", "description": "…", "inputSchema": { "...": "..." } },
      { "name": "gyrence_map",     "description": "…", "inputSchema": { "...": "..." } }
    ]
  }
}

tools/call

Invoke a tool. The arguments object matches the underlying HTTP primitive's request body.

curl -X POST https://www.gyrence.com/api/mcp \
  -H "Authorization: Bearer $GYRENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "gyrence_gyre",
      "arguments": { "url": "https://example.com", "maxPages": 5 }
    }
  }'

Response (success):

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"startUrl\":\"https://example.com\",\"totalPages\":1,\"pages\":[{\"url\":\"https://example.com\",\"title\":\"Example\",\"markdown\":\"...\",\"statusCode\":200,\"via\":\"http\"}],\"errors\":[]}"
      }
    ]
  }
}

The text field is a stringified copy of the underlying primitive's data payload. Parse it client-side; the schema is documented per primitive (see the table above).

Errors

Two error surfaces, depending on where the failure happens.

Transport-level errors

Returned as JSON-RPC error envelopes with HTTP status mirroring the failure:

CodeTypeDescription
-32001401Unauthorized: missing or invalid API key. Failed auth is never billed.
-32000405Method not allowed: GET or DELETE was used. Only POST is supported on this endpoint.
{
  "jsonrpc": "2.0",
  "error": { "code": -32001, "message": "Unauthorized: invalid or missing API key." },
  "id": null
}

Tool-level errors

Primitive failures (bad URL, credits exhausted, upstream error, etc.) come back inside the tools/call result with isError: true. The text content is the redacted error string in the form code: message.

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "isError": true,
    "content": [
      {
        "type": "text",
        "text": "credits_exhausted: workspace balance below request cost"
      }
    ]
  }
}

The code prefix is one of the standard envelope codes documented in Errors: bad_request, unauthorized, credits_exhausted, forbidden_url, not_found, timeout, rate_limited, upstream_error, unavailable.

Credits

Every MCP tools/call bills exactly the same as the equivalent HTTP call to the underlying primitive. The recording happens in the shared runEndpoint path — there is no MCP-specific credit code. See Credits for the live schedule.

Coverage & known limits
  • Header auth only. Keys in the URL path or request body are rejected. This is deliberate — URL paths leak into proxy access logs.
  • No standalone SSE. GET /api/mcp returns 405. SSE is only used as the response transport when the client negotiates it during tools/call.
  • Per-tool credit cost is fixed by the underlying primitive. Changing transports does not change cost.
  • Tool errors are not retried server-side. A upstream_error from the underlying primitive surfaces as isError: true; your client decides whether to retry. The same backoff rules from Rate limits apply.

Notes

  • Per-request server. A fresh McpServer instance is constructed per HTTP request, with the parsed API key captured in each tool's closure. Two concurrent requests authenticated with different keys cannot share server state.
  • Schemas are the single source of truth. searchHandler.schema, fetchHandler.schema, etc. are imported by both the HTTP route and the MCP tool — schema drift between transports is impossible.
  • Billing parity by construction. Each MCP tool's execute synthesizes an internal Request and calls the same handle() the HTTP route uses. The recordUsage write happens in shared code; MCP and HTTP rows are indistinguishable except for the url field's provenance.
  • Activity log. MCP calls show up in Console → Activity with the primitive endpoint (/gyre, /search, etc.) — not as /mcp. This is the correct attribution: the cost was the primitive's cost.
Sanity-check from your terminal

The fastest way to verify your key works over MCP is a single tools/list call (see above). It returns the tool definitions, costs zero credits (auth-only path), and confirms the endpoint is reachable from your network.