Skip to main content
Other agent platforms (Claude Desktop, Cursor, custom apps) can use Comis as an MCP backend, accessing Comis skills and a curated set of platform tools via a single Streamable HTTP endpoint at /mcp/v1. This is the inverse of MCP Integration: there, Comis connects to third-party MCP servers; here, Comis is the MCP server other platforms connect to.
Before you flip /mcp/v1 live on any publicly reachable Comis instance, complete the security-reviewer gate on the 51-tool classification (see Exposed tools). The conservative defaults that ship are the right starting point, but the literal safe / permission-gated / never-export split is the security policy and must be human-reviewed.

Why use this

External agent platforms benefit from Comis’s accumulated state and skills:

Claude Desktop

Hook into Comis’s per-tenant memory, search past sessions, or invoke web tools from any Claude Desktop conversation.

Cursor or other IDEs

Use Comis’s web search, document extraction, or workspace tools from inside your editor’s MCP integration.

Custom agent apps

Build internal agents that call Comis as a skill backend via a single HTTPS endpoint with bearer-token auth.

Cross-platform memory

A Claude Desktop agent reads what your Discord agent remembered — same memory store, same tenant.

Security model

The /mcp/v1 endpoint exposes only what the operator explicitly authorizes. Five invariants make this safe.
Every platform tool is annotated with mcpExportPolicy — one of safe, permission-gated, or never-export. Missing annotation is treated as never-export (default-deny). A CI architecture gate rejects pull requests that add a tool without an explicit classification.See Exposed tools for the full 51-tool table.
The mcp-client scope is rejected on any non-/mcp/v1 route. Tokens that try to co-issue admin and mcp-client are rejected at config-load with [scope_disjointness]. An MCP client cannot escalate by calling tokens_manage against itself — the admin scope is structurally unreachable from the MCP path.
Every tools/call increments a per-(client, tool) minute bucket. Calls beyond the ceiling return [rate_limit_exceeded] with a resetAt epoch-ms. The default is 30/min, overridable per token via mcpClient.toolRateLimit[name].
resources/read filters out outbound messages that have not yet been delivered to the channel adapter (deliveryStatus !== "pending"). External MCP clients never see in-flight outbound, only what’s already been delivered.
The dispatcher strips any _trustLevel field from MCP tool args before invoking the underlying RPC, and the composition root’s indirection (daemonRpcForMcpClient) never spreads _trustLevel: "admin". Even if a never-export tool slipped past the policy filter, the dispatch path makes admin-trust behavior unreachable from the MCP wire.
The endpoint inherits the gateway’s TLS configuration. Strongly recommended: run /mcp/v1 behind TLS in any deployment where the client is not on the same host. See Hardening for gateway.tls setup.

Bootstrap — issuing an mcp-client token

Token issuance is a two-step operator workflow.
1

Mint the token via the admin LLM

An operator with an admin-scoped session asks the admin agent to call tokens_manage:
Operator: "Create a new token with scopes ['mcp-client']."

Admin agent -> tokens_manage(action="create", scopes=["mcp-client"])
The agent returns the new token’s id and secret. Capture the secret once — it is hashed in storage and not recoverable.
The agent will refuse to create a token that co-issues admin and mcp-client — the schema’s [scope_disjointness] refine blocks this at config-load. Never request both scopes on one token.
2

Attach the per-client config block in ~/.comis/config.yaml

Add the mcpClient block under the matching token entry. This is the operator’s tool-export policy for this MCP client.
gateway:
  enabled: true
  host: "0.0.0.0"
  port: 4766
  tokens:
    - id: claude-desktop-1
      secret: "<the secret returned by tokens_manage>"
      scopes: ["mcp-client"]
      mcpClient:
        # Permission-gated tools this client may invoke. Tools NOT in this
        # list (and not in the always-on "safe" bucket) are hidden.
        allowlist: ["memory_search", "web_search", "session_search"]
        # Sessions this client may read via resources/*. Empty = no
        # session resources visible.
        sessionAllowlist: ["default:discord:guild123:channel456:user789"]
        # Per-tool rate-limit override (calls / minute). Omitted tools
        # use the 30/min default.
        toolRateLimit:
          memory_search: 60   # double the default for this client
          web_search: 10      # tighten
