Skip to main content
Glama

selfMCP

A personal Model Context Protocol (MCP) server. It exposes a profile — bio, skills, projects, work experience — as structured tools that any MCP-compatible AI client (Claude, ChatGPT, Codex) can query directly, secured with OAuth 2.1 and Dynamic Client Registration (DCR, RFC 7591) so clients can connect without any manually-issued API key.

Stack

  • Node.js + TypeScript + Express

  • SQLite via node:sqlite (Node's built-in driver, stable as of Node 22.5+) — no native addon compilation required, so npm install works out of the box on any machine, including one without build tools installed

  • @modelcontextprotocol/sdk for the MCP protocol itself (Streamable HTTP transport) and for the full OAuth 2.1 authorization server implementation (mcpAuthRouter), including Dynamic Client Registration

  • jose for signing/verifying access tokens (stateless JWTs)

  • EJS for the landing page and OAuth consent screen — no frontend build step

Related MCP server: Pavan Madduri — Personal Knowledge MCP Server

Project layout

src/
  config/env.ts        Environment variable loading + validation (zod)
  db/                   SQLite schema, seed script, and typed repository functions
  mcp/
    server.ts           Builds an McpServer and registers tools
    tools/               get_bio, list_skills, list_projects, search_projects, list_experience
    router.ts            Mounts the Streamable HTTP transport at POST /mcp
  oauth/
    store.ts             SQLite-backed OAuthRegisteredClientsStore (handles DCR persistence)
    provider.ts           Implements the SDK's OAuthServerProvider interface
    tokens.ts              JWT access tokens + hashed, rotating refresh tokens
    consent.ts             Signs/verifies the short-lived consent-screen round trip
  web/
    routes.ts             Landing page (GET /) and consent decision handler (POST /consent)
    views/                 landing.ejs, consent.ejs
  app.ts                 Wires everything into one Express app
  server.ts              Entry point
public/style.css        Landing page styling

Getting started

npm install
cp .env.example .env

Generate a signing secret and put it in .env as TOKEN_SIGNING_SECRET:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Edit src/db/seed.ts with your real name, bio, skills, projects, and experience, then run:

npm run seed
npm run dev

The server listens on http://localhost:3000 by default. Visit it in a browser to see the landing page, or run npm run inspector in another terminal to poke the MCP endpoint directly with the official MCP Inspector.

Scripts

Script

Purpose

npm run dev

Run with hot reload (tsx watch)

npm run build

Compile TypeScript to dist/

npm start

Run the compiled build (node dist/server.js)

npm run seed

(Re-)populate the database from src/db/seed.ts

npm run typecheck

tsc --noEmit

npm run lint

ESLint

npm run format

Prettier (writes)

npm run inspector

Launch the MCP Inspector dev tool

How the OAuth / DCR flow works

This server is both the MCP resource server and its own OAuth 2.1 authorization server, built on the SDK's mcpAuthRouter:

  1. Discovery — clients fetch /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource/mcp to learn where to register and authenticate.

  2. Registration (DCR)POST /register lets any client dynamically obtain a client_id (RFC 7591), no pre-registration or manual API key needed.

  3. AuthorizationGET /authorize renders a consent screen (src/web/views/consent.ejs). The pending request (client, redirect URI, PKCE challenge, scope, state) is carried in a short-lived signed JWT in a hidden form field rather than server-side session state, since there's nothing else to persist between the redirect and the user's click.

  4. Consent decisionPOST /consent issues a one-time authorization code (stored in SQLite, 60s TTL by default) and redirects back to the client's redirect_uri.

  5. Token exchangePOST /token exchanges the code (with PKCE verification handled by the SDK itself) for an access token (a signed, stateless JWT, 1 hour TTL by default) and a refresh token (opaque, hashed at rest, single-use with rotation — reusing a spent refresh token fails immediately).

  6. Calling the serverPOST /mcp requires Authorization: Bearer <access_token>, verified by requireBearerAuth against the same provider.

Trade-off worth knowing: because access tokens are stateless JWTs, they can't be individually revoked before they expire — only refresh tokens are revocable. Given the short (1 hour) default TTL, this is a standard and acceptable trade-off, not an oversight.

Helmet gotchas for OAuth servers specifically

Helmet's secure-by-default headers ship configured for a typical web app, not an OAuth authorization server, and two of its defaults will silently break real MCP/OAuth clients while looking completely fine under curl (since curl doesn't enforce any browser-side policy):

  • CSP form-action 'self' blocks the browser from following the redirect /consent issues after an Allow/Deny decision, since that redirect must go to whatever redirect_uri the connecting client registered — a different origin, by design. The POST completes correctly server-side (you'll see a 302 in your logs) but the browser silently refuses to follow it and reverts to the previous page. Fixed here by allowing formAction: ["'self'", '*'].

  • Cross-Origin-Opener-Policy: same-origin severs the window.opener relationship the moment a popup/redirected window navigates to this origin, which breaks clients that track flow completion via window.opener or postMessage. Fixed here by disabling COOP entirely (crossOriginOpenerPolicy: false).

Both are set in src/app.ts. If you're deploying behind a proxy (Render, most PaaS hosts), also see the trust proxy note there — without it, express-rate-limit can't safely read X-Forwarded-For and throws on every rate-limited route.

Testing / connecting an MCP client

All of the methods below point at the same URL — <deployed-url>/mcp (e.g. https://selfmcp.onrender.com/mcp) — and each one auto-discovers the OAuth metadata and completes DCR + the consent flow on first connection; no manual API key needed.

If the server has been idle, the first request can take 50+ seconds to wake up — see Render (free tier) below. That's expected, not a failure.

Fastest: no account needed (MCP Inspector)

The official MCP Inspector can call every tool directly, with no Claude subscription, ChatGPT plan, or OpenAI account required:

npx @modelcontextprotocol/inspector

In the UI: Add Server → transport Streamable HTTP → paste the /mcp URL → toggle the server on → click Allow on the consent screen that opens → open the Tools tab and try get_bio or list_skills directly.

Claude Desktop / Claude Code

Add a remote connector via Settings → Connectors, or in claude_desktop_config.json:

{
  "mcpServers": {
    "selfmcp": { "url": "https://your-deployed-url/mcp" }
  }
}

ChatGPT

This one has a real, non-obvious prerequisite step — custom connectors are gated behind "Developer mode", which is off by default:

  1. Settings → Security and login → scroll to Developer mode → turn it on (labeled "elevated risk" — it just means you can add your own connectors, not a security downgrade for your account)

  2. Go to the Plugins page → click the + next to the search box → Add manually

  3. Server URL: the /mcp URL; Authentication: OAuth (default) → check the risk acknowledgment → Create

  4. Click Sign in, then Allow on the consent screen

Codex CLI

npm install -g @openai/codex
codex mcp add selfmcp --url https://your-deployed-url/mcp

This registers the server via DCR and opens a browser to the consent screen automatically — click Allow and it's connected. (codex mcp get selfmcp confirms it afterward.)

Once connected, try asking

  • "What's this person's professional background?"

  • "List their skills relevant to a backend engineering role."

  • "Search their projects for anything related to TypeScript or MCP."

Deployment

Any host that can run a persistent Node process works (Render, Railway, Fly.io, a small VM). Avoid serverless/functions platforms — the Streamable HTTP transport and SSE want a long-lived connection, and the SQLite file needs a persistent disk.

  1. Set BASE_URL to your real HTTPS URL (OAuth requires HTTPS in production; only localhost is exempted).

  2. Set TOKEN_SIGNING_SECRET to a real random secret (never reuse the .env.example placeholder).

  3. Make sure the volume/disk backing DATABASE_PATH persists across restarts.

  4. Run npm run build && npm run seed && npm start, or use the included Dockerfile.

Render (free tier)

A render.yaml Blueprint is included: on Render, New + → Blueprint, connect this repo, and it configures the service automatically (build command, start command, and a generated TOKEN_SIGNING_SECRET).

The free plan has no persistent disk — its filesystem resets not just on every deploy but every time the service wakes up from idle (it spins down after ~15 minutes of inactivity). Two consequences of that, and how this project handles them:

  • Profile/skills/projects/experience data would be lost on every wake-up. render.yaml works around this by running npm run seed as part of the start command (not just at build time), so this static data is restored every time the process boots.

  • OAuth client registrations and refresh tokens are dynamic, so they can't be "reseeded" the same way — they're genuinely wiped on each wake-up. In practice this just means an MCP client that registered before a spin-down will get an invalid_client error on its next call and needs to redo Dynamic Client Registration, which is expected, spec-compliant behavior for a client talking to a server that doesn't guarantee permanent client storage — not a bug. If this matters for your use case, move to a paid Render plan with a persistent disk instead.

Known dependency advisory

npm audit flags a moderate path-traversal issue in @hono/node-server (a transitive dependency of @modelcontextprotocol/sdk's static-file-serving helper). This project never uses that static-serving code path — only the SDK's protocol/transport and auth modules — so it isn't exploitable here. Revisit this once the SDK bumps its @hono/node-server dependency.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    C
    maintenance
    An MCP server that provides a structured API for AI agents to query a person's resume, including profile, projects, writing, and gated access to experience and skills.
    Last updated
  • A
    license
    A
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server that exposes a professional profile — certifications, industry articles, open source contributions, and live GitHub activity — as a queryable API for AI agents.
    Last updated
    7
    11
    MIT
  • A
    license
    -
    quality
    D
    maintenance
    Exposes a personalized AI agent that reads your resume and provides intelligent responses about your professional background through a standardized MCP server interface with RAG capabilities.
    Last updated
    MIT
  • A
    license
    -
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server that provides unified access to one's professional profile, including experience, publications, career timeline, and social media presence.
    Last updated
    1
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • The personal context layer for AI: your profile and files, read by any MCP client over OAuth.

  • MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2

  • MCP server for verifying EUDI/Talao wallet data via OIDC4VP (pull) for AI agents.

View all MCP Connectors

Latest Blog Posts

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/jaiminbhaduri/selfmcp'

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