n8n running as a container is a decent stand-in for "how would a real automation platform actually call this stuff". Everything up to now has been me calling things directly. Two integrations, same workflow: Ollama first, since it's simpler, then the MCP tool from Entry 08.
Ollama went cleanly. Container running, one HTTP Request node pointed at http://host.docker.internal:11434/api/generate — host.docker.internal matters here specifically, it's how a container reaches something running on the host machine itself, not localhost, which inside the container just points back at the container. Real response came back, done: true, no drama.
Except for the response itself, which is worth keeping verbatim: "To check the status of a Pod in Kubernetes using oc, you can use the kubectl command-line tool." Asked about oc. Answered with kubectl, immediately, in the same sentence that acknowledged the question was about oc. Same unconstrained-model bias from Entries 03 and 10, just a cleaner, funnier example of it this time — the model contradicts itself in one breath.
MCP was the actual project. I'd built the Entry 08 server over stdio — the transport where a client spawns your script as a subprocess and talks to it over stdin/stdout. n8n has a community node, n8n-nodes-mcp, that supports exactly that. Installed it, configured a credential, tried to execute:
Failed to execute operation: The file or directory does not exist
Worth stopping on this one rather than just patching around it, because the real cause is bigger than a wrong path. n8n runs inside its own container — a completely separate filesystem from the Mac. Pointing the STDIO credential at ~/mcp-env/bin/python3 was asking the container to find a file that, from its perspective, doesn't exist anywhere. And even mounting that path in wouldn't have actually fixed it: that venv's python3 is a macOS binary, and the n8n container runs Linux. A Linux container can't execute a macOS binary no matter where you mount it — that's not a path problem, that's a "these two things are architecturally incompatible" problem.
So: switched the server from stdio to SSE — a real network transport instead of a spawned subprocess — which sidesteps the whole cross-filesystem, cross-OS mess entirely. The container doesn't need to touch anything on the Mac's disk; it just makes a network request to a server the Mac is already running.
First attempt at that:
mcp.run(transport="sse", host="0.0.0.0", port=8090)
TypeError: FastMCP.run() got an unexpected keyword argument 'host'
Turns out host and port belong on the FastMCP() constructor in this SDK version, not on .run() — an easy mistake given how many things about this exact package have already moved around mid-series (the FastMCP → MCPServer rename from Entry 08 wasn't even the last surprise it had). Fixed, confirmed the server actually starts:
Uvicorn running on http://0.0.0.0:8090
Didn't assume the SSE path was /sse — checked directly instead:
curl -N http://localhost:8090/sse
event: endpoint
data: /messages/?session_id=f2000338ea514f89bcd2c695d56f49f7
: ping - 2026-09-28 20:28:31.952790+00:00
Real session, real pings. Confirmed.
Then n8n's side: Failed to execute operation: The service refused the connection. One more thing worth checking before assuming it was a config typo — this machine only has Podman installed, not Docker Desktop, even though the docker command works (Podman provides Docker-API compatibility). Whether host.docker.internal resolves the same way under Podman wasn't something I wanted to guess at, so tested it directly from inside the container:
podman exec -it n8n node -e "require('http').get('http://host.docker.internal:8090/sse', r => console.log('status:', r.statusCode))"
status: 200
It actually worked fine — Podman handles that hostname the same way Docker does here. So the earlier "connection refused" was something else, most likely a typo or leftover default in the node's endpoint field rather than a real networking gap. Fixed the field, re-ran.
Real result:
type: text
text: [02-oc-cli-mentor-system-prompt.md] (distance: 437.7) ...
437.7 — the exact same distance Claude Code got for this same query back in Entry 08. Different client, different transport, same underlying Chroma store, same number. That's about as clean a confirmation as this series has produced that the whole thing is actually wired together correctly, not just superficially working.
One correction on my own assumption before closing this out: I'd been telling myself we needed to switch to n8n's separate, official MCP Client Tool node once stdio was ruled out. Turned out unnecessary — the same community node that failed on STDIO also supports an SSE credential type directly. Same node, just a different saved credential, confirmed by opening the credential's own configuration panel directly rather than assuming from the node's label:
Looking back at the whole thing: none of the individual failures here were exotic. A wrong path, a renamed API, an untested assumption about hostname resolution, a mislabeled credential. What made this entry different from something like Entry 08 is that every layer — the model, the container runtime, the SDK, the automation tool — was a separate thing that could be individually right and still add up to a broken chain. Wiring four systems together doesn't multiply the failure points, it compounds them: each fix had to survive contact with the next layer before I actually knew it worked.
The one number that made all of it worth doing was that 437.7. Not because it's a good number — it's just a distance — but because it was the same 437.7 Claude Code got back in Entry 08, through a completely different path. That's the actual proof this series has been chasing since the RAG entries started: the same underlying system, reachable correctly from more than one direction, giving the same answer either way. Everything else in this entry was just the cost of getting there.



Top comments (0)