This guide is for administrators, DevOps engineers, and developers who need to self-host the Context7 MCP server, integrate Context7's libraries into production systems, or understand how this monorepo is built. It is the exhaustive, source-derived companion to the User Guide.
Important
This repository hosts the MCP server, CLI, SDKs, and integrations only. The Context7 API backend, parsing engine, and crawling engine that build and serve the documentation index are private and not part of this repository. Self-hosting the MCP server still relies on the hosted Context7 API at
context7.com/api(overridable viaCONTEXT7_API_URL).
1. Executive Summary
Context7 is an up-to-date documentation retrieval system for AI coding agents. It exposes two capabilities — resolve a library name to a canonical ID, and fetch version-specific documentation — through five distinct delivery surfaces published from one monorepo.
| Package | Version | Role | Runtime |
|---|---|---|---|
ctx7 |
0.4.5 | CLI: agent setup, doc queries, skill management | Node >=18 |
@upstash/context7-mcp |
3.1.0 | MCP server (stdio + HTTP) — the one deployable | Node >=18 (HTTP needs Redis) |
@upstash/context7-sdk |
0.3.0 | Typed HTTP client for the Context7 API | Node / browser |
@upstash/context7-tools-ai-sdk |
0.2.3 | Vercel AI SDK tools + agent | Node, AI SDK >=6 |
@upstash/context7-pi |
0.1.0 | pi coding-agent extension | pi runtime, Node >=22.19 |
Key architectural facts:
- The MCP server is a thin, stateless-per-request proxy in front of the private Context7 API. It holds no documentation itself — it forwards
resolveandquerycalls and formats results for LLM consumption. - HTTP mode tracks MCP sessions in Upstash Redis purely for spec compliance and log correlation; sessions are not an auth primitive, and the store fails open.
- Authentication is bearer API keys (prefix
ctx7sk) or JWTs validated against Clerk or Microsoft Entra ID. The CLI obtains tokens via OAuth 2.0 + PKCE. - All five surfaces ultimately call the same two backend endpoints:
GET /v2/libs/searchandGET /v2/context.
2. Architecture
2.1 System overview
┌─────────────────────────────────────────────┐
AI coding agent │ Context7 delivery surfaces │
(Claude, Cursor, …) │ │
│ │ ctx7 CLI ──┐ │
│ MCP protocol │ MCP server ─┤ │
├─────────────────►│ SDK ────────┼──► HTTPS ──► Context7 API │
│ │ AI-SDK tools ┤ (private backend) │
your code │ pi extension ┘ context7.com/api │
└─────────────────►│ │
└───────────────────┬─────────────────────────┘
│
GET /v2/libs/search (resolve)
GET /v2/context (fetch docs)
Every surface is a different client of the same backend API. The backend (crawling, parsing, indexing, ranking) is closed-source; this repo is the client/edge layer.
2.2 MCP server request flow (HTTP)
Client ──POST /mcp──► Express app
│
├─ CORS + header normalization
├─ extract API key (Authorization / X-API-Key / Context7-API-Key …)
├─ /mcp → anonymous allowed
│ /mcp/oauth → JWT required (Clerk or Entra)
├─ session: create on initialize / refresh otherwise (Redis)
├─ arg-aliasing hook (rewrites hallucinated tool-arg names)
├─ StreamableHTTPServerTransport (SSE response, per-request server)
└─ tool call → lib/api.ts → Context7 API → formatted text
A fresh McpServer and transport are constructed per request and torn down when the response closes. The Express layer owns session lifecycle; the MCP SDK transport does not (sessionIdGenerator: undefined).
2.3 Component inventory
| Component | Source | Responsibility |
|---|---|---|
| MCP entrypoint | packages/mcp/src/index.ts |
CLI parsing, transport setup, Express routes, tool registration |
| MCP API client | packages/mcp/src/lib/api.ts |
Calls /v2/libs/search and /v2/context; proxy/CA handling |
| Header builder | packages/mcp/src/lib/encryption.ts |
Builds API headers; AES-256-CBC client-IP encryption |
| JWT validation | packages/mcp/src/lib/jwt.ts |
Validates Clerk and Microsoft Entra v2 tokens via JWKS |
| Redis client | packages/mcp/src/lib/redis.ts |
Lazy Upstash Redis client from env |
| Session store | packages/mcp/src/lib/sessionStore.ts |
Create/refresh/delete MCP sessions (TTL 7d) |
| Result formatting | packages/mcp/src/lib/utils.ts |
Formats search results for LLM consumption |
| CLI entrypoint | packages/cli/src/index.ts |
Commander program, command registration, upgrade notice |
| CLI commands | packages/cli/src/commands/*.ts |
auth, docs, setup, remove, upgrade, skill, generate |
| CLI auth | packages/cli/src/utils/auth.ts |
OAuth PKCE flow, token storage, refresh |
| SDK client | packages/sdk/src/client.ts |
Context7 class, searchLibrary/getContext |
| SDK HTTP layer | packages/sdk/src/http/index.ts |
Fetch wrapper with retry/backoff |
2.4 The "duplicate-but-aligned" pattern
The pi package deliberately copies the API client, formatting, and type definitions from the MCP package (see the header comments in packages/pi/lib/*). This keeps pi's wire format and LLM-facing tool descriptions identical to the MCP server's while letting pi control its own HTTP runtime.
Important
When changing tool descriptions, result formatting, or error messages, update both
packages/mcp/src/lib/andpackages/pi/lib/together. They are intentionally kept in lockstep and there is no shared module enforcing it.
3. Requirements
3.1 Runtime
| Use case | Requirement |
|---|---|
| CLI / stdio MCP | Node.js >=18, a package runner (npx/pnpm/bun) |
| HTTP MCP server | Node.js >=18, Upstash Redis (REST), outbound HTTPS to context7.com |
| Building from source | pnpm (Corepack), TypeScript ^5.8, the repo's lockfile |
| AI-SDK tools | Vercel AI SDK >=6.0.0, zod >=4.0.0, @upstash/context7-sdk >=0.3.0 |
| pi extension | pi coding-agent runtime, Node >=22.19 |
3.2 Build tooling
The monorepo uses pnpm workspaces (packages/*). Per-package build tools: tsup (CLI, SDK, AI-SDK tools), tsc (MCP), and vitest for tests. Releases are managed by Changesets.
pnpm install # install all workspace deps
pnpm -r run build # build every package
pnpm -r run test # run all test suites
pnpm typecheck # typecheck all packages
pnpm lint # eslint across packages
4. Deploying the HTTP MCP Server
Self-hosting is appropriate when you want the MCP edge inside your own network, behind your own auth, or co-located with corporate proxies/CAs. The server still forwards to the hosted Context7 API unless you point CONTEXT7_API_URL at a private deployment.
4.1 Docker (recommended)
The repo ships a production Dockerfile at packages/mcp/Dockerfile. It is a two-stage build that compiles the MCP package and ships a production-only image:
# Build stage compiles @upstash/context7-mcp, production stage runs it
EXPOSE 8080
CMD ["node", "dist/index.js", "--transport", "http", "--port", "8080"]
Build and run:
# From the repo root (Dockerfile copies the monorepo manifests + packages/mcp)
docker build -f packages/mcp/Dockerfile -t context7-mcp .
docker run -d --name context7-mcp \
-p 8080:8080 \
-e UPSTASH_REDIS_REST_URL="https://<your-db>.upstash.io" \
-e UPSTASH_REDIS_REST_TOKEN="<token>" \
-e CLIENT_IP_ENCRYPTION_KEY="<64-hex-chars>" \
context7-mcp
Context7 Documentation MCP Server v3.1.0 running on HTTP at http://localhost:8080/mcp
Note
The image exposes 8080, while the server's own default port is 3000. The Docker
CMDoverrides it with--port 8080. Match your reverse-proxy upstream to whichever you run.
4.2 Smithery
packages/mcp/smithery.yaml declares an HTTP start command with no required configuration, so the server can be deployed via Smithery as @upstash/context7-mcp.
4.3 Running from source
pnpm install --frozen-lockfile
pnpm --filter @upstash/context7-mcp build
node packages/mcp/dist/index.js --transport http --port 3000
4.4 Deployment checklist
- [ ] Provision an Upstash Redis database; set
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN. - [ ] Set a real
CLIENT_IP_ENCRYPTION_KEY(64 hex characters). Do not ship the built-in default. - [ ] If behind a proxy, set
HTTPS_PROXY(andNODE_EXTRA_CA_CERTSfor custom CAs). - [ ] Put the server behind TLS via a reverse proxy (the server speaks plain HTTP).
- [ ] Forward client IPs via
X-Forwarded-Forat the proxy so rate-limiting works. - [ ] Decide auth posture:
/mcp(anonymous) vs/mcp/oauth(JWT-required). - [ ] If using Entra SSO, ensure the backend has the tenant/audience config registered.
- [ ] Health-check
GET /ping. - [ ] Confirm clients use POST (a
GET /mcpcorrectly returns405).
5. Configuration Reference
5.1 MCP server CLI flags
| Flag | Default | Notes |
|---|---|---|
--transport <stdio|http> |
stdio |
Invalid values exit with an error |
--port <number> |
3000 |
HTTP only; rejected with --transport stdio |
--api-key <key> |
— | stdio only; rejected with --transport http |
-v, --version |
— | Prints SERVER_VERSION (from package.json) |
Unknown flags are tolerated (allowUnknownOption) so MCP Inspector and wrappers can pass extras through. On EADDRINUSE, HTTP mode auto-increments the port up to +10 before giving up.
5.2 Environment variables
These are consumed across the MCP server, SDK, CLI, and pi. The repo's .env.example is the authoritative list.
| Variable | Used by | Purpose | Default |
|---|---|---|---|
CONTEXT7_API_KEY |
all | Bearer key for the Context7 API | — |
CONTEXT7_API_URL |
MCP, SDK*, pi* | Backend base URL | https://context7.com/api |
UPSTASH_REDIS_REST_URL |
MCP (HTTP) | Upstash Redis REST URL | — (required for HTTP) |
UPSTASH_REDIS_REST_TOKEN |
MCP (HTTP) | Upstash Redis REST token | — (required for HTTP) |
RESOURCE_URL |
MCP (HTTP) | OAuth protected-resource URL advertised in metadata | https://mcp.context7.com |
AUTH_SERVER_URL |
MCP (HTTP) | OAuth authorization server | https://context7.com |
OPENAI_APPS_CHALLENGE_TOKEN |
MCP (HTTP) | Serves the OpenAI Apps domain-verification challenge | — (404 if unset) |
CLIENT_IP_ENCRYPTION_KEY |
MCP | 64-hex-char AES-256-CBC key for client-IP encryption | insecure built-in default |
HTTPS_PROXY / HTTP_PROXY |
MCP | Outbound proxy for API calls | — |
NODE_EXTRA_CA_CERTS |
MCP | Path to extra CA certificates | — |
GITHUB_TOKEN / GH_TOKEN |
CLI | Token for fetching skills from private GitHub repos | — |
CTX7_TELEMETRY_DISABLED |
CLI | Disable anonymous CLI usage events | — |
EDITOR |
CLI | Editor for reviewing generated skills | open |
CLAUDE_CONFIG_DIR |
CLI | Override Claude config location during setup | — |
* The hosted SDK base URL (https://context7.com/api) and pi base URL are compiled in; the MCP server reads CONTEXT7_API_URL. The CLI talks to https://context7.com (overridable with --base-url).
Caution
CLIENT_IP_ENCRYPTION_KEYhas a hard-coded default value inencryption.ts. It is a placeholder, not a secret — always set your own 64-hex-character key in any real deployment. If the key is malformed, the server logs an error and falls back to sending the client IP unencrypted.
5.3 HTTP endpoints exposed by the MCP server
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /mcp |
None | Anonymous MCP protocol endpoint |
| POST | /mcp/oauth |
JWT required | Authenticated MCP endpoint |
| DELETE | /mcp, /mcp/oauth |
— | Terminate an MCP session (needs Mcp-Session-Id) |
| GET | /mcp* |
— | Returns 405 (server sends no SSE/server-initiated notifications) |
| GET | /ping |
None | Health check → { "status": "ok", "message": "pong" } |
| GET | /.well-known/oauth-protected-resource |
None | RFC 9728 resource metadata |
| GET | /.well-known/oauth-authorization-server |
None | Proxies the auth server's metadata |
| GET | /.well-known/openai-apps-challenge |
None | OpenAI Apps verification (404 unless token set) |
| * | (any other) | — | Catch-all 404 |
Accepted API-key headers (HTTP mode, checked in order): Authorization: Bearer …, Context7-API-Key, X-API-Key, Context7_API_Key, X_API_Key.
6. Security
6.1 Authentication & authorization
API keys. Keys carry the ctx7sk prefix and are sent as bearer tokens to the backend. The SDK warns (but does not fail) if a key lacks the prefix; the backend returns a 401 with guidance if a key is invalid.
JWT validation (lib/jwt.ts). On the /mcp/oauth endpoint, if the presented credential is a JWT (three dot-separated segments), it is verified:
- Clerk tokens (issuer
https://clerk.context7.com) are verified against Clerk's JWKS. - Microsoft Entra v2 tokens (issuer
https://login.microsoftonline.com/<tenant>/v2.0) are verified against the tenant's JWKS. The server fetches per-audience Entra config (tenant ID, required scope) from the backend, caches it for 5 minutes, and enforces the required scope if configured.
Validation failures return spec-compliant JSON-RPC errors with messages like Token expired, Invalid signature, or Missing required scope.
OAuth (CLI). The CLI uses OAuth 2.0 Authorization Code + PKCE (S256):
- Authorize:
GET /api/oauth/authorize, token exchange:POST /api/oauth/token. - Client ID
2veBSofhicRBguUT, scopeprofile email,response_type=code. - A local callback server listens on
127.0.0.1:52417(/callback) with a 5-minute timeout and validates thestateparameter to prevent CSRF. - Tokens are stored in
~/.context7/credentials.json(directory mode0700, file mode0600) and refreshed automatically using the refresh token when expired.
6.2 Client-IP encryption
The MCP server encrypts the caller's IP (used for backend rate-limiting/abuse signals) with AES-256-CBC before sending it as the mcp-client-ip header. A random 16-byte IV is prepended. Private/internal ranges (10., 192.168., 172.16–31.) are skipped when parsing X-Forwarded-For so the first public IP is used.
6.3 Session handling
- Sessions live in Redis under
#mcp#session#<uuid>, TTL 7 days, refreshed (sliding) only when under the 1-day threshold. - Sessions are not an authentication or authorization mechanism — just opaque identifiers for log correlation and StreamableHTTP spec compliance.
- The store fails open: Redis errors are logged and the request proceeds. Ghost sessions self-heal — a missing key returns
404and the client re-initializes.
6.4 Input-safety guards (CLI)
The CLI installs files into agent directories, so it hardens against path traversal:
assertSkillNameInRoot/isSafeSkillNamereject skill names with.., null bytes, or characters outside[a-zA-Z0-9._-], and ensure the resolved path stays directly under the skills root.installSkillFilesrejects any file whose resolved path escapes the target directory (this is the source of the… resolves outside the target directoryerror fixed for Windows in issue #2361).- Skills fetched from GitHub skip files whose relative path contains
... - Skill content flagged for prompt injection by the backend is blocked from install and reported, not silently dropped.
6.5 Data handling & disclosure
Tool descriptions explicitly instruct agents not to include secrets, credentials, personal data, or proprietary code in queries — only the question and library name are sent to the API. The project's SECURITY.md directs vulnerability reports to GitHub private advisories or [email removed], with a 48-hour acknowledgment target and a 30-day resolution goal for critical issues.
Warning
Anonymous
/mcpaccess means anyone who can reach your self-hosted server can consume your backend quota under whatever key/identity the server forwards. If you self-host, front it with your own gateway or require/mcp/oauth.
7. Operations
7.1 Health & monitoring
- Liveness:
GET /pingreturns200with{"status":"ok","message":"pong"}. - Logs: the server logs to stderr (so stdout stays clean for the stdio transport). Watch for
Error handling MCP request, OAuth upstream errors, and Redis session errors. - Startup banner: confirms transport, version, and bound port.
7.2 Scaling
The HTTP server is effectively stateless — all shared state lives in Redis, and a new MCP server/transport is created per request. You can run multiple replicas behind a load balancer without sticky sessions, since session validation is a Redis lookup, not in-process state.
7.3 Networking
- Outbound HTTPS to
context7.com(or yourCONTEXT7_API_URL) is required. - Corporate proxies: set
HTTPS_PROXY; for TLS interception, setNODE_EXTRA_CA_CERTSto your CA bundle path. The API client wires these into an undiciProxyAgent/Agentat module load. - CORS is wide open (
Access-Control-Allow-Origin: *) to support browser-based MCP clients; restrict at your proxy if needed.
7.4 Backups & state
There is no durable application data to back up — Redis holds only ephemeral, self-healing session keys. Treat the deployment as cattle.
8. Repository Structure (Developer Reference)
context7/
├── packages/
│ ├── cli/ ctx7 — Commander CLI
│ │ └── src/
│ │ ├── index.ts program + command registration
│ │ ├── commands/ auth, docs, setup, remove, upgrade, skill, generate
│ │ ├── setup/ agents.ts, mcp-writer.ts, templates.ts
│ │ └── utils/ api, auth, deps, github, ide, installer, update-check, tracking
│ ├── mcp/ @upstash/context7-mcp — MCP server
│ │ ├── src/index.ts transports + Express + tool registration
│ │ ├── src/lib/ api, jwt, redis, sessionStore, encryption, utils
│ │ └── Dockerfile, smithery.yaml
│ ├── sdk/ @upstash/context7-sdk — typed client
│ │ └── src/ client.ts, http/, error/, commands/
│ ├── tools-ai-sdk/ @upstash/context7-tools-ai-sdk — Vercel AI SDK
│ │ └── src/ tools/, agents/, prompts/
│ └── pi/ @upstash/context7-pi — pi extension
│ └── lib/, extensions/, skills/, prompts/
├── plugins/ Claude Code, Cursor, context7-power, gemini-extension
├── skills/ find-docs, context7-mcp, context7-cli (installable skills)
├── rules/ context7-cli.md, context7-mcp.md (agent rules)
├── docs/ MkDocs/Mintlify documentation site (.mdx)
└── i18n/ Translated READMEs (15 languages)
8.1 CLI internals
- Commander drives the program. Two
preActionhooks handle--base-urloverrides and the once-a-day upgrade notice. setup/agents.tsdefines each agent's MCP config path/key, rule type, and skill directory.setup/mcp-writer.tsreads/merges/writes JSON and TOML MCP configs idempotently.setup/templates.tsrenders the rule and skill content per agent.utils/update-check.tspollsregistry.npmjs.org/<pkg>/latest(1.5 s timeout), caches result and notification state in~/.context7/cli-state.json(24 h TTL), and computes an install-method-aware upgrade plan (npm/pnpm/bun, global vs ephemeral runner).utils/tracking.tsposts anonymous events to/api/v2/cli/eventsunlessCTX7_TELEMETRY_DISABLEDis set.
8.2 SDK internals
Context7wraps anHttpClient(baseUrl=https://context7.com/api, retry 5×, exponential backoffexp(n)*50ms,cache: no-store).- Commands subclass a generic
Command<TResult>;SearchLibraryCommand→GET v2/libs/search,GetContextCommand→GET v2/context. Both supporttype: "json" | "txt"; JSON responses are mapped intoLibrary[]/Documentation[], text passes through. Errors throwContext7Error.
8.3 Backend API endpoints (consumed by these clients)
| Endpoint | Method | Used by |
|---|---|---|
/v2/libs/search |
GET | MCP, SDK, CLI (library), pi |
/v2/context |
GET | MCP, SDK, CLI (docs), pi |
/api/v2/skills, /skills/suggest, /skills/quota, /skills/questions, /skills/generate |
GET/POST | CLI skills + generate |
/api/v2/cli/events |
POST | CLI telemetry |
/api/oauth/authorize, /api/oauth/token |
GET/POST | CLI OAuth |
/api/dashboard/whoami, /api/dashboard/api-keys |
GET/POST | CLI whoami, key generation |
/v2/entra/config/<audience> |
GET | MCP Entra JWT validation |
9. Testing Strategy
Each package ships a Vitest suite (*.test.ts), run via pnpm test (or pnpm -r run test at the root).
| Package | Test focus |
|---|---|
cli |
auth utils/commands, installer, remove, setup, skill-list, update-check, upgrade |
mcp |
JWT validation, certificate handling |
sdk |
client constructor, searchLibrary/getContext (live API), error handling, type inference |
tools-ai-sdk |
tool structure, multi-step flows via Amazon Bedrock, Context7Agent behavior |
pi |
extension registration |
Note
SDK and AI-SDK tests hit the live Context7 API and a live model (Bedrock), so they need
CONTEXT7_API_KEYand AWS credentials. They are integration tests, not hermetic unit tests — keep that in mind in CI.
Lint/format is ESLint (flat config) + Prettier, enforced per package (lint:check, format:check).
10. Code Patterns & Conventions
- ES modules throughout,
.jsimport specifiers in TypeScript (NodeNext resolution). - Per-package path aliases (
@commands,@http,@tools,@agents,@prompts) resolved bytsup/vitest. - Fail-open infrastructure: Redis, telemetry, and update checks never block the primary operation.
- LLM-robustness hook: the MCP server rewrites hallucinated tool-argument names (
userQuery→query,libraryID/context7CompatibleLibraryID→libraryId) before Zod validation, so minor model deviations don't fail tool calls. - Shared-by-copy: pi mirrors MCP's client/format/types verbatim (documented in file headers) rather than depending on the MCP package.
- Changesets for versioning and publishing; each package is versioned independently.
11. Potential Improvements & Tech Debt
These are observable from the source and the issue tracker — actionable items for maintainers:
ctx7 skillsdeprecation. The Skill Hub command tree (install/search/info/suggest) is marked for removal (TODO(deprecate-skills-phase-2)), with deprecation warnings already live. Plan the phase-2 deletion and migrate users tosetup+generate.- XDG compliance. Config currently lives in
~/.context7/(credentials.json,cli-state.json). Issue #2638 requests XDG-base-directory support. - Credential storage. Tokens sit in a
0600JSON file. Issue #2639 requests OS keyring storage with JSON fallback. - Insecure default encryption key.
CLIENT_IP_ENCRYPTION_KEYships with a placeholder default; consider failing fast (or warning loudly) when the default is detected in HTTP mode. - Remote-login UX. The fixed
localhost:52417callback breaks headless/SSH logins (issues #2242, #2693). A device-code flow would remove the need for port-forwarding. - Monorepo dependency discovery.
ctx7 skills suggestmisses subpackage deps in pnpm monorepos (issue #1860) —detectProjectDependenciesonly reads the CWD's manifest. - pi/MCP drift risk. The copy-paste alignment between
packages/pi/libandpackages/mcp/src/libis enforced only by comments; a shared internal package would prevent silent divergence.
12. Quick Reference
Run the server
# stdio (local agent)
npx @upstash/context7-mcp --api-key ctx7sk-...
# HTTP (self-hosted), Redis required
UPSTASH_REDIS_REST_URL=... UPSTASH_REDIS_REST_TOKEN=... \
node packages/mcp/dist/index.js --transport http --port 3000
Build & test
pnpm install
pnpm -r run build
pnpm -r run test
pnpm --filter @upstash/context7-mcp build # single package
Health check
curl -s http://localhost:8080/ping
# {"status":"ok","message":"pong"}
Minimum HTTP-server env
| Variable | Required | Notes |
|---|---|---|
UPSTASH_REDIS_REST_URL |
yes | Sessions throw without it |
UPSTASH_REDIS_REST_TOKEN |
yes | — |
CLIENT_IP_ENCRYPTION_KEY |
strongly | 64 hex chars; default is insecure |
CONTEXT7_API_URL |
no | Defaults to hosted backend |
Further reading
- Developer Guide — run Context7 MCP locally
- API Reference — REST API documentation
- All Clients — 30+ MCP client recipes
- The User Guide — end-user CLI, setup, and library usage