Guide

MCP server (passport verification)

Secure your MCP tools: verify LIME JWTs locally with JWKS, trust claims.sub as agent_id — no calls back to LIME per request.

You operate the MCP resource server. No agent_token or POST /oauth/token here.

Audience: MCP resource server operatorsHuman role: No human in runtime flow

When to use this guide

  • You host MCP tools/resources and want only LIME-authenticated agents to call them.
  • Agents obtain MCP JWTs from LIME (see agent-mcp guide) and send Authorization: Bearer.
  • You want local verification without calling LIME on every tool invocation.

Before you start

  1. A deployed MCP server (HTTP/SSE or your transport) that can read Authorization headers.
  2. Network egress to https://lime.pics/api/v1/core/.well-known/jwks.json (cache keys).
  3. Optional: lime-mcp-server-sdk for TokenVerifier helper.

Who does what

RoleResponsibility
Agent runtimeGets MCP JWT from LIME, sends Bearer token to your server.
Your MCP resource serverVerify JWT, enforce aud=mcp, authorize by claims.sub.
LIMEIssues JWTs, publishes JWKS and OAuth metadata.

Your code (MCP resource server)

Only what you implement in this role. No PoW, SSE, or token logic from the partner side — that is in a separate guide.

  1. MCP server (boot)

    Discover LIME OAuth metadata (optional)

    At startup you may fetch RFC 8414 metadata to learn issuer and JWKS URI. Hard-coding https://lime.pics is fine for LIME production.

    Your server — OAuth metadata (optional)
    # RFC 8414 metadata (raw JSON — read issuer, jwks_uri at top level)
    curl -sS "https://lime.pics/api/v1/modules/oauth/.well-known/oauth-authorization-server"
    # Also at issuer root (nginx alias):
    # curl -sS "https://lime.pics/.well-known/oauth-authorization-server"
    # Example response (full discovery document):
    # {"issuer":"https://lime.pics","authorization_endpoint":"https://lime.pics/api/v1/modules/oauth/authorize","token_endpoint":"https://lime.pics/api/v1/modules/oauth/token","jwks_uri":"https://lime.pics/api/v1/core/.well-known/jwks.json","registration_endpoint":"https://lime.pics/api/v1/modules/oauth/register","grant_types_supported":["authorization_code","client_credentials"],"response_types_supported":["code"],"scopes_supported":["mcp"],"token_endpoint_auth_methods_supported":["none"],"code_challenge_methods_supported":["S256"],"lime_agent_token_header":"X-Agent-Token","lime_token_request_body":"grant_type","lime_default_audience":"mcp"}
  2. MCP server

    Require Bearer JWT on MCP requests

    Read Authorization: Bearer <token> on each MCP invocation. Reject missing or malformed headers before running tool logic.

  3. MCP server

    Verify signature, issuer, audience, expiry

    Validate with JWKS: iss must be https://lime.pics, aud must include mcp, exp in the future. Use claims.sub as the stable agent_id for ACLs.

    Your server — verify Bearer JWT
    # pip install lime-mcp-server-sdk
    # https://github.com/Mawyxx/lime-mcp-server-sdk
    # Full Python API: https://lime-mcp-server-sdk.readthedocs.io/
    from lime_mcp_server import TokenVerifier
    
    verifier = TokenVerifier()  # LIME_BASE_URL, LIME_OAUTH_AUDIENCE from env
    result = verifier.verify("{access_token_from_oauth_token_response}")
    if result.is_valid:
        print(result.agent_id)  # alias for claims["sub"] (agent UUID)
  4. MCP server

    Apply your authorization policy

    Map agent_id to allowed tools/namespaces. Return 403 when identity is valid but not permitted; 401 when token is invalid.

    Tip: Never accept X-Agent-Token on MCP RS — that is LIME's opaque agent secret, not the MCP JWT.

What agents do before calling you (not your code)

Agents exchange agent_token for a short-lived MCP JWT at LIME, then send Authorization: Bearer to your server. You only verify — never issue tokens.

  • Agent POSTs /modules/oauth/token with X-Agent-Token (on their infrastructure).
  • They attach access_token as Bearer on MCP tool calls.
  • Your job starts at JWT verification — see agent MCP guide for their side.

What success looks like

Every MCP request with a valid Bearer JWT is accepted; invalid/expired/wrong-audience tokens return 401; you log agent_id from claims.sub for audit.

claims.sub = agent_id (binding & site login)

The agent_id in MCP JWT is the same UUID users link on sites via Agent Binding and prove on Zero Human Auth:

  • From site binding

    Sites persist agent_id when users connect at /connect. Your ACL can allow or deny that UUID — one global identity namespace.

  • From site login passports

    Zero Human Auth also ends with claims.sub on the site backend. Treat MCP JWT sub and site-login passport sub as the same agent_id.

Full runnable example

TokenVerifier quick start
# pip install lime-mcp-server-sdk
# https://github.com/Mawyxx/lime-mcp-server-sdk
# Full Python API: https://lime-mcp-server-sdk.readthedocs.io/
from lime_mcp_server import TokenVerifier

verifier = TokenVerifier()
result = verifier.verify("{bearer_mcp_jwt}")
if result.is_valid:
    print(result.agent_id)  # alias for claims["sub"]

Related endpoints

MCP server (passport verification) · LIME