Back to Omniroute

OmniRoute MCP Server Documentation

docs/frameworks/MCP-SERVER.md

3.8.4937.3 KB
Original Source

OmniRoute MCP Server Documentation

Model Context Protocol server with 105 tools across routing, cache, compression, memory, skills, proxy, pool, and context source operations.

Source of truth: open-sse/mcp-server/server.ts computes 105 unique tools with countUniqueMcpTools(): 42 canonical definitions (including the six CCR lifecycle tools and the agent-skills trio), plus memory (3), skills (4), GitHub skills (3), pool (6), gamification (8), plugins (8), Notion (6), Obsidian (22), and two RTK-only compression tools.

Installation

OmniRoute MCP is built-in. Start it with:

bash
omniroute --mcp

Or via the open-sse transport:

bash
# HTTP streamable transport (port 20130)
omniroute --dev  # MCP auto-starts on /mcp endpoint

Transports

The MCP server exposes three transports, all backed by the same createMcpServer() factory:

TransportWhereWhen to use
stdioopen-sse/mcp-server/server.tsIDE integrations (Claude Desktop, Cursor, etc.)
ssePOST/GET /api/mcp/sse via httpTransportBrowser/agent clients that need an event stream
streamable-httpPOST/GET/DELETE /api/mcp/streamMulti-session HTTP clients (mcp-session-id header)

The active HTTP transport (sse or streamable-http) is selected by the mcpTransport setting. Switching transports closes existing sessions on the other transport.

Remote access (manage-scope bypass)

