How MCP Handles Authentication for Hosted Deployments in OpenSEO
OpenSEO validates every request to hosted MCP endpoints through a five-step OAuth flow that checks the auth context against a strict schema, enforces the "mcp" scope, verifies organization membership, validates the Origin header, and instantiates the request handler with authenticated user roles.
OpenSEO's Model Context Protocol (MCP) server implements strict authentication for hosted deployments to ensure only authorized users can access SEO automation tools. The authentication logic resides in src/server/mcp/transport.ts and protects the /mcp endpoint through multi-layered validation. Understanding this flow is essential for developers integrating with OpenSEO's hosted MCP infrastructure.
The MCP Authentication Flow for Hosted Deployments
The handleAuthenticatedOpenSeoMcpRequest function in src/server/mcp/transport.ts orchestrates validation through five sequential checks. Each step hardens the endpoint against unauthorized access or cross-origin misuse.
Step 1: OAuth Payload Schema Validation
The incoming request’s auth context is parsed against hostedWorkersOAuthMcpPropsSchema using safe parsing. If the payload structure does not match the expected schema, the server immediately rejects the request with 403 "MCP auth context required".
Source: hostedWorkersOAuthMcpPropsSchema.safeParse(props) at lines 62-64 in src/server/mcp/transport.ts.
Step 2: MCP Scope Enforcement
After parsing, the system verifies that the auth context includes the MCP scope ("mcp"). This constant is defined in src/lib/oauth-resource.ts as MCP_SCOPE. Requests missing this scope receive 403 "MCP scope required".
Source: Scope constant definition in src/lib/oauth-resource.ts lines 2-3; enforcement in src/server/mcp/transport.ts lines 66-68.
Step 3: Organization Membership Verification
Using the AuthRepository, the code fetches the user-organization membership record for the userId and organizationId supplied by the OAuth token. If the membership no longer exists—indicating the user was removed from the organization—the server responds with 401 "Organization access revoked" and includes a WWW-Authenticate header prompting the client to refresh its token.
Source: Membership lookup and error handling in src/server/mcp/transport.ts lines 84-93.
Step 4: Origin Header Validation
The request’s Origin header must match either the hosted base URL (retrieved via getHostedBaseUrl()) or the dedicated Chrome-extension origin used by the Surfmind extension. Any other origin triggers 403 "Invalid Origin", preventing cross-site request forgery.
Source: Origin validation logic in src/server/mcp/transport.ts lines 70-78.
Step 5: MCP Request Handler Instantiation
Upon passing all validations, the server constructs a McpProps object containing the authenticated user’s role (fetched from the membership record). It then instantiates the MCP request handler via createRequestHandler with these props, adding appropriate CORS headers to the response before processing the JSON-RPC request.
Source: Props creation at lines 100-104 and handler invocation at lines 105-108 in src/server/mcp/transport.ts.
Implementing MCP Authentication in Client Applications
To interact with OpenSEO's hosted MCP endpoints, clients must obtain an OAuth token with the mcp scope and include proper headers.
Making Authenticated Requests
import fetch from "node-fetch";
const MCP_BASE = "https://my-openseo-hosted.com";
const MCP_ENDPOINT = `${MCP_BASE}/mcp`;
async function callMcp(method: string, params: any, accessToken: string) {
const body = {
jsonrpc: "2.0",
method,
params,
id: Date.now(),
};
const response = await fetch(MCP_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
Origin: MCP_BASE,
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error(`MCP error ${response.status}: ${await response.text()}`);
}
return response.json();
}
Obtaining OAuth Tokens with MCP Scope
const tokenResponse = await fetch("https://openseo.com/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: authCode,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: "offline_access mcp",
redirect_uri: REDIRECT_URI,
}),
});
const { access_token } = await tokenResponse.json();
Key Source Files for MCP Authentication
src/server/mcp/transport.ts– ContainshandleAuthenticatedOpenSeoMcpRequest, the core function that validates OAuth payloads, scopes, organization membership, and origin headers for hosted MCP requests.src/lib/oauth-resource.ts– Defines theMCP_SCOPEconstant and helper utilities for constructing MCP resource URLs.src/server/auth/repositories/AuthRepository.ts– Provides thegetMembershipmethod used to confirm active user-organization relationships during the authentication flow.
Summary
- Schema validation ensures the auth context matches
hostedWorkersOAuthMcpPropsSchemabefore processing continues. - Scope enforcement requires the
"mcp"scope defined insrc/lib/oauth-resource.tsfor all hosted requests. - Membership verification uses
AuthRepository.getMembershipto confirm the user still belongs to the specified organization. - Origin validation restricts requests to the hosted base URL or approved Chrome extension origins via
getHostedBaseUrl(). - Request instantiation creates a
McpPropsobject with the user’s role and invokescreateRequestHandlerto process valid requests.
Frequently Asked Questions
What error does OpenSEO return if the MCP scope is missing?
The server responds with 403 "MCP scope required" when the parsed auth context does not include the "mcp" scope defined in src/lib/oauth-resource.ts.
How does OpenSEO verify that a user still has access to an organization?
During authentication, the system calls AuthRepository.getMembership with the userId and organizationId from the OAuth token. If no active membership exists, it returns 401 "Organization access revoked" with a WWW-Authenticate header instructing the client to refresh the token.
Can MCP requests originate from any browser domain?
No. The Origin header must match either the hosted deployment's base URL (via getHostedBaseUrl()) or the specific Chrome-extension origin used by the Surfmind extension. Mismatched origins receive 403 "Invalid Origin".
Which file contains the main authentication logic for hosted MCP deployments?
The primary implementation resides in src/server/mcp/transport.ts, specifically within the handleAuthenticatedOpenSeoMcpRequest function that orchestrates the five-step validation flow.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →