MMetadata /docs
Docs/MCP reference

MCP reference

What the server speaks, what it advertises, and the raw calls your client is making on your behalf.

Endpoint and transport

Endpointhttps://mcp-server.metadata.io/mcp
TransportStreamable HTTP. POST JSON-RPC 2.0; responses arrive as text/event-stream, so send Accept: application/json, text/event-stream.
Protocol version2025-11-25
AuthAuthorization: <token>, raw — no Bearer prefix. PAT (pat-…) or JWT. This is the opposite of the MCP spec, which requires the Bearer form: on this server Bearer is accepted by tools/list and rejected by tools/call with -32001, so send it raw.
A GET or HEAD on the endpoint returns 405. That is the server working correctly, not an outage. Use POST.

Handshake

initialize
curl -s -X POST https://mcp-server.metadata.io/mcp \
  -H "Authorization: $METADATA_PAT" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-11-25","capabilities":{},
                 "clientInfo":{"name":"my-agent","version":"1.0"}}}'

The server replies with its capabilities and version. Capabilities advertised today: tools, prompts, resources and logging, with listChanged on tools, prompts and resources.

Calling a tool

Every tool is tools/call with a name and an arguments object matching that tool's JSON Schema. This one takes no arguments and changes nothing, which makes it the right first call:

tools/call
curl -s -X POST https://mcp-server.metadata.io/mcp \
  -H "Authorization: $METADATA_PAT" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"get_current_date","arguments":{}}}'

The response, verbatim from the server:

response
{
 "jsonrpc": "2.0",
 "id": 2,
 "result": {
  "content": [ { "type": "text", "text": "{
    \"current_date\": \"2026-09-05\",
    \"current_quarter\": \"Q3\",
    \"timezone\": \"UTC\"
  }" } ],
  "isError": false
 }
}

Results come back as content blocks. Text blocks hold a JSON string, so most tools need one more parse after the envelope.

Errors

What you seeWhat it means
401 / UnauthorizedThe token is missing, wrong, or being sent with a Bearer prefix it does not want. Test with the tools/list curl above before debugging your client.
405You used GET. The endpoint is POST-only.
"isError": trueTransport succeeded, the tool refused. The content block says why; it is usually a missing required argument or an id that does not resolve in this account.
Client says unauthorized, curl worksThe fault is your client, not the server or the key. A client reads its config once at startup, so a config edit needs a restart to take effect.

Account scope

Every call acts on one account. Read which with get_account_details, list what you can reach with list_user_accounts, and switch with impersonate_account — the platform enforces entitlement and rejects a switch you are not allowed to make. stop_impersonation switches back.