Skip to content

Connecting over MCP

The endpoint

The MCP server is at /mcp on the origin you are reading this from. It speaks Streamable HTTP. POST /mcp carries the JSON-RPC messages; GET and DELETE are answered with a JSON-RPC "method not allowed" error.

Reach exactly /mcp, with no trailing slash. A token is issued for that exact resource, and its audience is checked against it.

The credential

/mcp accepts one credential: an OAuth access token issued for it, sent as Authorization: Bearer <access-token>. An API key is not accepted here; it is for the API. A token issued for any other audience is refused, and no token is passed through to anything else.

Discovery

A request with no token, or a token that is refused, is answered 401 with a WWW-Authenticate header that points at the protected resource metadata (RFC 9728):

WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource/mcp"

A client follows it:

  • /.well-known/oauth-protected-resource/mcp names the resource and the authorization server that issues tokens for it.
  • /.well-known/oauth-authorization-server names that server's authorization, token and registration endpoints and its key set (RFC 8414).

Authorization: OAuth 2.1 with PKCE

A client that supports MCP authorization runs this on its own:

  1. Read the protected resource metadata, then the authorization server's.
  2. Register: by dynamic client registration, or with a client ID metadata document. Both are in authentication.
  3. Run the authorization-code flow with PKCE (S256, required), with the resource parameter (RFC 8707) set to the MCP endpoint, so the token is bound to it.
  4. A person signs in, or signs up, and approves the client on the consent page.
  5. Exchange the code for an access token, and call /mcp with it. Use the refresh token when the access token expires.

A tool call that needs a scope the token lacks is answered 403 with an insufficient_scope challenge naming the scopes. Authorize again asking for them.

Calling the server

With a token, negotiate with initialize, list tools with tools/list and call one with tools/call.

  • Start with help_explore and no arguments. It returns the top help page: every service with its status for your account, a quick start for each one you have on, and a table of help pages with their ids. Call it again with {"helpPageId": "<id>"} from that table to read a page. An id you were not shown answers not found.
  • services_list shows every service and whether it is on. services_enable with "trial": true starts a free trial.
  • A service's own tools are reached through toolsets: toolsets_list shows the toolsets you have on, toolsets_open gives a toolset's tools and their schemas, and the call tool that a tool's callWith names calls it: toolsets_calltool_read, toolsets_calltool_write or toolsets_calltool.

Testing the connection

List the tools with curl. Set ORIGIN to the origin you are reading this from and TOKEN to an access token issued for /mcp:

curl -X POST "$ORIGIN/mcp" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'

Without a token, the same call shows the 401 and its WWW-Authenticate header. The MCP Inspector (npx @modelcontextprotocol/inspector) runs the whole flow, from discovery to a tool call, against /mcp.