Skip to content

MCP endpoint

Long Tail exposes its full tool surface through the MCP (Model Context Protocol) Streamable HTTP transport at /mcp. External MCP clients (Claude Desktop, Cursor, other agents or custom applications) connect to this endpoint to discover and invoke tools.

Every request carries Authorization: Bearer <token>. The endpoint is mounted at /mcp, outside the /api prefix. See MCP for the concepts and the MCP reference for the tools.

POST /mcp

Sends a JSON-RPC message (initialize, tools/list, tools/call). The endpoint runs in stateless mode: each request is self-contained and carries its own credential.

Headers

Header Value
Authorization Bearer <api-key>
Content-Type application/json
Accept application/json, text/event-stream

Example request

Terminal window
curl -X POST https://lt.acme.dev/mcp \
-H "Authorization: Bearer $LT_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":1}'

Response 200: A JSON-RPC result (or an event stream when the client accepts one).

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('https://lt.acme.dev/mcp'),
{
requestInit: {
headers: { 'Authorization': `Bearer ${apiKey}` },
},
},
);
const client = new Client({ name: 'my-app', version: '1.0.0' });
await client.connect(transport);
// Discover tools
const { tools } = await client.listTools();
console.log(`${tools.length} tools available`);
// Invoke a tool
const result = await client.callTool({
name: 'list_roles',
arguments: {},
});
Terminal window
# Initialize
curl -X POST https://lt.acme.dev/mcp \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}},"id":1}'
# List tools
curl -X POST https://lt.acme.dev/mcp \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}'
# Call a tool
curl -X POST https://lt.acme.dev/mcp \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_settings","arguments":{}},"id":3}'
Method Description
GET /mcp Returns 405: stateless mode serves no SSE streams
POST /mcp JSON-RPC messages: initialize, tools/list, tools/call
DELETE /mcp Returns 405: stateless mode keeps no sessions
Status Meaning
401 Missing or invalid Bearer token
405 GET or DELETE request (stateless mode accepts POST only)
500 Internal server error

Connect Claude Code to your Long Tail instance as an MCP server. Once connected, Claude Code can discover and invoke all 110 tools: query escalations, manage workflows, store knowledge and more.

Start Long Tail (docker compose up -d --build). On first start, docker compose sets LT_SEED_SERVICE_KEYS=true, so the container’s stdout shows two seeded API keys:

[seed-mcp] read key: lt_bot_<read-key>
[seed-mcp] full key: lt_bot_<full-key>

The read key exposes 57 read-safe tools (queries, listings). The full key exposes all 110 tools.

Copy the example config and add your API key:

Terminal window
cp .mcp.example.json .mcp.json

Edit .mcp.json and replace <your-api-key> with the key from step 1:

{
"mcpServers": {
"long-tail": {
"type": "http",
"url": "https://lt.acme.dev/mcp",
"headers": {
"Authorization": "Bearer lt_bot_<your-api-key>"
}
}
}
}

.mcp.json is gitignored because it holds secrets. .mcp.example.json is the committed template, the same pattern as .env and .env.example.

Or use the CLI:

Terminal window
claude mcp add --transport http long-tail https://lt.acme.dev/mcp \
--header "Authorization: Bearer lt_bot_<your-key>"

Restart Claude Code, then try:

“How’s the system doing?”

Claude Code calls get_system_overview, and one call returns triage, throughput, trends, infrastructure and process status. Try more:

“What roles exist in the system?”

“Show me the most recent worker stream message”

“List all pending escalations”

“Store a knowledge entry: domain=notes, key=today, data={message: ‘shipped MCP’}”

“What MCP servers are registered?”

The credential travels in the Authorization: Bearer header; the host’s session cookie does not authenticate /mcp. Three token types are accepted:

Type Format Use case
OAuth access token Issued by the Long Tail OAuth server for this resource (when the OAuth server is enabled) MCP clients that sign in a person
JWT Signed user token, such as the one from POST /api/auth/login Interactive sessions, testing
API key lt_bot_* prefix Service accounts, automation

When the OAuth server is enabled, a 401 response carries a WWW-Authenticate: Bearer resource_metadata="..." challenge so MCP clients can discover how to sign in. An access token authenticates only while its grant is live. See OAuth and delegation.

  1. Create a service account: POST /api/bot-accounts.
  2. Generate an API key with scopes: POST /api/bot-accounts/:id/api-keys.
  3. Use the key as a Bearer token for /mcp requests.

API key scopes control which tools are visible:

Scope Tools Description
mcp:read 57 Read-safe tools only: queries, listings, discovery
mcp:read + mcp:full 110 All tools, including those that change state

A read key cannot invoke write operations (create, update, delete, invoke workflows). Use the read key for monitoring and exploration and the full key for automation.

Long Tail seeds an mcp-service account at startup with two API keys:

  • read: scopes ["mcp:read"]
  • full: scopes ["mcp:read", "mcp:full"]

With LT_SEED_SERVICE_KEYS=true (local docker compose), the keys are minted at first start and printed once to stdout, never through the logger; they cannot be retrieved again. Otherwise the account is created with no keys, and a superadmin mints them from the dashboard or the bot-accounts API.

Deployment-wide configuration controls which servers and tools are available on the /mcp endpoint. Set it through startConfig.mcp.exposure:

Option Type Default Description
readOnly boolean false Expose only read-safe tools to all callers
hideAiWhenUnavailable boolean true Hide AI-dependent servers when no API key is configured
allowServers string[] all shipped Explicit server allowlist
denyServers string[] none Server denylist

Exposure config is deployment-wide and scopes are per API key. Both layers apply: exposure filters first, then scope.