docs: record how a plugin's .mcp.json reaches apm, and document the gitea prerequisites
A review of this PR concluded that MCP was not an apm primitive, that the
.mcp.json edit therefore did nothing, and that the declaration belonged in
plugins/gitea/apm.yml under dependencies.mcp. The first half was right about
the primitive and wrong about everything that followed.
MCP is a first-class apm primitive. But the .mcp.json route already reaches
it: apm resolves a plugin manifest in the order plugin.json,
.github/plugin/plugin.json, .claude-plugin/plugin.json, so the generated
Copilot manifest wins, its mcpServers string pointer is followed, and
.mcp.json is injected into the package's dependencies.mcp with ${VAR} env
references intact. Verified against the real remote: a git-sourced install of
plugins/gitea at this branch deploys the gitea server with both references
unexpanded. No code change is needed and none is made here.
Moving the declaration into plugins/gitea/apm.yml would have broken the
build. apm-audit-ci runs apm audit --ci inside every plugins/*/, so a declared
dependency arms lockfile-exists there, which then demands an apm.lock.yaml in
the package plus that package's whole deployed tree inside the package
directory: 93 missing deployed files and 79 drifted paths, measured.
So this commit documents rather than changes:
- AGENTS.md and docs/spec/architecture.md said .mcp.json was plugin-root
material with no .apm/ source, true of .apm/ and read as 'apm has no MCP
concept'. Both now state what .mcp.json is, how it reaches dependencies.mcp,
and that a plugin's own apm.yml is the one place not to declare it.
- architecture.md also records the env-strip: apm pack inlines .mcp.json into
.claude-plugin/plugin.json and its sanitiser drops env and headers blocks
unconditionally, ${VAR} included. Inert under apm, which never reads that
file, but a native Claude Code plugin install reads exactly it and would
start the server with no credentials.
- README.md gains the go toolchain prerequisite and the two environment
variables the server needs, with placeholder values only.
- LESSONS.md records both process failures, including that three scratch
installs inverted the result by using local ./path dependencies, where apm
skips the plugin normalisation that injects .mcp.json.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmiHiknxqtZPEBnW7ujgNz
This commit is contained in:
@@ -15,6 +15,8 @@ This file carries only what applies to **every** session. Setup, prerequisites,
|
||||
|
||||
Not everything in a plugin root is generated. `README.md`, `docs/`, `bin/`, `sources.md`, `.mcp.json` and per-plugin extras are hand-authored there with no `.apm/` source — edit those in place. The rule is per-path, not per-directory. But a file placed *inside* a mirrored directory is deleted on the next sync (`sync_dir` runs `rm -rf` before every copy), so plugin-root documentation goes in `docs/`, never in `hooks/` or `skills/`.
|
||||
|
||||
`.mcp.json` is hand-authored but it is **not** outside apm. MCP is a first-class apm primitive, and a plugin's `.mcp.json` is how this repo declares one: apm reads the `mcpServers` pointer in the generated `.github/plugin/plugin.json`, resolves it to `.mcp.json`, and injects the result into that package's `dependencies.mcp` when a consumer installs it. Declare MCP servers there and **never** in the plugin's own `apm.yml` — that arms a per-package gate this repo cannot satisfy (`LESSONS.md`, 2026-09-12).
|
||||
|
||||
Full model: `docs/spec/architecture.md`.
|
||||
|
||||
## Prefer plugin skills over raw shell
|
||||
|
||||
Reference in New Issue
Block a user