Sophon 1.15 is here
Sophon Docs
Integrations

MCP Server — Exposing Sophon Tools

Turn on Sophon's MCP server so external clients (Claude Desktop, Cursor, custom agents) can invoke Sophon tools and read Sophon resources.

Sophon includes a full MCP server. Enable it, pick transports, mint Bearer tokens, and external AI clients can invoke Sophon's tools (memory.search, workflow.trigger, document.query, …) and read Sophon's resources (documents, memory entries, agent files).

This turns Sophon into a hub: clients (Claude Desktop, Cursor, your own agent) can query it for memory and documents, trigger workflows, or chain Sophon's tools into their own agent loops.

Enabling the server

Dashboard → Settings → MCP → Server. Toggle Enabled. Pick transports:

  • stdio — for local CLI-style clients (Claude Desktop's native MCP config reads from stdio)
  • SSE — for remote streaming clients
  • StreamableHTTP — for remote request/response clients

Or edit ~/.sophon/config/mcp-server.json:

{
  "enabled": true,
  "transports": {
    "stdio": { "enabled": true },
    "sse": { "enabled": true, "path": "/mcp/sse" },
    "streamableHttp": { "enabled": true, "path": "/mcp/http" }
  },
  "auth": {
    "tokens": [
      { "id": "claude-desktop", "token": "{{vault:mcp_claude_token}}" }
    ]
  },
  "expose": {
    "tools": ["memory.*", "document.*", "workflow.list", "workflow.trigger", "insights.query"],
    "resources": ["documents/*", "memory/*", "agents/*"]
  }
}

Transport endpoints

TransportEndpoint
stdioLaunched by the client as a subprocess — sophon mcp serve --stdio
SSEhttps://<gateway>/mcp/sse (events); clients POST to https://<gateway>/mcp/sse/message
StreamableHTTPhttps://<gateway>/mcp/http

For stdio, give the client this command in its own MCP config:

{
  "mcpServers": {
    "sophon": {
      "command": "sophon",
      "args": ["mcp", "serve", "--stdio"],
      "env": { "SOPHON_GATEWAY": "http://localhost:8080" }
    }
  }
}

Authentication

stdio has no network boundary — the auth is your shell identity, and calls run as the local default user (see Per-user identity).

SSE and StreamableHTTP require Bearer tokens. Generate one per client:

Dashboard → Settings → MCP → Server → Tokens → Generate. Give the token a label (e.g., claude-desktop). Copy it once; it's not stored in clear text afterwards.

Clients send Authorization: Bearer <token> on every request. Unauthenticated requests are rejected with 401.

Rotate a token by regenerating; the old one is invalidated immediately.

Per-user identity

Every MCP session is bound to a Sophon userId, and every tool call and resource read on that session runs as that user — exactly like a call made from the Dashboard or a channel. There is no shared "system" identity.

  • Tokens carry the identity. When you generate a token you can bind it to a specific Sophon userId; everything done over that token then runs as that user. A token without a bound userId resolves to default.
  • SSE binds the userId once, at connect time, for the life of the stream.
  • StreamableHTTP is stateless per request; the client-supplied X-Session-Id header carries the binding across calls. The session key is always scoped by the token's id ({tokenId}:{header}), so two different tokens can never collide on one session slot — even if they happen to send the same header value.
  • stdio (sophon mcp serve) always runs as the local default user. There's no per-call auth on stdio — it's a local child process, not a network listener, so there's nothing to bind a token to.

Upgrading from an older Sophon: tool calls used to run as the literal user mcp-client, and resources were exported for the literal user system. Memory or documents written under either of those placeholder ids are no longer reachable over MCP — there is no automatic migration. Generate a fresh token bound to your real userId (single-user Personal tier falls back to default). Legacy tokens without a bound userId resolve to default.

What's exposed by default

Tools

By default, Sophon exposes a safe subset:

  • memory.search, memory.list, memory.get, memory.graph, memory.diagram (read-only)
  • document.search, document.get, document.summarize (read-only)
  • workflow.list, workflow.describe, workflow.trigger (trigger requires user to have trusted the workflow)
  • insights.query (user's own analytics)
  • task.list, task.describe (read-only)

Not exposed by default: anything that writes memory, modifies workflows, sends email, executes shell commands, configures connections. You can opt-in via expose.tools if you trust the connecting client — but do it deliberately.

Resources

By default, read-only URIs:

  • sophon://memory/long-term — curated facts, preferences, and decisions (markdown)
  • sophon://memory/daily — recent daily activity logs (markdown)
  • sophon://memory/entities — entities tracked in the memory graph, up to 500 (JSON)
  • sophon://memory/graph — the entity/entry graph, nodes and edges, capped at 250 nodes (JSON)
  • sophon://memory/graph.mmd — the same graph rendered as a Mermaid flowchart
  • sophon://documents/{id} — an extracted document's text
  • sophon://agents/{id}/soul — an agent's SOUL.md personality file

Resources are scoped to the token's bound user. If user A's token queries sophon://documents/xyz but that document belongs to user B, the server returns 404. The three graph resources require a local graph store, so they're hidden in sophon mcp serve (CLI stdio mode).

Claude Desktop example

Once Sophon's stdio MCP server is enabled, add this to Claude Desktop's MCP config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "sophon": {
      "command": "sophon",
      "args": ["mcp", "serve", "--stdio"]
    }
  }
}

Restart Claude Desktop. You'll see Sophon's tools listed in Claude's tool picker. Claude can now search your Sophon memory, query your documents, and list workflows as part of its own reasoning.

Cursor example

Cursor speaks StreamableHTTP. Add Sophon to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "sophon": {
      "url": "http://localhost:8080/mcp/http",
      "headers": {
        "Authorization": "Bearer sk_cursor_abc123..."
      }
    }
  }
}

Restart Cursor. Sophon's tools are available inside Cursor's agent panel.

Monitoring connected clients

Dashboard → Settings → MCP → Server → Connections lists live clients, their transport, their token ID, last request, and total call count. Disconnect a client by revoking its token.

Observability

Every inbound MCP call is logged with:

  • Client token ID, tool / resource name, arguments (redacted for sensitive args)
  • User identity (mapped from the token)
  • Response status, duration

This is the same audit log that covers REST and SignalR calls. Enterprise audit streams include MCP activity.

Limits

  • stdio is single-client — Sophon can only have one stdio connection at a time (tied to the subprocess). For multiple clients, use SSE / HTTP.
  • Per-token rate limit — 60 calls/minute. Busier clients need a higher limit per token (configurable).
  • Max payload — 5 MB request, 10 MB response. Truncation applies to large tool results (same 8000-char truncator that Sophon's native pipeline uses).
  • Token lifetime — tokens don't expire by default. Rotate quarterly or on employee turnover.

Security considerations

  • Only expose what you trust. The default allowlist is conservative for a reason. Opening memory.write or connection.configure to an external client gives that client write access to your memory and credentials.
  • Never share tokens across clients. Each client gets its own token so you can audit and revoke independently.
  • TLS in front of SSE/HTTP in production. Don't expose /mcp/* over plain HTTP except on localhost.
  • SSRF concerns don't apply on the server side — clients call into Sophon, not the other way around. But if your MCP server is behind a corporate proxy, make sure the proxy passes the Authorization header.

CLI

sophon mcp serve --stdio           # run the stdio server
sophon mcp tokens list
sophon mcp tokens create --label cursor
sophon mcp tokens revoke <token-id>
sophon mcp clients                 # who's connected right now

Where to go next