Skip to content
Hoody.com

Model Context Protocol servers bring third-party tools into a session; their tools surface to the model as mcp__* — the server name and the tool name joined by double underscores. These endpoints are the config plane for them — the same surface the TUI’s Agents ▸ MCP servers mode drives. Servers are stored under mcp_servers in a settings layer, and every call is resolved against a live session_id, because the effective config is the merge of the layers that session was opened with.

mcp_servers is a security-load-bearing settings key, so PATCH /api/v1/agent/settings refuses it (403 settings_key_protected) — the key decides which binary the daemon executes. These routes are the dedicated, narrow surface that writes it instead.


Returns the effective merged mcp_servers config for a live session, the per-layer settings files behind it, and the live runtime state of each server: whether it is connected, the protocol revision it negotiated, its tool count, the pid of a stdio child, why it was revoked, and the tail of its stderr. Credential values are never returned — env and headers come back as key names only, because a redacted value invites a client to write the placeholder back as the real secret. Each file entry carries the content hash to pass as expect_hash on a write.

NameInTypeRequiredDescription
session_idquerystringNoLive session id. MCP config is resolved against the session’s settings layers; the daemon RPC requires it.
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
{
"status": "ok",
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
},
{
"name": "sentry",
"transport": "streamable",
"url": "https://mcp.sentry.dev/mcp",
"env_keys": [],
"header_keys": ["Authorization"],
"allowed_tools": ["search_issues", "search_events"],
"enabled": false,
"require_confirmation": false,
"scope": "project",
"connected": false
}
],
"files": [
{ "scope": "user", "path": "/home/you/.hoody/settings.json", "exists": true, "hash": "sha256:7c1f…" },
{ "scope": "project", "path": "/workspace/.hoody/settings.json", "exists": true, "hash": "sha256:a90b…" },
{ "scope": "local", "path": "/workspace/.hoody/settings.local.json", "exists": false, "hash": "sha256:e3b0…" }
],
"warnings": []
}
Terminal window
curl -X GET "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/servers?session_id=sess_8f2c1a" \
-H "Authorization: Bearer <token>"

Mints the single-use nonce every MCP write requires (mcp.begin_write) and returns the target settings path plus its current mcp_servers hash. The nonce binds {session, op, resolved path}: a write presenting a nonce minted for a different op or scope fails closed. Pass the returned hash back as expect_hash so a concurrent edit is reported as a conflict rather than silently overwritten.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id (MCP config is resolved against the session’s settings layers).
opstringYesWhich write the nonce authorizes. The minted nonce is valid for this op alone. One of upsert, delete, set_enabled, import.
scopestringNoSettings layer to write. Defaults to user, or project when there is no user layer (which is the case under —config-dir). One of user, project, local.
{
"status": "ok",
"nonce": "3f8c1d0e5a7b4926",
"path": "/home/you/.hoody/settings.json",
"hash": "sha256:7c1f…"
}
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/write-intents" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"op": "upsert",
"scope": "user"
}'

Creates or updates one mcp_servers entry (mcp.upsert), merging field by field over any existing entry of the same name — fields you omit keep their stored value, including fields this build does not model. Requires the begin-write nonce minted for op:upsert. A body carrying the redaction placeholder in place of a credential is refused rather than stored. On success a re-pointed server is revoked in every live session before the response returns, and the new config is connected in the session you named before the response returns — so the tools you just added are usable the moment this call comes back. Other live sessions reconnect in the background, so this call never waits out an unrelated session’s slow server. That background pass is best-effort: under sustained write pressure it is skipped, and those sessions pick the change up on the next write or an explicit POST /api/v1/agent/mcp/reconnect. Revocation is never best-effort.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
noncestringYesSingle-use nonce from beginMCPWrite minted for op:upsert and this scope; the RPC fails closed without it.
scopestringNoSettings layer to write. Must match the scope the nonce was minted for. One of user, project, local.
expect_hashstringYesThe mcp_servers hash you last read, as returned by beginMCPWrite or listMCPServers. REQUIRED: a mismatch returns a conflict instead of overwriting a concurrent edit, and a first write into a file that does not exist yet states its expectation with the empty-array hash rather than omitting this.
serverobjectYesThe server entry: name (letters, digits, _ and -; no __, and neither hoody nor mcp), type (stdio, http/url or sse), command+args for stdio or url for the HTTP transports, optional env/headers whose values support full ${VAR} expansion, allowed_tools, require_confirmation and enabled.
{
"status": "ok",
"sessions": 2,
"revoked": 0,
"deferred_sessions": 1,
"deferred_started": true,
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
}
],
"path": "/home/you/.hoody/settings.json",
"hash": "sha256:7c1f…"
}
Terminal window
curl -X PUT "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/servers" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"nonce": "mcpw_a9b8c7d6e5f40392",
"scope": "user",
"expect_hash": "9f2b1c7ae4d05836bb1f0a2d3e4c5b6a7d8e9f00112233445566778899aabbcc",
"server": {
"name": "github",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}'

Removes one mcp_servers entry (mcp.delete) from the named settings layer. Requires the begin-write nonce minted for op:delete. The server is revoked in every live session before the response returns, so a caller mid-turn cannot still reach it; a stdio child is reaped once its last holder releases.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
noncestringYesSingle-use nonce from beginMCPWrite minted for op:delete and this scope.
scopestringNoSettings layer to write. Must match the scope the nonce was minted for. One of user, project, local.
namestringYesThe server name to remove.
expect_hashstringYesThe mcp_servers hash you last read.
{
"status": "ok",
"sessions": 2,
"revoked": 0,
"deferred_sessions": 1,
"deferred_started": true,
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
}
],
"path": "/home/you/.hoody/settings.json",
"hash": "sha256:7c1f…"
}
Terminal window
curl -X DELETE "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/servers" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"nonce": "mcpw_1b2c3d4e5f607182",
"scope": "user",
"name": "github",
"expect_hash": "4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b"
}'