Then reload Comis (pm2 restart comis in dev, or HUP your daemon process in prod) to pick up the new token.

Claude Desktop config

Once your token is minted and the mcpClient block is attached, configure Claude Desktop’s mcpServers block.
{
  "mcpServers": {
    "comis": {
      "url": "https://my-comis-host:4766/mcp/v1",
      "headers": { "Authorization": "Bearer <your-mcp-client-secret>" }
    }
  }
}
The Claude Desktop config file lives at one of these platform-specific paths:
~/Library/Application Support/Claude/claude_desktop_config.json
Restart Claude Desktop. The Comis MCP server’s tools and resources appear in the conversation’s tool picker.
The same JSON shape works for Cursor, Continue, and most MCP-compatible clients — only the host config-file path differs. Cursor reads ~/.cursor/mcp.json.

Per-client config reference

The gateway.tokens[i].mcpClient block has three optional fields:
FieldTypeDefaultPurpose
allowliststring[][]Permission-gated tools this token may invoke. Tools in the safe bucket are exposed even with an empty allowlist. Tools NOT in this list and NOT in safe are hidden from tools/list and rejected on tools/call.
sessionAllowliststring[][]Session keys this token may read via resources/list and resources/read. Session-key format: {agent}:{channelType}:{channelId}:{userId} (e.g. default:discord:guild123:channel456:user789). Empty means no session resources visible.
toolRateLimitRecord<string, number>{}Per-tool rate-limit override in calls/minute. Tools not listed use the 30/min default. Buckets reset on the UTC-minute boundary.
The mcpClient block is optional. A token with scopes: ["mcp-client"] and no mcpClient block can only call safe tools, sees no session resources, and hits the default 30/min/tool ceiling.

Exposed tools

Tools are partitioned into three buckets per mcpExportPolicy. This is the starting classification — see the security-reviewer gate before flipping /mcp/v1 live on a publicly reachable instance.

safe (3) — exposed to any mcp-client token

No allowlist required. These tools have no PII surface, perform no Comis state read, and operate purely on caller-supplied input.
ToolWhy safe
web_searchPublic web search; no Comis state read
web_fetchPublic HTTP GET; no Comis state read
browserPublic web browsing; no Comis state read

permission-gated (21) — exposed only if token’s mcpClient.allowlist includes the tool

Caller-data-dependent. These read Comis state OR consume caller media that may resolve to Comis-stored content.
ToolWhy permission-gated
readWorkspace file read
lsWorkspace directory listing
findWorkspace search by name
grepWorkspace content search
memory_searchReads Comis memory (per-tenant)
memory_getReads Comis memory by key
session_searchReads session history
session_statusReads session metadata
sessions_listEnumerates sessions
sessions_historyReads full session transcript
obs_queryObservability read
obs_explainIncident report (digest-only) — runs the assembler directly under daemon authority, NOT the admin RPC; allowlist is the grant, no admin trust
discover_toolsReveals registered tool surface (meta)
image_analyzeVision over caller-supplied OR Comis-stored media — TODO: security-reviewer re-confirm
describe_videoSame caveat as image_analyze
extract_documentSame caveat as image_analyze
transcribe_audioSame caveat as image_analyze

never-export (28) — NEVER exposed under any operator config

Admin, mutation, outbound channel sends, cross-account, and cost-bearing synthesis. These cannot be added to an allowlist — the runtime filter always drops them.
Do NOT attempt to allowlist any of these. The runtime filter ignores them even if listed; the entry is silently dropped. Use a permission-gated tool if you need partial read access, or build a constrained admin delegation outside the MCP server surface.
CategoryTools
Filesystem mutationwrite, edit, apply_patch
Process / command executionexec, process
Memory write / deletememory_store, memory_manage
Session mutation, send, spawnsessions_manage, sessions_send, sessions_spawn, subagents
Scheduled taskspipeline, cron
Admin (9)gateway, heartbeat_manage, channels_manage, tokens_manage, skills_manage, mcp_manage, agents_manage, providers_manage, models_manage
Outbound channel sendmessage, whatsapp_action, discord_action, telegram_action, slack_action
Cost-bearing synthesistts_synthesize
Total: 3 safe + 21 permission-gated + 28 never-export = 52 unique tools, the full platform-tool surface.

