Agents · How MCP works

How the hosted MCP server handles a request.

One POST to /mcp. The agent lists tools, calls one and gets JSON back — the same projects, issues and traces as the dashboard.

The endpoint

The server is POST https://api.newtalaria.com/mcp. Locally that is the Serverpod web server at http://localhost:8082/mcp; dashboard RPC stays on port 8080.

The body is JSON-RPC 2.0. The route implements initialize, notifications/initialized, ping, tools/list and tools/call. initialize answers with protocolVersion 2025-03-26, a capabilities object whose only key is tools, and serverInfo.

JSON-RPC
// POST https://api.newtalaria.com/mcp
{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": { "protocolVersion": "2025-03-26" } }

// 200 OK · Mcp-Session-Id: 9f1c…
{ "jsonrpc": "2.0", "id": 1, "result": {
  "protocolVersion": "2025-03-26",
  "capabilities": { "tools": {} },
  "serverInfo": { "name": "talaria", "instructions": "authenticate, get_connection, ask before creating a project, verify a test event" } } }

Clients speak Streamable HTTP. Each POST gets one JSON body back. A notification with no id is HTTP 204 with an Mcp-Session-Id header and no body. A method the route does not implement comes back as JSON-RPC method not found.

One request

Every call takes the same path. The bearer is resolved before the JSON-RPC method runs, and every handshake, tools/list, tool call and auth failure is logged with secret-shaped fields and tal_live_ values redacted.

  1. Client

    POST /mcp with a JSON-RPC body

  2. McpRoute

    Reads or mints Mcp-Session-Id and returns it

  3. RequestAuth

    resolveMcpAuth resolves the bearer. tal_live_… is rejected

  4. Transfer meter

    assertCanRead for the org before the call

  5. McpToolExecutor

    Checks MCP scope and project access

  6. Use case

    The same one the dashboard runs, capability checked again

  7. Result

    One text block holding the tool’s JSON, metered as data transfer

Who can call what

CallBearer
initialize · notifications/initialized · pingNot required
tools/call on docs_list, docs_search, docs_getNot required when the client names the tool
tools/listAlways required — a 401 starts OAuth
Every other tools/callGrant with the tool’s scope

The 401 body is invalid_token. The WWW-Authenticate header names realm Talaria and points resource_metadata at /.well-known/oauth-protected-resource.

OAuth and the personal token

Discovery is the protected-resource and authorization-server documents under /.well-known. The client registers with POST /oauth/register, then uses /oauth/authorize, /oauth/token and /oauth/revoke. Consent is the dashboard page at /settings/integrations/cursor. The grant is one user and one organisation.

A personal token is minted with client id tal_pat. It is an opaque single-segment bearer, not a three-part JWT. You choose 30 days, 90 days or until you revoke it.

After connect, get_connection is how the agent learns the signed-in user, the organisation and the scopes on the grant. switch_organization rebinds it.

A tool call

tools/call builds an McpToolContext from the grant: user, organisation, grant id and scope. McpToolExecutor checks the MCP scope for that tool, and when the arguments include a projectId it checks the user can reach that project. It then runs the same use case the dashboard uses — queryEventsIssues for a search, updateIssueStatus for a status change.

The result is one content block of type text holding the tool’s JSON. A domain error (a missing note, a status the issue cannot move to, a project the user cannot see) comes back as a JSON-RPC error on HTTP 200, with the use-case message.

Docs and organisation data

docs_list, docs_search and docs_get read a pinned Markdown snapshot shipped with the server, synced from the public docs. They return the same pages as /docs on this site. Every other tool reads or writes the organisation’s projects, issues, events, traces, sessions and feature flags — the records the dashboard shows for that grant.

Issue triage

search_errors lists grouped issues. get_error returns one issue, its latest event and its comments. search_events accepts issueId so the agent can see whether it is still firing. update_issue_status requires mcp:write; a note is required for resolved and ignored and is stored as a comment.

openresolvedignorednote requirednote requiredsame fingerprint reopensreopens if setting on (default)resolved ↔ ignored is not allowed

Where to connect a client

The URL is the same for every client. The config key is not.

{
  "mcpServers": {
    "talaria": {
      "url": "https://api.newtalaria.com/mcp"
    }
  }
}

Connect the agent, then open the dashboard.

Developer is $5 per month. Settings → Integrations copies the Cursor MCP file. Other clients use the setup page for their config.