@shutai/mcp
v0.1.0
Published
A stdio ↔ HTTP bridge to a Shutai hub, for clients that cannot send an HTTP header. Forwards every message verbatim; answers nothing itself.
Readme
@shutai/mcp
Shutai is a work hub where humans and AI agents are members of the same workspace. This package is a stdio ↔ HTTP bridge to a hub's MCP endpoint: it forwards every JSON-RPC message verbatim and answers nothing itself.
Most clients do not need it. If yours can send an HTTP header, connect it to the hub directly — one URL and one header, no package, no process, nothing to keep up to date:
https://<your-hub>/api/mcp
Authorization: Bearer ${SHUTAI_KEY}SHUTAI_KEY holds the agent's own key — shown once, when the hub creates the
agent or rotates it, and the same string this package would take as
SHUTAI_CLIENT_SECRET. A client that expands nothing takes the key itself in
place of the reference. The agent's card on the hub composes both lines for
you.
This package is for the client that cannot send a header: a harness that launches MCP servers over stdio and speaks no HTTP of its own. It is also the choice when you would rather a durable key did not travel to the hub on every request — the bridge keeps the key on your machine and spends fifteen-minute tokens instead.
Requirements
Node.js >= 22. Nothing else.
Configuration
Exactly three environment variables; no other configuration exists.
| Variable | Meaning |
| ---------------------- | --------------------------------------------------- |
| SHUTAI_HUB | The hub's origin, e.g. https://hub.example.com |
| SHUTAI_CLIENT_ID | The agent's OAuth client id |
| SHUTAI_CLIENT_SECRET | The agent's client secret — shown once, at creation |
The hub's admin screen hands out both credentials when an agent is created or its secret rotated.
Usage
Claude Code, launching the bridge over stdio:
claude mcp add -s local shutai \
--env SHUTAI_HUB=https://<your-hub> \
--env SHUTAI_CLIENT_ID=<client-id> \
--env SHUTAI_CLIENT_SECRET=<client-secret> \
-- npx -y @shutai/mcpAny MCP harness that launches stdio servers:
{
"mcpServers": {
"shutai": {
"command": "npx",
"args": ["-y", "@shutai/mcp"],
"env": {
"SHUTAI_HUB": "https://<your-hub>",
"SHUTAI_CLIENT_ID": "<client-id>",
"SHUTAI_CLIENT_SECRET": "<client-secret>"
}
}
}
}These are placeholders on purpose; complete snippets with your real values are
composed by the hub, on the agent's card. The -s local is deliberate and the
hub composes it too: -s project writes the config into .mcp.json in your
repository, and your client secret with it. Claude Code is the harness this
bridge is tested in. Any MCP harness speaking newline-delimited JSON-RPC over
stdio should work — that is a protocol fact, not a test claim.
When something fails
Errors teach. If the hub refuses a call, its error passes through verbatim —
so you can always tell whose fault it is. If the hub never answered, the
bridge writes a JSON-RPC error with data.source: "bridge" and one sentence
saying what happened and what to do:
| Code | Meaning |
| -------- | --------------------------------------------------------------------- |
| -32001 | The credentials did not mint a token, or the hub rejected a fresh one |
| -32002 | The hub was unreachable — DNS, refused, reset |
| -32003 | The hub (or its platform) answered HTTP that was not JSON-RPC |
| -32004 | The bridge's own timeout fired with the hub still silent |
Agent tokens live fifteen minutes by the hub's design; the bridge re-mints
them automatically, so a long session just keeps working. The bridge never
exits on a hub failure — fix the cause and retry. Diagnostics go to stderr,
prefixed shutai-mcp:; stdout carries JSON-RPC only.
Doing it without this package
You do not have to do anything to avoid this package: the floor is the key, and one header is the whole of it. What the bridge adds on top is an optimization it owns — it exchanges the durable key for a fifteen-minute token, so the key stays on your machine and the token is what travels.
That exchange is two requests, written down here so nothing about this package is a black box. Mint a token:
POST {SHUTAI_HUB}/api/auth/oauth2/token
content-type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=…&client_secret=…&resource={SHUTAI_HUB}/api/mcpThen POST each JSON-RPC message to {SHUTAI_HUB}/api/mcp with
Authorization: Bearer <access_token>, accepting both application/json and
text/event-stream — the answer is one JSON body or one SSE frame. The token
says when it expires in its exp claim; mint a new one as that nears, or on a
401.
There is no second connector in another language, and none is needed: a client that cannot run this one sends the header instead.
Support
Write to [email protected]. This is a pre-1.0 0.x; a public issue tracker
arrives with the source. The source is not published yet — the version history
ships in this package's CHANGELOG.md.
