# How to Configure MCP Server Tools and Scope Enforcement in OmniRoute

> Learn to configure MCP server tools and scope enforcement in OmniRoute. Master fine-grained access control and secure your environment efficiently.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-26

---

**OmniRoute's MCP server enforces fine-grained access control by validating caller scopes against each tool's requirements configured in the tool definition, using environment variables and middleware wrappers.**

OmniRoute (diegosouzapw/OmniRoute) exposes AI-agent capabilities through a Model Context Protocol (MCP) server that validates permissions before executing tool calls. Configuring MCP server tools and scope enforcement requires defining required scopes in the tool schema and enabling runtime checks via environment variables.

## Core Architecture of MCP Scope Enforcement

OmniRoute implements scope enforcement through a middleware pipeline that intercepts tool invocations. The system extracts caller identity and scopes from request metadata, then evaluates them against the tool's declared requirements.

### Key Components

The enforcement mechanism relies on four primary source files:

- **[`open-sse/mcp-server/scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/scopeEnforcement.ts)**: Contains `resolveCallerScopeContext()` to extract the caller's identity (`clientId` or `sessionId`) and scopes from `authInfo` or `_meta` payloads. It also exports `evaluateToolScopes()` which checks if required tool scopes are satisfied.

- **[`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts)**: Declares the **MCP_TOOL_MAP** and every tool's Zod schema alongside its `scopes` array (e.g., `["read:health"]`). This map drives the scope validation logic.

- **[`open-sse/mcp-server/server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/server.ts)**: Bootstraps the MCP server via `createMcpServer()`. At lines 95-101, it reads `OMNIROUTE_MCP_ENFORCE_SCOPES` and `OMNIROUTE_MCP_SCOPES` from the environment. Each tool handler is wrapped with `withScopeEnforcement` before registration via `server.registerTool`.

- **[`open-sse/mcp-server/httpAuthContext.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/httpAuthContext.ts)**: Propagates internal authentication headers (`X-MCP-Auth-ClientId`, `X-MCP-Auth-Scopes`) when the MCP server calls the OmniRoute HTTP API, ensuring scope context persists across service boundaries.

### Request Processing Flow

When an AI agent invokes a tool, OmniRoute processes the request through this pipeline:

1. The incoming JSON-RPC request hits `server.registerTool`, triggering the `withScopeEnforcement` wrapper.

2. The wrapper calls `resolveCallerScopeContext(extra, fallbackScopes)`, where `extra` contains forwarded `authInfo` from the client's API-key metadata.

3. `evaluateToolScopes(toolName, callerScopes, MCP_ENFORCE_SCOPES, toolScopes)` validates permissions:
   - If enforcement is disabled, the call proceeds immediately.
   - If enabled and scopes are missing, the call rejects with an error and logs via `logToolCall`.

4. Upon successful validation, the original handler (e.g., `handleGetHealth`) executes and returns results.

## Configuring Scope Enforcement Environment Variables

