HTTP/SSE wrapper around erickt23/joplin-server-mcp so a Joplin Server MCP can be reached over the network by Claude Code, Cursor, etc. — instead of only locally over stdio.
The upstream project ships a stdio MCP server. This image puts it behind:
supergatewayto expose it as streamable HTTP / SSE, andnginxfor bearer-token auth (header or?token=query param), so the endpoint can be safely published behind your reverse proxy.
It also carries two small patches:
- A pydantic
model_validatorinjected into every*Inputmodel that accepts a JSON-encoded string in addition to a parsed dict — FastMCP wraps large tool bodies as strings under supergateway's stdio framing, which the upstream models reject otherwise. - A UTF-8 response-hook patch to
joppy(the Joplin client). Joplin Server's item/contentendpoint returnstext/plainwith no charset, sorequestsmis-decodes the body and silently corrupts non-ASCII note content (mojibake compounds on every get→update). The patch pinsresponse.encoding = "utf-8"for every joppy response. Upstream fix proposed at marph91/joppy#36; once merged the local patch can be dropped.
docker run -d \
-p 8080:8080 \
-e JOPLIN_SERVER_URL=https://your-joplin.example.com \
-e JOPLIN_SERVER_EMAIL=you@example.com \
-e JOPLIN_SERVER_PASSWORD=… \
-e MCP_BEARER_TOKEN=<a long random secret> \
ghcr.io/<your-org>/joplin-mcp:latestThen point your MCP client at https://<host>:8080/, sending Authorization: Bearer <MCP_BEARER_TOKEN>.
docker build -t joplin-mcp .When building in a CI that has a pull-through cache for Docker Hub (e.g. the GitLab dependency proxy), pass --build-arg REGISTRY=<cache-prefix>/ to route python:slim through it.