Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

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, logging

Examples Overview

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

Quick Start

mark3labs SDK

Simple:

cd examples/mark3labs/simple
go run main.go

Advanced:

cd examples/mark3labs/advanced
go run main.go

Official SDK

Simple:

cd examples/official/simple
go run main.go

Advanced:

cd examples/official/advanced
go run main.go

All 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

  1. Go to Security > API in Okta Admin Console
  2. Click Add Authorization Server or use the default
  3. Note your Issuer URI (e.g., https://dev-12345.okta.com)
  4. 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 URL

4. 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-server

Option B: Using Okta Dashboard

  1. Go to Security > API > Authorization Servers
  2. Click your authorization server
  3. Go to Token Preview tab
  4. 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 HTTPS

Using 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:

  • ConfigBuilder for 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.

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:

  • ConfigBuilder for 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.


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" claim

Common 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_SECRET matches the secret used to sign the token
  • For 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

  • Use OIDC provider (Okta/Google/Azure), not HMAC
  • Set SERVER_URL to 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

Further Reading


Need Help?