What travels through the door
The capabilities, not the assistant.
The client already has a model, so we export no persona, no knowledge, no memory, and none of the built-in primitives. Nothing about your agent’s character crosses over.
The URL
Paste that URL into any client that speaks Streamable HTTP. For Cursor:
headers block. The client discovers how to authenticate from our 401.
Turning it on
Two things, both of which you may already have:1
Publish the agent
Publishing mints the public id, and the MCP URL exists from that moment. The dashboard shows it on the published agent with a paste-ready snippet.
2
Give its connection a login URL
Set MCP login URL on the connection the agent uses. That is your login bridge — the one page you host, which authenticates your user and hands us back a signed subject.
404 and authorization is refused. Identity is the whole requirement — there is no MCP infrastructure for you to stand up.
The login URL lives on the connection, not the agent. Two agents pointing at different connections can serve different user pools; agents on the same connection share one.
Who the user is
You own identity. We run the OAuth machinery. Patchwork is both the resource server that hosts the MCP URL and the authorization server the client talks to. We never see your users’ credentials, and we never invent a user — the one step only you can do, proving who someone is, is the one step we hand back to you.Discovery endpoints
A client follows these on its own; they are listed so you can see what it will touch.Two consents, cleanly split
- Which tenant am I, and may I be here at all — your bridge, your policy, baked into the subject.
- May this client act as me on this agent — our consent screen, which records the grant.
What exports
tools/list is the agent’s wired tools, filtered, with each one projected like this:
Tools come back sorted by key. Any
@ mention in a title or description is rewritten to a plain label first, so the client’s model is never told to load knowledge it cannot reach or to call a tool absent from its own list.
A tool is exported only if all of these hold:
Writes export, but only deliberately
A write is exported the same as a read, and it really runs — as the user, against your backend, under your own authorization. What stops a write from leaking out is the permission on the wiring. Because risk can depend on arguments, a tool can pass the catalog filter and still escalate on a particular call. That call is refused withconfirmation_required rather than run without a confirmation nobody can give.
Choosing a connection
A client that can send headers may name one per call:Every call is a run
Atools/call opens a run, dispatches the tool, and closes it. The conversation stayed in the client, so the run has no model turn — but everything else is the same spine you already read:
sourceismcpon the run, and the dashboard badges it so it does not read as a broken chat.- The tool call is recorded with redacted arguments and result, risk, and timing, and
GET /v1/loom/runs/:id/tracereads back as usual. - Events carry
origin: "mcp", and a webhook endpoint can subscribe to that origin alone. - The subject on the run is the one your bridge asserted, so you can answer “what did this user do from their own client” without a second log.
GET /v1/loom/threads so your chat history stays chat history — read the runs instead.
Managing access
The grant lives with us, which is what makes revocation immediate. List and revoke with your workspace API key:Scopes
Consent asks forread and write, and the granted scopes are recorded on the grant for you to read back.
The exported catalog does not currently narrow with the scope. What a client can call is set by the agent’s wiring — the permission and risk filters above — not by what it asked for at consent. Wire the agent to the smallest set you want reachable.
Errors
Errors split cleanly in two. Anything about the door is an HTTP status, because the client has to do something about it:
Anything about a tool comes back as a normal MCP result with
isError: true and the code inside, so the client keeps its session and can try something else:
Either way the trace holds the real detail — the arguments, the egress request, and the failure — which is where to look rather than at what the client printed.
What is not supported yet
- Elicitation and confirmation. Hence no Always ask tools, and no
proposed_actionor handoff patches, which assume your frontend. - Refresh tokens. An access token lasts an hour; after that the client runs the authorization flow again.
- API keys on this door. OAuth only — there is no paste-a-key path.
- Custom domains. The URL is on our host.
- Several connections per exported agent. One agent, one connection.
- Prompts, resources, subscriptions, and server-pushed catalog changes.