# How OmniRoute's MCP Server Exposes 109 Tools Across 33 Scopes

> Learn how OmniRoute's MCP server exposes 109 tools across 33 scopes. Discover runtime scope enforcement and permission validation for secure tool execution.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: internals
- Published: 2026-08-20

---

**OmniRoute's Model Context Protocol (MCP) server exposes 109 tools grouped into 33 fine-grained scopes, with runtime scope enforcement through `resolveCallerScopeContext` and `evaluateToolScopes` functions that validate caller permissions before tool execution.**

The **OmniRoute** project provides a sophisticated bridge between AI agents and enterprise routing capabilities through its MCP server implementation. This server allows Claude Desktop, Cursor, VS Code, and custom agents to invoke a rich catalog of tools while maintaining strict security boundaries. The scope-based architecture ensures multi-tenant deployments can control exactly what each agent is permitted to do.

## Understanding the 109 Tools and 33 Scopes Architecture

OmniRoute's MCP server organizes its functionality into **109 distinct tools** spanning core routing, memory management, skill execution, and system operations. These tools are protected by **33 granular scopes** that follow a consistent `{action}:{resource}` naming pattern.

The scope design enables precise permission modeling. `read:*` scopes provide observability, `write:*` scopes allow configuration changes, and `execute:*` scopes permit active operations like completions and searches.

### Core Scope Categories

| Pattern | Purpose | Example Scopes |
|---------|---------|--------------|
| `read:{resource}` | Observability and metrics | `read:health`, `read:combos`, `read:quota`, `read:usage` |
| `write:{resource}` | Configuration and mutation | `write:combos`, `write:budget`, `write:resilience`, `write:cache` |
| `execute:{action}` | Active operations | `execute:completions`, `execute:search` |

According to the OmniRoute source code in [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts), each tool declares its required scopes in its Zod schema definition. The `MCP_TOOL_MAP` populated from these schemas drives runtime enforcement.

## Scope Enforcement Implementation in [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts)

