Skip to content

feat: official Docker image + optional Redis for HTTP (closes #214)#2840

Closed
enesgules wants to merge 5 commits into
masterfrom
feat/publish-official-docker-image
Closed

feat: official Docker image + optional Redis for HTTP (closes #214)#2840
enesgules wants to merge 5 commits into
masterfrom
feat/publish-official-docker-image

Conversation

@enesgules

@enesgules enesgules commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

What

Publishes an official, always-current Docker image for the Context7 MCP server (#214), and fixes the underlying reason the image couldn't run standalone: the HTTP transport required Upstash Redis.

Changes

Make Redis optional for HTTP (packages/mcp)

  • The HTTP transport previously required UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN and crashed on startup without them — so docker run -p 8080:8080 <image> failed out of the box.
  • Added an in-memory session store and fall back to it when Redis isn't configured. --transport http now runs standalone on a single instance; Redis is still used when set, to share sessions across multiple instances.
  • Session IDs are opaque correlation identifiers (not auth), so in-memory is safe for single-instance use.
  • Added tests for the in-memory store + fallback selection. Minor version bump via changeset.

Publish workflow (.github/workflows/docker-publish.yml)

  • Builds packages/mcp/Dockerfile multi-arch (linux/amd64, linux/arm64) and pushes to ghcr.io/upstash/context7-mcp and upstash/context7-mcp (Docker Hub), tagged latest + version.
  • Triggers automatically on release (tags @upstash/context7-mcp@*) and via manual dispatch.

Dockerfile

  • Split the final command into ENTRYPOINT + CMD so users can append --transport stdio cleanly; default stays HTTP on :8080.

Docs (all-clients.mdx)

  • "Using Docker" now pulls the official image, documents both stdio (clients) and HTTP (self-hosted, Redis optional for multi-instance) usage, and mentions the hardened DHI image as an enterprise option.

Required before Docker Hub publishing works

Add repo Actions secrets DOCKERHUB_USERNAME and DOCKERHUB_TOKEN (push scope) and create upstash/context7-mcp under the official upstash org. GHCR needs no setup.

Verification

  • pnpm typecheck + full test suite (17 tests) pass; new session-store tests pass.
  • Built the image locally and confirmed HTTP starts and responds with no Redis env (in-memory fallback logged, valid initialize response with mcp-session-id), and --transport stdio works.

Closes #214

🤖 Generated with Claude Code

Closes #214.

Adds a `Publish Docker Image` workflow that builds packages/mcp/Dockerfile
(multi-arch: linux/amd64, linux/arm64) and pushes it to both the GitHub
Container Registry (ghcr.io/upstash/context7-mcp) and Docker Hub
(upstash/context7-mcp). It runs automatically on each MCP release
(tags matching `@upstash/context7-mcp@*`) and via manual dispatch, tagging
both `latest` and the released version.

Splits the Dockerfile's final command into ENTRYPOINT + CMD so the default
behaviour is unchanged (HTTP on :8080 when run with no args), but users can
cleanly append `--transport stdio` to run it as a local MCP server.

Updates the "Using Docker" docs to pull the official image instead of
building one, with a note that HTTP mode is for self-hosted deployments and
requires Upstash Redis credentials.

Requires repo secrets DOCKERHUB_USERNAME and DOCKERHUB_TOKEN for the Docker
Hub push (GHCR uses the built-in GITHUB_TOKEN).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mintlify

mintlify Bot commented Jun 29, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
context7 🟢 Ready View Preview Jun 29, 2026, 10:51 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Context7 is also published as a Docker Hardened Image (dhi.io/context7-mcp)
with signed provenance, an SBOM, and near-zero CVEs. Add it to the "Using
Docker" section as a hardened/enterprise option alongside the free public
image. Note that it runs over stdio and requires `docker login dhi.io` and
a Docker Hardened Images subscription.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The HTTP transport previously required UPSTASH_REDIS_REST_URL and
UPSTASH_REDIS_REST_TOKEN and crashed on startup without them, which made the
official Docker image (HTTP by default) unusable out of the box.

Add an in-memory session store and fall back to it when Redis is not
configured, so `--transport http` runs standalone on a single instance.
Redis is still used when configured, for sharing sessions across multiple
instances. Session IDs are opaque correlation identifiers (not auth), so an
in-memory store is safe for single-instance deployments.

Update the Docker docs to show the HTTP run command works without Redis, and
add tests for the in-memory store and the fallback selection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@enesgules enesgules changed the title feat: publish official Docker image for the MCP server (closes #214) feat: official Docker image + optional Redis for HTTP (closes #214) Jun 30, 2026
enesgules and others added 2 commits June 30, 2026 12:44
The in-memory fallback could grow without limit: every initialize mints a
session that lived for the 7-day TTL, so a flood of inits would exhaust the
heap (and the per-create full-map sweep was O(n), degrading to O(n^2) under a
burst).

Cap the store at MAX_MEMORY_SESSIONS (100k) with O(1) oldest-first eviction on
create and lazy expiry on access — no scans. Refresh re-inserts to approximate
LRU so active sessions are evicted last; an evicted live session just gets a
404 and re-initializes. Memory is now bounded to tens of MB regardless of load.

Add tests for eviction and unbounded-flood behaviour; the cap is injectable for
testing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions

Each HTTP request already builds a fresh transport and the server keeps no
per-session state between requests, so the session store's only job was to
404 sessions an instance doesn't recognize. On a single instance there is
nothing to recognize, so tracking sessions in memory bought nothing and only
risked unbounded growth.

Replace the in-memory store with a stateless no-op store for the no-Redis
path: create/delete do nothing and refresh always succeeds, accepting any
session ID. Zero memory growth, no OOM surface. Redis remains required for
multi-instance deployments, where sessions must be shared and validated
across replicas.

Verified end to end: with no Redis, initialize -> tools/list returns both
tools over HTTP (200), including for a never-initialized session ID.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@enesgules

Copy link
Copy Markdown
Collaborator Author

closing, will reopen after MCP v2 release

@enesgules enesgules closed this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish an official docker image

1 participant