MCP server
AICODEBOX_MCP_MODE=1 exposes the agent as a Model Context Protocol server over streamable HTTP, so an MCP client can hand it prompts and read or write workspace files. It runs beside any foreground mode. The code is aicodebox/modes/api/mcp_server.py.
Where it listens
| Foreground mode | URL |
|---|---|
| API | http://<host>:8080/mcp/ (/mcp works too), on the API port and in the API process. |
| Telegram, cron or passthrough | http://<host>:8081/, a separate process on AICODEBOX_MCP_MODE_PORT. |
Authentication
Set AICODEBOX_MCP_MODE_TOKEN and send it as Authorization: Bearer <token>. Clients that cannot set headers can append ?apiToken=<token> to the URL. A wrong or missing token gives 401 {"detail":"unauthorized"}. With the variable empty or unset, MCP has no auth.
The MCP token is separate from AICODEBOX_API_MODE_TOKEN. There is no fallback between them: an API token does not open MCP, and an empty MCP token leaves MCP open even when the API has a token.
Host and origin checks
MCP keeps the SDK’s DNS rebinding protection on. By default it accepts only loopback Host values (127.0.0.1, localhost, [::1], with any port) and loopback http origins. A request with another Host gets 421, one with another Origin gets 403.
Behind a reverse proxy, a tunnel or a public DNS name, list exactly what it forwards:
docker run --rm -p 8080:8080 \
-e AICODEBOX_API_MODE=1 \
-e AICODEBOX_MCP_MODE=1 \
-e AICODEBOX_MCP_MODE_TOKEN="$MCP_TOKEN" \
-e AICODEBOX_AVAILABLE_MODELS=model-a \
-e AICODEBOX_MCP_MODE_ALLOWED_HOSTS=agent.example.com \
-e AICODEBOX_MCP_MODE_ALLOWED_ORIGINS=https://agent.example.com \
your/child-image:latest
Both variables are comma-separated and replace the defaults. A value may end in :* to allow any port. Setting either one to an empty string is an error, so leave it unset to keep the default. Do not turn the protection off or use broad wildcards on an endpoint that faces the internet.
Tools
| Tool | Arguments | Returns |
|---|---|---|
run_prompt | prompt, and optional workspace, model, system_prompt, append_system_prompt, no_continue (default true), resume, thinking, json_schema | The agent’s final text, or with json_schema the validated JSON. |
list_files | path (default root) | JSON {"path", "entries": [{"name", "type"}]}. |
read_file | path | The file as text, with undecodable bytes replaced. |
write_file | path, content | Overwrites or creates the file and its parents. JSON {"status": "ok", "path", "size"}, where size counts characters. |
delete_file | path | JSON {"status": "ok", "path"}. Refuses directories. |
Paths are relative to AICODEBOX_WORKSPACE. A path that resolves outside it returns an error result instead of touching the file.
run_prompt takes the per-workspace lock that /run and the OpenAI endpoint share. When the workspace is busy with another run, the tool returns an error result instead of starting the agent. The standalone MCP process has its own lock, so there it only keeps MCP runs apart.
With json_schema, run_prompt validates the answer and retries like /run, with a fresh session for each retry. It returns the parsed JSON, or an error result naming the validation error when every attempt fails.
Client setup
Point the client at the URL from the table above, with the token in a header:
{
"mcpServers": {
"aicodebox": {
"type": "http",
"url": "http://localhost:8080/mcp/",
"headers": {
"Authorization": "Bearer your-mcp-token"
}
}
}
}
The exact file and keys depend on the client.