The server respects two environment variables read at startup (see lines 95-101 of [`server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/server.ts)):

```typescript
const MCP_ENFORCE_SCOPES = process.env.OMNIROUTE_MCP_ENFORCE_SCOPES === "true";
const MCP_ALLOWED_SCOPES = new Set(
  (process.env.OMNIROUTE_MCP_SCOPES || "")
    .split(",")
    .map((s) => s.trim())
    .filter(Boolean)
);

```

### Enabling Strict Scope Checking

Set `OMNIROUTE_MCP_ENFORCE_SCOPES` to `"true"` to activate runtime validation:

```bash
export OMNIROUTE_MCP_ENFORCE_SCOPES=true

```

When enabled, any tool call lacking the required scopes defined in [`tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tools.ts) receives an error response indicating the missing permissions.

### Setting Fallback Scopes

`OMNIROUTE_MCP_SCOPES` defines comma-separated fallback scopes for unauthenticated callers:

```bash
export OMNIROUTE_MCP_SCOPES=read:health,read:models

```

These scopes apply when a caller does not provide its own scopes via `authInfo` headers, evaluated by `resolveCallerScopeContext` as the final fallback tier.

## Defining and Modifying Tool Scopes

All tool definitions reside in [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts). Each tool exports a definition containing a `scopes` array:

```typescript
export const getHealthTool: McpToolDefinition<typeof getHealthInput, typeof getHealthOutput> = {
  name: "omniroute_get_health",
  description: "...",
  inputSchema: getHealthInput,
  outputSchema: getHealthOutput,
  scopes: ["read:health"],
  auditLevel: "basic",
  phase: 1,
  sourceEndpoints: [...]
};

```

To modify a tool's requirements:

1. Edit the `scopes` array in the tool definition within [`tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tools.ts).
2. Rebuild the application or restart the MCP server to regenerate **MCP_TOOL_MAP** (lines 1500-1505).

The `withScopeEnforcement` wrapper automatically reads updated requirements from the regenerated map on subsequent requests.

## Practical Implementation Examples

### Starting the Server with Enforcement Enabled

Create a `.env` file or export variables before launching:

```bash

# .env configuration

OMNIROUTE_MCP_ENFORCE_SCOPES=true
OMNIROUTE_MCP_SCOPES=read:health,read:models

# Launch via CLI

omniroute --mcp

```

The server emits a startup banner (`[MCP] OmniRoute MCP Server starting…`) and reports the registered tool count via `TOTAL_MCP_TOOL_COUNT`.

### Calling Tools with Authenticated Scopes

Use an API key with sufficient scopes:

```javascript
import { McpClient } from "@modelcontextprotocol/sdk/client/mcp.js";

const client = new McpClient({
  apiKey: "sk_abcdef123456", // API key possessing `read:health` scope
});

async function getHealth() {
  const result = await client.callTool("omniroute_get_health", {});
  console.log(result);
}

```

Missing scopes produce an error: `Insufficient MCP scopes for omniroute_get_health. Missing: read:health. Caller=anonymous, source=env.`

### Overriding Scopes Per Request

Bypass global fallback scopes by providing explicit `authInfo`:

```javascript
const result = await client.callTool(
  "omniroute_get_models_catalog",
  { provider: "openai" },
  {
    authInfo: {
      clientId: "my-temp-key",
      scopes: ["read:models"]
    }
  }
);

```

The `resolveCallerScopeContext` function prioritizes these explicit scopes over `OMNIROUTE_MCP_SCOPES`.

### Disabling Enforcement for Development

Unset or clear the enforcement variable to allow all calls:

```bash
export OMNIROUTE_MCP_ENFORCE_SCOPES=
omniroute --mcp

```

In this mode, `evaluateToolScopes` logs tool calls via `logToolCall` but never rejects requests based on scope permissions.

## Summary

- **Scope enforcement** validates caller permissions against tool requirements using middleware in [`server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/server.ts) and logic in [`scopeEnforcement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scopeEnforcement.ts).
- **Configuration** relies on two environment variables: `OMNIROUTE_MCP_ENFORCE_SCOPES` (boolean toggle) and `OMNIROUTE_MCP_SCOPES` (fallback list).
- **Tool definitions** declare required scopes in [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts) via the `scopes` array property.
- **Caller identity** propagates through `authInfo` metadata or `X-MCP-Auth-*` HTTP headers, parsed by `resolveCallerScopeContext`.
- **Deployment** requires restarting the MCP server after modifying tool scopes or environment variables for changes to take effect.

## Frequently Asked Questions

### What happens if a caller lacks the required scopes for an MCP tool?

The `evaluateToolScopes` function rejects the call with an error message indicating the missing scope (e.g., `Missing: read:health`), logs the attempt via `logToolCall`, and returns the error to the client without executing the tool handler.

### How do I add a new scope to an existing MCP tool in OmniRoute?

Edit the tool's definition in [`open-sse/mcp-server/schemas/tools.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/mcp-server/schemas/tools.ts) to include the new scope in the `scopes` array (e.g., `scopes: ["read:health", "admin:config"]`). Restart the server to regenerate the **MCP_TOOL_MAP** and apply the new requirements immediately.

### Can I disable scope enforcement temporarily for testing?

Yes. Set `OMNIROUTE_MCP_ENFORCE_SCOPES` to any value other than `"true"` or unset it entirely. This disables the enforcement check in `evaluateToolScopes`, allowing all tool calls to proceed regardless of the caller's scopes while still logging access attempts.

### Where does the MCP server read the caller's scopes from?

The server extracts scopes from multiple sources in priority order: first from the JSON-RPC request's `authInfo` metadata (populated via API-key policies), then from the `_meta` payload, and finally falls back to the comma-separated list in the `OMNIROUTE_MCP_SCOPES` environment variable. Internally, [`httpAuthContext.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/httpAuthContext.ts) translates these into `X-MCP-Auth-Scopes` headers for downstream HTTP calls.