Skip to main content
Glama
nanabrownsnr

Twynity OAuth 2.0 MCP Template

by nanabrownsnr

Twynity OAuth 2.0 MCP Template

A production-shaped FastMCP server template for building a Twynity MCP where each user logs in to their own account at an upstream provider via OAuth 2.0 — like ClickUp, Google, Microsoft, GitHub, etc. Tokens are exchanged through the Twynity Interconnector oauth category and stored encrypted in MongoDB, scoped to the exact (user_id, persona_id) pair.

This is the right starting point when your MCP needs the user's own provider credentials (access/refresh tokens) rather than a shared API key or a static configuration.

Features

  • Twynity Interconnector oauth category:

    • GET /api/v1/auth/{provider}/login?redirect_uri={uri} — mints a single-use state (TTL-expired Mongo oauth_sessions collection) and returns the provider authorization URL

    • POST /api/v1/auth/{provider}/token-callback?redirect_uri={uri}&code={code} — looks up state, exchanges the code for tokens, stores them encrypted in oauth_tokens, deletes the one-shot session

    • POST /api/v1/auth/{provider}/logout — best-effort provider-side revoke + deletes the stored tokens

  • Encrypted access/refresh token storage in MongoDB (Fernet, scoped to (user_id, persona_id))

  • public_metadata returns only has_access_token/has_refresh_token — never the raw tokens (Interconnector §11.3, enforced by a test)

  • GET /api/v1/external-connection/me connection-status endpoint

  • MCP manifest (/.well-known/mcp.json) declaring external_connections.oauth

  • Twynity JWT auth (audience-checked JWTVerifier) + Persona-Id scoping

  • Tools resolve identity from FastMCP's verified access-token context (no re-verify of the stripped authorization header)

  • Docker + Render deployment (Python 3.12 pinned)

OAuth configuration (env vars)

Set these for your upstream provider (see .env.example):

  • OAUTH_PROVIDER — the {provider} path segment (e.g. clickup)

  • OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET — your OAuth app credentials

  • OAUTH_REDIRECT_URI — the redirect URI Twynity provides. It must exactly match what you registered with the OAuth provider, or the flow fails silently. This is not your callback endpoint — Twynity calls your token-callback route after the provider bounces here.

  • OAUTH_AUTHORIZE_URL / OAUTH_TOKEN_URL / OAUTH_REVOKE_URL — your provider's endpoints

  • OAUTH_SCOPES — the scopes to request

  • OAUTH_SESSION_TTL_SECONDS — how long an unexchanged state stays valid

Related MCP server: Entra ID On-Behalf-Of MCP

Setup

Prerequisites

  1. Python 3.11 or higher

  2. MongoDB instance (for token + session storage)

  3. An OAuth app registered with your upstream provider, configured with the Twynity redirect URI

  4. A Twynity account-service URL + the MCP registered on Twynity (so user JWTs carry your hyphenated service ID in aud)

Installation

  1. Install the dependencies:

uv sync --locked
  1. Copy .env.example to .env and configure the environment variables:

cp .env.example .env

Edit .env with your configuration:

  • MONGODB_URI - MongoDB connection string for storing encrypted connections

  • ENCRYPTION_KEY - Fernet encryption key for securing credentials (generate with uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")

  • ACCOUNT_SERVICE_URL - Twynity account service URL

  • ACCOUNT_SERVICE_JWKS_ENDPOINT - JWKS endpoint for verifying JWTs

  • ACCOUNT_SERVICE_JWKS_CACHE_TTL - Cache TTL for JWKS

  • LICENSE_KEY - License key for usage tracking

  • LICENSE_SERVER_BASE_URL - License server base URL

  • LICENSE_SERVER_JWKS_ENDPOINT - JWKS endpoint for license verification

  • LICENSE_SERVER_ACTIVATION_ENDPOINT - License activation endpoint

  • USAGE_REPORT_ENDPOINT - Usage reporting endpoint

Run the Server

uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

Tools

Replace the say_hello example tool with your own. A typical tool reads the user's stored OAuth token:

from fastmcp.tools import ToolResult
from app.tools.connection import get_current_connection

async def my_tool(...) -> ToolResult:
    token = await get_current_connection()  # {"id", "access_token", "refresh_token"}
    # call your upstream API with token["access_token"]
    return ToolResult(content=[...], structured_content={...})

get_current_connection() returns the decrypted token grant for the verified user/persona, or raises an actionable auth error if the user hasn't completed the OAuth flow yet. Handle expired access tokens by refreshing with refresh_token against your provider's token URL.

Configuration

The server expects a .env file with the following variables:

# MongoDB for secure connection storage
MONGODB_URI=mongodb://localhost:27017
DATABASE_NAME=twynity_mcp

# Encryption key (required)
ENCRYPTION_KEY=your_fernet_encryption_key_here

# Twynity account service details  
ACCOUNT_SERVICE_URL=https://accounts.twynity.com
ACCOUNT_SERVICE_JWKS_ENDPOINT=/oauth2/keys
ACCOUNT_SERVICE_JWKS_CACHE_TTL=300

# License service details
LICENSE_KEY=
LICENSE_SERVER_BASE_URL=https://license.twynity.com
LICENSE_SERVER_JWKS_ENDPOINT=/oauth2/keys
LICENSE_SERVER_ACTIVATION_ENDPOINT=/activate

# Usage reporting endpoint
USAGE_REPORT_ENDPOINT=https://usage.twynity.com/api/v1/report

# Public URL for the server
PUBLIC_URL=http://localhost:8000

# Environment (development, staging, production)
ENVIRONMENT=development

# Allowed origins for CORS
ALLOWED_ORIGINS=*

Authentication and Security

This server uses Twynity's authentication system which requires:

  1. A valid bearer JWT token

  2. A Persona-Id header identifying the user's project/persona context

Credentials are stored securely encrypted in MongoDB, with each connection scoped to a specific user and persona pair.

Development

Running Tests

uv run pytest -q

Code Quality

uv run ruff check app tests

Deployment

Docker

docker build -t oauth-mcp .
docker run -p 8000:8000 oauth-mcp

License

MIT License - see LICENSE for details.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to exchange an MCP-audience token for a Microsoft Graph token and call Graph as the signed-in user, with tools for identity verification and recent mail access.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables a single authenticated MCP endpoint to resolve users to the correct tenant, role, permissions, and tenant-specific backend integration, with support for shared, individual, and hybrid identity modes.
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables existing apps to expose their users and data to external AI agents via MCP with OAuth 2.1 authentication and scoped tools.
    45 npm
    MIT