3.6 KiB
webfetch-mcpo-docker
A single Docker image exposing webfetch-mcp's
web_search and web_fetch tools over HTTP/OpenAPI, via mcpo.
webfetch-mcp is a stdio-only MCP server; mcpo exposes a wrapped MCP server over
HTTP by spawning it as a local child process. Since that spawn happens in-process
(not over the network) and webfetch-mcp has no HTTP/SSE mode of its own, both have
to live in one image — that's what this repo builds.
Build
docker build -t webfetch-mcpo-docker .
Run
docker run -p 8000:8000 \
-e MCPO_API_KEY=some-secret \
-e SEARXNG_BASE=http://searxng.example.internal:8080 \
webfetch-mcpo-docker
Interactive API docs: http://localhost:8000/docs (and /openapi.json). These are
served without authentication even when MCPO_API_KEY is set — only the generated
tool endpoints (/web_search, /web_fetch) require it, as
Authorization: Bearer <MCPO_API_KEY>.
Environment variables
| Variable | Effect |
|---|---|
MCPO_API_KEY |
If set, tool endpoints require Authorization: Bearer <value>. If unset, mcpo serves unauthenticated (its own default behavior). |
MCPO_PORT |
Port mcpo listens on inside the container. Default 8000. |
SEARXNG_BASE |
Passed through to webfetch-mcp; its own default (http://localhost:8080) applies if unset. |
DEBUG |
Passed through to webfetch-mcp. "true" enables debug logging. |
DETAILED_LOG |
Passed through to webfetch-mcp. Defaults on; set to "false" to disable its detailed log file. |
No explicit plumbing is needed to get these into webfetch-mcp: mcpo builds the
spawned child process's environment as the union of its own process environment and
any per-server overrides, so anything set on the container's environment is
inherited by the node server.mjs child automatically. (Verified against mcpo's
MCPConnectionManager source, not assumed.)
Known characteristics
- No URL filtering / SSRF protection.
webfetch-mcp'sweb_fetchtool fetches whatever URL it's given, including private/internal addresses. This is a known, accepted characteristic ofwebfetch-mcpitself — out of scope for this image to fix. - No TLS termination. This image serves plain HTTP; put a reverse proxy or firewall in front of it if you need TLS or network restriction.
webfetch-mcpwrites a detailed log file next toserver.mjsinside the image by default (DETAILED_LOGdefaults on). That directory needs to stay writable at runtime — don't run this image with a read-only root filesystem without accounting for that (e.g. a volume mount, or setDETAILED_LOG=false).
Pinned revisions
webfetch-mcp: pinned viaARG WEBFETCH_MCP_COMMITin theDockerfile, vendored from the Gitea mirror athttps://code.aneur.in/mirrors/webfetch-mcp, not upstream GitHub.mcpo: pinned viaARG MCPO_VERSIONin theDockerfile, installed from PyPI.
Bump either by updating the corresponding ARG default in the Dockerfile. When
bumping mcpo, double check its CLI flags still match what entrypoint.sh assumes
(--host, --port, --api-key, --).
CI
.gitea/workflows/docker-build.yml builds and pushes
code.aneur.in/cloud/webfetch-mcpo-docker:latest on every push to main. It
authenticates using the repo secrets PACKAGE_REGISTRY_USER and
PACKAGE_REGISTRY_TOKEN — the default Gitea Actions token doesn't have
package-registry write permission on this instance, so these must be created
manually under repo Settings → Actions → Secrets, backed by a personal access token
with package-write scope.