MCP 2026-07-28 · Streamable HTTP · ADR 0010 / 0011
Same server.
Two placements.
TacLab is not a stdio subprocess. It is POST /mcp with a lab static bearer.
There is no OAuth Protected Resource Metadata. Clients that require PRM will not discover this server.
Full contract: docs/MCP.md.
Local MCP
Client and taclabd share a host, or you SSH-tunnel port 8080. Start the lab from quick start first.
{
"mcpServers": {
"taclab": {
"url": "http://127.0.0.1:8080/mcp",
"headers": {
"Authorization": "Bearer REPLACE_ME",
"MCP-Protocol-Version": "2026-07-28"
}
}
}
}
Works in Claude Desktop / Claude Code, Cursor (.cursor/mcp.json), and VS Code Copilot HTTP servers. Token file after labgen: deployments/compose/secrets/api_admin_token.
If the client only speaks stdio MCP, it cannot attach. TacLab is Streamable HTTP only.
Remote / hosted MCP
Deploy Compose on a lab VM. Terminate HTTPS. Keep custom headers. Do not publish ports 49 and 300 to the internet.
taclab.example.invalid {
reverse_proxy 127.0.0.1:8080
}
nginx must disable buffering and raise proxy_read_timeout so subscriptions/listen survives. Forward Authorization, MCP-Protocol-Version, Mcp-Method, and Mcp-Name.
{
"mcpServers": {
"taclab": {
"url": "https://taclab.example.invalid/mcp",
"headers": {
"Authorization": "Bearer REPLACE_ME",
"MCP-Protocol-Version": "2026-07-28"
}
}
}
}
Set api.mcp.allowed_origins only if a browser origin will call /mcp. Leave require_origin: false for desktop agents. Distribute the bearer out of band.
Wire contract
| Method | POST /mcp only · GET/DELETE → 405 |
| Protocol | MCP-Protocol-Version: 2026-07-28 |
| Auth | Authorization: Bearer · no .well-known/oauth-protected-resource |
| Headers | Mcp-Method · ASCII Mcp-Name on call/read |
| Accept | application/json, text/event-stream |
| Listen | URI-only notify on taclab://events/recent; pull with taclab.events.list |
| SDK | github.com/modelcontextprotocol/go-sdk v1.7.0, stateless JSON |
Agent card
You are operating TacLab via MCP 2026-07-28 Streamable HTTP. Do not look for OAuth PRM. Send Authorization: Bearer. Use tools/list; a missing tool means a missing scope. Mutations need expected_revision. Overlay is memory-only. subscriptions/listen is URI-only — pull events.list. This is a lab, not production AAA.