Skip to content

MCP

Long Tail is an MCP server and an MCP client. As a server, it gives any agent its queues, workflows and diagnostics at /mcp. As a client, it turns the tools of any registered MCP server into durable activities your workflows call. This page covers both directions.

One command, then sign in once in the browser:

Terminal window
claude mcp add --transport http long-tail https://lt.acme.dev/mcp

Run /mcp in Claude Code and pick Authenticate. The consent page shows the app, your account and the return address, and offers two grants:

Grant The client may
Allow read-only Read what you can read and run workflows marked read-safe
Allow as me Do anything you can do: claim, resolve, invoke and administer wherever your roles allow

Allow as me appears only when it grants more than read-only. Either way the client acts as you: results are limited to your roles and every action is recorded under your name.

Then ask in plain language:

How many escalations are pending, by role?
Find the escalation where orderId is ord-123 and show its status.
Claim escalation <id> and resolve it as approved.
Diagnose workflow <id>: is it waiting normally or stuck?
URL POST https://<host>/mcp
Transport Streamable HTTP, stateless: one request, one response per call
Auth Authorization: Bearer <token>: an OAuth access token, a service-account key or a signed user token

Access tokens last 5 minutes and refresh silently. The refresh token rotates on each use and lasts 30 days. Every request reads the grant, so a disconnected app, a revoked token or a deactivated account stops on the next call. Disconnect a client under Connected apps in the user menu.

Turn it on with auth.oauthServer in start(), or LT_OAUTH_ISSUER in the environment:

index.ts
await start({
database: { connectionString: process.env.DATABASE_URL },
auth: {
oauthServer: {
issuer: 'https://lt.acme.dev',
allowedRedirectUris: ['https://claude.ai/api/mcp/auth_callback'],
},
},
});

Clients register themselves (RFC 7591). Loopback redirects on any port are always allowed, which covers Claude Code and Claude Desktop. An https redirect must equal an entry in allowedRedirectUris. Authorization responses carry iss (RFC 9207).

A service account connects without a browser. Create one under Accounts > Service Accounts, give it the roles it should act under, and generate a key with a scope. The raw key is shown once. The same is available as tools: create_bot_account, then create_bot_api_key.

List one entry per environment in .mcp.json, with keys read from your shell:

.mcp.json
{
"mcpServers": {
"longtail-local": { "type": "http", "url": "http://localhost:3000/mcp", "headers": { "Authorization": "Bearer ${LONGTAIL_LOCAL_KEY}" } },
"longtail-staging": { "type": "http", "url": "https://staging.acme.dev/mcp", "headers": { "Authorization": "Bearer ${LONGTAIL_STAGING_KEY}" } },
"longtail-prod": { "type": "http", "url": "https://lt.acme.dev/mcp", "headers": { "Authorization": "Bearer ${LONGTAIL_PROD_KEY}" } }
}
}

Each server keeps its tools under its own name, so you choose an environment by naming it: “on production, find orphaned signals”, “reproduce it locally”. Every listed server is live at once, so give production a read key by default.

Two checks decide what a connected agent can do. Both must pass.

Scope decides read or write. A key or grant is mcp:read (list, search, diagnose, export) or mcp:full (also create, claim, resolve, invoke, configure). mcp.exposure.readOnly in start() limits every caller to read-safe tools, and allowServers and denyServers hide whole servers.

Role decides which tools and which records. Each tool declares a gate, the same gate its REST twin uses, and appears only to accounts that hold it:

Gate Held by Covers
Caller Any account Escalations, tasks, workflow invocation, scan codes, docs, reads of users, roles and configuration
Admin Admin or superadmin Workflow configuration, diagnostics, pruning, role assignment
Builder Superadmin or the engineer role Users, bot accounts, knowledge, YAML workflows, agents, topics, MCP servers, file and HTTP tools
Role manager Admin, superadmin or engineer Roles, personas, scan rules, announcements
Superadmin Superadmin The human-queue tools workflows use, other users’ OAuth connections

An account with mcp:full and only the reviewer role resolves reviewer escalations. It does not route work to finance or manage users.

A workflow marked read-safe is invocable by read-scoped callers through invoke_workflow_read_safe. The flag defaults off and fails closed:

index.ts
workers: [
{ taskQueue: 'lookups', workflow: priceLookup, config: { readSafe: true } },
],

A workflow without the flag fails with a clear error when called this way.

The long-tail-human-queue server exposes the escalation queue as MCP tools. An agent routes work to a person the same way it calls any other tool:

Tool Does
escalate_and_wait Creates an escalation and pauses until it is resolved
escalate_to_human Creates an escalation and returns its id
check_resolution Reads whether an escalation is resolved, and its payload
get_available_work Lists pending, unclaimed escalations for a role
claim_and_resolve Claims and resolves in one atomic call
resolve_escalation Resolves an escalation that is already claimed
resolve_batch_item, accumulate_item, remove_item Fill a batch item, add to or remove from an open accumulator

