Files
mcp/CLA.md

91 lines
4.7 KiB
Markdown
Raw Normal View History

feat(mcp): initial implementation — MCP server, framework indexer, 10 tools, 8 validation rules (v0.1.0) Introduces code.nochebuena.dev/einherjar/mcp — the Einherjar Model Context Protocol server. A remote, streamable-HTTP service that teaches AI assistants about every other module of the framework: which package exposes which type, what each module guarantees through its compliance tests, the canonical wiring shape for a service, and whether a Go snippet follows the conventions. Indexes the framework on disk at build time and ships a self-contained binary via go:embed; imports nothing from other einherjar/* modules at compile time. server (cmd/server): - Streamable-HTTP MCP server built on github.com/modelcontextprotocol/go-sdk v1.0.0 - mcp.NewServer + mcp.NewStreamableHTTPHandler, served via net/http on EINHERJAR_MCP_ADDR (default :8080) and EINHERJAR_MCP_PATH (default /mcp) - /healthz liveness endpoint; structured JSON logging via log/slog - Loads the embedded data/index.json once at startup; in-memory for the process lifetime indexer (cmd/indexer): - Walks an Einherjar repository checkout (default ../), parses every sibling module's go.mod, README.md, CHANGELOG.md, docs/adr/ADR-*.md, doc.go package comments, every exported type/interface/func/method/const/var (via go/doc on go/parser ASTs), and compliance_test.go - Captures module dependency edges by regex over each go.mod's require lines (einherjar/* paths only; self-reference filtered) - Appends a synthetic "wire" module documenting canonical application wiring conventions, authored at internal/index/builtins/README.md and embedded via go:embed; participates in list_modules / get_module / get_example like a real module internal/index: - Schema einherjar.mcp/index/v1; types: Index, Module, SubPackage, Symbol, ADR, Example, Compliance, InterfaceAssert, ComplianceTest - Build(repoRoot) → *Index walks the repo; BuildBuiltins() returns the synthetic wire module from the embedded markdown - Load([]byte) → *Index validates the schema version on read - FindModule, SearchSymbols helpers used by tools internal/tools (10 tools): - list_modules — enumerate every module with purpose + sub-packages - get_module — package doc, dependencies, sub-packages, key symbols, ADRs, compliance counts; optional embedded README - search_symbols — full-text across name, doc, sub-package, module; filterable by module and kind - get_symbol — full signature, doc comment, source file:line for one symbol - list_adrs — list ADRs across the framework or within one module - get_adr — fetch one ADR's markdown body - get_example — canonical usage snippets extracted from module READMEs and from the synthetic wire conventions - get_compliance — interface assertions (var _ Iface = impl) and structural test names from a module's compliance_test.go - get_changelog — full CHANGELOG.md markdown for one module - validate_snippet — pattern-match a Go snippet against framework conventions internal/rules (8 rules, registered via init() against a single registered slice): - launcher.missing-run — launcher constructed but Run() never called - launcher.no-components — launcher.New() called without any .Append(...) - launcher.run-error-discarded — lc.Run() invoked as an ExprStmt (return ignored) - logz.direct-env-read — os.Getenv("EINHERJAR_LOG_*") bypassing logz config - web.server-not-appended — web/server constructed but not added to the launcher - wire.hook-bad-signature — with<Feature>(...) first param is not launcher.Launcher - wire.hook-outside-beforestart — repo/service/handler construction or route registration at the top level of a hook (outside lc.BeforeStart) - wire.route-specific-after-param — /users/{id} registered before a sibling /users/me of the same length and method (chi would shadow the literal route) Synthetic wire module (internal/index/builtins/README.md): - Project layout (cmd/<app>/main.go + internal/wire/*.go + per-feature domain dirs) - Canonical Run() shape: config → logger → infra (db, cache, pool, mc, srv) → cross- cutting (validator, permission provider) → launcher.New → lc.Append(infra...) → withMigrations / withSuperAdminSeed / withHealth / withFeature hooks → return lc.Run() - Canonical with<Feature> hook shape: signature (launcher.Launcher first, server.Server second, deps last), single lc.BeforeStart closure containing all construction + route registration - chi route ordering, srv.With(authz(...)) authorization, middleware helpers (authz / skipPublicPaths / skipMethodPath), tokenSignerAdapter pattern showing that the framework exposes Signer.Sign as a primitive and the application owns the access/refresh response shape Packaging: - Multi-stage Dockerfile that builds from the einherjar repository root (docker build -f mcp/Dockerfile .) so cmd/indexer can walk every sibling module at image-build time; runtime layer is gcr.io/distroless/static-debian12:nonroot - 86-byte placeholder data/index.json committed once with `git add -f`; subsequent indexer runs overwrite it locally but the file is .gitignored - .gitea/CODEOWNERS and pull_request_template.md mirror the sibling layout Design notes: - mcp depends on nothing in einherjar/* — it reads the framework via the filesystem at index time. This keeps mcp outside the framework dependency graph and lets it index any version of einherjar without versioning itself in lock-step. - All structured-output tool responses initialise empty slices ([]Type{}) rather than relying on Go's nil-marshals-to-null default, so the SDK's JSON-schema output validator never rejects a tools/call result.
2026-05-29 18:12:45 +00:00
# Contributor License Agreement
By contributing to any Einherjar repository, you agree to the terms of this Contributor License Agreement ("Agreement"). Please read it carefully before submitting your first Pull Request.
---
## 1. Definitions
| Term | Meaning |
|---|---|
| **You** | The individual or legal entity submitting a Contribution |
| **Contribution** | Any original work — source code, documentation, tests, configuration — submitted to an Einherjar repository |
| **Project** | The Einherjar framework and all repositories under `code.nochebuena.dev/einherjar/` |
| **Maintainers** | The individuals responsible for maintaining the Project |
---
## 2. You Retain Ownership
This Agreement does **not** transfer your copyright to the Maintainers. You remain the legal owner of your Contribution. What you grant here is a broad license to use it — not ownership of it.
---
## 3. Copyright License Grant
You grant the Maintainers and all recipients of the Project a **perpetual, worldwide, non-exclusive, royalty-free, irrevocable** license to:
- Reproduce, modify, and create derivative works of your Contribution
- Publicly display and perform your Contribution
- Distribute your Contribution and derivative works, in source or compiled form, under any terms
- Sublicense the above rights to third parties
- **Relicense** your Contribution under a different open-source or commercial license at the Maintainers' sole discretion
The Maintainers commit to keeping the Project available under at least one OSI-approved open-source license at all times.
---
## 4. Patent License Grant
You grant the Maintainers and all recipients of the Project a **perpetual, worldwide, non-exclusive, royalty-free, irrevocable** patent license to make, use, sell, offer for sale, import, and distribute your Contribution — limited to patent claims you own or control that are necessarily infringed by your Contribution alone, or in combination with the Project to which you submitted it.
---
## 5. Your Representations
By submitting a Contribution, you confirm that:
1. **Original work.** The Contribution is your original work, or you have the legal right to submit it under these terms.
2. **No infringement.** To your knowledge, the Contribution does not infringe any third-party intellectual property rights, including patents, copyrights, and trade secrets.
3. **Employer rights.** If your employer holds rights over intellectual property you create, you have obtained written permission to submit the Contribution on behalf of that employer, or your employer has explicitly waived such rights for contributions to open-source projects.
4. **No warranty implied.** You understand that your Contribution may or may not be included in the Project, and the Maintainers are under no obligation to use it.
---
## 6. No Support Obligation
You are not required to provide maintenance, support, or updates for your Contributions. They are accepted **"as-is"**, without any warranty of fitness for a particular purpose or correctness.
---
## 7. How to Sign
Consent is given by **posting a comment** on your Pull Request with the following exact text:
```
I have read the Einherjar Contributor License Agreement (CLA.md) and I agree to all its terms.
I confirm this Contribution is my original work. I grant the Maintainers the rights described
therein, including the right to relicense, and I retain ownership of my copyright.
This agreement covers all future Contributions I submit to any Einherjar repository under
this account.
```
**Why a comment and not a checkbox?**
PR description checkboxes can be silently toggled on and off by anyone with write access to the branch at any time. A comment creates a timestamped, author-attributed record in the PR activity log — it cannot be quietly retracted. If a comment is deleted, the deletion itself is visible in the activity log.
No handwritten or electronic signature is required beyond the comment above. A Maintainer will verify the comment before merging. PRs without the comment will not be merged.
If you are contributing on behalf of a company or organization, ensure that an authorized representative of that entity has reviewed and accepted these terms before submitting. The comment must be posted by the account that owns the Contribution.
---
## 8. Governing Terms
This Agreement is intended to be simple and broadly fair. It follows the model established by widely adopted CLAs from the Apache Software Foundation, Google, and MongoDB — granting the Project the flexibility to evolve while fully preserving your ownership of what you wrote.
If any provision of this Agreement is found unenforceable, the remaining provisions continue in full effect.
---
*For those who come after. — The Einherjar Maintainers*