BoundBench

Context7

Upstash's MCP server that serves up-to-date, community-indexed library documentation into coding agents' context.

github.com/upstash/context7 › packages/mcp · 2026-10-04 · bfa02ea

Defense-in-depth score

6.5 / 10

Moderate

Context7's MCP server is a small, read-only surface: two documentation lookups against one fixed API, no code execution, no files, no memory, no plugins. The dominant risk is what it delivers: community-contributed documentation goes into your agent's context as plain text with no provenance or untrusted marking, alongside tool descriptions that themselves direct the model, so any prompt injection in an indexed library reaches an agent that may hold far more powerful tools. It also forwards your API key or OAuth token to the Context7 backend without validating most tokens itself, and it keeps no per-call record of what was asked.

Key gaps (1)

  1. The server forwards the client's API key or JWT unchanged to the Context7 API (MCP token passthrough), validating tokens only on the /mcp/oauth route; token validation there is not a strict boundary. C1 · Identity & least privilege

Criteria

C1 Identity & least privilege

Minimal 0.25 / 1.00

The server holds no broad credential of its own: each request carries the user's own Context7 API key (or OAuth token), and the server only ever uses it for two read-only lookups against the Context7 API, so one user's request cannot act as another user. But the server does not validate most tokens itself: on the default /mcp endpoint any key or token is forwarded unchecked to the backend, and token validation on the protected endpoint is not a strict boundary. Forwarding the client's token downstream is the MCP 'token passthrough' pattern, which caps this criterion.

C2 Approval gates

Hardened 1.00 / 1.00

The server exposes exactly two tools, both pure lookups against the Context7 documentation API, and both carry accurate read-only, non-destructive annotations. Neither tool can change state anywhere: the only upstream calls are two HTTP GETs to a fixed host. There is nothing consequential for a host to approve, and the tool set is hard-coded with no way to add tools at runtime.

C3 Tool & action scoping

Strong 0.75 / 1.00

The tools are narrow by design: instead of a generic HTTP fetch, each builds a request to one fixed Context7 endpoint, with the model's arguments placed into encoded query parameters, so the model cannot choose the host or the path. Arguments are only typed as strings, though: there is no length limit and no format check on the library ID, and the server does not cap how much documentation it returns.

C4 Code-execution isolation

N/A · full credit 1.00 / 1.00

The server never interprets model text as code: there is no shell, subprocess, eval, or dynamic code loading anywhere in the MCP package. Arguments only become URL query parameters on a lookup request.

C5 Untrusted input blast radius

Minimal 0.10 / 1.00

The server's job is to put third-party, community-contributed documentation into the model's context, and it does so as plain text with no provenance marker or untrusted flag that the host could act on. Its own tool descriptions and server instructions also contain directives to the model ('You MUST call this function', 'Use even when you think you know the answer'), so content and instructions are mixed. The server itself cannot take actions, which limits what a hijack can do through it, but every query the model writes is sent to Context7 and there is no no-egress mode.

C6 Memory, context & configuration integrity

N/A · full credit 1.00 / 1.00

The MCP server is stateless: it keeps no memory, writes no files, and loads no workspace instruction or config files. Only operator-scope environment variables configure it. (The Context7 documentation index is a shared, community-written store, but it lives in the private backend and is reached here only as untrusted input, scored under C5.)

C7 Third-party extensions

N/A · full credit 1.00 / 1.00

The server loads no third-party code at runtime: no plugins, no MCP sub-servers, no package installs. Its only dynamic imports load its own telemetry modules.

C8 Secrets & sensitive-data protection

Minimal 0.42 / 1.00

API keys arrive per request (HTTP) or from an environment variable or command-line flag (stdio) and are kept in memory only. They are never echoed back into tool results, and the telemetry records only tool names and outcomes, never arguments or headers. There is, however, no redaction layer: secrets stay out of logs only because no code path happens to log them, not every error path keeps secrets out of its output, and the keys themselves are long-lived.

C9 Audit & traceability

Minimal 0.30 / 1.00

In the shipped configuration the server keeps no per-call record of what it was asked: only errors are printed to stderr, and aggregate metrics count calls by tool and outcome. OpenTelemetry spans exist but go nowhere unless the operator installs an exporter, and even then they hold the tool name and outcome, not the arguments or who asked.

C10 Limits & kill switch

Moderate 0.63 / 1.00

Each upstream lookup has a hard 60-second timeout, OAuth metadata fetches have 10 seconds, SSE keep-alives and notification subscriptions are disabled, and shutdown is bounded. The server itself has no rate limit, no concurrency cap and no output size limit (quotas are enforced by the private backend), and a client's cancellation of a tool call does not abort the in-flight upstream request.