selfmcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@selfmcpwhat is your professional experience?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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, sonpm installworks out of the box on any machine, including one without build tools installed@modelcontextprotocol/sdkfor the MCP protocol itself (Streamable HTTP transport) and for the full OAuth 2.1 authorization server implementation (mcpAuthRouter), including Dynamic Client Registrationjosefor 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 stylingGetting started
npm install
cp .env.example .envGenerate 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 devThe 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 |
| Run with hot reload ( |
| Compile TypeScript to |
| Run the compiled build ( |
| (Re-)populate the database from |
|
|
| ESLint |
| Prettier (writes) |
| 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:
Discovery — clients fetch
/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource/mcpto learn where to register and authenticate.Registration (DCR) —
POST /registerlets any client dynamically obtain aclient_id(RFC 7591), no pre-registration or manual API key needed.Authorization —
GET /authorizerenders 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.Consent decision —
POST /consentissues a one-time authorization code (stored in SQLite, 60s TTL by default) and redirects back to the client'sredirect_uri.Token exchange —
POST /tokenexchanges 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).Calling the server —
POST /mcprequiresAuthorization: Bearer <access_token>, verified byrequireBearerAuthagainst 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/consentissues after an Allow/Deny decision, since that redirect must go to whateverredirect_urithe connecting client registered — a different origin, by design. The POST completes correctly server-side (you'll see a302in your logs) but the browser silently refuses to follow it and reverts to the previous page. Fixed here by allowingformAction: ["'self'", '*'].Cross-Origin-Opener-Policy: same-originsevers thewindow.openerrelationship the moment a popup/redirected window navigates to this origin, which breaks clients that track flow completion viawindow.openerorpostMessage. 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/inspectorIn 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:
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)
Go to the Plugins page → click the + next to the search box → Add manually
Server URL: the
/mcpURL; Authentication: OAuth (default) → check the risk acknowledgment → CreateClick Sign in, then Allow on the consent screen
Codex CLI
npm install -g @openai/codex
codex mcp add selfmcp --url https://your-deployed-url/mcpThis 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.
Set
BASE_URLto your real HTTPS URL (OAuth requires HTTPS in production; onlylocalhostis exempted).Set
TOKEN_SIGNING_SECRETto a real random secret (never reuse the.env.exampleplaceholder).Make sure the volume/disk backing
DATABASE_PATHpersists across restarts.Run
npm run build && npm run seed && npm start, or use the includedDockerfile.
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.yamlworks around this by runningnpm run seedas 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_clienterror 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.
This server cannot be installed
Maintenance
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
- Flicense-qualityCmaintenanceAn 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
- AlicenseAqualityDmaintenanceA 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 updated711MIT
- Alicense-qualityDmaintenanceExposes 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 updatedMIT
- Alicense-qualityDmaintenanceA Model Context Protocol (MCP) server that provides unified access to one's professional profile, including experience, publications, career timeline, and social media presence.Last updated1Apache 2.0
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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