-
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