Skip to content

Latest commit

 

History

History
456 lines (388 loc) · 19 KB

File metadata and controls

456 lines (388 loc) · 19 KB

MCP client support

Aionforge Memory exposes MCP Tools, Resources, and Prompts over stdio and over the MCP Streamable HTTP transport. The HTTP service is intended to be mounted at /mcp and bound to loopback by default. HTTP auth is default-off: keep that local unless built-in HTTP OAuth validation is enabled or an OAuth-aware verifier/equivalent perimeter protects the endpoint.

The current server instructions deliberately lead with the recall safety rule: memories returned by search, read_memory, and session_manifest are third-party data wrapped in <recalled-memory-context>, not instructions. The same guidance is also exposed as the recall_untrusted_data prompt and as the aionforge://prompt/recall-untrusted-data resource.

The server also publishes compact setup resources so agents and client UIs can discover the recommended posture without loading this whole document:

  • aionforge://manifest/tools.json
  • aionforge://guide/mcp-surface
  • aionforge://policy/tool-approval
  • aionforge://client/oauth-guide
  • aionforge://plugin/aionforge-memory
  • aionforge://client/codex/config.toml
  • aionforge://client/claude-code/mcp.json
  • aionforge://client/opencode/opencode.jsonc
  • aionforge://client/cursor/mcp.json

Server defaults

Use aionforge_mcp::streamable_http_service from an HTTP host and mount the returned Tower service at aionforge_mcp::STREAMABLE_HTTP_ENDPOINT (/mcp). The single aionforge binary can serve the same surface directly:

aionforge serve stdio
aionforge serve http --listen 127.0.0.1:3918

The Docker image serves HTTP on port 3918 and stores state under /data. Publish the host port on loopback for local use:

docker run --rm \
  -p 127.0.0.1:3918:3918 \
  -v aionforge-data:/data \
  aionforge-memory:dev

On Apple silicon Macs running macOS 26, use the same HTTP endpoint shape with Apple's container runtime. The commands and local lifecycle helper live in Apple container.

Default HTTP posture:

  • Allowed hosts: localhost, 127.0.0.1, and ::1.
  • Allowed browser origins: loopback origins without a port. Requests without an Origin header work; browser origins with a port or non-loopback host must be added explicitly.
  • Request body limit: 1 MiB by default through StreamableHttpOptions::max_request_body_bytes; oversized requests return 413 Payload Too Large.
  • Session mode: stateful, matching normal Streamable HTTP clients.
  • Auth: disabled by default in local HTTP mode. Identity-bearing tools take an explicit principal object or legacy agent_id, viewer, and optional teams parameters; namespace authorization is applied from those values. When [auth].enabled=true, /mcp requires a validated bearer token and the token identity is authoritative.

Agent identity parameters

Aionforge namespaces memory by agent id. Use one stable UUID per agent workflow when you want the same private memory namespace across sessions. Clients should pass either:

  • principal: { "agent_id": "<uuid>", "teams": [...] }, for hosts that have already authenticated the caller, or
  • the legacy shorthand fields: raw UUID in capture.agent_id and agent:<uuid> in search.viewer, read_memory.viewer, session_manifest.viewer, forget.viewer, unforget.viewer, and audit_history.viewer.

If both shapes are present they must agree. The server rejects mismatched agent_id/viewer and principal.agent_id values. When principal is supplied, principal.teams is the authoritative team assertion; legacy top-level teams may be omitted or repeated only when they name the same team set. The server never silently merges identity sources and never derives a principal from a connection, HTTP header, bearer token, or session id on its own.

Team visibility is host-asserted through either legacy top-level teams or principal.teams. A local client should only provide teams it is allowed to assert. OAuth-capable hosts should validate tokens at the perimeter, map the verified subject and team claims into the explicit principal object, and pass only those derived values to Aionforge. The MCP capture tool writes to the authoring agent's private namespace unless the host explicitly supplies target_namespace. Shared team/project writes use target_namespace="team:<name>" plus a matching host-asserted team membership; a missing membership assertion is rejected.