The security model centers on two key functions in [`open-sse/mcp-server/scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/scopeEnforcement.ts):

### `resolveCallerScopeContext`

This function extracts caller scopes from three sources in order of precedence:

1. **`extra.authInfo.scopes`** — Authentication payload (highest priority)
2. **`extra._meta.scopes`** — Tool call metadata
3. **`OMNIROUTE_MCP_SCOPES`** environment variable — Fallback for local development

If no scopes are found, the caller receives an empty scope list and is treated as anonymous.

### `evaluateToolScopes`

This function performs the actual authorization check with signature:
- Tool name lookup in `MCP_TOOL_MAP`
- Required scope retrieval
- Pattern matching via `scopeMatches` (exact, wildcard `read:*`, prefix `read:health*`)

The function returns a structured result: `{ allowed: boolean, required: string[], provided: string[], missing: string[], reason?: string }`.

Scope enforcement activates when `OMNIROUTE_MCP_ENFORCE_SCOPES=true`. When disabled, all calls proceed unchecked — useful for development but never for production.

## Complete Tool-to-Scope Mapping

The following representative tools demonstrate how OmniRoute assigns scopes. The full catalog spans 33 distinct scope values.

| Scope | Representative Tools | File Reference |
|-------|---------------------|----------------|
| `read:health` | `omniroute_get_health`, `omniroute_simulate_route`, `omniroute_get_provider_metrics` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:combos` | `omniroute_list_combos`, `omniroute_get_combo_metrics`, `omniroute_best_combo_for_task` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:quota` | `omniroute_check_quota` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:usage` | `omniroute_cost_report`, `omniroute_explain_route`, `omniroute_get_session_snapshot` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:models` | `omniroute_list_models_catalog` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:cache` | `omniroute_cache_stats` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `read:compression` | `omniroute_compression_status`, `omniroute_list_compression_combos` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `write:combos` | `omniroute_switch_combo`, `omniroute_create_combo` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `write:budget` | `omniroute_set_budget_guard` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `write:resilience` | `omniroute_set_resilience_profile` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `write:cache` | `omniroute_cache_flush` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `write:compression` | `omniroute_compression_configure`, `omniroute_set_compression_engine` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `execute:completions` | `omniroute_route_request`, `omniroute_test_combo` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |
| `execute:search` | `omniroute_web_fetch`, `omniroute_web_search` | [`README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/README.md) tool table |

Additional scopes cover proxy operations, pricing management, catalog administration, and specialized memory and skill operations.

## Accessing OmniRoute MCP Tools: Three Methods

### Python Client with Automatic Scope Handling

The MCP Python SDK automatically includes caller scopes in tool invocations:

```python
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def demo():
    server = StdioServerParameters(
        command="npx",
        args=["tsx", "open-sse/mcp-server/server.ts"],
        env={"OMNIROUTE_BASE_URL": "http://localhost:20128"}
    )
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as sess:
            await sess.initialize()

            # Requires `read:health` scope

            health = await sess.call_tool("omniroute_get_health", {})
            print("Health:", health.content[0].text)

            # Fails without `write:combos` scope

            try:
                await sess.call_tool("omniroute_switch_combo", {
                    "comboId": "c1", 
                    "active": True
                })
            except Exception as e:
                print("Scope error:", e)

```

The [`open-sse/mcp-server/scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/scopeEnforcement.ts) validation runs automatically on each call.

### Direct TypeScript Scope Inspection

For debugging or custom implementations, use the enforcement functions directly:

```typescript
import { 
  resolveCallerScopeContext, 
  evaluateToolScopes 
} from "./scopeEnforcement.ts";

const extra = {
  authInfo: { 
    clientId: "agent-123", 
    scopes: ["read:health", "read:combos"] 
  },
  sessionId: "sess-xyz",
};

const ctx = resolveCallerScopeContext(extra);
const check = evaluateToolScopes(
  "omniroute_get_health", 
  ctx.scopes, 
  true  // enforceScopes flag
);

console.log(
  check.allowed 
    ? "Allowed" 
    : `Missing: ${check.missing.join(", ")}`
);

```

This executes the same logic at lines 72-96 and 99-135 of [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts) that the server uses internally.

### HTTP API with Manual Scope Header

For direct HTTP integration, scopes pass via header:

```bash
curl -X POST http://localhost:20128/mcp \
  -H "Content-Type: application/json" \
  -H "X-OmniRoute-Scopes: read:health,read:quota" \
  -d '{"tool":"omniroute_check_quota","args":{}}'

```

The server extracts `X-OmniRoute-Scopes` and processes through identical enforcement pipeline as stdio transport.

## Audit Logging and Observability

Every tool invocation is recorded in [`open-sse/mcp-server/audit.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/audit.ts). The implementation:

- SHA-256 hashes input arguments for privacy
- Stores truncated output previews
- Maintains SQLite-backed history for compliance tracing

This logging operates independently of scope enforcement, ensuring complete audit trails even when enforcement is disabled.

## Key Source Files

Understanding OmniRoute's MCP server requires familiarity with these components:

| File | Responsibility |
|------|---------------|
| [`open-sse/mcp-server/README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/README.md) | Human-readable tool and scope documentation |
| [`open-sse/mcp-server/scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/scopeEnforcement.ts) | Core authorization logic (`resolveCallerScopeContext`, `evaluateToolScopes`, `scopeMatches`) |
| [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts) | Zod schemas defining tool signatures and required scopes |
| [`open-sse/mcp-server/audit.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/audit.ts) | SQLite audit logger with SHA-256 input hashing |
| [`open-sse/mcp-server/server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/server.ts) | Transport bootstrap (stdio/HTTP) and tool dispatcher |
| [`open-sse/mcp-server/__tests__/essentialTools.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/__tests__/essentialTools.test.ts) | Scope enforcement validation tests |

## Summary

- **OmniRoute's MCP server exposes 109 tools** protected by **33 fine-grained scopes** following `{action}:{resource}` naming conventions
- **Scope enforcement** occurs through `resolveCallerScopeContext` extracting from auth payload, metadata, or environment, followed by `evaluateToolScopes` performing pattern-matched validation
- **Three transport modes** support scope passing: stdio (automatic), TypeScript SDK (programmatic), and HTTP (`X-OmniRoute-Scopes` header)
- **Development override** via `OMNIROUTE_MCP_ENFORCE_SCOPES=false` disables checks for local testing
- **Complete audit trail** via [`audit.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/audit.ts) with hashed inputs stored in SQLite

## Frequently Asked Questions

### How are the 33 scopes defined and where can I see the complete list?

The complete scope-to-tool mapping is documented in [`open-sse/mcp-server/README.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/README.md) under the Security & Scope Enforcement section. The source of truth is [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts), where each tool's Zod schema includes a `scopes` array. The README renders this as a readable table covering all 33 scopes from `read:health` through specialized scopes like `execute:search` and `write:compression`.

### What happens when a tool call lacks required scopes?

The `evaluateToolScopes` function returns `{ allowed: false, missing: [...] }` with a descriptive reason. When `OMNIROUTE_MCP_ENFORCE_SCOPES=true`, the server rejects the call before execution. The caller receives an error indicating which scopes are required versus which were provided. This check occurs at lines 99-135 of [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts).

### Can I use wildcards or patterns in scope assignments?

Yes. The `scopeMatches` function supports three patterns: exact string match (`read:health` equals `read:health`), wildcard suffix (`read:*` matches any read scope), and prefix wildcards (`read:health*` matches `read:health` and `read:health-metrics`). This allows coarse-grained permission grants without enumerating every specific scope.

### How do I add custom scopes for my organization's tools?

Extend [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts) with new tool definitions including your custom `scopes` array. The `MCP_TOOL_MAP` automatically incorporates these. Ensure your authentication system or environment configuration populates `extra.authInfo.scopes` or `OMNIROUTE_MCP_SCOPES` with your custom scope values. No changes to [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts) are required — the pattern matching handles arbitrary scope strings.