Skip to content

Containerize truecopy-mcp for Glama / image-based MCP hosts#72

Merged
askalf merged 1 commit into
masterfrom
docker-mcp-glama
Jul 20, 2026
Merged

Containerize truecopy-mcp for Glama / image-based MCP hosts#72
askalf merged 1 commit into
masterfrom
docker-mcp-glama

Conversation

@askalf

@askalf askalf commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Why

The awesome-mcp-servers listing (punkpeye/awesome-mcp-servers#10332) is gated by Glama's check, which builds an image and sends an MCP introspection (initialize + tools/list). truecopy had no Dockerfile, and a naive one wouldn't pass anyway:

truecopy-mcp is a gate, not a server — it filters a downstream server's tools down to the pinned set. With nothing pinned, every tool is unpinned → dropped, so tools/list comes back empty and the check hollows out.

What

A Dockerfile that wraps the MCP reference server (@modelcontextprotocol/server-everything) and pins its tools at build time:

  • docker/pin-everything.mjs launches the downstream, captures its live tools/list, and emits a truecopy manifest.
  • truecopy add pins those tools into /app/truecopy.lock. Since partsOf and the runtime gate hash tools with the same sha256(canonicalJson(t)), the same server at runtime advertises byte-identical tools → all served as vetted.
  • Both package versions are pinned via ARG for a reproducible image + lock.

This doubles as a live demo of the gate: a real server, passed through untouched, with drift/poison dropped.

Verified locally

$ docker build -t truecopy-mcp .      # ✓ pinned everything ed37632474ad
$ docker run --rm -i truecopy-mcp     # initialize OK -> mcp-servers/everything
                                      # tools/list -> 13 vetted tools

Files

  • Dockerfile, .dockerignore
  • docker/pin-everything.mjs — build-time tool-capture helper
  • README "As a container" note + CHANGELOG entry

🤖 Generated with Claude Code

truecopy-mcp is a gate, not a standalone server: with nothing pinned it
correctly drops every tool, so a bare container introspects an empty
tools/list and fails hosts (e.g. Glama) that require a working server.

Ship a Dockerfile that wraps the MCP reference server
(@modelcontextprotocol/server-everything) and pins its tools at build
time — docker/pin-everything.mjs captures the live tools/list and feeds
it to `truecopy add`, so at runtime the same server advertises
byte-identical tools and the gate serves all 13 as `vetted`. Both
versions are pinned via build args for a reproducible image and lock.

Verified: image builds and `docker run -i` answers initialize +
tools/list with 13 vetted tools over stdio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@sprayberry-reviewer sprayberry-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review from the Sprayberry Labs fleet code reviewer.

Verdict: No blocking issues found — approving.

What I checked

  • gh pr diff 72 in full (5 files: .dockerignore, CHANGELOG.md, Dockerfile, README.md, docker/pin-everything.mjs).
  • Cross-referenced the new Dockerfile/pin-everything.mjs against the existing CLI entrypoints (src/cli.mjs runAdd, src/mcp-cli.mjs) and src/skill.mjs's MCP-manifest loader to confirm the truecopy add everything.json --lock ... / truecopy-mcp --lock ... --name ... -- mcp-server-everything stdio invocations match the real CLI argument parsing.
  • Verified mcp-server-everything's actual bin entry and CLI usage (dist/index.js [stdio|sse|streamableHttp], default stdio) against npm registry metadata for @modelcontextprotocol/server-everything@2026.7.4 — matches the pinned ARG EVERYTHING_VERSION and the stdio arg passed in both the RUN pin step and the ENTRYPOINT.
  • Verified @askalf/truecopy@0.9.0's registry bin map (truecopy, truecopy-mcp) matches what the Dockerfile/README invoke.
  • CI check-rollup: all 9 checks green (CI ×6 matrix jobs, CodeQL ×2, "verify pinned skills" gate) as of the latest commit.

Findings

None blocking. docker/pin-everything.mjs's JSON-RPC handshake (send initialize id:1 → on ack send notifications/initialized + tools/list id:2 → capture result.tools) is correctly ordered, guards non-JSON banner lines, fails closed on an empty/missing tool array, and has a 60s timeout for a hung downstream. The Dockerfile's arg parsing (everything -- mcp-server-everything stdio) is consumed correctly by the script's argv.indexOf('--') split.

Minor (non-blocking): pin-everything.mjs only wires srv.on('error', ...) for a spawn failure (e.g. ENOENT). If the downstream process starts but crashes immediately after (exits without ever writing a tools/list response), the script has no exit/close handler and relies on the 60s timeout to fail closed rather than surfacing the crash immediately. Not a correctness bug — it does still fail closed — just a slower failure mode than necessary for a build-time script.

What's good

  • The Dockerfile and script are well-commented and self-explanatory about why (gate-needs-something-to-gate), which matches the PR description precisely.
  • Version pins (TRUECOPY_VERSION, EVERYTHING_VERSION) verified against the actual published npm versions — reproducible as claimed.
  • .dockerignore correctly scopes the build context to just the one script the image needs, consistent with installing truecopy/server-everything from npm rather than copying the working tree.
  • README/CHANGELOG additions accurately describe the new container path and don't overstate what it does.

@askalf
askalf merged commit 84120a6 into master Jul 20, 2026
9 checks passed
@askalf
askalf deleted the docker-mcp-glama branch July 20, 2026 02:15
askalf added a commit that referenced this pull request Jul 20, 2026
…context — scope it to the MCP image (#76)

* ci(fuzz): scope the docker ignore to the MCP image — root .dockerignore blanked ClusterFuzzLite's build context

* ci(fuzz): drop root .dockerignore (moved to Dockerfile.dockerignore)
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.

2 participants