This directory contains example MCP servers demonstrating OAuth integration with both supported SDKs.
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, logging
| SDK | Example | Tools | Provider | Features |
|---|---|---|---|---|
| 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 |
Simple:
cd examples/mark3labs/simple
go run main.goAdvanced:
cd examples/mark3labs/advanced
go run main.goSimple:
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.
All examples use Okta as the OAuth provider. Before running, you need to set up Okta:
Sign up at https://developer.okta.com (free developer account)
- 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)
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 URLOption 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
# 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
}'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 HTTPSTo 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",
}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.
What it shows:
ConfigBuilderfor flexible configuration- Environment 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.
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.
What it shows:
ConfigBuilderfor flexible configuration- Multiple 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.
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
})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.
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" claimCause: No Authorization header or invalid format.
Solution:
# Make sure to include Bearer token
curl -H "Authorization: Bearer YOUR_TOKEN" ...Cause: Invalid token or wrong secret.
Solution:
- For HMAC: Ensure
HMAC_SECRETmatches the secret used to sign the token - For OIDC: Verify issuer, audience, and that the token is from the correct provider
Cause: Missing Accept header (official SDK only).
Solution:
curl -H "Accept: application/json, text/event-stream" ...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"]- Use OIDC provider (Okta/Google/Azure), not HMAC
- Set
SERVER_URLto your actual domain (HTTPS) - Store secrets in environment variables or secret manager
- Enable HTTPS (use reverse proxy like nginx or Caddy)
- Configure proper CORS if needed
- Set up monitoring and logging
- Review OAuth scopes and permissions
- Migration Guide: ../MIGRATION-V2.md
- Main README: ../README.md
- Project Documentation: ../CLAUDE.md
- Implementation Details: ../docs/generic-implementation.md
- Issues: https://github.com/tuannvm/oauth-mcp-proxy/issues
- Discussions: https://github.com/tuannvm/oauth-mcp-proxy/discussions
- Documentation: See files in
/docsdirectory