Skip to main content
Glama
hasnaties

MCP Connector Test

by hasnaties

MCP Connector — OAuth 2.1 auth prototype (Firebase-backed)

A small, self-contained remote MCP server that demonstrates the full authentication handshake a Claude Connector goes through — OAuth 2.1 discovery, dynamic client registration, PKCE, an interactive sign-in page, and a token-protected tool call. Users are authenticated against a Firebase project, and a single whoami tool returns their real identity (profile + plan) read from Firestore.

It was built as a prototype for a Smodin Claude Connector, but it works with any Firebase project — plug in your own and run it.

⚠️ Prototype, not production. This server's own access/refresh tokens are HS256 JWTs signed with a shared secret, and all OAuth state (registered clients, auth codes) is kept in memory and resets on restart. The user identity is real (verified Firebase ID token + Firestore lookup), but the token layer is intentionally simple. Don't deploy this as-is.

How it works

Claude / Inspector          This server (:8000)              Firebase
     │  POST /mcp (no token) ──▶ 401 + WWW-Authenticate
     │  reads /.well-known/*  ──▶ OAuth discovery + PKCE metadata
     │  POST /register        ──▶ dynamic client registration
     │  opens /authorize ─────▶ 302 → /login (our sign-in page)
     │                              │  Firebase JS SDK sign-in ──▶ ID token
     │                              │  POST /login/complete (ID token)
     │                              │  verify token + read Firestore profile/plan
     │  POST /token (+PKCE) ──▶ access + refresh token
     │  POST /mcp (Bearer) ───▶ whoami → real identity

The MCP SDK's mcpAuthRouter and requireBearerAuth provide the OAuth HTTP plumbing. This repo implements the authorization-server logic (OAuthServerProvider), the Firebase sign-in page, and the Firestore identity lookup.

Related MCP server: MCP Access OAuth Server

Project structure

File

Purpose

src/index.ts

Express app: OAuth router, sign-in routes, token-protected /mcp (Streamable HTTP).

src/config.ts

Environment config; derives all OAuth URLs from PUBLIC_BASE_URL.

src/tokens.ts

Sign/verify the server's JWT access + refresh tokens.

src/auth/provider.ts

OAuthServerProvider implementation (authorize / token / PKCE / verify).

src/auth/store.ts

In-memory stores: clients, pending authorizations, auth codes, refresh tokens.

src/auth/login-page.ts

Firebase sign-in screen (GET /login) + POST /login/complete.

src/firebase/admin.ts

firebase-admin init + verifyIdToken.

src/firebase/smodin-user.ts

Firestore profile/plan lookup + paid-status logic.

src/mcp/server.ts

MCP server + the whoami tool.

scripts/seed-user.mjs

Seed a Firestore profile for a test user (optional).

Prerequisites

  • Node.js 18+

  • A Firebase project (a free/throwaway one is fine)

Firebase setup

  1. Authentication → enable a sign-in method. Email/Password is recommended (works on localhost and any tunnel with no extra config). Google works too, but see the caveat below.

  2. Firestore Database → create it (Native mode). Required even if empty — the profile lookup errors if no database exists.

  3. Service account (Project settings → Service accounts → Generate new private key) → download the JSON. This lets the server read Firestore. Keep it outside the repo.

  4. Grab your web app config (Project settings → General → Your apps) for the FIREBASE_* values.

Configuration

cp .env.example .env

Fill in .env (see comments in .env.example):

Variable

What it is

FIREBASE_PROJECT_ID

Your Firebase project id

FIREBASE_WEB_API_KEY

Web API key (public — shipped to the browser)

FIREBASE_AUTH_DOMAIN

<project-id>.firebaseapp.com

GOOGLE_APPLICATION_CREDENTIALS

Absolute path to the service-account JSON

TOKEN_SECRET

Long random string for signing this server's JWTs

PUBLIC_BASE_URL

Only needed behind a tunnel (see below)

Run

npm install
npm run build      # type-check + compile
npm run dev        # watch mode on http://localhost:8000

Quick health check:

curl http://localhost:8000/.well-known/oauth-authorization-server
curl -i -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'   # -> 401 + WWW-Authenticate

Test the full flow (MCP Inspector)

npm run inspect

In the Inspector: transport Streamable HTTP, URL http://localhost:8000/mcp, Connect. It runs OAuth discovery → registration → opens the sign-in page. Sign in with a test user (email/password), then call whoami — it returns that user's real identity.

On a fresh project with no Firestore documents, whoami returns the real uid/email with plan: free. To see a real plan, seed a profile:

npm run seed -- <FIREBASE_UID> test@example.com "Test User" premium

(Get <FIREBASE_UID> from Firebase console → Authentication → Users. Pass free instead of premium for a free account.)

Add it to claude.ai

Custom connectors require a paid Claude plan and a public HTTPS URL.

  1. Tunnel to the local server:

    cloudflared tunnel --url http://localhost:8000   # or: ngrok http 8000
  2. Set PUBLIC_BASE_URL in .env to the tunnel URL and restart (all OAuth URLs derive from it).

  3. In claude.ai → Settings → Connectors → Add custom connector → paste https://<your-tunnel-host>/mcp.

  4. Sign in on the connector's page, then ask Claude to run whoami.

Caveats

  • Google sign-in needs an authorized domain. signInWithPopup requires the app origin to be in the Firebase project's Authorized domains. localhost is allowed by default; ad-hoc tunnel hosts are not (you'd add them). Email/password has no such restriction.

  • Project alignment. The ID token's aud, the client-config projectId, and the admin projectId must all be the same Firebase project.

  • The profile/plan is snapshotted into the access token at login (fine for a prototype).

Security notes

  • Never commit .env or the service-account JSON — both are gitignored.

  • The web API key is intentionally public; the service-account key is a secret — keep it out of the repo and rotate it if exposed.

  • Replace the in-memory token layer before any real deployment.

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A remote MCP server implementation that demonstrates authentication and authorization capabilities using OAuth 2.1. This is a workshop project for learning how to build secure MCP servers with user authentication.
    18,182 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    This MCP server implements a secure OAuth 2.1 authorization server with Google login, enabling authenticated tool execution and a user interface for MCP applications.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Remote MCP server with built-in OAuth authentication via Cloudflare Access, enabling secure tool access and user identity-based restrictions.
    -