Flips one entry’s enabled flag (mcp.set_enabled) without touching the rest of its config, so credentials and options survive a disable. Requires the begin-write nonce minted for op:set_enabled. Disabling revokes the server in live sessions immediately; a disabled server keeps its config but is neither connected nor advertised.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
noncestringYesSingle-use nonce from beginMCPWrite minted for op:set_enabled and this scope.
scopestringNoSettings layer to write. Must match the scope the nonce was minted for. One of user, project, local.
namestringYesThe server name.
enabledbooleanYestrue to enable, false to disable.
expect_hashstringYesThe mcp_servers hash you last read.
{
"status": "ok",
"sessions": 2,
"revoked": 0,
"deferred_sessions": 1,
"deferred_started": true,
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
}
],
"path": "/home/you/.hoody/settings.json",
"hash": "sha256:7c1f…"
}
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/servers/enable" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"nonce": "mcpw_2c3d4e5f60718293",
"scope": "project",
"name": "internal-api",
"enabled": true,
"expect_hash": "1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809"
}'

Imports a batch of servers (mcp.import) from a pasted config document or an explicit array. Three dialects are understood — hoody’s own mcp_servers list, the Claude/Cursor mcpServers map, and the VS Code servers map — and a document carrying more than one of them is refused rather than guessed at. Validation is whole-batch: one bad entry aborts everything, because a partial import leaves a config the operator did not author. Imported servers land disabled for review; turn them on with setMCPServerEnabled. Requires the begin-write nonce minted for op:import.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
noncestringYesSingle-use nonce from beginMCPWrite minted for op:import and this scope.
scopestringNoSettings layer to write. Must match the scope the nonce was minted for. One of user, project, local.
documentstringNoA pasted config document in any supported dialect. Mutually exclusive with servers.
serversarrayNoExplicit server entries, in hoody’s own shape. Mutually exclusive with document.
replacebooleanNoOverwrite entries whose name already exists. Without it, a collision aborts the whole import.
expect_hashstringYesThe mcp_servers hash you last read.
{
"status": "ok",
"sessions": 2,
"revoked": 0,
"deferred_sessions": 1,
"deferred_started": true,
"imported": 3,
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
}
],
"path": "/home/you/.hoody/settings.json",
"hash": "sha256:7c1f…"
}
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/import" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"nonce": "mcpw_3d4e5f6071829304",
"scope": "user",
"document": "{\"mcpServers\":{\"filesystem\":{\"command\":\"npx\",\"args\":[\"-y\",\"@modelcontextprotocol/server-filesystem\",\"/workspace\"]}}}",
"expect_hash": "9f2b1c7ae4d05836bb1f0a2d3e4c5b6a7d8e9f00112233445566778899aabbcc"
}'

Parses a pasted config document into the entries an import would write, without touching any file (mcp.parse). Credential values are stripped from the preview. Use it to show someone what they are about to import; it needs no nonce because it writes nothing.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
documentstringYesA config document in any supported dialect.
{
"status": "ok",
"dialect": "claude",
"servers": [
{
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
"env_keys": [],
"headers_keys": [],
"enabled": false
}
],
"count": 1
}
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/parse" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"document": "{\"mcpServers\":{ \u2026 }}"
}'

Connects to a candidate server config, reports the tools it advertises and the protocol revision it negotiated, then tears the connection down (mcp.probe). Nothing is written. This route is human-only: probing starts a process (stdio) or makes an outbound request to a caller-chosen URL (http/sse), so a machine caller may not self-approve it and receives 403 human_only. The deny list is enforced against the candidate config before anything is started.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id (supplies the deny list and transport policy).
serverobjectYesThe candidate entry, same shape as the server field on upsertMCPServer.
{
"code": "bad_request",
"message": "invalid request"
}
Error CodeTitleDescriptionResolution
bad_requestBad requestThe request was malformed or carried invalid parameters.Correct the request body or query parameters.
realm_scope_unsupportedRealm scope unsupportedA per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope.Omit the realm header on this route, or open a session to scope by realm.
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/probe" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a",
"server": {
"name": "github",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
]
}
}'

Re-reads the settings layers and reconciles every live session’s MCP pool (mcp.reconnect): servers that vanished or were re-pointed are revoked, the rest are reconnected, and a healthy unchanged server is not restarted. Revocation lands in every live session before the response returns; reconnection is awaited only for the session you named, and other sessions reconnect in the background, best-effort. Use it after editing a settings file by hand, or to recover a server that died.

NameInTypeRequiredDescription
realmquerystringNoPer-request realm selector — alias of X-Hoody-Realm (read only when the header is absent): "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
session_idstringYesLive session id.
{
"status": "ok",
"sessions": 2,
"revoked": 0,
"deferred_sessions": 1,
"deferred_started": true,
"servers": [
{
"name": "github",
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
"env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
"header_keys": [],
"enabled": true,
"require_confirmation": false,
"scope": "user",
"connected": true,
"protocol_version": "2026-07-28",
"server_name": "github-mcp-server",
"server_version": "0.19.0",
"tool_count": 42,
"pid": 5821
}
]
}
Terminal window
curl -X POST "https://abc123-def456-agent-1.us-east-1.containers.hoody.icu/api/v1/agent/mcp/reconnect" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_8f2c1a"
}'