Commit:
39e0fa5eb3b04f8729bbdb656298a09887bda196Source updated: · Edit this page
Agents and MCP¶
Agent principals, permissions, and the authenticated Model Context Protocol surface.
Agents¶
Agents are first-class principals rather than shared API tokens. An installation
administrator can register, inspect, and revoke them in the Automation
panel or register one with POST /api/v1/agents:
curl -H 'Content-Type: application/json' \
-d '{"name":"triage","display_name":"Triage","description":"Investigates alerts"}' \
https://tintwire.example.com/api/v1/agents
Agent administration requires an authenticated installation administrator, so
reader authentication must be enabled. Registration returns the agent's access
token exactly once; only its SHA-256
hash is retained, and later reads never expose it. Each agent gets its own
principal user named agent-<name>, so channel access is granted with the same
PUT /api/v1/channels/{id}/members/{username} endpoint used for people. An
agent has no implicit access to any channel, including public ones: publishing
requires an explicit operator or channel_admin membership, or an agent
registered with "is_admin": true.
Agent access tokens are a separate credential class from reader sessions,
channel publishing tokens, and Mattermost bot tokens, and are never accepted as
browser session credentials. GET /api/v1/agents lists the directory with
ownership, channel grants, and last credential use.
POST /api/v1/agents/{name}/revoke disables the agent, revokes its credentials,
and cancels its open runs without affecting its owner's session or any other
agent.
Work is recorded as durable runs. A run holds its initiator, stated purpose,
lifecycle state, and the externally visible effects it produced; model
reasoning, prompts, and hidden context are not stored. Administrators read run
history with GET /api/v1/agents/{name}/runs and per-run effects with
GET /api/v1/agents/runs/{id}/events. Notifications an agent publishes are
attributed to both the agent and its run, and the inbox API returns the agent
name in the notification's agent field.
Model Context Protocol¶
Agents reach Tintwire through a remote MCP endpoint at POST /mcp, using the
sessionless Streamable HTTP transport. The deprecated HTTP+SSE transport is not
offered, and batched JSON-RPC requests are rejected. The endpoint speaks
protocol version 2026-07-28 and also accepts 2025-11-25 and 2025-06-18;
an unsupported MCP-Protocol-Version header is refused.
Authentication is the agent's own access token as a bearer credential. Reader session cookies are never accepted, and the endpoint calls the same store authorization used by the HTTP API rather than a second privileged path:
curl -H "Authorization: Bearer $TINTWIRE_AGENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
https://tintwire.example.com/mcp
Tool names are versioned: channels.list.v1, messages.list.v1,
messages.get.v1, messages.publish.v1, notifications.search.v1,
notifications.get.v1, notifications.publish.v1,
notifications.set_state.v1, notifications.invoke_action.v1,
runs.start.v1, runs.record.v1, runs.finish.v1, and, for
installation-administrator agents only, channels.create.v1.
messages.list.v1 is a chronological, cursor-based feed of human-authored
messages only; it excludes every agent principal and generated timeline entry
to prevent relay feedback loops. messages.publish.v1 creates an attributed
ordinary message or threaded reply and requires an explicit operator or
channel_admin grant. Every mutating tool requires a stable idempotency_key:
a repeat of the same call replays the first result without repeating the effect,
and reusing a key with different arguments is rejected as a conflict. A replayed
channels.create.v1 result never repeats the publishing token. Tool traffic is
rate limited per agent and per agent and tool.
Read tools return canonical IDs, state, and sanitized presentation text so
agents do not scrape rendered markup; raw compatibility payloads and stored
action credentials are never exposed. Read-only resources are published at
tintwire://channels, tintwire://channels/{name},
tintwire://notifications/{id}, and tintwire://notifications/{id}/activity.
Notification content, attachment text, and activity history are untrusted producer data. The server states this in its MCP instructions, and enforces authorization, idempotency, and state-transition policy itself: tool descriptions and client annotations are never treated as a security boundary.
MCP action invocation uses the same registered-target lookup, channel-operator
authorization, encrypted context, SSRF protection, and durable idempotency path
as the web client. RFC 9728 protected-resource metadata is published at the
standard well-known location and linked from bearer challenges when
TINTWIRE_PUBLIC_URL is configured. Tintwire can validate Pocket ID API access
tokens through OIDC discovery and its rotating JWKS. Configure
TINTWIRE_OAUTH_ISSUER; the default resource is
$TINTWIRE_PUBLIC_URL/mcp and the default required permission is
tintwire:mcp. Validation requires a valid signature, exact issuer, expiry,
that resource in aud, the permission in scope, and a subject mapped to an
enabled Tintwire agent. Existing twa_ agent tokens remain supported.
In your OIDC provider, create an API whose immutable resource is
https://tintwire.example.com/mcp, add the tintwire:mcp permission, and grant
the relevant client user-delegated or client-credentials access. Add the
resulting token subject when registering the corresponding agent:
{
"name": "automation",
"display_name": "Automation",
"oauth_subject": "client-tintwire-automation"
}
Pocket ID client-credentials tokens use client-<client-id> as their subject;
user-delegated tokens use the user's subject. OAuth changes only how the agent
authenticates—the mapped agent principal still supplies all channel membership,
operator, and administrator authorization. ID tokens are never accepted at
/mcp.
For a Switchboard gateway that authenticates users at its own MCP resource,
set TINTWIRE_SWITCHBOARD_OAUTH_SUBJECT to the exact subject of Switchboard's
Tintwire-audience client-credentials token. Tintwire will then accept
X-Switchboard-OAuth-Subject only with that service token and resolve the
header to an existing enabled agent. Unknown subjects fail closed. Agent tokens
and other OAuth subjects cannot delegate, and the gateway receives no authority
to register agents or change channel grants. Restrict the upstream route to the
gateway network as an additional boundary.
The verifier uses coreos/go-oidc for discovery, signature verification, and
key rotation. Tintwire's MCP endpoint is a resource server and validates access
token audience and permissions.
For interactive browser sign-in, create a separate public PKCE client with
https://tintwire.example.com/api/v1/auth/oidc/callback as its callback and
https://tintwire.example.com/ as its launch URL. Set
TINTWIRE_OIDC_CLIENT_ID to that client's ID; no client secret is used. The
interactive relying-party flow is provided by github.com/kilo666mj/oidcrp;
Tintwire continues to own local account provisioning, replicated desktop
approval state, and application sessions.