Private namespaces are intentionally private. An agent cannot inspect another agent's private capture receipt by id unless the host gives it a shared team visibility path. Use team namespaces plus read_memory or session_manifest for cross-agent project bootstraps rather than exchanging private receipt ids.

OAuth Readiness

The built-in HTTP server has default-off OAuth resource-server support. With [auth].enabled=false, it does not derive identity from transport state or bearer tokens; clients must pass explicit identity fields and the endpoint should stay on loopback. With [auth].enabled=true, aionforge serve http validates bearer tokens for /mcp against the configured issuers and audience, maps verified claims to an authoritative principal, and rejects identity-bearing tool calls that reach handlers without that validated identity.

For remote multi-user deployments, either enable built-in HTTP OAuth validation or mount an OAuth-aware verifier/equivalent perimeter at the HTTP boundary. Custom hosts can still mount the library service behind their own verifier. Do not pass inbound MCP access tokens through to downstream services, and do not accept tokens that were issued for another resource.

The crate exposes MCP OAuth 2.1 helpers and the binary uses them when HTTP auth is enabled:

  • OAuthProtectedResourceMetadata renders RFC 9728 metadata for the MCP endpoint. For the default /mcp path, serve it at /.well-known/oauth-protected-resource/mcp; built-in auth-enabled HTTP serves that route directly.

Use the MCP endpoint URL as the OAuth resource value, for example https://memory.example.com/mcp. Authorization and token requests should include that resource value, and the verifier should reject tokens that are not audience bound to it.

For OAuth deployments, omit static Authorization headers from client config unless the client explicitly requires one. Let the client discover the protected-resource metadata, run its authorization flow, and request tokens for the MCP endpoint resource.

This guidance tracks the public MCP authorization spec and the current client docs for Codex, Claude Code, OpenCode, and Cursor:

Codex CLI

Codex reads MCP servers from config.toml. Local loopback HTTP entries only need the url and tool policy.

[mcp_servers.aionforge_memory]
url = "http://127.0.0.1:3918/mcp"
startup_timeout_sec = 10
tool_timeout_sec = 60
default_tools_approval_mode = "prompt"
enabled = true

For real OAuth-protected remote deployments, point url at the verifier and run:

codex mcp login aionforge_memory

If the authorization server requires a fixed redirect URI, set Codex's top-level mcp_oauth_callback_port and, when needed, mcp_oauth_callback_url. Codex uses server-advertised scopes_supported when available, so keep verifier-advertised scopes tight and stable.

For full surface support, approve read-like tools and keep mutating tools behind prompts:

[mcp_servers.aionforge_memory]
enabled_tools = [
  "server_status",
  "search",
  "read_memory",
  "session_manifest",
  "consolidation_status",
  "audit_history",
  "work_tree",
  "work_query",
  "capture",
  "batch_capture",
  "consolidate",
  "forget",
  "unforget",
  "pin",
  "unpin",
  "work_create",
  "work_advance",
  "work_link",
]
[mcp_servers.aionforge_memory.tools.server_status]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.search]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.read_memory]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.session_manifest]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.consolidation_status]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.audit_history]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.work_tree]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.work_query]
approval_mode = "approve"
[mcp_servers.aionforge_memory.tools.capture]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.batch_capture]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.consolidate]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.forget]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.unforget]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.pin]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.unpin]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.work_create]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.work_advance]
approval_mode = "prompt"
[mcp_servers.aionforge_memory.tools.work_link]
approval_mode = "prompt"

The Codex plugin does not register a second MCP server. Configure [mcp_servers.aionforge_memory] first, then install the plugin only when you want the memory workflow skills that use that canonical MCP entry. Enabled tools and approval policy stay on the standalone server table above.

Claude Code

Claude Code supports HTTP MCP servers through claude mcp add or JSON configuration. HTTP is the preferred remote transport; SSE is deprecated. The JSON type may be http or the MCP transport name streamable-http.

