Docs / Agent and MCP Layered Architecture

Agent and MCP Layered Architecture

GoPress treats Agent as a stable Core capability and MCP as a replaceable protocol adapter. This follows the same dependency rule as themes and plugins: extensions depend on generic Core contracts; Core does not depend back on an extension implementation.

Dependency Direction

MCP client -> plugins/gopress-mcp -> core/agent -> generic Core domains
business plugin -> core/plugin.AgentHost -> core/agent.Registry
active theme -> core/content.Registry

core -X-> gopress-mcp
gopress-mcp -X-> theme
theme -X-> gopress-mcp

Theme-declared content types affect generic content tools through the Content Registry only. The adapter neither reads private theme options nor imports theme packages.

Code Map

core/agent/
  tool.go                 Tool, Call, Result, PermissionRequirement
  registry.go             concurrent registry, revision, handles
  principal.go            principal and scopes
  credential.go           user/service-account credentials
  authorize.go            scope + RBAC + ownership
  policy.go               read_only / safe_write policy
  executor.go             mandatory execution pipeline
  validation.go           restricted JSON Schema validation
  idempotency.go          write idempotency state machine
  audit.go                Agent call audit
  core_tools.go           six read tools
  core_write_tools.go     six write tools

core/content/command.go   shared content mutation invariants
plugins/gopress-mcp/      protocol, HTTP, admin, settings

Engine Assembly

The Engine constructs one site-level Registry, Policy, Credential Service, Idempotency Store, Audit Store, Authorizer, and Executor. It registers Core read and write tools against generic content, taxonomy, media, option, hook, and cache services.

The public plugin capability is intentionally narrow:

type AgentHost interface {
    AgentToolRegistry() *agent.Registry
    AgentExecutor() *agent.Executor
}

The official adapter privately composes additional Core capabilities for credentials, audit, policy, options, hooks, admin authentication, and RBAC. No MCP type crosses back into Core.

Request Path

sequenceDiagram
    participant C as MCP Client
    participant H as HTTP Security Chain
    participant M as MCP SDK Adapter
    participant X as Agent Executor
    participant D as Domain Service
    participant I as Idempotency Store
    participant A as Agent Audit

    C->>H: POST /mcp + Bearer
    H->>H: no-store / rate / origin / auth / protocol
    H->>M: authenticated MCP request
    M->>X: agent.Call + Principal + ClientInfo
    X->>X: schema / scope / RBAC / owner / policy
    X->>A: start or denied/failed event
    opt write tool
        X->>I: reserve credential + tool + key
    end
    X->>D: bounded handler invocation
    D-->>X: structured result
    opt write tool
        X->>I: complete result and resource
    end
    X->>A: succeeded / failed / replayed
    X-->>M: protocol-neutral result/error
    M-->>C: MCP CallToolResult

The HTTP chain applies no-store headers, bounded source rate limiting, cross-origin protection, mandatory Bearer authentication, protocol gating, and the official SDK Streamable HTTP handler. Protocol errors and Tool/domain errors remain separate.

Permission-Aware Discovery

For each authenticated request the adapter asks Executor.VisibleTools for a scope/RBAC/policy-filtered set. It still registers the full Registry with the SDK so an explicit call to a hidden tool reaches Core and produces a stable denial audit. A list middleware removes hidden descriptions and returns a private 30-second TTL plus Agent revision.

Domain Reuse

Content reads use context-aware repository queries and the Content Registry. Writes use content.CommandService, which enforces registered/editable types, type plus ID boundaries, declared metadata, reserved routes, sanitization, transactions, optimistic locking, explicit transitions, hooks, and page-cache invalidation.

Taxonomy reads stay within taxonomies attached to the requested type. Media reads hide filesystem paths, while metadata writes are limited to alt text, title, and caption and trigger the shared media mutation observer.

Persistence

Prefixed Core tables store:

Model Purpose
ServiceAccount Passwordless non-human principal; Core exists, stock MCP UI does not manage it yet
Credential Subject, token digest, scopes, audience, expiry, revocation, last use
IdempotencyRecord Credential/tool/key uniqueness, request digest, state, result and resource, 24-hour default TTL
AuditEvent Request/client/principal/tool/risk/status/error/duration and redacted digests

Raw credentials and argument/content values are not stored in Agent audit. Completed idempotency records do retain structured result JSON for correct replay and should be protected as site database data.

Lifecycle and Revision

Registry register/revoke operations increment a revision. Handles include an owner and generation so stale handles cannot remove later registrations. Serializable snapshots are sorted and strip handlers/resolvers. Policy has its own revision, and discovery combines registry and policy change signals.

Deactivating the adapter removes route hooks and returns the runtime policy to read-only. Re-activation reloads the persisted protocol-neutral Agent Policy.

OAuth discovery, refresh tokens, advanced MCP primitives, and third-party Tool governance remain later phases and must preserve the same adapter -> core/agent -> domain direction.