# How the OmniRoute MCP Server with 104 IO4 Tools Works: Architecture, Tool Registry, and Scope System Explained

> Explore the OmniRoute MCP server architecture and how it uses 104 IO4 tools. Understand its unified endpoint, scope system, and request handling for efficient API integration.

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

---

**The OmniRoute MCP server is a JSON‑RPC gateway that exposes 104+ IO4 tools through a unified HTTP/WebSocket endpoint, enforcing OAuth‑style scopes via a three‑tier resolution system before invoking domain‑specific handlers.**

The **OmniRoute Multi‑Client Protocol (MCP) server** provides a lightweight, secure RPC layer that bridges external clients to the IO4 (Input/Output‑oriented) tool ecosystem. This article examines how the server processes requests, registers tools, and enforces granular permissions across functional domains like skills, memory, Obsidian, and gamification.

## MCP Server Core Architecture

The server entry point resides in `open‑sse/mcp‑server/server.ts`, which initializes an HTTP and WebSocket listener on port 20128 (configurable). The core flow follows three stages:

1. **Transport handling** — [`httpTransport.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/httpTransport.ts) manages raw request/response cycles and protocol upgrade logic
2. **Authentication context building** — [`httpAuthContext.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/httpAuthContext.ts) extracts caller identity from headers and constructs an `McpToolExtraLike` object containing `authInfo` and optional `meta` fields
3. **Request dispatch** — The server parses JSON‑RPC payloads, maps `method` names to registered tools, and orchestrates scope enforcement before handler execution

The protocol endpoint is `/api/mcp`, accepting POST requests with standard JSON‑RPC 2.0 envelopes.

## IO4 Tool Registry Structure

All 104+ tools are defined under `open‑sse/mcp‑server/tools/` as individual TypeScript modules. Each tool exports a standardized interface:

```ts
// open-sse/mcp-server/tools/skillTools.ts
export const readSkill = {
  description: "Read a skill definition",
  scopes: ["read:skills"],           // Required OAuth-style permissions
  handler: async (args) => {
    // Implementation returns JSON-serializable result
  }
};

```

The toolchain spans multiple functional domains. Tool categories include:

- **skillTools** (`read:skills`, `write:skills`, `execute:skills`)
- **memoryTools** (`read:memory`, `write:memory`)
- **obsidianTools** (`read:obsidian`, `write:obsidian`)
- **notionTools** (`read:notion`, `write:notion`)
- **pluginTools** (`read:plugins`, `write:plugins`)
- **poolTools** (`read:health`, `write:resilience`)
- **compressionTools** (`read:compression`, `write:compression`)
- **gamificationTools** (`read:gamification`, `write:gamification`)
- **localCorpusTools** (`read:local-corpus`)

Additional utility and meta-tools are registered through the same pattern, with scope requirements varying from highly restrictive to implicitly granted fallback scopes.

## Three-Tier Scope Resolution System

Before any handler executes, [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts) resolves caller permissions through `resolveCallerScopeContext` (lines 72‑96). The resolution hierarchy prioritizes sources in this order:

1. **authInfo scopes** (lines 81‑84) — Extracted directly from the OAuth token's `scopes` claim in the `Authorization` header
2. **meta scopes** (lines 86‑89) — Override or supplement via a `scopes` field inside the request's `meta` object
3. **fallback scopes** (lines 91‑94) — Environment-defined default scopes applied when no authentication is present

The resulting `CallerScopeContext` contains `callerId`, `scopes` array, and `source` indicator for audit logging.

## Scope Matching and Authorization Logic

The `evaluateToolScopes` function (lines 99‑135) performs the actual authorization check using `scopeMatches` (lines 61‑68), which supports:

- **Exact matches** — `read:skills` requires `read:skills`
- **Wildcards** — `*` grants access to all scopes
- **Prefix patterns** — `read:*` satisfies `read:skills`, `read:memory`, etc.

When authorization fails, the server returns a JSON‑RPC error object with `code: -32001` and `data.missing_scopes` listing the unsatisfied requirements.

## Domain-Specific Scope Catalog

The following table maps functional domains to their defined scopes with source file locations:

