Model Context Protocol (MCP) Support
Pomerium provides secure access to Model Context Protocol (MCP) servers, enabling AI agents and applications to safely interact with your internal resources through standardized interfaces. This capability allows you to expose local databases, APIs, and services to external AI clients while maintaining strict authentication and authorization controls.
On This Page
- Overview
- Architecture - Three integration patterns
- Bearer Token Types - External and Internal tokens
- Configuration Options - Server and client configuration
- User Identity and Claims - JWT headers and verification
- Security Considerations - Access control and token security
- Observability - Logging and monitoring MCP activities
- Policy-Based Tool Access Control - Fine-grained tool permissions
- Best Practices
- Demo and Examples
Overview
Model Context Protocol (MCP) is an open standard that allows AI agents to securely connect to external data sources and tools. Pomerium's MCP integration acts as a secure gateway between MCP clients (like Claude.ai, OpenAI APIs, or custom applications) and your internal MCP servers.
For an understanding of Pomerium's core capabilities, see Authentication and Authorization.
MCP support is currently an experimental feature only available in the main
branch or Docker images built from main
. To enable MCP functionality, you must set the following feature flag in your Pomerium configuration:
runtime_flags:
mcp: true
Key Benefits
- Secure Remote Access: Expose internal MCP servers to external AI clients without compromising security
- OAuth Integration: Seamlessly handle upstream OAuth flows for services requiring authentication
- Centralized Authorization: Apply consistent access policies across all MCP endpoints
- Token Management: Automatic token refresh and secure credential handling
- Observability: Complete visibility into AI agent interactions with your resources through specialized logging
Try It Out
Explore the MCP App Demo for a hands-on example of integrating MCP with Pomerium. The demo shows a full workflow including UI, MCP server, and LLM API integration—perfect for testing and learning.
If you're new to Pomerium, start with the Quickstart Guide to set up your first Pomerium deployment.
Architecture
Pomerium supports three primary MCP integration patterns. For detailed route configuration information, see the Routes reference documentation.
1. Exposing Internal MCP Servers
This pattern allows external MCP clients to access your internal MCP servers through Pomerium's secure gateway.
- Your MCP server does not need to implement any specific authentication or authorization logic. Works best with internal services that provide access to shared resource like databases, APIs taking API keys, or other internal tools.
- MCP clients users must authenticate, and Pomerium enforces access policies for every request.
Route Configuration:
routes:
- from: https://my-mcp-server.your-domain.com
to: http://my-mcp-server.int:8080/mcp
name: My MCP Server
mcp:
server: {} # the brackets are significant, they indicate that this is an MCP server route
policy:
and:
- domain:
is: company.com
- mcp_tool:
starts_with: 'read_'
2. MCP Servers with Upstream OAuth
When your MCP server needs to access upstream services requiring OAuth authentication (GitHub, Google Drive, Notion, etc.).
- Pomerium handles the OAuth flow and token management with the remote upstream service.
- Your MCP server does not need to implement any of the OAuth logic, as Pomerium will manage the authentication and token refresh.
- MCP clients only observe the External Token (TE) issued by Pomerium, which is used to access the MCP server. The Internal Token (TI) used for upstream OAuth is managed by Pomerium and is never exposed to external clients.
For more details on OAuth configuration options, see Identity Provider Settings.
Route Configuration:
routes:
- from: https://github.your-domain
to: http://github-mcp.int:8080/mcp
name: GitHub
mcp:
server:
upstream_oauth2:
client_id: xxxxxxxxxxxx
client_secret: yyyyyyyyy
scopes: ['read:user', 'user:email']
endpoint:
auth_url: 'https://github.com/login/oauth/authorize'
token_url: 'https://github.com/login/oauth/access_token'
policy:
and:
- domain:
is: company.com
- mcp_tool:
starts_with: 'read_'
3. Building MCP-Enabled Applications
For internal applications that need to call MCP servers through AI APIs such as OpenAI or Anthropic, Pomerium provides:
- When a route is designated as
mcp: client
, an External Bearer Tokens would be passed to your application backend in theAuthorization: Bearer
header. - Your application backend can list MCP servers that are available on the Pomerium backend and initiate upstream OAuth flows if necessary.
- An External Token (TE) can be passed to LLM APIs to allow them to call MCP servers on behalf of the user.
For a complete working example, see the MCP App Demo section.
Route Configuration:
routes:
- from: https://mcp-app-demo.your-domain.com
to: http://mcp-app-demo:3000
mcp:
client: {}
policy: {}
- from: https://mcp-server.your-domain.com
to: http://mcp-server.int:8080/mcp
name: My MCP Server
mcp:
server: {}
policy: {}
Bearer Token Types
Understanding Pomerium's token system is crucial for MCP integration:
External Token (TE)
An externally-facing token issued by Pomerium representing the user's session. External clients use this token to authenticate requests to Pomerium-protected MCP servers.
Use cases:
- Providing to LLM APIs for MCP server access
- Authentication between external MCP clients and Pomerium
- Internal applications calling external AI services
Internal Token (TI)
An internal authentication token that Pomerium obtains from upstream OAuth providers on behalf of the user. This token is never exposed to external clients and is used by Pomerium to authenticate with upstream services.
Characteristics:
- Automatically refreshed by Pomerium
- Securely stored and managed
- Used for upstream API authentication
- Invisible to external clients
Configuration Options
MCP integration can be configured through route-level settings. For general route configuration guidance, see the Routes configuration reference.
MCP Server Configuration
For routes hosting MCP servers:
mcp:
server:
# Optional: Configure upstream OAuth2 for services requiring authentication
upstream_oauth2:
client_id: 'your-oauth-client-id'
client_secret: 'your-oauth-client-secret'
endpoint:
auth_url: 'https://provider.com/oauth/authorize'
token_url: 'https://provider.com/oauth/token'
auth_style: 'header' # or "params"
scopes: ['scope1', 'scope2']
# Optional: Maximum request body size (default: 4KiB)
max_request_bytes: 1048576
** Tool Call Authorization **
When using Pomerium Policy Language (PPL) with MCP routes, you can control access to specific tools, in addition to the standard route policies. For example, to allow only certain users to call a specific MCP tool:
policy:
allow:
and:
- email:
is: analyst@company.com
- mcp_tool:
is: database_query
For more information on route-level policies, see Route Policy Configuration. For advanced policy examples, see Policy-Based Tool Access Control.
MCP Client Configuration
For applications that consume MCP servers:
mcp:
# Provides the application with external tokens for MCP server access.
# the brackets are significant, they indicate that this is an MCP client route
client: {}
For Client routes, Pomerium exposes additional endpoints to manage MCP server discovery and upstream OAuth flows. See Building MCP-Enabled Applications for architectural details.
Listing Available MCP Servers
Applications can discover available MCP servers by making a request to the /.pomerium/mcp/routes
endpoint:
GET https://your-app.domain.com/.pomerium/mcp/routes
Authorization: Bearer <external-token>
Accept: application/json
Response:
{
"servers": [
{
"name": "Database Server",
"url": "https://db-mcp.your-domain.com",
"connected": true
},
{
"name": "GitHub Server",
"url": "https://github-mcp.your-domain.com",
"connected": false
}
]
}
The connected
field indicates whether the user has completed all required upstream OAuth flows.
Initiating Upstream OAuth
If a server shows connected: false
, redirect users to complete upstream authentication:
https://mcp-server.your-domain.com/.pomerium/mcp/connect?redirect_url=https://your-app.domain.com/callback
Requirements:
- The
redirect_url
must match a configured MCP client route host - Users will be redirected back to the specified URL after authentication
User Identity and Claims
Both MCP client applications and servers can access authenticated user information through the X-Pomerium-Assertion
HTTP header. This header contains a signed JWT with user details including email, name, and other claims.
Example JWT payload:
{
"sub": "user@example.com",
"email": "user@example.com",
"name": "John Doe",
"groups": ["engineering", "admin"],
"iss": "your-domain.com",
"aud": "your-app.domain.com"
}
JWT may be verified using standard JWT libraries or Pomerium's SDKs for Go or Python.
For detailed information about JWT verification in Pomerium, see Identity Verification with JWTs.
Security Considerations
For general security best practices with Pomerium, see the Security documentation.
Access Control
Apply appropriate policies to MCP routes:
routes:
- from: https://sensitive-mcp-server.domain.com
to: http://internal-server:8080/mcp
mcp:
server: {}
policy:
allow:
and:
- domain:
is: trusted-domain.com
Token Security
- External tokens (TE) have limited scope and lifetime
- Internal tokens (TI) are never exposed to external clients
- All tokens are automatically refreshed by Pomerium
- All authorization decisions are logged for audit (see Observability)
For more information on Pomerium's bearer token format, see Bearer Token Format.
Observability
Pomerium provides specialized logging capabilities to monitor and audit MCP tool calling activities. By configuring authorize_log_fields
, you can gain detailed insights into AI agent interactions with your MCP servers.
For general observability features, see Metrics and Tracing.
MCP-Specific Authorization Log Fields
Pomerium includes three specialized log fields for MCP monitoring:
Field | Description | Example Value |
---|---|---|
mcp-method | The MCP JSON-RPC method being called | "tools/call" , "tools/list" |
mcp-tool | The specific tool name being invoked (for tools/call requests) | "database_query" , "list_files" |
mcp-tool-parameters | The parameters passed to the tool | {"query": "SELECT * FROM users", "limit": 100} |
Configuration
To enable MCP-specific logging, add the desired fields to your authorize_log_fields
configuration:
authorize_log_fields:
- request-id
- user
- email
- mcp-method
- mcp-tool
- mcp-tool-parameters
Example Log Output
When an AI agent calls an MCP tool, Pomerium generates detailed authorization logs:
{
"level": "info",
"service": "authorize",
"request-id": "c9afae5a-ec5a-4242-864f-df4189f20e99",
"user": "google-oauth2|115420664726183323237",
"email": "analyst@company.com",
"mcp-method": "tools/call",
"mcp-tool": "database_query",
"mcp-tool-parameters": {
"query": "SELECT * FROM sales WHERE year = 2024",
"limit": 100,
"format": "json"
},
"allow": true,
"allow-why-true": ["domain-ok", "mcp-tool-ok"],
"deny": false,
"deny-why-false": [],
"time": "2024-06-24T10:26:33-04:00",
"message": "authorize check"
}
Understanding MCP Authorization Logs
For general information about authorization logs, see Authorize Log Fields.
Tool Call Authorization
When using Pomerium Policy Language (PPL) with MCP routes, you can control access to specific tools:
policy:
allow:
and:
- email:
is: analyst@company.com
- mcp_tool:
is: database_query
The authorization log will show:
allow: true
andmcp-tool-ok
when the tool is permittedallow: false
andmcp-tool-unauthorized
when the tool is blocked
Method-Level Monitoring
Different MCP methods appear in logs:
Tool Listing Request:
{
"mcp-method": "tools/list",
"allow": true,
"allow-why-true": ["authenticated-user"]
}
Tool Execution Request:
{
"mcp-method": "tools/call",
"mcp-tool": "search_knowledge_base",
"mcp-tool-parameters": {
"query": "company policies",
"max_results": 10
}
}
Resource Request:
{
"mcp-method": "resources/list",
"allow": true
}
Policy-Based Tool Access Control
Pomerium provides fine-grained access control for MCP tools through a specialized mcp_tool
policy criterion in Pomerium Policy Language (PPL). This allows you to control which users can access specific MCP tools, providing granular security for AI agent interactions.
For broader policy examples, see the Authorization documentation.
The mcp_tool
Criterion
The mcp_tool
criterion is designed specifically for MCP routes and allows policy enforcement at the individual tool level. It uses the String Matcher format and supports all standard string matching operators.
Operator | Description | Example |
---|---|---|
is | Exact match of the tool name | mcp_tool: { is: "database_query" } |
starts_with | Tool name starts with the specified prefix | mcp_tool: { starts_with: "db_" } |
ends_with | Tool name ends with the specified suffix | mcp_tool: { ends_with: "_query" } |
contains | Tool name contains the specified substring | mcp_tool: { contains: "read" } |
in | Tool name matches one of the provided values | mcp_tool: { in: ["list_tables", "describe_table"] } |
Example
Grant access to database query tools only to data analysts:
policy:
allow:
and:
- email:
ends_with: '@company.com'
- mcp_tool:
in: ['database_query', 'list_tables', 'describe_table']
- groups:
has: 'data-analysts'
For more advanced policy patterns, see the PPL documentation.
Understanding Authorization Results
The authorization logs show different reason codes based on the evaluation:
Successful Tool Access:
{
"allow": true,
"allow-why-true": ["domain-ok", "mcp-tool-ok"],
"mcp-tool": "database_query"
}
Blocked Tool Access:
{
"allow": false,
"allow-why-false": ["mcp-tool-unauthorized"],
"deny": false,
"mcp-tool": "admin_function"
}
Related Documentation
Core Pomerium Concepts
- Authentication - User authentication methods
- Authorization - Access control and policies
- Pomerium Policy Language (PPL) - Policy syntax and examples
- Routes Configuration - Route setup and options
- Identity Verification with JWTs - JWT headers and verification
Configuration References
- Route Policy Configuration - Policy configuration for routes
- Bearer Token Format - Token structure and validation
- Authorize Log Fields - Logging configuration
- Identity Provider Settings - OAuth provider setup
Observability and Security
- Metrics - Performance and usage metrics
- Tracing - Request tracing and debugging
- Security - Security best practices
Related Guides
- Self-Hosted LLM Behind Pomerium - Securing LLM interfaces with Pomerium
Demo and Examples
For complete end-to-end examples and reference implementations:
- MCP App Demo: Full demonstration showing custom UI frontend, MCP server integration, and remote LLM API calling through Pomerium
- MCP Servers: Collection of example MCP server implementations with Docker and Pomerium configurations
These repositories provide practical examples of all integration patterns described in this documentation.