escalate_and_wait takes role, message, and optionally data, form_schema, assigned_to, type, subtype, priority (1 highest, 4 lowest) and schema_version. Setting assigned_to pre-claims the row for one person, which is how a one-time user gets a single-item surface.

claim_and_resolve takes escalation_id, resolver_id, payload (resumes the workflow) and optional metadata, which merges outcome facets into the row where they stay queryable.

These tools act with full authority, so /mcp lists them for superadmins. Workflows and agents inside Long Tail call them directly. An external agent with another role works the queue through the role-checked tools: find_escalations, claim_escalation, admin_resolve_escalation.

Register an MCP server and its tools become proxy activities. Each call is checkpointed: if the process crashes after the tool returns, the replay reads the stored result and the server is not called again.

workflows/classify.ts
import { Durable } from '@hotmeshio/hotmesh';
import { McpClient, type LTEnvelope } from '@hotmeshio/long-tail';
const tools = await McpClient.toolActivities(serverId);
const { mcp_doc_analyzer_classify } = Durable.workflow.proxyActivities<typeof tools>({
activities: tools,
retry: { maximumAttempts: 3 },
});
export async function classifyDocument(envelope: LTEnvelope) {
const result = await mcp_doc_analyzer_classify({ content: envelope.data.content });
if (result.confidence >= 0.85) return { type: 'return', data: result };
return { type: 'escalation', data: result, message: 'Low confidence', role: 'reviewer' };
}

Activity names are mcp_{serverName}_{toolName}, with non-alphanumeric characters replaced by underscores.

Write the server in your app and pass a factory. It connects on first tool call over an in-memory transport and can use your database pool and services.

mcp/image-tools.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { registerMcpTool } from '@hotmeshio/long-tail';
export function createImageToolsServer(): McpServer {
const server = new McpServer({ name: 'image-tools', version: '1.0.0' });
registerMcpTool(server, 'resize_image', 'Resize an image.', {
path: z.string().describe('Path to the image'),
width: z.number().optional(),
}, async (args: any) => ({
content: [{ type: 'text', text: JSON.stringify(await resize(args)) }],
}));
return server;
}
index.ts
await start({
database: { connectionString: process.env.DATABASE_URL },
mcp: { serverFactories: { 'image-tools': createImageToolsServer } },
});

registerMcpTool wraps the SDK’s tool() so TypeScript skips its deep Zod inference. Inputs are still validated at call time. Pass { factory, config } instead of a bare factory to seed the server’s tags and tool manifest into the dashboard at startup.

The dashboard wizard (Servers & Tools > Register Server) collects the same fields: name, transport_type, transport_config, auto_connect, tags, compile_hints and credential_providers. POST /api/mcp/servers/test-connection lists a server’s tools without saving. POST /api/mcp/servers/:id/connect connects and caches the tool list. Registering, testing and connecting take builder access.

Field Use it for
tags Tag-based tool discovery. Use lowercase, hyphenated tags.
compile_hints Ordering, timeout or output guidance for the workflow compiler.
credential_providers Providers a tool needs per user. A missing credential raises MissingCredentialError naming the provider. See OAuth and delegation.
auto_connect Connect at every boot.

One instance calls another’s tools by registering the other’s /mcp as a remote server.

  1. On the remote, create a service account with only the roles the connection needs, and a key with mcp:read or mcp:full.

  2. On the caller, register https://<remote-host>/mcp with transport_type: "streamable-http" and the key in transport_config.headers.

  3. Test, then connect. With auto_connect: true it reconnects at every start.

The remote decides what the connection can do: it lists only the tools that account’s roles allow, applies the key’s scope and its own mcp.exposure, and records every action as that account. The caller decides who may use it: calling an external server’s tools directly is a builder capability. Everyone else reaches the remote through a deployed workflow with its own invocation roles.

Rotate a key by generating a new one on the remote, updating the server’s headers (PUT /api/mcp/servers/:id), then revoking the old key.

Long Tail ships its API as MCP servers. The main ones:

Server Covers
long-tail-admin Escalations, tasks, workflows, agents, users, roles, diagnostics
long-tail-human-queue Create, wait on and resolve escalations from workflows
long-tail-knowledge Persistent JSONB knowledge store
long-tail-events Publish events and browse the topic catalog
long-tail-file-storage Managed file storage
long-tail-http-fetch, long-tail-schema-exchange Outbound HTTP, schema-validated exchange with credential resolution
long-tail-oauth OAuth token management
long-tail-docs Documentation search
long-tail-vision, long-tail-translation, long-tail-claude-code AI tools (need an LLM API key)

Every tool, its gate and its read-safe flag are in the MCP reference.