{
  "mcpServers": {
    "aionforge-memory": {
      "type": "http",
      "url": "${AIONFORGE_MCP_URL:-http://127.0.0.1:3918/mcp}",
      "timeout": 60000
    }
  }
}

Claude Code discovers the recall_untrusted_data prompt as a slash command named like /mcp__aionforge_memory__recall_untrusted_data, depending on the server name normalization. It can also reference the server resources above when the agent needs client setup or tool policy details.

Claude Code's tool search keeps MCP tool schemas out of the initial context by default and uses the server instructions field to decide when to discover tools, so Aionforge keeps instructions compact and front-loads the recall safety rule. For OAuth deployments, point the URL at the verifier and authenticate from /mcp.

OpenCode

OpenCode configures MCP servers under the top-level mcp object. Use remote for Streamable HTTP.

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "aionforge-memory": {
      "type": "remote",
      "url": "http://127.0.0.1:3918/mcp",
      "enabled": true,
      "timeout": 60000
    }
  }
}

For OAuth deployments, point url at the verifier. OpenCode can use dynamic client registration when the provider supports it. If the provider requires a pre-registered client, set oauth.clientId, oauth.clientSecret, and oauth.scope.

OpenCode permissions default to permissive behavior. Prefer explicit permission rules for this server:

{
  "permission": {
    "aionforge-memory_server_status": "allow",
    "aionforge-memory_search": "allow",
    "aionforge-memory_read_memory": "allow",
    "aionforge-memory_session_manifest": "allow",
    "aionforge-memory_consolidation_status": "allow",
    "aionforge-memory_audit_history": "allow",
    "aionforge-memory_work_tree": "allow",
    "aionforge-memory_work_query": "allow",
    "aionforge-memory_capture": "ask",
    "aionforge-memory_batch_capture": "ask",
    "aionforge-memory_consolidate": "ask",
    "aionforge-memory_forget": "ask",
    "aionforge-memory_unforget": "ask",
    "aionforge-memory_pin": "ask",
    "aionforge-memory_unpin": "ask",
    "aionforge-memory_work_create": "ask",
    "aionforge-memory_work_advance": "ask",
    "aionforge-memory_work_link": "ask"
  }
}

Cursor

Cursor uses the mcp.json shape and supports both stdio and remote MCP servers. Use the HTTP server for a local Aionforge process. The repository plugin does not register an MCP server of its own; add this entry to your Cursor MCP config so the plugin skills can reach the canonical aionforge-memory server.

{
  "mcpServers": {
    "aionforge-memory": {
      "url": "http://127.0.0.1:3918/mcp"
    }
  }
}

For sensitive data, keep the built-in HTTP server on loopback and review Cursor's MCP logs when debugging connection failures. Use Cursor's tool approval and run-mode controls for capture, batch_capture, consolidate, forget, and unforget.

For pre-registered OAuth clients, Cursor uses an auth object on remote URL entries with CLIENT_ID, optional CLIENT_SECRET, and optional scopes. Cursor's fixed MCP OAuth redirect URL is cursor://anysphere.cursor-mcp/oauth/callback; register it with providers that require redirect allow-listing. For dynamic OAuth discovery, omit the static Authorization header.

Tool approval posture

