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.
| Method | POST |
| Path | /api/mcp |
| Auth | Bearer |
| Credits | Per-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.
| Tool | Underlying handler | Credit cost |
|---|---|---|
gyrence_search | POST /api/v1/search | 1 base; +1 per HTTP sub-fetch, +3 per browser sub-fetch when fetch: true |
gyrence_fetch | POST /api/v1/fetch | 1 (HTTP) or 3 (browser) |
gyrence_gyre | POST /api/v1/gyre | Sum of per-page costs across pages[] (1 / 3 per page), minimum 1 |
gyrence_extract | POST /api/v1/extract | 5 (HTTP) or 7 (browser) |
gyrence_map | POST /api/v1/map | 1 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:
| Code | Type | Description |
|---|---|---|
-32001 | 401 | Unauthorized: missing or invalid API key. Failed auth is never billed. |
-32000 | 405 | Method 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.
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.
- 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/mcpreturns 405. SSE is only used as the response transport when the client negotiates it duringtools/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_errorfrom the underlying primitive surfaces asisError: true; your client decides whether to retry. The same backoff rules from Rate limits apply.
Notes
- Per-request server. A fresh
McpServerinstance 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
executesynthesizes an internalRequestand calls the samehandle()the HTTP route uses. TherecordUsagewrite happens in shared code; MCP and HTTP rows are indistinguishable except for theurlfield'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.
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.
