MCP Endpoint¶
Backend.AI GO can act as an MCP (Model Context Protocol) server: external MCP clients such as Claude Code, Claude Desktop, Codex CLI, and IDE integrations connect to a single HTTP endpoint and call Backend.AI GO's built-in tools (file search, shell and Python execution, web fetch, Data Hub access, and more).
This is the opposite direction from Settings > Tools & extensions > MCP Servers, which connects Backend.AI GO to remote MCP servers as a client. The MCP endpoint makes Backend.AI GO itself the server. It speaks the MCP Streamable HTTP transport, protocol revision 2025-03-26, at:
The port is the Management API server port (default 8001). The MCP Endpoint card always shows the address the server is listening on right now, so copy the URL from there rather than typing it.
Enabling the endpoint¶
The endpoint is off by default. While disabled, /api/v1/mcp answers 404 Not Found, so a stock installation exposes nothing.
- Open API > Management API and turn on Enable MCP endpoint. This also turns on the Management API server that serves the endpoint, if it was off.
- Copy the connection URL shown in the card. The card shows a URL only while the server is actually listening; if the server is off or failed to start (for example, the port is already in use), the card says so instead, and the Management API server card directly above it is where you fix it.
- To change the port, require an API key, or allow access from other devices, use the Management API server card on the same tab.
The Management API server and the MCP endpoint are two separate switches. Turning the MCP endpoint on also turns the server on, because the endpoint cannot work without it. Turning the MCP endpoint off leaves the server running for other clients, and turning the server off under API > Management API leaves the MCP toggle on but shows the endpoint as unreachable until the server is back.
Connecting Claude Code¶
With Require API key on (API > Management API), requests must carry an access key issued under API > Access keys, sent as the X-API-Key header:
claude mcp add --transport http backend-ai-go http://127.0.0.1:8001/api/v1/mcp \
--header "X-API-Key: <your-access-key>"
With Require API key off (the default on a localhost bind), omit the --header flag. The card's Claude Code command already reflects the current setting.
Then verify inside a Claude Code session:
The backend-ai-go server should be listed as connected, with the tool catalog available. Any other MCP client that supports the Streamable HTTP transport works the same way: give it the URL and the X-API-Key header.
Which tools are exposed¶
The endpoint advertises the same built-in tool catalog the app's own agent uses, filtered to what can actually run over this transport:
- Tools that require the desktop app shell (clipboard, notifications, audio transcription, image generation, memory bank, and the model-oriented AppControl tools such as
load_modelorlist_downloads) are not advertised, because they need a running desktop UI process state that the HTTP transport does not carry. - Tools denied by an enterprise tool allow/deny policy are not advertised, and a call to one is rejected. Policy enforcement and audit logging go through the same shared execution service as the REST
POST /api/v1/tools/executepath, so MCP-initiated calls are gated and audited identically. - Autonomous-agent write tools stay advertised when the endpoint itself is reachable, but add call-time scope checks:
send_autonomous_messagerequiresautonomous_message_sendorAdmin, anddecide_hermes_approvalrequirescontainer_writeorAdmin. A missing scope is returned as an audited policy-denied tool result.
A failed tool call (including a policy rejection) is reported as an MCP tool result with isError: true, as the MCP specification requires; JSON-RPC errors are reserved for protocol faults such as an unknown method.
Autonomous-agent tools¶
The seven autonomous-agent tools are advertised over this endpoint and are also callable through POST /api/v1/tools/execute. They use the same provider registry, gateway state, channel service, and Hermes approval service as the REST API.
| Tool | Approval | Extra headless scope | Purpose |
|---|---|---|---|
list_autonomous_providers | none | none | List provider availability, unavailable reasons, capabilities, install state, and gateway status. |
get_autonomous_gateway | none | none | Return the latest cached gateway status for one provider. |
list_autonomous_channels | none | none | List up to 50 messaging channels for one provider. |
list_autonomous_channel_messages | none | none | List recent messages for one provider channel, capped at 50 messages. |
send_autonomous_message | required | autonomous_message_send or Admin | Send a message through one provider channel. |
list_hermes_pending_approvals | none | none | List Hermes governance requests waiting for an operator decision. |
decide_hermes_approval | required | container_write or Admin | Approve or deny one pending Hermes governance request. |
list_autonomous_providers is intentionally useful even on a headless server with no registered provider: it reports the known provider kinds and why they are unavailable. The mutation tools require the MCP client to ask its user before calling them, because the host does not display an interactive approval prompt on this transport.
Squad tools¶
The thirteen squad tools are advertised over this endpoint, so an MCP client connected to aigo-server can inspect and drive squads. They are also callable through POST /api/v1/tools/execute.
| Tool | Approval | Purpose |
|---|---|---|
list_squads | none | List squads with name, description, agent count, and status. |
get_squad | none | One squad's configuration and its agent roster (id, name, role, model). |
list_squad_templates | none | List installed squad templates, built-in and user-created. |
list_squad_tasks | none | A squad's managed tasks, optionally filtered by status. |
get_squad_execution | none | One execution's stage, wave progress, plan tasks, final result, and token usage. |
list_squad_executions | none | Recorded execution history, newest first. |
create_squad | required | Create a squad, optionally seeded from a template. |
submit_squad_request | required | Submit a request, creating an execution. |
approve_squad_plan | required | Approve a plan that is awaiting approval and start the run, the same on the desktop and on a headless server. |
reject_squad_plan | required | Reject a plan. The feedback goes to the planner, which re-plans the same execution; the corrected plan is left waiting for approval and the result reports its task and wave counts. |
cancel_squad_execution | required | Cancel an execution that has not finished. |
steer_squad_execution | required | Send a standing instruction to a running, paused, or unapproved execution. |
send_squad_agent_message | required | Send a message to one agent and run its turn. |
Both run the same work on a headless server as on the desktop since issue #4954: submit_squad_request runs the planner and, with autoApprove, starts the executor, and approve_squad_plan starts the executor for a plan that was waiting. Each result still reports what happened rather than leaving it to be assumed, as plannerStarted and executorStarted. plannerStarted answers whether a planner actually decomposed the request, not whether the runtime called the submission path: run_planner_decomposition degrades to a one-task-per-agent split when the router is down, the planner agent has no usable model, or the planner reply creates no task, and a submission that landed on that split reports plannerStarted: false with plannerDegradedReason naming the cause (issue #4966). The reason stays on the execution, so get_squad_execution carries it on every later poll as well. A squad task's own tool calls go through the same capability and policy gates as POST /tools/execute, so a tool that needs the desktop app is refused with the reason the catalog gives.
Every state-changing tool in that table carries requires_approval: true. An MCP client is responsible for asking its user before calling one; the host does not prompt on this transport.
Protocol details¶
- Supported methods:
initialize,notifications/initialized,tools/list,tools/call, andping. initializeassigns anMcp-Session-Idheader that clients must send on every later request. Sessions expire after an idle timeout (default 1 hour) and are capped in number (default 10). At the cap a newinitializeevicts the least recently used session rather than failing, so a client that restarts without sendingDELETEnever locks itself out. An expired, evicted, or unknown session id answers404, telling the client to re-initialize.DELETE /api/v1/mcpwith the session id header terminates a session explicitly.GET /api/v1/mcpanswers405 Method Not Allowed: this server responds with plain JSON per request and does not offer the optional server-to-client SSE stream.- JSON-RPC batch requests (a top-level array) are rejected with a single JSON-RPC error.
- The
resources,prompts, andsamplingcapabilities are not offered; the endpoint advertises tools only.
Security notes¶
- Anyone who can reach the endpoint can run tools, including shell and Python execution. Keep access keys secret and treat them like a shell credential.
- Default binding is localhost. The Management API binds
127.0.0.1by default, so only processes on the same machine can reach the endpoint. With the default Require API key off, every local process can call it; turn the key requirement on under API > Management API if that is not acceptable on your machine. - No unauthenticated network exposure. The desktop app refuses to start the Management API on a non-localhost address (such as
0.0.0.0) unless Require API key is on. The Allow access from other devices switch stays disabled until the key requirement is enabled, and a hand-editedsettings.jsonthat combines the two is reported as a start failure rather than served. - Requests carrying a browser
Originheader from a non-localhost origin are rejected, which blunts DNS-rebinding attacks against the localhost binding. - Loopback host guard. While the Management API is bound to a loopback address, it rejects any request whose
Hostheader is not a loopback host, and any request carrying a non-loopbackOriginthat is not listed in the configured CORS allowed origins. This is what stops a web page from reaching the local server after rebinding its own domain to127.0.0.1. The guard covers every route, not just the MCP endpoint, and is off when the server is bound to a non-loopback address, where authentication is required instead. - A
POSTmust carryContent-Type: application/json, the media type the Streamable HTTP spec has clients send. Any other type is refused with415 Unsupported Media Type. This is what stops a web page served from some other port on the same machine from driving a tool call: the content types a browser may send cross-origin without a preflight are exactly the ones the endpoint refuses. - Turning the toggle off immediately hides the endpoint again (
404), with no restart needed.