Security-reviewer gate on the 51-tool classification

Before flipping /mcp/v1 live on any publicly reachable Comis instance, a security reviewer must audit each classification against the threat model. Use the rubric:
  • safe — no PII, no Comis state read, no mutation, no outbound. Pure caller-supplied input → pure caller-supplied output.
  • permission-gated — reads Comis state OR consumes caller data; the operator gates per-token via mcpClient.allowlist.
  • never-export — admin, mutation, outbound channel send, secrets, cross-account, or anything whose RPC contract is scoped ["admin"].
The four media tools (image_analyze, describe_video, extract_document, transcribe_audio) are conservatively classified as permission-gated. The reviewer decides whether any can be upgraded to safe (if the tool only ever reads caller-supplied media) or must stay permission-gated (if any code path resolves a Comis-stored media ID).

Wire-format notes

The Comis MCP server runs @modelcontextprotocol/sdk@1.29.0. Compatible client SDK versions: 1.20.0 and newer. Older clients may fail at initialize if the protocol-version negotiation cannot find a common version. By default the transport uses Server-Sent Events (SSE). The SDK’s enableJsonResponse option supports a JSON-only response mode, but Comis ships SSE by default. Most Claude Desktop and Cursor versions handle SSE natively. If you see a silent hang or an early-close from your client, verify the client’s transport configuration matches.

Resource caching

resources/read returns the current CONFIRMED state of a session. Re-reading the same URI may return additional messages as outbound delivery completes (an in-flight outbound message that was hidden on the first read may appear on a later read once the channel adapter confirms delivery). This matches the MCP spec’s “resources may change” semantics. Cache invalidation is the client’s responsibility — if your client caches by URI, set a short TTL or invalidate on every conversation turn.

Troubleshooting

Error / symptomLikely causeFix
401 UnauthorizedBearer token missing or invalidCheck the Authorization: Bearer ... header; re-mint the token via tokens_manage if you lost the secret.
403 Insufficient scopeToken doesn’t include mcp-clientIssue a new token with scopes: ["mcp-client"].
403 disjoint-scope violationToken co-issues admin and mcp-clientConfig validation should have caught this at load time. Re-mint the token with only mcp-client; check daemon logs for the [scope_disjointness] line.
tools/list returns only 3 toolsEmpty mcpClient.allowlist — only safe tools surfaceAdd the permission-gated tool names you want exposed to mcpClient.allowlist and reload.
[rate_limit_exceeded] on every callDefault 30/min/tool exhaustedTune via mcpClient.toolRateLimit[name] for the specific tool; or wait until the next UTC-minute boundary (resetAt in the error).
resources/list returns emptymcpClient.sessionAllowlist is emptyAdd the specific session keys you want exposed. Format: {agent}:{channelType}:{channelId}:{userId}.
Silent connection close after initializeSDK version mismatchVerify client SDK >= 1.20.0. Check daemon logs for protocol-version-negotiation-failed.

What’s NOT exposed

Out of scope for the current server, deferred:
  • sampling/createMessage — server-initiated LLM calls from Comis back to the client. Not advertised.
  • roots/notifications — workspace-root change notifications. Not advertised.
  • prompts/* — Comis does not expose prompts via MCP. The prompts capability is not advertised; clients should fall back gracefully.
  • Native binary content in tools/call results — image and audio tool outputs are returned as text descriptions (JSON-stringified). Native {type: "image", data: base64} content is deferred.

See also

  • MCP Integration — Comis as MCP client, the inverse direction.
  • Token Security — token storage and rotation.
  • Hardening — TLS, reverse proxy, and gateway hardening.
  • Rate limiting — gateway-level rate limits that apply before the per-tool MCP rate limit.