| Domain | Scopes | Definition Location |
|--------|--------|---------------------|
| **Skills** | `read:skills`, `write:skills`, `execute:skills` | [`skillTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/skillTools.ts#L28), L59, L75 |
| **Memory** | `read:memory`, `write:memory` | [`memoryTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/memoryTools.ts#L38), L77, L103 |
| **Obsidian** | `read:obsidian`, `write:obsidian` | [`obsidianTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/obsidianTools.ts#L44)‑L154, L174‑L281 |
| **Notion** | `read:notion`, `write:notion` | [`notionTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/notionTools.ts#L15)‑L55, L95 |
| **Plugins** | `read:plugins`, `write:plugins` | [`pluginTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/pluginTools.ts#L39)‑L182, L67‑L206 |
| **Pool / Health** | `read:health`, `write:resilience` | [`poolTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/poolTools.ts#L161)‑L201, L177‑L185 |
| **Compression** | `read:compression`, `write:compression` | [`compressionTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/compressionTools.ts#L551)‑L651, L559‑L622 |
| **Gamification** | `read:gamification`, `write:gamification` | [`gamificationTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/gamificationTools.ts#L13)‑L41, L90‑L116 |
| **Local Corpus** | `read:local-corpus` | [`localCorpusTools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/localCorpusTools.ts#L14)‑L43 |
| **IO4 Core** | `read:io4` | Implicit fallback scope |

This taxonomy ensures clients receive **principle of least privilege** access—an automation script syncing Obsidian notes never receives memory write permissions unless explicitly granted.

## Complete Request Lifecycle

The execution flow from client call to tool response:

```ts
// Step 1: Client constructs JSON-RPC payload
const payload = {
  jsonrpc: "2.0",
  id: 1,
  method: "readSkill",
  params: { skillId: "my-awesome-skill" }
};

// Step 2: HTTP POST with bearer token containing required scope
const response = await fetch("http://localhost:20128/api/mcp", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <token-with-read:skills>"
  },
  body: JSON.stringify(payload)
});

```

Server-side processing:

1. [`server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/server.ts) receives POST to `/api/mcp`
2. [`httpAuthContext.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/httpAuthContext.ts) builds `McpToolExtraLike` from headers
3. `resolveCallerScopeContext` extracts `["read:skills", "read:memory"]` from token
4. `evaluateToolScopes` verifies `read:skills` satisfies `read:skills` requirement
5. `readSkill.handler` executes with `{ skillId: "my-awesome-skill" }`
6. JSON‑RPC response returned with `result` or standardized error

## Scope-Free Tools and Fallback Behavior

Certain utility tools require no explicit caller scopes but still pass through the enforcement layer. The `pickFastestModel` tool exemplifies this pattern:

```ts
import { pickFastestModel } from "omniroute-mcp-client";

const best = await pickFastestModel({
  comboId: "auto",
  candidates: [{ provider: "openai", model: "gpt-4o" }]
});
// Returns fastest model per telemetry in catalog.ts

```

These tools typically declare empty `scopes: []` or rely on the implicit `read:io4` fallback granted to all authenticated sessions. The [`catalog.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/catalog.ts) module provides dynamic model rankings derived from performance telemetry.

## Authorization Failure Handling

Scope violations return structured errors for programmatic handling:

```ts
// Attempting write:memory without authorization
{
  jsonrpc: "2.0",
  id: 2,
  error: {
    code: -32001,
    message: "Insufficient scopes",
    data: {
      missing_scopes: ["write:memory"],
      available_scopes: ["read:memory", "read:skills"]
    }
  }
}

```

This design enables clients to implement **scope escalation flows**, requesting additional permissions when operations fail.

## Key Implementation Files

| File | Purpose |
|------|---------|
| `open‑sse/mcp‑server/server.ts` | Main entry point, HTTP/WebSocket listener |
| `open‑sse/mcp‑server/httpTransport.ts` | Low-level request handling |
| `open‑sse/mcp‑server/httpAuthContext.ts` | Authentication context extraction |
| `open‑sse/mcp‑server/scopeEnforcement.ts` | Scope resolution and authorization logic |
| `open‑sse/mcp‑server/tools/*.ts` | Individual tool definitions and handlers |
| `open‑sse/mcp‑server/catalog.ts` | Model catalog and telemetry aggregation |

## Summary

- The **OmniRoute MCP server** exposes 104+ IO4 tools through a JSON‑RPC endpoint at `/api/mcp`, implementing the Multi‑Client Protocol for standardized client integration
- **Scope enforcement** operates through three resolution tiers: OAuth token claims, request meta overrides, and environment fallbacks, evaluated by `resolveCallerScopeContext` in [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts)
- **Authorization logic** in `evaluateToolScopes` supports exact, wildcard, and prefix matching, returning structured `missing_scopes` errors on failure
- Tools are organized by **functional domain** (skills, memory, Obsidian, gamification, etc.) with granular `read:` and `write:` permissions, preventing unauthorized cross-domain access
- The **handler invocation flow** guarantees scope verification precedes execution, ensuring the IO4 ecosystem maintains strict security boundaries

## Frequently Asked Questions

### What protocol does the OmniRoute MCP server use?

The OmniRoute MCP server implements **JSON‑RPC 2.0** over HTTP and WebSocket transports. Clients POST requests to `/api/mcp` with standard JSON‑RPC envelopes containing `method`, `params`, `id`, and `jsonrpc: "2.0"` fields. This protocol choice enables language-agnostic integration and straightforward debugging with standard HTTP tools.

### How are the 104 tools organized in the codebase?

Tools reside in `open‑sse/mcp‑server/tools/` as individual TypeScript modules grouped by functional domain. Each module exports tool objects with `description`, `scopes` array, and `handler` function properties. The server discovers and registers these tools at startup, creating a unified dispatch table that maps method names to their implementations.

### Can I call MCP tools without authentication?

Unauthenticated calls receive only **fallback scopes** defined in environment configuration, typically limited to `read:io4` or empty arrays. Most production tools require explicit OAuth tokens with domain-specific scopes. The [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts) module processes unauthenticated requests through the same code path but with restricted `callerId` and minimal permission grants.

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

The server returns a JSON‑RPC error response with `code: -32001` and a `data.missing_scopes` array listing the unsatisfied requirements. The response includes `available_scopes` for debugging. This standardized error format allows clients to detect permission gaps and trigger re-authentication or scope escalation workflows.