-
Release v0.1.1 Stable
released this
2026-05-29 14:09:46 -06:00 | 0 commits to main since this releasev0.1.1
code.nochebuena.dev/einherjar/mcpPatch release. Two changes to
cmd/servermake the binary cleaner to run
behind a unix socket on a reverse-proxied host, plus two repository-hygiene
changes that follow from the same deployment exercise.
Changes
cmd/server-
Systemd socket activation. The binary now inherits the listener from
systemd'sLISTEN_FDSprotocol via
github.com/coreos/go-systemd/v22/activation
when present, falling back transparently to TCP-addrbinding when not.
The startup log records"mode":"socket-activated"or"mode":"tcp"so
operators can confirm which path is live. Same binary, same flags, both
modes — no env var or flag toggles behaviour. -
Health probe moves under
<path>/healthz. The handler is now
registered relative to the-pathflag. With the default-path /mcp,
the probe URL becomes/mcp/healthz. The legacy root-level/healthz
route is no longer registered. This lets a reverse proxy expose the entire
MCP service through one location prefix instead of needing a second
forward for the probe.
Docs
- Deployment section in
README.mdrewritten to be hosting-agnostic.
The v0.1.0 draft prescribed a specific systemd layout; the new text
points at theDockerfileand at systemd socket activation as a supported
binary mode without dictating one operator's setup. Adds an explicit note
that any reverse proxy must disable response buffering on the/mcp
location (streamable MCP delivers tool results via Server-Sent Events;
default nginx, Envoy, or Caddy buffering breaks the stream).
Repository hygiene
/deploy/is now.gitignored. Local deployment artefacts (systemd
units, reverse-proxy templates, per-release scripts) are operator-specific
by design and live outside the public repository. TheDockerfileat the
module root remains the only portable, public-facing build artefact.
Upgrade Notes
If you… Action Consume the MCP service from an MCP client (Claude, Cursor, Zed, etc.) None — the /mcpendpoint is unchanged.Monitor the service via the healthz probe Update the probe URL from /healthzto/mcp/healthz(or<your -path>/healthzif you have customised the path).Run the binary directly (no reverse proxy) None — the legacy -addrflag still binds a TCP listener; activation only kicks in when systemd has passed a listener.Run the binary under systemd with a socket unit The same binary now inherits the systemd listener automatically; no recompile, no flags.
API
No tool surface, no validation rules, no index schema, and no behaviour of
the indexer changed. The 10 tools and 8 validation rules listed in
v0.1.0's release notes remain the public surface. The only
externally-visible URL change is the move of/healthzto
<path>/healthz.
Install
go install code.nochebuena.dev/einherjar/mcp/cmd/server@v0.1.1
Dependencies
Module Version Status Role github.com/modelcontextprotocol/go-sdkv1.0.0 unchanged from v0.1.0 Official Go MCP SDK — server, streamable-HTTP transport, tool registration github.com/coreos/go-systemd/v22v22.7.0 new in v0.1.1 Inherit listener from systemd via LISTEN_FDS; loaded only bycmd/servergithub.com/google/jsonschema-gov0.3.0 unchanged (indirect) JSON Schema generation for tool input/output validation github.com/yosida95/uritemplate/v3v3.0.2 unchanged (indirect) RFC 6570 URI template support used by the SDK Downloads
-
-
Release v0.1.0 Stable
released this
2026-05-29 12:14:53 -06:00 | 1 commits to main since this releasev0.1.0
code.nochebuena.dev/einherjar/mcp
Architecture Decisions Resolved
Decision Outcome Deployment model — remote HTTP vs MCPB bundle vs local stdio Remote streamable-HTTP — every Einherjar user adds one URL; no per-machine Go install Knowledge model — live filesystem reads at runtime vs build-time index Build-time index — cmd/indexerproduces JSON; server embeds viago:embed; runtime reads nothing from diskSDK / language — TypeScript vs Python (FastMCP) vs Go Go — github.com/modelcontextprotocol/go-sdkv1.0.0; natural for a framework that is GoTool surface — 1-tool-per-action vs search+execute 1-per-action (10 tools) — surface is small enough to enumerate; AI assistants discover everything from tools/listModule dependency on einherjar/* None at compile time — indexer parses framework source on disk; mcp stays outside the framework dependency graph Wiring conventions exposure Synthetic 15th "wire" module — authored in internal/index/builtins/README.md, participates inlist_modules/get_module/get_examplelike a real moduleValidation engine — real Go AST checks vs pattern rules Pattern rules (go/parser + selector-based matchers) — lightweight, no external tooling required at request time Root doc.gopackage comment surfaceFirst-class Module.Docfield — promoted from the empty-nameSubPackageentry and returned byget_modulecompliance_test.go indexing Parsed for var _ Iface = implassertions andTest*function names + doc comments; surfaced viaget_complianceModule dependency edges Captured from each go.mod's require lines (einherjar/* only); returned byget_module.dependsOnauth-jwt.IssueTokenPairparity with micro-libIntentionally not provided by the framework — wirecanonical example shows the application signing access and refresh tokens itself viaSigner.Sign(...)data/index.jsongit handlingCommitted once as a stub via git add -f;.gitignorestrips subsequent indexer regenerations
Tools
Ten tools registered on initialise. Tool descriptions are surfaced via the MCP
tools/listmethod; this section documents the input schemas and structured
output shapes.list_modules// input {} // output { "modules": [{ "name": "core", "importPath": "code.nochebuena.dev/einherjar/core", "purpose": "...", "goVersion": "1.26", "subPackages": ["launcher", "..."] }] }get_module// input { "name": "core", "includeReadme": false } // output { "name": "core", "importPath": "...", "purpose": "...", "doc": "<root doc.go comment>", "goVersion": "1.26", "dependsOn": ["contracts"], "subPackages": [{ "name": "launcher", "importPath": "...", "doc": "..." }], "keySymbols": [{ "kind": "interface", "name": "Launcher", "subPackage": "launcher", "signature": "type Launcher interface { ... }" }], "adrs": [{ "id": "ADR-001", "title": "core module composition" }], "compliance": { "interfaceAssertCount": 7, "testCount": 15 }, "readme": "<markdown, when includeReadme=true>" }search_symbols// input { "query": "Launcher", "limit": 25, "module": "core", "kind": "interface" } // output { "results": [{ "module": "core", "subPackage": "launcher", "kind": "interface", "name": "Launcher", "signature": "...", "doc": "...", "file": "launcher/launcher.go", "line": 18 }], "total": 1 }get_symbol// input { "module": "core", "name": "Launcher", "subPackage": "launcher" } // output { "matches": [{ "module": "core", "subPackage": "launcher", "kind": "interface", "name": "Launcher", "signature": "...", "doc": "...", "file": "...", "line": 0 }] }list_adrs// input { "module": "core" } // output { "adrs": [{ "module": "core", "id": "ADR-001", "title": "core module composition" }] }get_adr// input { "module": "core", "id": "ADR-001" } // output { "module": "core", "id": "ADR-001", "title": "...", "body": "<markdown>" }get_example// input { "module": "wire", "topic": "hook" } // output { "examples": [{ "module": "wire", "subPackage": "", "title": "Feature hook", "language": "go", "code": "<source>" }] }get_compliance// input { "module": "core" } // output { "module": "core", "interfaceAsserts": [{ "module": "core", "interface": "logging.Logger", "impl": "logz.New(logz.Config{})", "file": "compliance_test.go", "line": 27 }], "tests": [{ "module": "core", "name": "TestAtMostOneExportedTypePerFile", "doc": "", "file": "compliance_test.go", "line": 0 }] }get_changelog// input { "module": "core" } // output { "module": "core", "changelog": "<markdown>" }validate_snippet// input { "code": "package wire\n\nimport ..." } // output { "summary": "1 error, 2 warnings, 0 notes", "findings": [{ "ruleId": "launcher.missing-run", "severity": "error", "module": "core", "message": "core/launcher constructed but Run() never called...", "hint": "After lc := launcher.New(logger); lc.Append(...); call ...", "line": 7 }] }Validation rules shipped at v0.1.0
Rule ID Severity Module What it catches launcher.missing-runerror core Launcher constructed without lc.Run()launcher.no-componentswarning core launcher.New()called without any.Append(...)launcher.run-error-discardedwarning core lc.Run()invoked as a statement (return value ignored)logz.direct-env-readwarning core os.Getenv("EINHERJAR_LOG_*")bypassing logz configweb.server-not-appendedinfo web web/server constructed but not added to the launcher wire.hook-bad-signaturewarning wire with<Feature>(...)first param is notlauncher.Launcherwire.hook-outside-beforestartwarning wire repo/service/handler construction or route registration at the top level of a hook (outside lc.BeforeStart)wire.route-specific-after-paramwarning web /users/{id}registered before sibling/users/me(chi shadows the literal route)
Commands
cmd/serverUsage: einherjar-mcp [flags] Flags: -addr string listen address (default ":8080", env EINHERJAR_MCP_ADDR) -path string MCP HTTP path (default "/mcp", env EINHERJAR_MCP_PATH) Endpoints: POST /mcp — streamable-HTTP MCP transport GET /healthz — liveness probe (200 "ok")cmd/indexerUsage: indexer [-out path] <einherjar-repo-root> Flags: -out string output path for the generated index (default "data/index.json") Argument: einherjar-repo-root directory containing sibling Einherjar modules (auth, core, web, …); defaults to ".."
Environment
Variable Default Effect EINHERJAR_MCP_ADDR:8080Listen address for the MCP server EINHERJAR_MCP_PATH/mcpHTTP path served by the streamable-HTTP endpoint
Install
Binary
go install code.nochebuena.dev/einherjar/mcp/cmd/server@v0.1.0 einherjar-mcp -addr :8080 -path /mcpThe installed binary embeds whatever framework index was produced at the moment
the module was built. For an index built against your own checkout, build
locally — see README.md.Container
docker build -f mcp/Dockerfile -t einherjar-mcp:0.1.0 . # from the einherjar repo root docker run --rm -p 8080:8080 einherjar-mcp:0.1.0The image is multi-stage; runtime is
gcr.io/distroless/static-debian12:nonroot.
Dependencies
Module Version Role github.com/modelcontextprotocol/go-sdkv1.0.0 Official Go MCP SDK — server, streamable-HTTP transport, tool registration github.com/google/jsonschema-gov0.3.0 (indirect) JSON Schema generation for tool input/output validation github.com/yosida95/uritemplate/v3v3.0.2 (indirect) RFC 6570 URI template support used by the SDK mcphas no compile-time dependency on anycode.nochebuena.dev/einherjar/*
module. The indexer reads framework source from disk and writes a JSON blob; the
server embeds the blob. This isolation letsmcpindex any version of the
framework without versioning itself in lock-step.Downloads