Files
summercms/.planning/notes/2026-10-17-generic-mcp-module.md

4.3 KiB

title, date, context
title date context
Generic MCP module for SummerCMS applications 2026-10-17 /msd-explore session. Agents already drive applications (for example a quiz/presentation app) through plugin management APIs with personal tokens; an MCP surface would be smoother. Records the shape agreed before Phase 19.7 is planned.

Generic MCP module for SummerCMS applications

Starting point

  • Agents mostly call plugin-specific management routes (user.api_token + user.scope:* + user.permission:<code>), not cabana's generic admin CRUD. Generating tools from fields.yaml therefore does not cover the use case.
  • The route table (pact.Router) holds only method, path, handler and middleware names. From that alone the token-accepting routes, read or write (scope middleware or method), path parameters and the required permission code can be derived. Descriptions, request body shapes and response meaning cannot.
  • surf.APIDocsProvider (one OpenAPI document per application) does not fit applications assembled from plugins in several repositories.

Decisions

  1. In-binary, opt-in module. A new framework module (beach name to pick) mounts an MCP endpoint (for example /mcp) when enabled in config, in the same way http.api_docs.enabled mounts /api-docs. Disabled by default; an application without it is unaffected.
  2. Plugins declare their tools. A new optional pact capability, the counterpart of WinterCMS registerMcpTools() in Plugin.php: each tool has a name, a description, an input Go struct (its JSON schema is reflected) and the route it maps to. A plugin that declares nothing exposes nothing. A shared plugin carries its tools into every application that mounts it.
  3. Each tool declares its guard (user for sm-user-plugin principals, backend for cabana principals) and inherits the permission requirements of its route.
  4. tools/list is computed per principal. A tool is offered only when the principal passes the route's checks: user.scope:* and user.permission:<code> through MergedPermissions / HasPermission for frontend users, cabana.Allows with the token's scope limit for backend users. The user's own tri-state permissions (allow / inherit / deny, already supported by the permissioneditor radio mode) therefore shape the tool list with no new permission system.
  5. One person, one connector. The editor adds the site's MCP URL as a connector and signs in once through wristband OAuth as their frontend user. If that frontend user has a verified link to a backend_users row, the grant also carries that backend principal, and backend-guarded tools (Journal) run as it. tools/list is the union of what both identities allow; a person without a link sees no backend tools.
  6. Journal stays on backend_users. Authors remain backend users; moving them to frontend users would break a core plugin. The account link bridges the two instead.

An admin picking any frontend user in My Profile would let that admin act through MCP as someone else. The link is therefore saved only after the frontend account signs in (My Profile → "Link frontend account" → site sign-in). A superuser can set or remove links on the Users screen behind a new backend permission, for onboarding editors. Revoking the link or the OAuth grant removes the backend tools. Never link by matching email.

Prerequisites (todos)

  • Plugins register their frontend permission codes in Go (.planning/todos/pending/2026-10-17-plugin-registered-frontend-permissions.md).
  • Verified frontend ↔ backend account link (.planning/todos/pending/2026-10-17-frontend-backend-account-link.md).

Open for Phase 19.7 discussion

  • Transport (streamable HTTP) and whether to take the MCP Go SDK as a dependency; it needs a decision note naming it and its version (CLAUDE.md dependency rule). Unresolved: not researched in this session.
  • How a tool call reaches its handler: an in-process request through the surf router with the resolved principal, so the route's own middleware (throttles, scope, permission) still runs, rather than calling the handler directly.
  • Whether plain personal tokens (user user_api_tokens, cabana g15_…) may also open an MCP session for single-identity agents, next to OAuth.
  • Tool naming across plugins (prefix by plugin code to avoid collisions) and how a tool describes its response.