Skip to content

aldo-linux/mcp-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP Users Server

A Model Context Protocol (MCP) server that wraps the JSONPlaceholder users API, protected by Auth0 browser-based authentication.

Tools

Tool Description Parameters
list_users Get all users
get_user Get a user by ID id (number)
search_users_by_username Find users by username username (string)
search_users_by_email Find users by email email (string)

Auth0 Setup

The server uses Auth0 as the authorization server. When an MCP client (Claude Desktop, VS Code) first connects, it detects that the server requires authentication, opens the user's browser for an Auth0 login, and then uses the resulting token on every subsequent request.

Step 1 — Create an Auth0 account and tenant

Sign up at auth0.com if you do not already have an account. Note your tenant domain (shown in the top-left of the Auth0 dashboard), e.g. my-tenant.us.auth0.com.

Step 2 — Register an API (resource server)

  1. In the Auth0 dashboard go to Applications → APIs → Create API.
  2. Fill in:
    • Name: MCP Users Server (or any label you like)
    • Identifier (audience): a URI that uniquely identifies the API, e.g. https://mcp-users-server/. This does not have to be a real URL.
    • Signing Algorithm: RS256 (the default — required for JWT verification via JWKS)
  3. Click Create. Copy the Identifier — you will use it as AUTH0_AUDIENCE.

Step 3 — Enable PKCE for browser-based clients

MCP clients authenticate using the Authorization Code flow with PKCE (Proof Key for Code Exchange). This is Auth0's default for SPAs and native apps, so no extra configuration is required. The clients detect support by reading code_challenge_methods_supported from Auth0's discovery document.

Step 4 — Configure the Auth0 callback URL exactly

Auth0 validates redirect_uri by exact match. For mcp-remote, the browser callback path is /oauth/callback, so you should pin Claude Desktop to a fixed localhost port and add that exact URL to your Auth0 application.

  1. In the Auth0 dashboard open Applications → Applications.
  2. Open the Auth0 application whose Client ID you use in Claude Desktop.
  3. Under Application URIs → Allowed Callback URLs add http://localhost:3334/oauth/callback.
  4. Save changes.

If you prefer a different port, use that same port both in Auth0 and in the mcp-remote arguments below.

Step 5 — Configure environment variables

Copy .env.example to .env and fill in your values:

cp .env.example .env
AUTH0_DOMAIN=my-tenant.us.auth0.com        # your tenant domain (no https://)
AUTH0_AUDIENCE=https://mcp-users-server/   # the API Identifier from Step 2
PORT=3000
SERVER_URL=http://localhost:3000

Never commit .env to source control. It is already listed in .gitignore.

The server loads .env automatically at startup. It checks these locations in order:

  1. The path in MCP_ENV_FILE, if you set it.
  2. .env in the current working directory.
  3. .env in the project root relative to the built dist files.

This is important for Claude Desktop because it launches the server as a child process and may not provide the same shell environment you see in a terminal.


How the Auth0 integration works

MCP Client                    This Server              Auth0
(Claude Desktop / VS Code)    (Express + MCP SDK)      (Authorization Server)
      │                             │                        │
      │── POST /mcp ───────────────▶│                        │
      │                             │ 401 Unauthorized       │
      │◀── WWW-Authenticate ────────│ (resource_metadata     │
      │    resource_metadata=URL    │  points to this server)│
      │                             │                        │
      │── GET /.well-known/ ───────▶│                        │
      │   oauth-protected-resource  │ 200 JSON               │
      │◀────────────────────────────│ (points to Auth0       │
      │                             │  as auth server)       │
      │                             │                        │
      │── GET /.well-known/ ───────────────────────────────▶│
      │   openid-configuration      │                       │ 200 JSON
      │◀──────────────────────────────────────────────────── │
      │                             │                        │
      │ [browser opens]             │                        │
      │── Authorization request ──────────────────────────▶│
      │   + PKCE code_challenge     │                       │ Login page
      │◀── redirect with code ──────────────────────────────│
      │                             │                        │
      │── POST /oauth/token ──────────────────────────────▶│
      │   code + code_verifier      │                       │ JWT access token
      │◀── access_token (JWT) ──────────────────────────────│
      │                             │                        │
      │── POST /mcp ───────────────▶│                        │
      │   Authorization: Bearer JWT │ verify JWT via JWKS   │
      │                             │────────────────────────▶│
      │                             │◀─ public keys (cached) ─│
      │                             │ signature ✓ / exp ✓    │
      │◀── MCP response ────────────│                        │

