MCP Server Architecture
August 13, 2026 · View on GitHub
Sage ships a shared MCP (Model Context Protocol) server implementation to support:
- False-positive reporting from the local audit log (
~/.sage/audit.jsonl) to Sage Proxy (POST /v2/fp-report). - (Optional) Allowlist management tools, when the host platform can provide “recent user approval” signals.
This document explains:
- What the shared MCP server is (
@gendigital/sage-mcp) - Which clients are supported
- How Sage registers the MCP server on supported clients
High-level design
Sage’s MCP server is implemented once in @gendigital/sage-mcp and then bundled into each platform distribution that needs a runnable MCP server process.
flowchart TD auditLog[~/.sage/audit.jsonl] core[@gendigital/sage-core] mcp[@gendigital/sage-mcp] host[HostClient(CLI/IDE)] sageProxy[SageProxy(/v2/fp-report)] core --> auditLog mcp --> core host -->|stdio JSON-RPC| mcp mcp -->|"POST /v2/fp-report"| sageProxy mcp -->|"read + filter by conversation_id"| auditLog
Packages involved
packages/core(@gendigital/sage-core)-
Detection engine, config, exceptions, and audit log writer.
-
Audit entries now include:
entry_id(UUID)conversation_id(used for report scoping)agent_runtime(best-effort source platform identifier)signals(best-effort structured signal metadata for reporting, includingamsi_checkson Windows/WSL)content(structured snapshot of the tool input, sanitized — same shape as the detection-telemetrycontentfield; per-field caps and home-path scrubbing applied upstream bybuildContentSnapshot)
See Audit Log for the full on-disk schema.
-
packages/mcp(@gendigital/sage-mcp)- Shared MCP server implementation (stdio transport) + tool registration.
- Reads the audit log via
@gendigital/sage-coreand sends reports via HTTPPOST /v2/fp-report. - Platform bundles (runnable scripts)
- Claude Code:
packages/claude-code/dist/mcp-server.cjs - Cursor/VS Code VSIX:
packages/extension/dist/mcp-server.cjs - OpenCode:
packages/opencode/dist/mcp-server.cjs - OpenClaw:
packages/openclaw/dist/mcp-server.cjs
- Claude Code:
Supported clients
Claude Code
- Uses the plugin manifest
.claude-plugin/plugin.jsonto registermcpServers.sage. - Sage bundles the MCP server into
packages/claude-code/dist/mcp-server.cjs.
Cursor
- Sage registers the
sageMCP server via Cursor’s MCP API. - Cursor handles enable/disable automatically based on whether Sage protection is enabled.
VS Code
Sage’s VS Code extension manages Copilot hooks (in ~/.copilot/hooks/hooks.json) for hooks.
For MCP, Sage registers an MCP server definition provider so that the server shows up in VS Code’s MCP UI.
- VS Code requires a manual start. Use the command palette:
MCP: List Server→sage→Start server.
OpenCode
- The Sage plugin’s
confighook injectsmcp.sageinto the resolved config before OpenCode’s MCP service initialises, so the server is auto-registered with no user configuration required. process.execPath(the running Bun/opencode binary) is used as the server command withBUN_BE_BUN=1, so the server runs correctly regardless of whether a separatenodebinary is on PATH.
OpenClaw
- OpenClaw’s native plugin API does not support programmatic MCP server registration.
- Users must add the server manually to their OpenClaw
mcp.serversconfig, pointing atpackages/openclaw/dist/mcp-server.cjswithnodeas the runtime. See the OpenClaw Platform Guide for the exact config snippet.
Tooling
sage_list_audit_entries
Lists recent audit entries from ~/.sage/audit.jsonl, optionally filtered by conversation_id. This is intended to help users pick entry_ids for reporting.
sage_report_false_positive
Reports audit entries as false positives to Sage Proxy (POST /v2/fp-report).
- Scoping: filters to entries matching
conversation_id.- If
conversation_idis not provided, Sage will infer it from the most recentruntime_verdictentry in the audit log.
- If
- User input: the tool requires:
description: a short description of what is wrongreasoning: why it’s a false positive
- Entry selection: callers should call
sage_list_audit_entriesfirst and pass the relevantentry_id(s) via theentry_idsparameter.- With
entry_idsprovided: at most 10 entries per call. Larger arrays are rejected with an actionable error. - With
entry_idsomitted (fallback):allowverdicts are filtered out and only the 3 most recentdeny/askentries for the conversation are submitted, to avoid flooding the backend with unrelated verdicts.
- With
- Payload: one report per audit entry, shaped like the Sage FP Submit Structure. It includes standard Sage context (runtime/platform metadata plus current Sage protection settings). The structured
contentfield stored on the audit entry is forwarded verbatim — the tool does not reconstruct content from the truncatedtool_input_summary.
Configuration
The sage_report_false_positive tool is always available (it cannot be disabled via configuration).
Environment overrides:
SAGE_FALSE_POSITIVE_TIMEOUT_SECONDSSAGE_APP_ROOT— absolute path to the host application root (vscode.env.appRootfor Cursor / VS Code). When set, the MCP server readsproduct.jsonfrom this directory at startup to resolve the host runtime version (e.g. Cursor3.1.14, VS Code1.117.0). Set automatically by the Sage extension when it registers the MCP server; only needs to be supplied manually for non-extension hosts.SAGE_AGENT_RUNTIME_VERSION— fallback used when the caller does not provide an explicit agent runtime version andSAGE_APP_ROOTis unset or itsproduct.jsonis unreadable. If neither resolves to a value, the runtime version is reported as"unknown".
Auto-installation details
Cursor (VSIX)
- On startup (and when protection is manually re-enabled), Sage registers the
sageMCP server viavscode.cursor.mcp.registerServer(...). - When protection is disabled until restart, Sage unregisters it via
vscode.cursor.mcp.unregisterServer("sage"). The server is re-registered on the next startup.
VS Code (VSIX)
- VS Code does not currently expose an API to programmatically enable/disable (start/stop) an MCP server.
- Sage registers a server definition provider (via
contributes.mcpServerDefinitionProviders+vscode.lm.registerMcpServerDefinitionProvider(...)) so the server appears in the MCP UI. - The user must start the server manually using:
MCP: List Server→sage→Start server.
Notes and constraints
- No copy/paste across connectors: protocol + tool logic lives in
@gendigital/sage-mcp; connectors only provide a thin runnable entrypoint and (optionally) an approval adapter. - Conversation id quality is host-dependent: Sage records the best available conversation/session identifier from each host and stores it as
conversation_idin the audit log.