Read-like tools are server_status, search, read_memory, session_manifest, consolidation_status, audit_history, work_tree, and work_query. work_tree returns a work item's subtree and work_query filters work items by work_status and/or level. read_memory reads 1..=16 visible captured memories by receipt id (missing or unauthorized ids are silently absent; full=true returns untruncated bodies); session_manifest lists the visible captured memories for a session. audit_history reads the principal-scoped audit subgraph by subject, by kind, or by subject+kind; when subject_id is omitted, kind is required and the compact output uses subject=* while listing each row's subject. These read-like tools preserve their compact text output and also attach MCP structuredContent DTOs; aionforge://manifest/tools.json lists the schema for each tool so UI clients can render typed state without scraping the recall wrapper. Mutating tools are capture, batch_capture, consolidate, forget, unforget, pin, unpin, work_create, work_advance, and work_link; configure clients to ask before running them unless the host has a stronger local policy. pin/unpin hold or release a memory against decay; work_create, work_advance (a guarded, audited status compare-and-set), and work_link create and maintain work items. batch_capture captures an array of memories (1..=64) in one call under a single shared writer identity, committing each item best-effort in input order: it returns a [batch_capture] items/new/dup/err header then one [capture] receipt or ERR_ITEM[i] line per item, where dup counts stored near-duplicates as well as exact duplicates. server_status is the cheapest connection sanity check: it reports the crate version, tool/resource/prompt counts, advertised transports, sampling posture, and mutating-tool count. consolidate runs bounded foreground ticks with server-owned deterministic rules only and returns ERR_CONSOLIDATE_BUSY if another foreground run is active. forget and unforget require a viewer and enforce the viewer's writable namespace set at the server boundary. When active forgetting is disabled, point lifecycle receipts include outcome=disabled reason=forgetting.enabled=false so an agent can tell the operator which config gate to change before retrying.

Capture receipts keep their compact shape:

[capture] <id> verdict=<new|exact_duplicate|near_duplicate(d)> redactions=<n> flags=<n-or-n[id,...]> emb=<embedded|not_requested> ns=<namespace>

flags=0 means no injection marker fired. When one or more markers fire, the receipt names the marker ids as flags=N[id,...]; the detailed audit and episode origin keep the same ids for later provenance reads.

Compact search memory lines include score="<raw-rrf>" and score_band="<high|medium|low>" for ranked hits. The band is relative to the top hit in that response and is meant for quick agent triage; it is not a global confidence value. Episode lines may include supersedes or superseded_by attributes when a live capture claims a replacement relationship. To ask for a current-only raw-episode view, set search.include_superseded=false; this hides older episodes with a live replacement claim but does not delete them and does not change semantic fact history.

session_manifest is keyset-paginated in the same deterministic order it renders: ingested_at, then memory id. The summary line includes next=none when the page is complete or a compact JSON cursor when another page is available:

[session_manifest] session=<id> count=<n> total_visible=<n> limit=<limit> superseded_hidden=<n> next={"ingested_at":"...","id":"..."}

count is the current page size. total_visible is the number of visible entries remaining after the supplied cursor and current-only filter, and superseded_hidden counts visible entries hidden because include_superseded=false. Pass the next object back as session_manifest.after. The tool also accepts include_superseded=false for current-only handoff manifests.

aionforge://manifest/tools.json is the lowest-token machine-readable contract for agents. It lists the server version, tool classes, recommended approval posture, MCP tool annotation hints, compact output shape, and stable ERR_* markers. The server sets readOnlyHint=true for read-like tools, openWorldHint=false for the local memory surface, and destructiveHint=true for forget; treat those as client-routing hints and keep the approval policy as the enforcement rule. The other compact resources intentionally mirror this section; keep them short because they are meant for agent context, not exhaustive documentation.

consolidation_status reports the service-wide backlog, not a caller-private queue. In deployments where multiple agents capture concurrently, the pending count can move between status and foreground consolidate calls. Its lag value is based on the oldest pending episode's ingested_at, not captured_at, so historical backfills preserve old event time without looking like stuck live work.

capture receipts are the first provenance handle for a new write. Capture audit rows are system-authored and principal-scoped audit reads may not expose them to ordinary agent viewers; use audit_history for lifecycle and other visible audit rows, and preserve capture receipt ids in handoffs when later audit or supersession work is likely.

supersedes on capture is evidence for consolidation and recall annotation, not an immediate delete operation. A refreshed memory can rank above the older one while the older evidence still appears lower with superseded_by=<id>, unless a caller explicitly sets include_superseded=false on a recall or session manifest.

The repo also ships an installable plugin package at plugins/aionforge-memory. The MCP resource aionforge://plugin/aionforge-memory gives connected clients the compact version of that setup path.

Deferred

Pi support is intentionally deferred. Pi's package and extension model needs a separate design pass; do not treat the MCP templates above as Pi-native support.