In late April 2026, "My Notes on Thoroughly Learning OAuth 2.1 to Build an MCP Server" hit the Zenn Trending list. As projects involving public exposure or client-facing delivery of MCP (Model Context Protocol) servers grow, "How should we handle authentication?" has become a question raised in nearly every consultation.
In our custom development practice, we handled four consecutive projects over the past six months aimed at "turning internal corporate systems into MCP servers to allow secure invocation by client AI agents." In this article, we break down how to protect custom-built MCP servers with OAuth 2.1 from the practical perspective of custom development.
Why OAuth 2.1 is becoming the de facto standard for MCP servers
While the specification offers several authentication methods for MCP servers, OAuth 2.1 is rapidly becoming virtually the sole option when building on the premise of integrating into a client's production environment in custom development.
| Authentication method | Viability in custom development | Rationale |
|---|---|---|
| API Key | △ | Rotation and auditing are weak |
| Basic authentication | ✕ | Plaintext password transmission, out of the question |
| mTLS | △ | Distributing client certificates across client environments is cumbersome |
| OAuth 2.0 | ○ | Older specification causing confusion around PKCE and Implicit flow |
| OAuth 2.1 | ◎ | Unified on the secure side by mandating PKCE and deprecating Implicit flow |
| OIDC | ○ | Authentication also possible via OAuth 2.1 + ID token |
OAuth 2.1 is a specification that mandates OAuth 2.0 best practices, offering the advantage that modern baseline assumptions—such as mandatory PKCE and removal of the Implicit flow—can be taken for granted when exposing MCP servers in custom development.
Minimal flow for MCP × OAuth 2.1
Here is the minimal access flow architecture for an MCP server exposed in custom development.
[顧客側AIエージェント] [認可サーバー] [MCPサーバー]
↓ 1. 認可リクエスト + PKCE
────────────────────────────────→
↓ 2. ユーザ認証
↓ 3. 同意画面(スコープ表示)
←────────────────────────────────
↓ 4. 認可コード受領
↓ 5. トークンエンドポイント呼び出し(PKCE verifier)
────────────────────────────────→
↓ 6. アクセストークン発行
←────────────────────────────────
↓ 7. MCPツール呼び出し(Bearer)
──────────────────────────────────────────────────────────────→
↓ 8. トークン検証
↓ 9. スコープ確認
↓ 10. ツール実行
←──────────────────────────────────────────────────────────────
The key is an architecture that separates the authorization server from the MCP server. Because MCP tools will be added or removed over time in custom development, centralizing the authorization server ensures that authentication implementations do not need to be rebuilt every time a new tool is added.
Scope design tips to master in custom development
OAuth scopes directly correlate to MCP tool and resource granularity. Below is standard scope design for operation in custom development.
| Scope naming | Examples | Usage split in custom development |
|---|---|---|
mcp:tool:* | mcp:tool:db.query | Fine-grained permission for individual tools |
mcp:resource:* | mcp:resource:customer.read | Resource-level (combined with CRUD) |
mcp:scope:* | mcp:scope:read-only | Presets (read-only, etc.) |
mcp:tenant:* | mcp:tenant:acme-corp | Multi-tenant isolation |
In particular, multi-tenant isolation (mcp:tenant:*) is critical when running MCP servers for multiple clients on a single infrastructure in custom development. Unless you mandate the tenant claim in tokens and implement logic where the MCP server immediately rejects requests with mismatched claims, incidents crossing tenant boundaries will occur.
This represents the authentication and authorization layer counterpart to the "API-to-MCP bridging" discussed in Design Patterns for Converting Existing APIs into MCP Servers.
Token lifetimes and refresh: Operationally viable configurations for custom development
Because MCP servers are invoked by long-running agents, token lifetime design directly affects operations.
| Token type | Recommended lifetime | Operational design in custom development |
|---|---|---|
| Access token | 5–15 minutes | Premised on the agent refreshing as needed |
| Refresh token | 30–90 days | Rotated on each use (revoked upon reuse detection) |
| Consent expiration | 1 year | Prompt user for re-consent annually |
| MCP session | Equivalent to access token | Stateless per session/request |
Refresh Token Rotation is strongly recommended as an OAuth 2.1 best practice and should be included in project estimates as a mandatory implementation whenever public MCP servers are delivered in custom development.
Five major operational pitfalls
Here we review the pitfalls commonly encountered during implementation in the field.
| Pitfall | Consequence | Measure |
|---|---|---|
| Co-locating authorization server within application | Outages take down MCP alongside the app | Separate authorization server into a distinct process or service |
| Embedding excessive claims into access token | Size bloat triggers HTTP 426 or exceeds API gateway limits | Keep claims minimal; distribute only verification keys via JWKS |
| Reusing refresh tokens | Expands blast radius during leaks | Rotation + reuse detection mandatory |
| Refining scopes after release | Breaks all existing integrations | Start with coarse granularity and split into *:read and *:write later |
| Tokens remaining in plaintext in logs | Catastrophic impact if logs leak | Override OAuth library loggers and mask values in structured logging |
In particular, "co-locating the authorization server inside the application" is an anti-pattern frequently seen in early-stage custom development. Separating them once operations have begun requires structural refactoring, so agreeing to place it in a separate layer from the start within the SOW is prudent.
Permission boundaries for multi-tenant MCP servers
When designing architectures where multiple clients share the same MCP infrastructure in custom development, OAuth scopes and claim-based permission boundaries are critical lifelines. Here is the minimal implementation setup:
// MCP サーバー側のミドルウェア(疑似コード)
async function authenticate(request) {
const token = extractBearer(request);
const claims = await verifyJWT(token, jwksUri);
// 1. スコープ確認
if (!claims.scope?.includes(`mcp:tool:${request.toolName}`)) {
throw new ForbiddenError('insufficient_scope');
}
// 2. テナント境界
if (claims.tenant !== request.tenantId) {
throw new ForbiddenError('tenant_mismatch');
}
// 3. 監査ログ(テナント / 呼び出し者 / ツール)
await auditLog({
tenant: claims.tenant,
sub: claims.sub,
tool: request.toolName,
timestamp: Date.now(),
});
return claims;
}
The key is ensuring the three-stage check (scope → tenant → audit log) executes first in middleware. Missing even one check leads to tenant boundary violations or compliance failures.
This serves as the authorization-layer counterpart to the "guardrails against destructive operations" discussed in Production DB Deletion Guardrails for AI Agents. In the era of AI agents, systems must be architected to physically block actions on the machine side under the premise that "agents, not just humans, might connect to the wrong tenant."
Delivery checklist — 12 immediately usable items for custom development
- Authorization flow is implemented with OAuth 2.1 (PKCE mandatory)
- Implicit Flow and ROPC are completely eliminated
- Authorization server runs as a separate process or service from MCP server
- Access token lifetime is set to 5–15 minutes
- Refresh Token Rotation is active; immediate revocation upon reuse detection
- MCP middleware executes three-stage check: scope → tenant → audit
- Public key distribution via JWKS is operational
- Audit logs are isolated and stored per tenant
- OAuth library loggers mask tokens
- Scope naming conventions are documented
- Defenses against known vulnerabilities (CSRF, open redirect, etc.) are verified
- Budget for annual security review is specified in SOW
Conclusion: MCP authentication is the foundation supporting trust in custom development
Because an MCP server sits on the shortest path between "tools and client data," the quality of the authentication layer directly governs the overall reliability of systems built through custom development. Designing modern configurations—OAuth 2.1 + PKCE + Refresh Token Rotation + audit logs—from the outset falls squarely within the custom development team's responsibility.
At GleamHub, we provide a standardized package that comprehensively executes "authentication design → implementation → operational design" across three steps when launching new MCP server projects. Whether you are thinking, "We want to expose an MCP server externally but are stuck on authentication," or "We want an audit of an authentication layer implemented by another vendor," please feel free to reach out through our contact form.








