deploy: listmonk-mcp has no HTTP transport, no image and no CI #1
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
waiting-on-julian
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/listmonk-mcp#1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
listmonk-mcpcannot be deployed today. It speaks stdio, there is no image, and CI has never run. Three pieces of work, in order, and then it goes to Clark for Renovate, manifests and ArgoCD.What is actually there
Verified rather than recalled, 2026-08-25:
hatchling,uv.lockpresentmcp1.11.0, usingFastMCPfrommcp.server(the SDK's bundled FastMCP, not the standalonefastmcppackage)src/listmonk_mcp/server.pycallsserver.run()with no argument, which is stdio.github/workflows/publish.yml, inherited fromrhnvrm/listmonk-mcp, publishing to PyPI.actions/taskshastotal_count0: no Forgejo workflow has ever runforge.oddie.app/jlxq0holds caldav, carddav, jmap, m365, matrix and typst. Nolistmonk-mcpmaster, notmain, unlike the rest of the fleetmcp1.11.0 supportstransport="streamable-http". No dependency bump is needed for piece 1.Read this before choosing a base branch
origin/masteris byte-identical toupstream/master. Every change Julian has made to this fork sits unmerged onfeat/comprehensive-api-coverage:1192 insertions across
client.pyandserver.py, dated 2026-05-06 and 2026-05-07, with no pull request open for any of it.So a deployment built on
masterships upstream's server without the thirty tools. Land that branch first, in its own pull request, before building anything on top. That is piece 0 and it is not optional.It also settles the fork question the deployment work has to answer. The fork carries zero divergence from upstream on
mastertoday, and the divergence that exists is unlanded. A streamable-HTTP transport is small and genuinely upstreamable. The thirty tools are a larger conversation. Say in each pull request which of the two it is, rather than letting the fork accumulate carried patches by default.1. Streamable-HTTP transport
A server behind an HTTPRoute has to speak HTTP. stdio cannot be routed.
The deployment contract the other six servers already meet, read out of
caldav-mcp:0.0.0.0:3000, carrying the MCP endpoint at/mcpplus a health endpoint:9090, resolved as explicit env, then{POD_IP}:9090, then127.0.0.1:9090. It must never default to0.0.0.0Match that contract. Do not invent a different one, and do not skip the metrics split because Python makes one listener easier: the reason it is separate is that
/metricsmust not be publicly routable, and that reason does not depend on the language.Keep stdio working. It is how the server is used from a local client today, and removing it to add HTTP trades one deployment for another.
2. Dockerfile
caldav-mcp's is the reference for structure: pinned base by digest, dependencies cached in a layer separate from source, non-root runtime, OCI labels fed byBUILD_VERSION,BUILD_REVISIONandBUILD_CREATEDbuild args. Distroless will not carry a Python runtime, so the runtime stage differs; everything else should not.3. Forgejo Actions workflow
Building and pushing to
forge.oddie.app/jlxq0/listmonk-mcp, viabuildctlagainst the runner's buildkitd, as the other five do.One writer to the buildcache ref, from the first commit. m365-mcp#4 is the whole story: two
dockerjobs exporting to one unqualified:buildcacheref, one losing the blob write, failing a run whose image was already published. Fixed across the other five today. The shape is:Guard the export on the branch ref specifically, not on
!= pull_request. typst-mcp had exactly one export site guarded that way and still had two writers, because that condition is true on a tag push. Follow-up paths that remain open are in m365-mcp#7.How to verify it, given what does not work here
Three things this fleet learned today, each of which will otherwise waste an afternoon:
dockerjob proves nothing about cache behaviour. caldav-mcp tasks16484and16485overlapped, both exporting to one ref, and both passed.:buildcachemanifest digest proves nothing either. The cache manifest is content-addressed, so a full cache hit re-exports identical bytes to an identical digest. jmap-mcp16533exported and left the digest untouched..log.zst.grep -c "exporting cache to registry"returns0when the log is missing, and0is the answer that means "correct".What does work is executing the workflow's own branch logic. Extract the
dockerbuild script from the YAML with PyYAML, run it underrefs/heads/master,refs/tags/v0.2.0,refs/pull/1/headand one other branch, and assert the export-argument count is non-zero only for the first. Then break the guard deliberately and watch it go red before trusting it.Out of scope
Do not create a Listmonk API user or role. That is a change to a service Julian uses and the scope is his decision. Clark established that
campaigns:sendis distinct fromcampaigns:managein Listmonk v6.1.0, so a credential that can draft but not send is a real option. Whichever he picks, it arrives through an ExternalSecret from 1Password, never an env value in a manifest and never a.env.Two things that are no longer true in the description above, recorded rather than quietly skipped.
"CI has never run" and "
actions/taskstotal_count0" are stale. Six tasks have run since, four of them on #3.pythonanddockerwere both green ond7c6c73.Piece 0 is done. #2 merged at
3b80c11, somasternow carries the 41 tools and 1192 lines of divergence fromrhnvrm/listmonk-mcp. #3 is retargeted tomasterand closes this issue.One thing that is true and worth stating before anyone reads a merge as a rollout.
listmonk-mcphas no Kubernetes namespace at all — it is the one MCP server in this fleet not deployed. So a release tag here does not produce a rollout the way it does everywhere else: there is no image inforge.oddie.app/jlxq0to bump, nothing for Renovate to open a PR against, and no ArgoCD Application to sync. Standing that up the first time is infrastructure inoddie-apps/platformand it is Clark's.Merging #3 gives a repository that builds an image. Tagging gives an image in the registry. Neither gives a server answering in production, and the distance between the tag and that is the part this issue does not cover.