# How the OpenSEO Router Distinguishes MCP Requests from Standard App Requests

> Discover how the OpenSEO router expertly separates MCP requests from standard app requests using pathname and authentication mode checks. Optimize your application routing.

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

---

**The OpenSEO server uses a pathname and authentication mode check to route Model-Context-Protocol (MCP) requests to dedicated handlers while sending all other traffic to the standard application.**

OpenSEO is an open-source SEO platform maintained in the every-app/open-seo repository that supports both hosted OAuth flows and self-hosted deployments. Understanding how the OpenSEO router distinguishes MCP requests from standard app requests is essential for developers integrating AI agents or debugging routing issues in self-hosted environments.

## The Routing Logic

The OpenSEO router implements a simple but strict **pathname plus auth-mode** validation to separate MCP traffic from regular application traffic. This logic lives in the central request handler within [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts).

### Authentication Mode Constraints

The router first determines the current **authentication mode** using `getAuthMode(env.AUTH_MODE)`. The MCP endpoint is only exposed when the server runs in specific self-hosted configurations:

- **`cloudflare_access`** – Self-hosted deployments protected by Cloudflare Access
- **`local_noauth`** – Local development environments without authentication

Hosted deployments using OAuth mode never expose the MCP endpoint directly. Instead, they route AI interactions through the OpenSEO OAuth provider.

### Pathname Matching

The router extracts the `pathname` from the incoming request URL using `new URL(publicRequest.url).pathname`. It compares this against the constant `MCP_ROUTE`, defined in [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts) as the string `"/mcp"`.

The conditional check in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) follows this exact logic:

```typescript
if (
  (authMode === "cloudflare_access" || authMode === "local_noauth") &&
  pathname === MCP_ROUTE
) {
  return handleSelfHostedOpenSeoMcpRequest(publicRequest, authMode, env, ctx);
}

```

When this condition evaluates to true, the request forwards to the MCP transport layer. Otherwise, execution falls through to the standard application handler.

## Implementation Details

The routing decision relies on two critical source files that work together to enforce the separation of concerns.

### Central Request Router

In [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), the router coordinates the branching logic. The code inspects the raw request URL, determines the deployment context, and decides whether to invoke `handleSelfHostedOpenSeoMcpRequest` or the standard fetch handler (`appFetch`).

### MCP Context Definitions

The file [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts) exports the route constant and defines the authorization schema. This centralization ensures that both the router and the MCP handler reference the same path definition, preventing drift between the routing logic and the actual endpoint implementation.

## Code Examples

### Routing Logic Implementation

The following snippet from [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) demonstrates the complete decision tree:

```typescript
const authMode = getAuthMode(env.AUTH_MODE);
const pathname = new URL(publicRequest.url).pathname;

// MCP request?
if (
  (authMode === "cloudflare_access" || authMode === "local_noauth") &&
  pathname === MCP_ROUTE
) {
  // Forward to the MCP transport
  return handleSelfHostedOpenSeoMcpRequest(publicRequest, authMode, env, ctx);
}

// Anything else → normal app
return appFetch(request);

```

### Self-Hosted MCP Request

In a self-hosted environment running `local_noauth` mode, MCP requests reach the transport layer:

```bash

# Server running in local_noauth mode

curl -i http://localhost:8787/mcp \
  -H "Accept: application/json"

```

This request passes the auth-mode check and reaches `handleSelfHostedOpenSeoMcpRequest`, where the MCP server processes the Model-Context-Protocol payload.

### Hosted Deployment Behavior

On hosted deployments using OAuth authentication, the same request path behaves differently:

```bash

# Hosted deployment (auth mode = "oauth")

curl -i https://my-open-seo.example.com/mcp

```

Here, the condition fails because `authMode` is neither `"cloudflare_access"` nor `"local_noauth"`. The request falls through to the OAuth provider (`openSeoOAuthProvider.fetch`), typically returning a 404 or redirect rather than reaching the MCP transport.

## Summary

- **Pathname check**: The router validates against `MCP_ROUTE` (`"/mcp"`) defined in [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts)
- **Auth-mode guard**: MCP handling only activates in `cloudflare_access` or `local_noauth` modes, protecting hosted OAuth deployments from unauthorized MCP access
- **Clean separation**: Requests meeting both criteria route to `handleSelfHostedOpenSeoMcpRequest`; all others fallback to standard application handlers
- **Security by default**: Hosted deployments intentionally exclude the MCP endpoint, requiring AI integrations to use the OAuth provider instead

## Frequently Asked Questions

### What happens if I send an MCP request to a hosted OpenSEO instance?

The request fails the authentication mode check and routes to the standard OAuth handler. Hosted deployments (OAuth mode) intentionally disable direct MCP access to prevent unauthorized AI agent connections, returning a 404 or redirect instead.

### Can I change the MCP route path from `/mcp` to something else?

The path is defined as a constant in [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts). While you could modify the `MCP_ROUTE` export, doing so would require updating any client configurations expecting the standard `/mcp` endpoint. The router strictly enforces this pathname check according to the every-app/open-seo source code.

### Why does the router check both pathname and auth mode instead of just the path?

The dual-check approach provides **defense in depth**. Checking only the pathname would expose the MCP endpoint on hosted deployments, creating a security risk. The auth-mode constraint ensures that MCP functionality is only available in self-hosted contexts where administrators explicitly control access through Cloudflare Access or local development settings.

### Where is the actual MCP protocol handling implemented?

After the router validates the request in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), it delegates to `handleSelfHostedOpenSeoMcpRequest` (the MCP transport layer). This function, along with the route constant `MCP_ROUTE`, is defined in [`src/server/mcp/context.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/context.ts), which manages the Model-Context-Protocol-specific authorization and context schema.