Skip to main content
Glama
nanabrownsnr

Twynity API-Key MCP Template

by nanabrownsnr

Twynity API-Key MCP Template

A production-shaped FastMCP server template for building a Twynity MCP that needs a single secret credential per user — like a GitHub personal access token (ghp_...), a Slack token, or any one-line API key. The key is stored encrypted in MongoDB, scoped to the exact (user_id, persona_id) pair, and exposed over the Twynity Interconnector api_key category.

This is the right starting point when your MCP authenticates to an upstream service with one token the user pastes in — not a multi-field configuration, not an OAuth login.

Features

  • Per-user encrypted API-key storage in MongoDB (Fernet, scoped to (user_id, persona_id))

  • Twynity Interconnector api_key category: POST /api/v1/keys {name, key} + GET /api/v1/keys

  • GET /api/v1/keys returns names only — never the key (Interconnector §11.3 security note, enforced by a test)

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

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

  • 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)

  • MCP Apps UI example (the say_hello React app)

  • Docker + Render deployment (Python 3.12 pinned)

Related MCP server: vault-mcp

Setup

Prerequisites

  1. Python 3.11 or higher

  2. MongoDB instance (for key storage)

  3. 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 key:

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

async def my_tool(...) -> ToolResult:
    conn = await get_current_connection()  # {"id", "name", "key"}
    # call your upstream service with conn["key"]
    return ToolResult(content=[...], structured_content={...})

get_current_connection() returns the decrypted {id, name, key} for the verified user/persona, or raises an actionable auth error if none is set. The key is only ever decrypted inside a tool at call time — list/read routes never return it.

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 api-key-mcp .
docker run -p 8000:8000 api-key-mcp

License

MIT License - see LICENSE for details.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes OS keychain or AES-256-GCM encrypted file secrets as MCP tools, allowing reading, setting, and listing secrets without exposing values in conversation messages.
    3 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Encrypted-at-rest credential vault with MCP server for agent credential lookup and management.
    5 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes get, set, and delete operations over a Redis/Valkey-compatible key-value store as MCP tools, with per-user key namespacing and TTL support on writes. Enables clients to cache and retrieve arbitrary string values statelessly over SSE or direct HTTP, using their own backend.
    MIT