# Context7 Admin & Developer Guide

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](upstash__context7__UserGuide.md).

> [!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 via `CONTEXT7_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 `resolve` and `query` calls 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/search` and `GET /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/` and `packages/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**.

```bash
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:

```dockerfile
# Build stage compiles @upstash/context7-mcp, production stage runs it
EXPOSE 8080
CMD ["node", "dist/index.js", "--transport", "http", "--port", "8080"]
```

Build and run:

```bash
# 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
```

```text
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 `CMD` overrides 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](https://smithery.ai) as `@upstash/context7-mcp`.

### 4.3 Running from source

```bash
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_URL` and `UPSTASH_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` (and `NODE_EXTRA_CA_CERTS` for custom CAs).
- [ ] Put the server behind TLS via a reverse proxy (the server speaks plain HTTP).
- [ ] Forward client IPs via `X-Forwarded-For` at 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 /mcp` correctly returns `405`).

---

## 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_KEY` has a hard-coded default value in `encryption.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`, scope `profile email`, `response_type=code`.
- A local callback server listens on `127.0.0.1:52417` (`/callback`) with a **5-minute** timeout and validates the `state` parameter to prevent CSRF.
- Tokens are stored in `~/.context7/credentials.json` (directory mode `0700`, file mode `0600`) 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 `404` and the client re-initializes.

### 6.4 Input-safety guards (CLI)

The CLI installs files into agent directories, so it hardens against path traversal:

- `assertSkillNameInRoot` / `isSafeSkillName` reject skill names with `..`, null bytes, or characters outside `[a-zA-Z0-9._-]`, and ensure the resolved path stays directly under the skills root.
- `installSkillFiles` rejects any file whose resolved path escapes the target directory (this is the source of the `… resolves outside the target directory` error fixed for Windows in issue [#2361](https://github.com/upstash/context7/issues/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 `/mcp` access 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 /ping` returns `200` with `{"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 your `CONTEXT7_API_URL`) is required.
- Corporate proxies: set `HTTPS_PROXY`; for TLS interception, set `NODE_EXTRA_CA_CERTS` to your CA bundle path. The API client wires these into an undici `ProxyAgent`/`Agent` at 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 `preAction` hooks handle `--base-url` overrides and the once-a-day upgrade notice.
- `setup/agents.ts` defines each agent's MCP config path/key, rule type, and skill directory. `setup/mcp-writer.ts` reads/merges/writes JSON **and** TOML MCP configs idempotently. `setup/templates.ts` renders the rule and skill content per agent.
- `utils/update-check.ts` polls `registry.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.ts` posts anonymous events to `/api/v2/cli/events` unless `CTX7_TELEMETRY_DISABLED` is set.

### 8.2 SDK internals

- `Context7` wraps an `HttpClient` (`baseUrl=https://context7.com/api`, retry 5×, exponential backoff `exp(n)*50` ms, `cache: no-store`).
- Commands subclass a generic `Command<TResult>`; `SearchLibraryCommand` → `GET v2/libs/search`, `GetContextCommand` → `GET v2/context`. Both support `type: "json" | "txt"`; JSON responses are mapped into `Library[]` / `Documentation[]`, text passes through. Errors throw `Context7Error`.

### 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_KEY` and 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**, `.js` import specifiers in TypeScript (NodeNext resolution).
- **Per-package path aliases** (`@commands`, `@http`, `@tools`, `@agents`, `@prompts`) resolved by `tsup`/`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 skills` deprecation.** 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 to `setup` + `generate`.
- **XDG compliance.** Config currently lives in `~/.context7/` (`credentials.json`, `cli-state.json`). Issue [#2638](https://github.com/upstash/context7/issues/2638) requests XDG-base-directory support.
- **Credential storage.** Tokens sit in a `0600` JSON file. Issue [#2639](https://github.com/upstash/context7/issues/2639) requests OS keyring storage with JSON fallback.
- **Insecure default encryption key.** `CLIENT_IP_ENCRYPTION_KEY` ships with a placeholder default; consider failing fast (or warning loudly) when the default is detected in HTTP mode.
- **Remote-login UX.** The fixed `localhost:52417` callback breaks headless/SSH logins (issues [#2242](https://github.com/upstash/context7/issues/2242), [#2693](https://github.com/upstash/context7/issues/2693)). A device-code flow would remove the need for port-forwarding.
- **Monorepo dependency discovery.** `ctx7 skills suggest` misses subpackage deps in pnpm monorepos (issue [#1860](https://github.com/upstash/context7/issues/1860)) — `detectProjectDependencies` only reads the CWD's manifest.
- **pi/MCP drift risk.** The copy-paste alignment between `packages/pi/lib` and `packages/mcp/src/lib` is enforced only by comments; a shared internal package would prevent silent divergence.

---

## 12. Quick Reference

### Run the server

```bash
# 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

```bash
pnpm install
pnpm -r run build
pnpm -r run test
pnpm --filter @upstash/context7-mcp build   # single package
```

### Health check

```bash
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](https://context7.com/docs/resources/developer) — run Context7 MCP locally
- [API Reference](https://context7.com/docs/api-guide) — REST API documentation
- [All Clients](https://context7.com/docs/resources/all-clients) — 30+ MCP client recipes
- The [User Guide](upstash__context7__UserGuide.md) — end-user CLI, setup, and library usage

---

_Generated June 2026 from upstash/context7 at c436700. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
