The gateway serves MCP protocol 2025-11-25 at one Streamable HTTP endpoint. POST /mcp carries client messages, GET /mcp opens a server event stream, and DELETE /mcp ends a session.

Initialize

Bash
curl "$EYEBALL_MCP_URL/mcp" \
  -H "Authorization: Bearer $EYEBALL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-11-25",
      "capabilities": {},
      "clientInfo": {"name": "docs-example", "version": "1.0.0"}
    }
  }'

Retain the server-generated Mcp-Session-Id response header and send it on every later request. An unknown, expired, deleted, or differently authenticated session returns HTTP 404. Sessions expire after 24 hours by default.

Stream responses

A POST request without Accept: text/event-stream receives one JSON response, preserving the simple request/response profile. If Accept includes text/event-stream, the gateway returns SSE: an initial empty event primes reconnect handling, related notifications may follow, and the final event contains the JSON-RPC response.

Open a session event channel with:

Bash
curl -N "$EYEBALL_MCP_URL/mcp" \
  -H "Authorization: Bearer $EYEBALL_API_KEY" \
  -H "Accept: text/event-stream" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "MCP-Protocol-Version: 2025-11-25"

The GET stream carries task progress, task-status changes, and tool-list change notifications. Each event has a session-scoped event ID and one JSON-RPC message in data. End the session explicitly with:

Bash
curl -X DELETE "$EYEBALL_MCP_URL/mcp" \
  -H "Authorization: Bearer $EYEBALL_API_KEY" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "MCP-Protocol-Version: 2025-11-25"

Search the catalog

eyeball.search_tools is always present and accepts only query plus optional limit:

JSON
{
  "name": "eyeball.search_tools",
  "arguments": {
    "query": "add a note to a CRM contact",
    "limit": 5
  }
}

It returns compact cards with name, description, capability, toolkit, and an input-schema summary. In search discovery mode, invoke the selected result through the always-listed eyeball.execute_tool descriptor:

JSON
{
  "name": "eyeball.execute_tool",
  "arguments": {
    "name": "hubspot.create_contact",
    "input": {"email": "guest@example.com"}
  }
}

Call metadata

User and connection selectors may live under params._meta:

JSON
{
  "dev.eyeball/userId": "demo_user",
  "dev.eyeball/connectionId": "conn_01JZ6WCPX7X67K7NYYKAPX62T0",
  "dev.eyeball/idempotencyKey": "agent-turn:42:tool:1"
}

User precedence is the gateway's configured EYEBALL_USER_ID, then X-Eyeball-User-Id, then _meta["dev.eyeball/userId"]. A user-pinned inbound API key rejects any different value at any of those surfaces. Connection and idempotency metadata remain per-call overrides. Without an explicit idempotency value, mutations use mcp:<session-id>:<json-rpc-id>.

Terminal tool results include:

JSON
{
  "_meta": {
    "dev.eyeball/execution": {
      "executionId": "exe_01JZ6WA0Q73ZQ5B51SRYB6M4Z8",
      "tool": "gmail.search_emails",
      "toolVersion": "1.0.0",
      "catalogVersion": "1.1",
      "status": "succeeded",
      "latencyMs": 31
    }
  }
}

Provider-tool descriptors include _meta["dev.eyeball/tool"]; the built-in search and generic execute descriptors do not.

Tasks

Tasks are opt-in per initialized session. Under MCP 2025-11-25, a Tasks-capable client requests the top-level Tasks capability during initialization:

JSON
{
  "tasks": {}
}

The legacy capabilities.experimental.tasks alias is still accepted for compatibility, but new clients should use the top-level capability.

When the executor supports async allocation and status reads, the initialize result advertises tasks.requests.tools.call. tools/list then includes async-by-nature tools and adds execution.taskSupport: "required" for async-by-nature tools and "optional" for ordinary tools. Without this negotiation, async tools remain omitted and the existing terminal tool-result behavior is unchanged.

Create a task by adding task to tools/call params:

JSON
{
  "name": "twilio.start_call",
  "arguments": {
    "to": "+966500000000",
    "from": "+12025550173",
    "voiceAgentId": "vag_renewals_ar_01"
  },
  "task": {
    "ttl": 3600000
  },
  "_meta": {
    "progressToken": "renewal-call-481"
  }
}

The create response contains only the task. Its taskId is the underlying exe_* execution ID, so operations and MCP clients correlate one identity:

JSON
{
  "task": {
    "taskId": "exe_01JZ6WA0Q73ZQ5B51SRYB6M4Z8",
    "status": "working",
    "createdAt": "2026-07-19T00:00:00.000Z",
    "lastUpdatedAt": "2026-07-19T00:00:00.000Z",
    "ttl": 3600000,
    "pollInterval": 1000
  }
}

Poll with tasks/get. pending and running executions map to working; successful executions map to completed; failed tool results map to failed; cancelled executions map to cancelled. Retrieve the canonical terminal CallToolResult with tasks/result. That method waits if work is still active, and its result includes both _meta["dev.eyeball/execution"] and _meta["io.modelcontextprotocol/related-task"]. A cancelled task returns the underlying non-success tool result with execution_cancelled and the authoritative execution metadata rather than a fabricated protocol error.

If the original call supplied _meta.progressToken, the gateway publishes notifications/progress at queued, running, and terminal transitions. It also publishes optional notifications/tasks/status terminal notifications; clients must still poll tasks/get.

The stock HTTP bridge advertises tasks/cancel and forwards it to the executor only after resolving the task inside the currently authenticated MCP session. Cancellation returns the complete updated Task without related-task metadata. Cancelling a locally terminal task, or losing a downstream race to success or failure, returns JSON-RPC -32602.

Pre-dispatch cancellation is deterministic. If provider dispatch may already have begun, the returned Task is still durably cancelled, but local interruption is best effort and upstream work or external side effects may complete. A gateway retry reconstructs the cancelled task from the executor when the downstream response was lost. Task state is bound to the authenticated MCP session, retained for one hour by default, and stored through the injectable SessionStore seam.