# How OpenSEO Routes MCP Requests Across Authentication Modes

> Discover how OpenSEO routes MCP requests across Hosted OAuth, Cloudflare Access, and local no-auth modes using a unified /mcp endpoint before reaching a shared handler.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-09-04

---

**OpenSEO uses a single `/mcp` endpoint that branches into three distinct authentication flows—Hosted OAuth, Cloudflare Access self-hosted, and local no-auth—to validate requests before converging on a shared MCP server handler.**

OpenSEO implements a centralized MCP (Model Context Protocol) routing system in the `every-app/open-seo` repository that handles diverse authentication requirements through unified entry points. The architecture delegates credential validation to mode-specific handlers in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) before funneling all requests through a common processing pipeline that ensures consistent tool execution regardless of deployment context.

## The Three Authentication Entry Points

The routing logic in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) exposes two primary functions that handle three distinct authentication scenarios. Each path validates credentials differently but ultimately produces a standardized `ToolAuthContext` for downstream processing.

### Hosted OAuth Mode

The hosted flow begins at `handleAuthenticatedOpenSeoMcpRequest`, designed for multi-tenant SaaS deployments using OAuth 2.0 authentication.

The request must carry a valid OAuth token parsed by `hostedWorkersOAuthMcpPropsSchema`, which enforces the presence of the **MCP scope** (`MCP_SCOPE`). The system then verifies the token's user-organization membership via `AuthRepository.getMembership` (defined in [`src/server/auth/repositories/AuthRepository.ts`](https://github.com/every-app/open-seo/blob/main/src/server/auth/repositories/AuthRepository.ts)) to confirm the user still belongs to the claimed organization.

After validation, the handler builds a `ToolAuthContext` and passes it to `createWorkersOAuthMcpProps`. The request then flows to `createRequestHandler`, which instantiates `createOpenSeoMcpServer` and processes the call.

```typescript
// Hosted (OAuth) – called from the OAuth provider
await handleAuthenticatedOpenSeoMcpRequest(
  request,                // incoming HTTP request
  props,                  // OAuth-derived props (contains MCP auth context)
  env,                    // Cloudflare environment
  ctx                     // Execution context
);

```

### Self-Hosted Cloudflare Access

For enterprises using Cloudflare Access, the `handleSelfHostedOpenSeoMcpRequest` function accepts an `authMode` parameter set to `cloudflare_access`.

This path resolves identity through `resolveCloudflareAccessContext` (implemented in [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts)) without requiring OAuth tokens. The function examines the request for Cloudflare-issued identity headers, extracting the user ID, email, and organization ID.

The resolved identity wraps into `createWorkersOAuthMcpProps` and proceeds to `createRequestHandler`, utilizing the same MCP server implementation as the hosted mode but bypassing OAuth-client specific checks.

```typescript
// Self-hosted – Cloudflare Access
await handleSelfHostedOpenSeoMcpRequest(
  request,
  "cloudflare_access",   // auth mode
  env,
  ctx
);

```

### Local No-Auth Development Mode

Development and on-premise deployments use the same `handleSelfHostedOpenSeoMcpRequest` entry point with `authMode` set to `local_noauth`.

The `resolveLocalNoAuthContext` function (located in [`src/middleware/ensure-user/delegated.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/delegated.ts)) generates a synthetic admin-level identity, enabling unrestricted access for local development. This fake identity feeds into `createWorkersOAuthMcpProps` and follows the identical routing path to `createRequestHandler` as the Cloudflare Access mode.

```typescript
// Self-hosted – Local no-auth (development)
await handleSelfHostedOpenSeoMcpRequest(
  request,
  "local_noauth",
  env,
  ctx
);

```

## Request Validation and Context Creation

All authentication paths converge on a standardized validation and context-building phase defined in [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts).

### Token Verification and Membership Checks

The hosted mode performs the most rigorous validation. After schema validation via `hostedWorkersOAuthMcpPropsSchema`, the system queries `AuthRepository.getMembership` to verify the user-organization relationship remains active. This prevents revoked or transferred users from accessing organizational MCP resources.

Self-hosted modes skip membership database lookups, instead trusting Cloudflare Access headers or the local development identity.

### Building the ToolAuthContext

The `createMcpToolContext` function transforms validated `McpProps` into a `ToolAuthContext` containing:
- `userId`
- `organizationId`
- `role`
- `orgScope`
- Granted scopes list

This context attaches to every MCP tool invocation, ensuring authorization decisions have access to identity and permission metadata regardless of which authentication mode initiated the request.

## Unified Processing Pipeline

After authentication-specific handling, all requests flow through shared middleware and processing logic defined in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts).

### CORS and Legacy Request Handling

Every response passes through `withMcpCors`, which injects fixed CORS headers (`MCP_CORS_HEADERS`) to support cross-origin browser requests.

The system then performs legacy detection via `isLegacyRequest`. Legacy JSON-RPC calls route to `handleLegacyJsonRequest`, while modern MCP protocol requests dispatch through `createMcpHandler` from the Agents SDK. This dual-path support ensures backward compatibility while enabling new MCP features.

### MCP Server Initialization

The final routing stage calls `createRequestHandler`, which initializes `createOpenSeoMcpServer`. This centralized server definition ensures consistent tool availability and behavior across all authentication modes, preventing drift between hosted and self-hosted deployments.

## Summary

- **Single endpoint architecture**: OpenSEO exposes one `/mcp` route handled by `handleAuthenticatedOpenSeoMcpRequest` (hosted) or `handleSelfHostedOpenSeoMcpRequest` (self-hosted) in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts).
- **Three authentication modes**: Hosted OAuth validates tokens against `AuthRepository` membership; Cloudflare Access resolves identity from Cloudflare headers via [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts); local no-auth generates synthetic admin identities via [`src/middleware/ensure-user/delegated.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/delegated.ts).
- **Convergent processing**: All modes use `createWorkersOAuthMcpProps` to build a standardized `ToolAuthContext` before passing control to `createRequestHandler` and the shared MCP server.
- **Shared infrastructure**: CORS handling via `withMcpCors`, legacy request support through `isLegacyRequest`, and tool context creation via `createMcpToolContext` remain consistent across all authentication paths.

## Frequently Asked Questions

### How does OpenSEO verify organization membership in hosted mode?

In hosted OAuth mode, after validating the token schema and MCP scope, OpenSEO calls `AuthRepository.getMembership` to confirm the user ID extracted from the token still belongs to the claimed organization. This prevents access from users who have been removed from an organization but possess old tokens.

### Can self-hosted instances use the same MCP tools as the hosted version?

Yes. Both self-hosted modes (Cloudflare Access and local no-auth) ultimately call `createRequestHandler`, which instantiates the same `createOpenSeoMcpServer` used by the hosted flow. This ensures feature parity and prevents tool implementation fragmentation between deployment models.

### What security headers does OpenSEO apply to MCP responses?

All MCP responses pass through `withMcpCors`, which attaches `MCP_CORS_HEADERS` to enable cross-origin requests from browser-based MCP clients. This handling applies uniformly across all three authentication modes.

### Where does the local no-auth mode generate its identity?

The `resolveLocalNoAuthContext` function in [`src/middleware/ensure-user/delegated.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/delegated.ts), called within `handleSelfHostedOpenSeoMcpRequest` when `authMode` equals `local_noauth`, generates a synthetic admin-level identity. This bypasses external authentication services and is restricted to development or trusted on-premise environments.