/api/mcp/* is in the LOCAL_ONLY tier (src/server/authz/routeGuard.ts) — by default only loopback hosts (localhost, 127.0.0.1, ::1) can reach it. Since v3.8.2, non-loopback clients may connect if they present an Authorization: Bearer <api-key> whose key carries the manage scope. This is the only way to reach the remote MCP server through a tunnel, reverse proxy, or public hostname.

bash
# Grant manage scope: open the dashboard API Keys page and toggle
# "Management Access" on the key, or POST scopes:["manage"] when creating.

# Then connect from a remote MCP client:
curl -i \
  -H "Host: your-public-host.example" \
  -H "Authorization: Bearer sk-…" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"my-client","version":"0"}}}' \
  https://your-public-host.example/api/mcp/stream

A non-manage key (or no Bearer) returns 403 LOCAL_ONLY. The sibling prefix /api/cli-tools/runtime/* is intentionally NOT bypassable — see Route Guard Tiers — Manage-scope carve-out.

IDE Configuration

See MCP Client Configuration for Claude Desktop, Cursor, Cline, and compatible MCP client setup.


Essential Tools (8) — Phase 1

ToolScopesDescription
omniroute_get_healthread:healthUptime, memory, circuit breakers, rate limits, cache stats
omniroute_list_combosread:combosAll configured combos with strategies (optional metrics)
omniroute_get_combo_metricsread:combosPerformance metrics for a specific combo
omniroute_switch_combowrite:combosActivate or deactivate a combo
omniroute_check_quotaread:quotaQuota used/total, percent remaining, reset time, token health
omniroute_route_requestexecute:completionsSend a chat completion through OmniRoute routing
omniroute_cost_reportread:usageCost report by period (session/day/week/month)
omniroute_list_models_catalogread:modelsFull model catalog with capabilities, status, pricing
ToolScopesDescription
omniroute_web_searchexecute:searchWeb search through OmniRoute search gateway (Serper/Brave/Perplexity/Exa/Tavily/Google PSE/Linkup/SearchAPI/SearXNG) with failover

Advanced Tools (11) — Phase 2

ToolScopesDescription
omniroute_simulate_routeread:health, read:combosDry-run routing simulation with fallback tree
omniroute_set_budget_guardwrite:budgetSession budget with degrade/block/alert action
omniroute_set_routing_strategywrite:combosUpdate combo strategy at runtime (priority/weighted/auto/etc.)
omniroute_set_resilience_profilewrite:resilienceApply aggressive / balanced / conservative resilience preset
omniroute_test_comboexecute:completions, read:combosLive test of every provider in a combo using a real upstream call
omniroute_get_provider_metricsread:healthPer-provider metrics with p50/p95/p99 latency and circuit breaker state
omniroute_best_combo_for_taskread:combos, read:healthRecommend combo by task type with budget/latency constraints
omniroute_explain_routeread:health, read:usageExplain why a request was routed to a provider (scoring factors + fallbacks)
omniroute_get_session_snapshotread:usageFull session snapshot: cost, tokens, top models/providers, errors, budget guard
omniroute_db_health_checkread:health, write:resilienceDiagnose (and optionally auto-repair) database drift like broken combo refs / orphan rows
omniroute_sync_pricingpricing:writeSync pricing data from external sources (LiteLLM); supports dryRun

Cache Tools (2)

ToolScopesDescription
omniroute_cache_statsread:cacheSemantic cache, prompt-cache, and idempotency stats
omniroute_cache_flushwrite:cacheFlush cache globally or by signature/model

Compression Tools (13)

ToolScopesDescription
omniroute_compression_statusread:compressionCompression settings, analytics summary, and cache-aware stats (includes analytics.mcpDescriptionCompression metadata)
omniroute_compression_configurewrite:compressionConfigure compression mode, threshold, target ratio, system-prompt preservation, MCP description compression toggle
omniroute_set_compression_enginewrite:compressionPick the active engine (off/caveman/rtk/stacked) and Caveman/RTK intensity
omniroute_list_compression_combosread:compressionList named compression combos and their engine pipelines
omniroute_compression_combo_statsread:compressionAnalytics grouped by compression combo and engine
omniroute_ccr_storewrite:compressionStore caller-isolated content in the bounded in-memory CCR store and return a marker plus ccr:// reference
omniroute_ccr_retrieveread:compressionRetrieve CCR content in full or with head, tail, lines, grep, and stats modes
omniroute_ccr_inspectread:compressionInspect caller-owned CCR metadata without returning content
omniroute_ccr_listread:compressionList paginated metadata for caller-owned CCR blocks
omniroute_ccr_deletewrite:compressionDelete a caller-owned CCR block
omniroute_ccr_statsread:compressionReport caller-scoped memory usage, lifecycle counters, and store limits
omniroute_rtk_discoverread:compressionDiscover recurring noise in opt-in RTK output samples
omniroute_rtk_learnread:compressionGenerate a reviewable RTK filter draft from opt-in samples

CCR entries are in-memory only and disappear on restart. Each block is limited to 2 MiB, each principal to 16 MiB, and the global store to 64 MiB. Entries default to a 24-hour TTL (maximum seven days). Full MCP retrieval is limited to 256 KiB; larger blocks remain available through the ranged and grep modes. Storage, retrieval, listing, inspection, deletion, and stats are isolated by the authenticated API-key principal. Audit records contain hashes and size metadata, never content.

omniroute_compression_status reports MCP description compression separately under analytics.mcpDescriptionCompression. Those values are metadata-size estimates for MCP listable descriptions (tools, prompts, resources, and resourceTemplates); they are not provider usage receipts and are marked with source: "mcp_metadata_estimate".

MCP Accessibility Tree Filter (v3.8.0)

Separate from the compression tools above, OmniRoute includes a post-execution filter that compresses the tool results of MCP browser/accessibility tools before they are returned to the agent. This filter is not itself a tool — it runs transparently on any tool result that contains verbose accessibility-tree or browser-snapshot text (≥2000 chars).

Key behaviors:

  • Collapses ≥30 consecutive repeated sibling lines into head + tail summary
  • Preserves [ref=eXX] anchors required by Playwright/computer-use
  • Hard-truncates oversized text (>50,000 chars) with a navigation hint
  • Expected savings: 60–80% on browser snapshot payloads

Configuration: compression.mcpAccessibility in global settings (migration 056). Implementation: open-sse/services/compression/engines/mcpAccessibility/. Full docs: Compression Engines — MCP Accessibility Tree Filter.

See Compression Engines and RTK Compression for the runtime compression model behind these tools.

1Proxy Tools (3)

ToolScopesDescription
omniroute_oneproxy_fetchread:proxiesFetch free proxies from the 1proxy marketplace (protocol/country/quality/limit filters)
omniroute_oneproxy_rotateread:proxiesGet the next available proxy by strategy (random / quality / sequential)
omniroute_oneproxy_statsread:proxiesPool stats, sync status, distribution by protocol and country

Memory Tools (3)

Defined in open-sse/mcp-server/tools/memoryTools.ts. Auth/scope is enforced through the standard MCP scope pipeline.

ToolScopesDescription
omniroute_memory_searchread:memorySearch memories by query / type / API key with token-budget enforcement
omniroute_memory_addwrite:memoryAdd a new memory entry (factual / episodic / procedural / semantic)
omniroute_memory_clearwrite:memoryClear memories for an API key, optionally filtered by type or olderThan timestamp

Skill Tools (4)

Defined in open-sse/mcp-server/tools/skillTools.ts. Backed by src/lib/skills/registry + src/lib/skills/executor.

ToolScopesDescription
omniroute_skills_listread:skillsList registered skills with optional filtering by API key, name, or enabled state
omniroute_skills_enablewrite:skillsEnable or disable a specific skill by ID
omniroute_skills_executeexecute:skillsExecute a skill with provided input and return the execution record
omniroute_skills_executionsread:skillsList recent skill execution history

Notion Context Source (6)

Defined in open-sse/mcp-server/tools/notionTools.ts. Token stored in key_value table via src/lib/db/notion.ts. REST client in src/lib/notion/api.ts. Settings API in src/app/api/settings/notion/route.ts. Dashboard UI in src/app/(dashboard)/dashboard/endpoint/components/NotionSourceCard.tsx.

Configure your Notion integration token from the Context Sources tab in the Endpoint dashboard, or via the REST API:

bash
# Set token
curl -X POST http://localhost:20128/api/settings/notion \
  -H "Content-Type: application/json" \
  -d '{"token": "ntn_..."}'

# Check status
curl http://localhost:20128/api/settings/notion

# Disconnect
curl -X DELETE http://localhost:20128/api/settings/notion
ToolScopesDescription
notion_searchread:notionFull-text search across all pages and databases
notion_get_pageread:notionGet a page by ID with its properties
notion_list_block_childrenread:notionList the child blocks of a page or block
notion_query_databaseread:notionQuery a database with filters, sorts, and pagination
notion_get_databaseread:notionGet database schema by ID
notion_append_blockswrite:notionAppend children blocks to a parent block (max 100 per request)

Agent Skill Catalog Tools (3)

Defined in open-sse/mcp-server/tools/agentSkillTools.ts. Backed by src/lib/agentSkills/catalog. These tools expose the 42-entry Agent Skills documentation catalog to MCP clients and external agents. Scope: read:catalog.

ToolScopesDescription
omniroute_agent_skills_listread:catalogList all 42 agent skills with optional category (api|cli) and area filters; returns metadata + coverage
omniroute_agent_skills_getread:catalogGet full metadata + SKILL.md content for a single skill by canonical id
omniroute_agent_skills_coverageread:catalogCoverage stats: how many of the 22 API and 20 CLI skills have SKILL.md files on the filesystem vs catalog totals

See AGENT-SKILLS.md for the full catalog and how external agents consume it.

computed = 105, computed by countUniqueMcpTools()) is intentionally scoped to runtime routing/cache/compression/memory/skills/proxy/context-source operations. Two adjacent frameworks ship alongside the MCP server in v3.8.0 and are documented separately:

Cloud Agents

Cloud Agents are out-of-process AI coding agents (codex-cloud, devin, jules) wired into OmniRoute through the same connection model used for LLM providers. They are exposed via their own REST surface (/api/v1/agents/*) and are not part of the MCP tool catalog — calling a Cloud Agent does not consume an MCP scope.

  • Implementation: src/lib/cloudAgent/ (registry.ts, agents/codex-cloud.ts, agents/devin.ts, agents/jules.ts).
  • Lifecycle: createTask, getStatus, approvePlan, sendMessage, listSources.
  • Documentation: docs/frameworks/CLOUD_AGENT.md.

Guardrails

Guardrails are pre/post-execution filters (vision-bridge, pii-masker, prompt-injection) applied inside the chat pipeline. They run before the MCP tool/route layer is reached and emit structured violations to the audit pipeline; they are not invoked as MCP tools.

When debugging an MCP call that appears blocked, check both the MCP audit log (scope_denied:* entries) and the guardrails audit trail — a request may be rejected by a guardrail before it ever reaches the MCP scope enforcement layer.


REST API Endpoints

EndpointMethodDescriptionAuth
/api/mcp/statusGETServer status: heartbeat, HTTP transport state, audit activity summaryManagement (session/admin)
/api/mcp/toolsGETTool catalog (name, description, scopes, phase, source endpoints)Management
/api/mcp/sseGET / POSTSSE transport endpoint (gated by mcpEnabled + mcpTransport === "sse")API key + scopes
/api/mcp/streamPOST/GET/DELETEStreamable HTTP transport (uses mcp-session-id header; DELETE ends the session)API key + scopes
/api/mcp/auditGETAudit log entries from mcp_tool_audit (filters: limit, offset, tool, success, apiKeyId)Management
/api/mcp/audit/statsGETAggregated audit stats (totalCalls, successRate, avgDurationMs, top tools)Management

Source files: src/app/api/mcp/{status,tools,sse,stream,audit,audit/stats}/route.ts.

Both SSE and Streamable HTTP transports are blocked until the MCP server is enabled in Settings (mcpEnabled) and the appropriate mcpTransport is selected. If the wrong transport is configured the route returns HTTP 400 with a hint to switch settings.


Authentication & Scopes

MCP tools are authenticated through API key scopes. Scope enforcement is centralized in open-sse/mcp-server/scopeEnforcement.ts. Each tool requires specific scopes:

ScopeTools
read:healthget_health, get_provider_metrics, simulate_route, explain_route, best_combo_for_task, db_health_check
read:comboslist_combos, get_combo_metrics, simulate_route, best_combo_for_task, test_combo
write:combosswitch_combo, set_routing_strategy
read:quotacheck_quota
read:usagecost_report, get_session_snapshot, explain_route
read:modelslist_models_catalog
execute:completionsroute_request, test_combo
execute:searchweb_search
write:budgetset_budget_guard
write:resilienceset_resilience_profile, db_health_check
pricing:writesync_pricing
read:cachecache_stats
write:cachecache_flush
read:compressioncompression_status, list_compression_combos, compression_combo_stats
write:compressioncompression_configure, set_compression_engine
read:proxiesoneproxy_fetch, oneproxy_rotate, oneproxy_stats
read:notionnotion_search, notion_list_databases, notion_get_database, notion_query_database, notion_read
write:notionnotion_append_blocks
read:memorymemory_search
write:memorymemory_add, memory_clear
read:skillsskills_list, skills_executions
write:skillsskills_enable
execute:skillsskills_execute
read:catalogagent_skills_list, agent_skills_get, agent_skills_coverage

Wildcard scopes are supported: read:* grants all read-scopes, * grants full access.

mcp:connect — narrow route capability (#7895)

Reaching the HTTP/SSE MCP transport (/api/mcp/*) from non-loopback requires the /api/mcp/ LOCAL_ONLY carve-out (see docs/security/ROUTE_GUARD_TIERS.md). Historically that carve-out only accepted a full manage/admin-scope API key — too broad for a caller that only needs to talk MCP. src/shared/constants/managementScopes.ts now exports MCP_CONNECT_SCOPE = "mcp:connect": an additive, narrow scope (same precedent as SELF_USAGE_SCOPE) that authorizes ONLY the /api/mcp/ bypass in src/server/authz/policies/management.ts — it grants no other management-route access and is deliberately kept OUT of MANAGEMENT_API_KEY_SCOPES. A key holding manage/admin still passes the carve-out unchanged; mcp:connect is a lower-privilege alternative for remote MCP-only callers, checked via hasMcpConnectOrManageScope().

Per-key HTTP scope binding (#7895)

Over HTTP/SSE, open-sse/mcp-server/httpTransport.ts now resolves the caller's real api_keys.scopes via resolveMcpCallerAuthInfo() (open-sse/mcp-server/httpAuthContext.ts) and passes it to the MCP SDK's transport.handleRequest(req, { authInfo }), so extra.authInfo.scopes reaching each tool call reflects the Bearer key's own scopes. scopeEnforcement.ts's resolveCallerScopeContext() already prioritized authInfo over the _meta and OMNIROUTE_MCP_SCOPES env fallback — this only populates that first, highest-priority source, which was previously unfed over HTTP. When no API key resolves (no header, invalid key), authInfo stays undefined and resolution falls through to the existing meta/env chain unchanged. This does NOT flip OMNIROUTE_MCP_ENFORCE_SCOPES's default — enforcement still has to be explicitly enabled; this change only makes the per-key path take precedence once it is. stdio has no per-caller identity (see mcpCallerIdentity.ts) and is unaffected — it stays on the _meta/env fallback chain.


Environment Variables

VariableDefaultPurpose
OMNIROUTE_BASE_URLhttp://localhost:20128Base URL the MCP server uses when calling OmniRoute internal APIs
OMNIROUTE_API_KEY(empty)API key forwarded as Authorization: Bearer to internal API calls
OMNIROUTE_MCP_ENFORCE_SCOPESfalse (only "true" enables it)When enabled, missing scopes deny tool calls and log scope_denied:<reason> in audit log
OMNIROUTE_MCP_SCOPES(empty)Comma-separated allowlist of scopes considered "available" by default (used when caller does not provide its own scopes)
OMNIROUTE_MCP_COMPRESS_DESCRIPTIONS(unset = on)When set to 0/false/off/no, disables MCP description compression at registration time
OMNIROUTE_MCP_DESCRIPTION_COMPRESSION(unset = on)Alternate alias for the same toggle as above
MCP_TOOL_DENY(unset = no filter)Comma-separated tool names to drop from tools/list (tool-cardinality reduction — see below)
MCP_TOOL_ALLOW(unset = no filter)Comma-separated tool names to keep exclusively (allow-list mode — see below)
DATA_DIR~/.omnirouteHeartbeat file is written to ${DATA_DIR}/runtime/mcp-heartbeat.json

Description Compression

MCP tool, prompt, and resource registries can compress descriptions at registration/list time to reduce the metadata footprint exposed to clients (and therefore the prompt context cost). The implementation lives in open-sse/mcp-server/descriptionCompressor.ts and is wired into the MCP server via compressMcpRegistryMetadata inside createMcpServer().

  • Compression runs over the description text using the Caveman ruleset (getRulesForContext("all", "full")) with preserved-block extraction (code spans, fenced blocks, etc.) so structural content is not altered.
  • Toggle per-deployment via the compression.mcpDescriptionCompressionEnabled value in the key_value settings table (default: enabled) — exposed in the UI as Analytics → MCP description compression.
  • Toggle process-wide via either OMNIROUTE_MCP_COMPRESS_DESCRIPTIONS=false or OMNIROUTE_MCP_DESCRIPTION_COMPRESSION=false.
  • Realtime stats are surfaced via omniroute_compression_status under analytics.mcpDescriptionCompression and tagged source: "mcp_metadata_estimate" to disambiguate from real provider usage receipts.

Tool Cardinality Reduction (F4.3)

Description compression shrinks each tool's metadata; tool-cardinality reduction goes one step further by reducing how many tools are announced at all. Advertising fewer tools in the tools/list manifest cuts the per-request token cost the client's model pays for the tool catalog ("layer 5" compression). The implementation is a pure, stateless filter in open-sse/mcp-server/toolCardinality.ts (reduceToolManifest), wired into the registration loop in createMcpServer() (open-sse/mcp-server/server.ts).

Opt-in, off by default. The filter only runs when at least one of two environment variables is set; with neither set, all 105 tools are announced unchanged.

VariableMode
MCP_TOOL_DENYBlacklist — comma-separated tool names that are always dropped from tools/list
MCP_TOOL_ALLOWAllow-list — comma-separated tool names; only these survive, everything else is dropped

deny takes priority over allow. Names are comma-separated, trimmed, and empty entries are ignored. Examples:

bash
# Drop two tools from the catalog
MCP_TOOL_DENY="omniroute_get_health,omniroute_list_combos" omniroute --mcp

# Announce only the routing + quota tools (allow-list mode)
MCP_TOOL_ALLOW="omniroute_route_request,omniroute_check_quota" omniroute --mcp

How filtered tools are removed: registration always succeeds; a tool the profile rejects is then .disable()d on the MCP SDK handle, so it never appears in tools/list but the wiring stays intact (clean enable/disable, no re-registration). The profile parser is readMcpToolProfileFromEnv(process.env), which returns null (no filtering) when both vars are empty.

The richer ToolProfile shape behind reduceToolManifest also supports scope-intersection filtering (allowScopes, with read:*-style wildcard matching) and a deterministic maxTools cap, but those two knobs need the full manifest at registration time and are not exposed through the environment variables today (a tools/list-level hook is a tracked follow-up). estimateManifestTokens() is available to compare the manifest token cost before and after reduction.


Runtime Heartbeat

The stdio transport persists liveness to ${DATA_DIR}/runtime/mcp-heartbeat.json every 5 seconds. The dashboard (/api/mcp/status) reads this file plus PID liveness to derive online. HTTP transports report state from in-process getMcpHttpStatus() instead (no file write).

The heartbeat snapshot contains:

json
{
  "pid": 12345,
  "startedAt": "2026-05-13T12:34:56.000Z",
  "lastHeartbeatAt": "2026-05-13T12:35:01.000Z",
  "version": "1.8.1",
  "transport": "stdio",
  "scopesEnforced": false,
  "allowedScopes": [],
  "toolCount": 43
}

Audit Logging

Every tool call is logged to the SQLite mcp_tool_audit table by open-sse/mcp-server/audit.ts:

  • Tool name, arguments (hashed/truncated as per-tool auditLevel), result
  • Duration in ms, success/failure flag, error message (when applicable)
  • API key hash, timestamp
  • Scope denials are logged as scope_denied:<reason> with the missing scope list

Use the dashboard or the /api/mcp/audit and /api/mcp/audit/stats REST endpoints to inspect recent calls.


Files

FilePurpose
open-sse/mcp-server/server.tsMCP server factory, stdio entry point, scoped tool registrations
open-sse/mcp-server/httpTransport.tsSSE + Streamable HTTP transport (session management)
open-sse/mcp-server/scopeEnforcement.tsTool scope evaluation and caller resolution
open-sse/mcp-server/audit.tsTool call audit logging (mcp_tool_audit)
open-sse/mcp-server/runtimeHeartbeat.tsstdio heartbeat writer (mcp-heartbeat.json)
open-sse/mcp-server/descriptionCompressor.tsDescription compression for tool / prompt / resource registries
open-sse/mcp-server/schemas/tools.tsZod schemas + tool registry (MCP_TOOLS, 34 entries)
open-sse/mcp-server/tools/advancedTools.tsPhase 2 + cache + 1proxy tool handlers
open-sse/mcp-server/tools/compressionTools.tsCompression tool handlers
open-sse/mcp-server/tools/memoryTools.tsMemory tool definitions (3 tools)
open-sse/mcp-server/tools/skillTools.tsSkill tool definitions (4 tools)
open-sse/mcp-server/tools/notionTools.tsNotion context source tool definitions (6 tools)
open-sse/mcp-server/tools/gamificationTools.tsGamification tool definitions (8 tools)
open-sse/mcp-server/tools/pluginTools.tsPlugin registration and management tools (8 tools)
src/app/api/mcp/status/route.ts/api/mcp/status endpoint
src/app/api/mcp/tools/route.ts/api/mcp/tools endpoint
src/app/api/mcp/sse/route.ts/api/mcp/sse SSE transport route
src/app/api/mcp/stream/route.ts/api/mcp/stream Streamable HTTP transport route
src/app/api/mcp/audit/route.ts/api/mcp/audit audit log query
src/app/api/mcp/audit/stats/route.ts/api/mcp/audit/stats aggregated audit metrics
src/lib/notion/api.tsNotion REST API client (retry, timeout, error classification)
src/lib/db/notion.tsNotion token persistence (key_value table)
src/app/api/settings/notion/route.tsNotion settings API (GET/POST/DELETE)
src/app/(dashboard)/dashboard/endpoint/components/NotionSourceCard.tsxNotion token management UI
tests/unit/notion-api.test.tsNotion API client tests (7)
tests/unit/notion-tools.test.tsNotion tools scope enforcement tests (10)
tests/unit/db/notion.test.mjsNotion DB module tests (3)