OAuth MCP Proxy Examples
This directory contains example MCP servers demonstrating OAuth integration with both supported SDKs.
Directory Structure
examples/
├── mark3labs/ (mark3labs/mcp-go SDK examples)
│ ├── simple/ - Basic OAuth integration
│ └── advanced/ - ConfigBuilder, env vars, multiple tools
│
└── official/ (modelcontextprotocol/go-sdk examples)
├── simple/ - Basic OAuth integration
└── advanced/ - Multiple tools, env vars, loggingExamples Overview
mark3labs
simple
1 (greet)
Okta
Basic OAuth, env vars
mark3labs
advanced
3 (greet, echo, time)
Okta
ConfigBuilder, env vars, logging
official
simple
1 (greet)
Okta
Basic OAuth, env vars
official
advanced
3 (greet, whoami, server_time)
Okta
ConfigBuilder, env vars, logging
Quick Start
mark3labs SDK
Simple:
cd examples/mark3labs/simple
go run main.goAdvanced:
cd examples/mark3labs/advanced
go run main.goOfficial SDK
Simple:
cd examples/official/simple
go run main.goAdvanced:
cd examples/official/advanced
go run main.goAll examples start a server on http://localhost:8080 with OAuth protection.
Okta Setup
All examples use Okta as the OAuth provider. Before running, you need to set up Okta:
1. Create Okta Account
Sign up at https://developer.okta.com (free developer account)
2. Create API in Okta
Go to Security > API in Okta Admin Console
Click Add Authorization Server or use the default
Note your Issuer URI (e.g.,
https://dev-12345.okta.com)Create an Audience identifier (e.g.,
api://my-mcp-server)
3. Set Environment Variables
export OKTA_DOMAIN="dev-12345.okta.com" # Your Okta domain
export OKTA_AUDIENCE="api://my-mcp-server" # Your API identifier
export SERVER_URL="http://localhost:8080" # Your server URL4. Get a Test Token
Option A: Using Okta CLI
# Install Okta CLI
brew install --cask oktacli # macOS
# Login and get token
okta login
okta get token --audience api://my-mcp-serverOption B: Using Okta Dashboard
Go to Security > API > Authorization Servers
Click your authorization server
Go to Token Preview tab
Generate a token with your audience
5. Test the Server
# Save your Okta token
TOKEN="<your-okta-access-token>"
# Test with curl
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-X POST \
http://localhost:8080 \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}'Configuration Options
Environment Variables
All examples support these environment variables:
# Required Okta Configuration
export OKTA_DOMAIN="dev-12345.okta.com" # Your Okta domain
export OKTA_AUDIENCE="api://my-mcp-server" # Your API identifier
# Server Configuration
export SERVER_URL="http://localhost:8080" # Your server URL
export PORT="8080" # Server port (default: 8080)
export MCP_HOST="localhost" # Server host (default: localhost)
export MCP_PORT="8080" # Server port for ConfigBuilder
# Optional: For HTTPS
export HTTPS_CERT_FILE="/path/to/cert.pem" # If set, enables HTTPSUsing Other Providers
To use Google or Azure AD instead of Okta, modify the config:
Google:
&oauth.Config{
Provider: "google",
Issuer: "https://accounts.google.com",
Audience: "your-google-client-id.apps.googleusercontent.com",
}Azure AD:
&oauth.Config{
Provider: "azure",
Issuer: "https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0",
Audience: "api://your-app-id",
}Example Comparison
mark3labs/simple
What it shows:
Basic OAuth integration with
mark3labs.WithOAuth()Single tool with user context access
Okta provider configuration
Environment variable support
Use when: You want the simplest possible OAuth setup with mark3labs SDK.
mark3labs/advanced
What it shows:
ConfigBuilderfor flexible configurationEnvironment variable support (Okta domain, audience, server URL)
Multiple tools with different functionality
Custom logging
OAuth endpoint discovery logging
Production-ready patterns
Use when: You need production-ready configuration with mark3labs SDK.
official/simple
What it shows:
Basic OAuth integration with
mcpoauth.WithOAuth()Single tool with user context access
Official SDK tool definition patterns
Okta provider configuration
Environment variable support
Use when: You want the simplest possible OAuth setup with official SDK.
official/advanced
What it shows:
ConfigBuilderfor flexible configurationMultiple tools (greet, whoami, server_time)
Environment variable support (Okta domain, audience)
OAuth endpoint discovery logging
Production-ready patterns
Official SDK patterns
Use when: You need production-ready configuration with official SDK.
Code Patterns Comparison
mark3labs SDK
Setup:
import (
oauth "github.com/tuannvm/oauth-mcp-proxy"
"github.com/tuannvm/oauth-mcp-proxy/mark3labs"
)
_, oauthOption, _ := mark3labs.WithOAuth(mux, &oauth.Config{...})
mcpServer := mcpserver.NewMCPServer("name", "1.0.0", oauthOption)Adding Tools:
mcpServer.AddTool(tool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
user, _ := oauth.GetUserFromContext(ctx)
return mcp.NewToolResultText("Hello, " + user.Username), nil
})Official SDK
Setup:
import (
oauth "github.com/tuannvm/oauth-mcp-proxy"
mcpoauth "github.com/tuannvm/oauth-mcp-proxy/mcp"
)
mcpServer := mcp.NewServer(&mcp.Implementation{...}, nil)
_, handler, _ := mcpoauth.WithOAuth(mux, &oauth.Config{...}, mcpServer)
http.ListenAndServe(":8080", handler)Adding Tools:
mcp.AddTool(mcpServer, &mcp.Tool{...},
func(ctx context.Context, req *mcp.CallToolRequest, params *P) (*mcp.CallToolResult, any, error) {
user, _ := oauth.GetUserFromContext(ctx)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "Hello, " + user.Username}},
}, nil, nil
})Key Difference: mark3labs uses ServerOption before server creation, official SDK wraps the server with http.Handler after creation.
Accessing User Information
All examples show how to access authenticated user information:
user, ok := oauth.GetUserFromContext(ctx)
if !ok {
return nil, fmt.Errorf("authentication required")
}
// Available fields:
user.Subject // OAuth "sub" claim (user ID)
user.Username // "preferred_username" or "sub"
user.Email // "email" claimCommon Issues
"authentication required: missing OAuth token"
Cause: No Authorization header or invalid format.
Solution:
# Make sure to include Bearer token
curl -H "Authorization: Bearer YOUR_TOKEN" ..."authentication failed: token validation failed"
Cause: Invalid token or wrong secret.
Solution:
For HMAC: Ensure
HMAC_SECRETmatches the secret used to sign the tokenFor OIDC: Verify issuer, audience, and that the token is from the correct provider
"Accept must contain both 'application/json' and 'text/event-stream'"
Cause: Missing Accept header (official SDK only).
Solution:
curl -H "Accept: application/json, text/event-stream" ...Building for Production
Dockerfile Example
FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN go build -o server ./examples/mark3labs/advanced
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/server .
# Set production environment variables
ENV OAUTH_PROVIDER=okta
ENV SERVER_URL=https://your-server.com
CMD ["./server"]Production Checklist
Further Reading
Migration Guide: ../MIGRATION-V2.md
Main README: ../README.md
Project Documentation: ../CLAUDE.md
Implementation Details: ../docs/generic-implementation.md
Need Help?
Issues: https://github.com/tuannvm/oauth-mcp-proxy/issues
Discussions: https://github.com/tuannvm/oauth-mcp-proxy/discussions
Documentation: See files in
/docsdirectory
Last updated
Was this helpful?