Motivation
Magec already consumes external MCP servers (Home Assistant, GitHub, filesystem, etc.) as agent toolsets. What is missing is the inverse direction: exposing Magec's own admin API as MCP tools so any spec-compliant MCP client (Claude Code, Cursor, mcp-cli, etc.) can manage the instance from an editor or shell, without writing a custom REST wrapper.
Use cases:
- Operators describing changes in natural language and letting their assistant invoke the right tool (
magec_create_backend, magec_link_agent_mcp, etc.) instead of remembering REST paths.
- Reproducible setup scripts that drive the admin API through the same protocol the rest of the agent ecosystem already uses.
- Lower friction for new contributors: same authentication, same schemas, same Magec instance.
Proposed scope
Embed an MCP server inside magec-server on its own port (default 8082, opt-in via server.mcp.enabled). Transport: Streamable HTTP, the only transport that carries a bearer header, which is what every CLI MCP client supports.
Authentication reuses server.adminPassword as a bearer token. Same constant-time compare and per-IP rate limiter as the admin REST API. Without a password, both surfaces behave consistently (open with a startup WARN).
Tools call *store.Store directly. No HTTP roundtrip back to the admin port, following the spirit of the existing decision that the admin UI never reaches the user API.
Approximate catalogue (~61 tools, snake_case, magec_ prefix): full CRUD for backends, memory providers, MCP servers, agents (with link/unlink MCP), clients (with token regeneration), commands, flows (sharing ValidateFlowStep with admin REST), secrets (value never returned, mirroring admin), settings, conversations (incl. session reset), plus type catalogues for clients, memory and voice providers.
Out of scope for the first cut: skill upload/download and backup/restore, because they stream binary archives that do not map cleanly to MCP tool inputs and outputs. Both stay on admin REST as the single source of truth.
Why this design
- Same binary, separate port keeps the SSE/long-poll write-timeout independent from admin REST's short write-timeout, and lets operators expose the MCP port through a different firewall rule.
- Store-direct calls avoid duplicating the admin REST contract or coupling the MCP layer to HTTP semantics. Hot reload also propagates without extra wiring.
- Tools-only keeps every CLI client compatible. No resources/prompts unless a concrete operator need appears.
- Reuse the admin password keeps both surfaces in lockstep. One credential, one trust level.
Compatibility
Adds a new Server.MCP block in config.yaml (default disabled). No behavioural change to existing setups that do not opt in. The only schema-level change is omitempty on a handful of server-assigned fields (id, client token) in the store types so the MCP SDK's reflection does not mark them as required on create_* inputs. JSON wire shape on responses is unaffected because those fields are always populated at write time.
Open questions
- Whether to add MCP resources (e.g. live subscription to store changes) once an operator workflow asks for it.
- Whether per-IP rate limiting should be looser on the MCP port given that some clients may legitimately batch tool calls.
- CORS surface (
Mcp-Session-Id, Last-Event-ID) is already covered by the project-wide Access-Control-Allow-Headers: *, but worth a second look during review.
Pull request
I have a working implementation with tests and public docs ready in a PR. Happy to iterate on naming, scope and any architectural concerns before merge.
Motivation
Magec already consumes external MCP servers (Home Assistant, GitHub, filesystem, etc.) as agent toolsets. What is missing is the inverse direction: exposing Magec's own admin API as MCP tools so any spec-compliant MCP client (Claude Code, Cursor, mcp-cli, etc.) can manage the instance from an editor or shell, without writing a custom REST wrapper.
Use cases:
magec_create_backend,magec_link_agent_mcp, etc.) instead of remembering REST paths.Proposed scope
Embed an MCP server inside
magec-serveron its own port (default8082, opt-in viaserver.mcp.enabled). Transport: Streamable HTTP, the only transport that carries a bearer header, which is what every CLI MCP client supports.Authentication reuses
server.adminPasswordas a bearer token. Same constant-time compare and per-IP rate limiter as the admin REST API. Without a password, both surfaces behave consistently (open with a startup WARN).Tools call
*store.Storedirectly. No HTTP roundtrip back to the admin port, following the spirit of the existing decision that the admin UI never reaches the user API.Approximate catalogue (~61 tools, snake_case,
magec_prefix): full CRUD for backends, memory providers, MCP servers, agents (with link/unlink MCP), clients (with token regeneration), commands, flows (sharingValidateFlowStepwith admin REST), secrets (value never returned, mirroring admin), settings, conversations (incl. session reset), plus type catalogues for clients, memory and voice providers.Out of scope for the first cut: skill upload/download and backup/restore, because they stream binary archives that do not map cleanly to MCP tool inputs and outputs. Both stay on admin REST as the single source of truth.
Why this design
Compatibility
Adds a new
Server.MCPblock inconfig.yaml(default disabled). No behavioural change to existing setups that do not opt in. The only schema-level change isomitemptyon a handful of server-assigned fields (id, clienttoken) in the store types so the MCP SDK's reflection does not mark them as required oncreate_*inputs. JSON wire shape on responses is unaffected because those fields are always populated at write time.Open questions
Mcp-Session-Id,Last-Event-ID) is already covered by the project-wideAccess-Control-Allow-Headers: *, but worth a second look during review.Pull request
I have a working implementation with tests and public docs ready in a PR. Happy to iterate on naming, scope and any architectural concerns before merge.