Skip to main content
Glama

ChatGPT App with OAuth2 + MCP + Privy

by Jahnik
QUICK_COMPARISON.md7.21 kB
# Quick Reference: OAuth Implementation Differences ## At a Glance | Feature | mcp2 | mcp | ChatGPT Compatible? | |---------|------|-----|-------------------| | **Token Type** | JWT (RS256) | Opaque random | mcp2 YES, mcp NO | | **Token Self-Validating** | Yes | No | Required: Yes | | **JWKS Endpoint** | ✓ /.well-known/jwks.json | ✗ Missing | Required: Yes | | **Introspection Endpoint** | ✓ POST /token/introspect | ✗ Missing | Required: Yes | | **Issuer Validation** | ✓ In JWT & middleware | ✗ Not validated | Recommended | | **Audience Validation** | ✓ In JWT & middleware | ✗ Not validated | Recommended | | **PKCE** | Mandatory | Optional | Required | | **OAuth Metadata Location** | /.well-known/oauth-authorization-server | N/A | Standard RFC 8414 | | **Privy Token Exchange** | /token/privy/access-token | /privy/access-token | Either works | --- ## Why mcp Fails with ChatGPT ### The Chain of Failures: ``` ChatGPT OAuth Flow: 1. User authenticates 2. OAuth token received: ✓ 3. ChatGPT fetches /.well-known/jwks.json: ✗ 404 4. ChatGPT tries token validation: ✗ No JWKS, can't validate 5. ChatGPT makes introspection request: ✗ 404 endpoint not found 6. ChatGPT gives up: "connection problem" ``` ### What mcp2 Avoids: ``` mcp2 OAuth Flow: 1. User authenticates 2. OAuth token received: JWT with signature ✓ 3. ChatGPT fetches /.well-known/jwks.json: ✓ Gets public key 4. ChatGPT validates token signature: ✓ Valid 5. ChatGPT makes MCP request: ✓ 6. Server validates JWT: ✓ 7. Tools execute: ✓ ``` --- ## Token Format Comparison ### mcp2 JWT Token Example: ``` eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0xIn0. eyJzdWIiOiJkaWQ6cHJpdnk6WXBrNTBZM3p0WjI5dloyNXNiMjVwYm1WZlkyOXQiLCJzY29wZSI6InJlYWQgd3JpdGUgcHJvZmlsZSBwcml2eTp0b2tlbjpleGNoYW5nZSIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMiIsImNsaWVudF9pZCI6ImNoYXRncHQtY29ubmVjdG9yIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDozMDAyIiwiZXhwIjoxNzMxNDQ1NjYwLCJpYXQiOjE3MzE0NDIwNjB9. <RSA_SIGNATURE> ``` **Can be validated without server**: Yes - Signature proves it came from server - Issuer proves correct server created it - Audience proves it's for this service - Expiration prevents replay attacks ### mcp Opaque Token Example: ``` Q3d4WkVXdlJqaVZFMmM5TjFBQllUZ0tQVkJBRWdGNWFUZExGV1ZITVhWTFMyZFlabWRGYVU5UE1FRlE= ``` **Cannot be validated without server**: Always requires database lookup - No signature - No issuer claim - No expiration field in token itself - If server restarts, all tokens in-memory map are lost --- ## Endpoint Comparison ### Authorization Endpoints | Endpoint | mcp2 | mcp | Status | |----------|------|-----|--------| | GET /authorize | Express route | Function | mcp2 clearer | | POST /authorize | Express route | Function | mcp2 clearer | | POST /register | Express route (DCR RFC 7591) | Function | mcp2 standard | | GET /.well-known/oauth-authorization-server | ✓ Implemented | Function-based | mcp2 RFC 8414 | | GET /.well-known/jwks.json | ✓ Implemented | ✗ Missing | **CRITICAL** | | POST /token/introspect | ✓ Implemented | ✗ Missing | **CRITICAL** | | POST /token | ✓ Returns JWT | ✓ Returns opaque | Different approach | | POST /mcp | Requires JWT validation | Requires opaque lookup | Both work if auth works | --- ## Authentication Middleware Comparison ### mcp2 validateToken(): ```typescript jwt.verify(token, publicKey, { algorithms: ['RS256'], issuer: serverUrl, // ← Checked audience: serverUrl, // ← Checked - CRITICAL }) ``` - Cryptographically validates signature - No database lookup needed - Works when server is busy or slow - Works offline if key is cached ### mcp authenticatePrivy(): ```typescript validateAccessToken(token) // ← Just a Map lookup ``` - Looks up token in memory - No cryptographic validation - Requires server availability - Vulnerable to replay if token leaked - Lost if server restarts --- ## Configuration Differences ### mcp2 (Centralized): ```typescript // src/server/config.ts export const config = { privy: { appId, appSecret }, server: { baseUrl, port, nodeEnv }, jwt: { privateKey, publicKey, issuer, algorithm, expiresIn }, oauth: { endpoints... }, intentExtraction: { ...params }, }; ``` ### mcp (Distributed): ```typescript // Environment variables read throughout: // src/privy.ts // src/oauth.ts // src/server.ts // src/auth.ts ``` **mcp2 advantage**: Single source of truth, easier to maintain --- ## Which Should You Use? ### Use mcp2 if: - ChatGPT integration is priority - You want industry-standard OAuth - You want token validation without server calls - You want better security (JWT signatures) - You're doing production deployment ### Use mcp if: - You only need internal MCP tools - You don't care about ChatGPT compatibility - You have a single, always-online server - You prefer simpler token lookup mechanism - You're still in development/testing --- ## Specific File Locations ### Critical Files in mcp2: - `/Users/jahnik/index-network/mcp2/src/server/oauth/token.ts` - JWT issuance (line 236-275) - `/Users/jahnik/index-network/mcp2/src/server/oauth/wellknown.ts` - JWKS endpoint (line 84-104) - `/Users/jahnik/index-network/mcp2/src/server/middleware/auth.ts` - JWT validation (line 27-82) ### Critical Files in mcp: - `/Users/jahnik/index-network/mcp/src/oauth.ts` - Opaque token issuance (line 549-593) - `/Users/jahnik/index-network/mcp/src/auth.ts` - Opaque validation (line 36-103) - `/Users/jahnik/index-network/mcp/src/server.ts` - Missing JWKS (no line found) --- ## The Fix: What mcp Needs To make mcp work with ChatGPT: 1. **Add JWKS endpoint** (~50 lines) - Location: Expose public key in JWK format - File: `src/server.ts` or new `src/jwks.ts` - Route: `GET /.well-known/jwks.json` 2. **Convert tokens to JWT** (~100 lines) - Replace `randomBytes(32).toString('base64url')` - With `jwt.sign({...}, privateKey, {issuer, expiresIn, ...})` - Add `JWT_PRIVATE_KEY` and `JWT_PUBLIC_KEY` env vars 3. **Add introspection endpoint** (~30 lines) - Route: `POST /token/introspect` - Return: `{active, sub, scope, client_id, exp, iss, aud}` 4. **Update metadata** (~3 lines) - Add `jwks_uri: "${issuer}/.well-known/jwks.json"` - To: `authorizationServerMetadata()` **Total effort**: ~180 lines of code changes --- ## Testing Each Implementation ### For mcp2: ```bash # Check JWKS curl http://localhost:3002/.well-known/jwks.json # Should return: { "keys": [{ "kty": "RSA", ... }] } # Check token format # OAuth flow returns JWT starting with "eyJ" # Check validation works curl -H "Authorization: Bearer <JWT>" http://localhost:3002/mcp -d '{...}' # Should work ``` ### For mcp: ```bash # Check JWKS curl http://localhost:3002/.well-known/jwks.json # Returns: 404 Not Found ✗ # Check token format # OAuth flow returns: "Q3d4...JIg==" (opaque, no structure) # Check if token is JWT echo "Q3d4...JIg==" | base64 -d # Not valid JSON (unlike JWT payload) ``` --- ## Summary **mcp2**: Production-ready, ChatGPT compatible, industry-standard OAuth **mcp**: Development-friendly, custom tokens, requires server for validation For ChatGPT integration, **use mcp2**.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jahnik/mcp2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server