Two-layer structure: Sources (raw notes) + Wiki (compile output) Four domains: Dev (40), Venture (3), Homelab (23), Reference (0) Includes CLAUDE.md spec, index pages at all levels, compile log Co-Authored-By: Lovebug <lovebug@herbylab.dev>
5.3 KiB
5.3 KiB
| created | path | project | status | tags | type | updated | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-05-06 | Sources/Homelab | homelab-mcp-server | active |
|
session-notes | 2026-05-06 |
Homelab MCP Server Stand-Up
First successful end-to-end deployment of the homelab MCP server. This very note is the inaugural write through the new pipeline — vault saved via save_vault_note instead of email-to-n8n.
Outcome
Working remote MCP connector reachable from Claude (web and mobile), authenticated via Authentik OAuth, fronted by Cloudflare Tunnel. Four Phase 1 tools live: get_vault_schema, list_vault_projects, get_vault_project, save_vault_note.
What got built
Lovebug had the stack scaffolded before the session started — Python MCP server (FastMCP, Streamable HTTP), Authentik docker stack, cloudflared placeholder in compose, schema/git-writer modules. This session was the configuration and wiring pass.
- Authentik admin account + OAuth2 provider + application created via the wizard
- Cloudflare tunnel
homelab-mcpwith two public hostnames:mcp.herbylab.dev→homelab-mcp:8080,auth.herbylab.dev→authentik-server:9000 - All containers on the auto-created default Docker network; cloudflared reaches services by container name, not localhost
.envpopulated with public Authentik URLs for issuer/JWKS- Connector registered on claude.ai with OAuth client ID/secret from Authentik
Issues hit and resolved
- Wrong tab in Cloudflare ZT dashboard. Started in "Private Network" (which is the WARP-only feature) instead of "Public Hostname" / "Published applications." Cleared up by going into the tunnel detail page directly and using the right tab.
- 502 from initial curl. Cloudflare tunnel URLs were set to
localhost:8080andlocalhost:9000, but cloudflared runs as its own container with no host networking. Fix: change tunnel URLs to use container names (homelab-mcp:8080,authentik-server:9000) since all services share the default compose network. - Authentik external URL "problem" was a non-problem. Authentik 2025.4 derives its issuer URL from the request Host header automatically. No brand setting change needed; the discovery URL through
auth.herbylab.devreturned the correct public issuer immediately. - Missing OAuth Protected Resource Metadata. Claude expects
/.well-known/oauth-protected-resourceper RFC 9728. Initial server only served/.well-known/oauth-authorization-server. Lovebug added the protected-resource document. - Invalid Host header rejection. FastMCP's transport security check defaulted to localhost-only and was rejecting
mcp.herbylab.devwith 421. Lovebug addedmcp.herbylab.devto the allowed hosts list. list_vault_projectserrors on directories ending in.md. First test surfaced a bug — tool assumes every*.mdmatch is a file andos.open()s it. Real vault has at least one folder namedpbs-membership-loe1-phase3.md. Needsos.path.isfilefilter. Open for Lovebug.
Architecture decisions worth recording
- Streamable HTTP transport, not SSE. SSE deprecation is in motion; built on the durable transport.
- Single MCP server, organized by domain modules internally. Multiple servers were considered for trust scoping (vault read/write vs server-side execution). Decided trust separation lives between MCP and Dispatch instead — MCP for knowledge/state, Dispatch for execution. Code structured by domain so future split is mechanical, not a rewrite.
- n8n stops being the front door but stays the integration hub. Server writes vault directly + commits + pushes; n8n becomes downstream consumer for fan-out (tasks, Drive mirroring) when those tools come online.
- Read-only-from-Travis enforcement by absence. No edit/delete tools exist. Eliminates the concurrent-write problem class entirely. Vault repo on dev server, tower opens a local clone that pulls.
- TLS terminates at Cloudflare's edge. Internal cloudflared → service traffic stays HTTP since both are on the same host network. Standard tunnel pattern; no internal TLS plumbing needed.
Schema additions Lovebug shipped beyond the spec
domainstaxonomy (Dev / Content / Homelab / Reference) layered above folder pathsknowledge_sourcespopulated for all three (vault, openbrain, llm_wiki) — placeholder design held upfrontmatter_templateswith required-field declarations and concrete examples per note type
What's next
- Save the project plan as a separate
project-plannote (use the draft from the design session) - Fix
list_vault_projectsdirectory bug - Retire the email-to-n8n trigger once a few real notes have flowed through
- Phase 2 catalog: search tools, generic task tools (n8n routes), cross-system glue, memory/OpenBrain integration when workflow patterns establish
Key learnings
- Most "missing UI option" Authentik problems are version drift; check the discovery URL through the public domain first before hunting settings.
- For tunnels:
cloudflaredcontainer'slocalhostis the container, not the host. Use container names when all services share a compose network. - OAuth metadata for MCP requires both RFC 8414 (Authorization Server) and RFC 9728 (Protected Resource). Many implementations only ship the first.
- "Failed" tool calls are still a successful end-to-end test — every layer below the failure had to work to surface the bug.