Skip to content

feat(images): provide MDN MCP server via managed settings - #153

Merged
gatezh merged 3 commits into
masterfrom
feat/mdn-mcp-server
Sep 23, 2026
Merged

gatezh merged 3 commits into
masterfrom
feat/mdn-mcp-server

Conversation

@gatezh

@gatezh gatezh commented Sep 18, 2026

Copy link
Copy Markdown
Owner

What

Provides Mozilla's MDN MCP server to every Claude Code session in the claude-code and ralphex-fe images, through managedMcpServers in /etc/claude-code/managed-settings.json.

Why

MDN's server serves current web platform documentation and browser compatibility data, so Claude checks the DOM/CSS surface instead of recalling whatever was in its training set. Shipping it from the image means consumers get it with no per-project setup, and existing consumers pick it up through the Renovate rebuild + image-pull channel they already use.

managedMcpServers is the only seam that works here:

  • Not init-plugins.sh — it's a template consumers copy into their own repos, so editing it reaches new consumers only.
  • Not a baked user-scope config — /home/node/.claude is a volume mount, which would shadow it.
  • Not claude mcp add in postCreateCommand — devcontainer.json explicitly warns that claude CLI calls there race the extension's OAuth flow and can corrupt auth state.

Changes

  • claude-code — adds the managedMcpServers key to the existing managed-settings.json (already COPYed for the Playwright SessionStart hook), so no Dockerfile change beyond the comment.
  • ralphex-fe — new managed-settings.json plus mkdir/COPY. It runs as root throughout and drops privileges via gosu, so it needs none of the USER root/USER node guarding claude-code has.
  • Firewall — adds mcp.mdn.mozilla.net to .devcontainer/claude-sandbox/init-firewall.sh, the reference script the claude-code README points consumers at.
  • CI — both workflows assert the URL with the jq … | grep -qx idiom already used for the Playwright hook; build-ralphex-fe.yml gains a paths: trigger for the new file.
  • Docs — an MDN section in both image READMEs.
  • Drive-by — refreshes ralphex-fe's tool table, which had drifted from its Dockerfile across several Renovate bumps (Bun 1.3.9→1.4.2, Hugo 0.156.0→0.166.0, Claude Code 2.1.216→2.1.276, rtk 0.43.0→0.49.0, ralphex 1.6.0→1.7.0).

Notes

  • Requires Claude Code >= 2.1.259; earlier clients ignore the key silently. Both images pin 2.1.276.
  • Privacy — both entries send X-Moz-1st-Party-Data-Opt-Out: 1, Mozilla's documented opt-out from the query logging they do while the server is experimental.
  • Not imposed — claude mcp remove refuses a provided server, but each developer can turn it off for themselves in /mcp under Managed MCPs, or block it via deniedMcpServers.
  • The firewall entry is load-bearing. The sandbox is default-DROP and managed settings are read locally, so without it the server would report configured and healthy while every tool call was silently dropped. Consumers with their own firewall script need the same entry — the README now says so.
  • Experimental upstream. Mozilla may withdraw the server; that surfaces as a connect-failure line at session start, not a broken container.
  • Verified the COPY, resulting file modes (644, dir 755), and both workflows' verify pipelines — including a negative control — against a scratch image. actionlint, shellcheck, and hadolint all clean; hadolint reports the same 11 pre-existing DL3066 infos as master, none new.

Mozilla's MDN MCP server (mcp.mdn.mozilla.net) gives Claude current web
platform docs and browser compatibility data instead of whatever was in
its training set. Ship it from the image so consumers get it without
per-project setup.

managedMcpServers in /etc/claude-code/managed-settings.json is the only
seam that works here. init-plugins.sh is a template consumers copy into
their own repos, so editing it would reach new consumers only; the image
flows to existing ones through the Renovate rebuild + image-pull channel.
A user-scope config baked at build time would be shadowed by the volume
mounted at /home/node/.claude, and a `claude mcp add` in postCreateCommand
would race the extension's OAuth flow, which devcontainer.json warns
against.

claude-code already had the managed settings file for the Playwright
SessionStart hook, so it gains the key only. ralphex-fe gains the file
plus mkdir/COPY; it runs as root throughout and drops privileges via
gosu, so it needs no USER guarding. Managed settings are read at session
start, so ralphex's non-interactive `claude -p` runs get the server too.

Both send X-Moz-1st-Party-Data-Opt-Out: 1, Mozilla's documented opt-out
from the query logging they do while the server is experimental.
Developers can still turn it off per-user in /mcp under Managed MCPs.

The sandbox firewall is default-DROP, and the settings file is read
locally, so without an allowlist entry the server would look configured
and healthy while every tool call was dropped. Adds mcp.mdn.mozilla.net
to the reference firewall script the claude-code README points at.

CI asserts the URL in both images, following the jq | grep -qx idiom
already used for the Playwright hook.

Also refreshes ralphex-fe's tool table, which had drifted from its
Dockerfile across several Renovate bumps (Bun, Hugo, Claude Code, rtk,
ralphex).

Requires Claude Code >= 2.1.259; both images pin 2.1.276.
…fe tools

The previous commit added the MDN assertion only to the publish-time
verify commands in build-claude-code.yml and build-ralphex-fe.yml.
ci.yml runs its own verify at PR time and already carried the sibling
managed-settings assertion for the Playwright hook, so a regression that
dropped managedMcpServers would have gone green on the PR and failed
only after merge. Adds the assertion to all three ci.yml entries.

ralphex-fe's tool table listed wget, which the final image does not
contain — the apt block installs curl but not wget, and the wget calls
live in the alpine download stages. Verified against the published
image. procps in the claude-code table was checked the same way and is
present, so that row stands.
# Conflicts:
#	.github/workflows/build-claude-code.yml
#	.github/workflows/ci.yml
@gatezh
gatezh merged commit a9ed823 into master Sep 23, 2026
12 checks passed
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.

1 participant