Key components

src/auth.ts

fetchAuth0OAuthMetadata() — Called once at server startup. Fetches Auth0's OIDC discovery document (/.well-known/openid-configuration) and maps it to the OAuthMetadata shape the MCP SDK expects. This data is served by mcpAuthMetadataRouter so clients can discover Auth0 automatically.

createAuth0TokenVerifier() — Returns an OAuthTokenVerifier whose verifyAccessToken() method validates an Auth0 JWT using jose:

  • Fetches (and caches) Auth0's public signing keys from /.well-known/jwks.json.
  • Verifies the token signature, iss (issuer), aud (audience), and exp (expiry).
  • Returns an AuthInfo object (clientId, scopes, expiresAt) that the MCP SDK attaches to the request.

src/index.ts

mcpAuthMetadataRouter — Mounts GET /.well-known/oauth-protected-resource. This endpoint tells MCP clients that the server is OAuth-protected and points them to Auth0 as the authorization server. Without this, clients would not know how to authenticate.

requireBearerAuth — Express middleware placed in front of every /mcp route. It calls verifyAccessToken() on the Authorization: Bearer token, returns 401 if the token is missing or invalid, and attaches the decoded AuthInfo to req.auth if valid.

Session management — Each authenticated client gets a StreamableHTTPServerTransport + McpServer pair keyed by a UUID session ID. The session ID is returned in the Mcp-Session-Id response header on the first POST and must be echoed back by the client on all subsequent requests. Sessions are removed when the client sends DELETE /mcp or disconnects.


Running the server

Prerequisites

  • Node.js 18+
  • An Auth0 tenant configured as described above

Build and start

npm install
npm run build

# Copy and fill in environment variables
cp .env.example .env
# edit .env with your AUTH0_DOMAIN and AUTH0_AUDIENCE

npm start

The server prints three URLs on startup:

MCP server listening on http://localhost:3000
MCP endpoint:    http://localhost:3000/mcp
OAuth metadata:  http://localhost:3000/.well-known/oauth-protected-resource

Configure Claude Desktop

Claude Desktop expects command-style MCP entries. Use mcp-remote as a bridge to this HTTP MCP server.

  1. Keep this server running:
npm start
  1. Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
  "mcpServers": {
    "users": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://localhost:3000/mcp",
        "3334",
        "--host",
        "localhost",
        "--static-oauth-client-info",
        "{\"client_id\":\"YOUR_AUTH0_APP_CLIENT_ID\"}",
        "--debug"
      ]
    }
  }
}

YOUR_AUTH0_APP_CLIENT_ID is the Auth0 Application Client ID for a pre-registered app (typically a Native application with PKCE).

With the config above, the exact redirect URI sent to Auth0 is http://localhost:3334/oauth/callback, which must appear in the Auth0 application's Allowed Callback URLs.

Why this is required: many Auth0 tenants disable Dynamic Client Registration (DCR). In that case mcp-remote fails during registerClient unless static client info is supplied.

  1. Restart Claude Desktop.

On the first use it will open your browser to Auth0 for login. After you authenticate, Claude Desktop stores the token and uses it automatically for all subsequent sessions.

Configure VS Code

Add the following to your VS Code settings.json (or workspace settings):

{
  "mcp": {
    "servers": {
      "users": {
        "type": "http",
        "url": "http://localhost:3000/mcp"
      }
    }
  }
}

VS Code will similarly prompt for browser authentication on first use.


Project structure

src/
  auth.ts      Auth0 JWT verification and OAuth metadata helpers
  index.ts     Express HTTP server, MCP routes, session management
.env.example   Environment variable template
SPEC.md        Feature specification
INSTALL.md     Legacy stdio installation notes

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors