Expose native MCP endpoint alongside mcpo
Build and push image / build (push) Successful in 3m59s

Run supergateway on port 8080 (streamable HTTP at /mcp) next to mcpo on
8000, each spawning its own webfetch-mcp child. Supervise both under tini.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit was merged in pull request #2.
This commit is contained in:
2026-10-06 17:27:28 +01:00
co-authored by Claude Sonnet 5.5
parent 5e8abfd6ef
commit 291703ecc3
3 changed files with 119 additions and 25 deletions
+45 -12
View File
@@ -1,12 +1,17 @@
# webfetch-mcpo-docker
A single Docker image exposing [`webfetch-mcp`](https://code.aneur.in/mirrors/webfetch-mcp)'s
`web_search` and `web_fetch` tools over HTTP/OpenAPI, via [`mcpo`](https://github.com/open-webui/mcpo).
`web_search` and `web_fetch` tools in two ways at once:
`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.
| Port | Protocol | For |
|---|---|---|
| `8000` | OpenAPI, via [`mcpo`](https://github.com/open-webui/mcpo) | Open WebUI |
| `8080` | Native MCP (streamable HTTP) at `/mcp`, via [`supergateway`](https://github.com/supercorp-ai/supergateway) | Coding agents (opencode etc.) |
`webfetch-mcp` is a stdio-only MCP server with no HTTP mode of its own. `mcpo` and
`supergateway` each expose a wrapped stdio server over HTTP by spawning it as a local
child process, so they have to live in the same image as `webfetch-mcp`. Each spawns
its own `node server.mjs`.
## Build
@@ -17,7 +22,7 @@ docker build -t webfetch-mcpo-docker .
## Run
```sh
docker run -p 8000:8000 \
docker run -p 8000:8000 -p 8080:8080 \
-e MCPO_API_KEY=some-secret \
-e SEARXNG_BASE=http://searxng.example.internal:8080 \
webfetch-mcpo-docker
@@ -28,24 +33,48 @@ served without authentication even when `MCPO_API_KEY` is set — only the gener
tool endpoints (`/web_search`, `/web_fetch`) require it, as
`Authorization: Bearer <MCPO_API_KEY>`.
### opencode (or any MCP client)
In `opencode.json`:
```json
{
"mcp": {
"webfetch": { "type": "remote", "url": "http://<host>:8080/mcp" }
}
}
```
The `:8080` endpoint has no authentication; `MCPO_API_KEY` applies only to `:8000`.
`/healthz` on `:8080` returns `ok`.
## 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`. |
| `MCP_PORT` | Port the native MCP endpoint listens on. Default `8080`. |
| `ENABLE_MCPO` / `ENABLE_MCP` | Set either to `false` to run only the other side. Both default `true`. |
| `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
No explicit plumbing is needed to get these into `webfetch-mcp`: both `mcpo` and
`supergateway` start the child with the container's environment inherited, so
anything set on the container's environment reaches `node server.mjs` automatically. (Verified against `mcpo`'s
`MCPConnectionManager` source, not assumed.)
## Process supervision
`entrypoint.sh` runs both servers under `tini`. If either one exits, the other is
stopped and the container exits non-zero, so the orchestrator restarts the whole
thing rather than leaving it half up.
## Known characteristics
- **The `:8080` endpoint is unauthenticated.** Intended for a trusted LAN only.
- **No URL filtering / SSRF protection.** `webfetch-mcp`'s `web_fetch` tool fetches
whatever URL it's given, including private/internal addresses. This is a known,
accepted characteristic of `webfetch-mcp` itself — out of scope for this image to
@@ -64,9 +93,13 @@ inherited by the `node server.mjs` child automatically. (Verified against `mcpo`
GitHub.
- `mcpo`: pinned via `ARG MCPO_VERSION` in the `Dockerfile`, installed from PyPI.
Bump either by updating the corresponding `ARG` default in the `Dockerfile`. When
- `supergateway`: pinned via `ARG SUPERGATEWAY_VERSION` in the `Dockerfile`, installed
from npm.
Bump any of them 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`, `--`).
(`--host`, `--port`, `--api-key`, `--`); for `supergateway`, `--stdio`,
`--outputTransport`, `--port` and `--healthEndpoint`.
## CI