feat: per-target MCP config overrides + plugin-root files - #11
Merged
steve-calvert-glean merged 2 commits intoJul 27, 2026
Merged
Conversation
eshwar-sundar-glean
marked this pull request as ready for review
July 27, 2026 10:52
Two capabilities that let a local MCP-server plugin (e.g. glean-vnext) live as a normal source plugin and be folded into an emitted plugin: 1. Per-target MCP config override — target is threaded through SourceProvider.readMcpServers -> readMcpServers (applies resolveTargetOverride to .mcp.json) -> resolveMcpServers -> targets/engine.ts. So targets/<host>/.mcp.json wins for that host only; the manifest mcpServers form has no per-file override. 2. Plugin-root files — files: record(safeRelativePath, safeRelativePath) on the source-plugin manifest; emitted verbatim at the plugin root in readPluginFiles with target overrides on the source path, tracked as managed output, with collision / unsafe-path / missing-source guards. Rebased onto the 0.8.0 target-registry refactor (src/targets.ts -> src/targets/). npm run test:all green (80 tests: format/lint/typecheck/ build/docs), incl. 4 new tests: per-target MCP override, plugin-root files, collision guard, missing-source guard.
eshwar-sundar-glean
force-pushed
the
eshwar/per-target-mcp-and-plugin-root-files
branch
from
July 27, 2026 10:59
82cc4ca to
444d6fe
Compare
steve-calvert-glean
requested changes
Jul 27, 2026
Comment on lines
+127
to
+131
| // Arbitrary files emitted verbatim at the emitted plugin's root, in addition | ||
| // to its component and static files. Map of destination (plugin-root | ||
| // relative) -> source (source-plugin relative). Supports target overrides: | ||
| // a targets/<host>/<source> file wins for that host. | ||
| files: z.record(safeRelativePath, safeRelativePath).optional(), |
Contributor
There was a problem hiding this comment.
4/5 (serious issue: blocking)
Can we rename this to additionalFiles. Using files is fine, but pretty generic. additionalFiles gives the clear indication that you can add things additionally, and they're not part of the default configuration of components that pluginpack supports by default.
Also, can we make sure that comment is actually needed? It's probably good enough to just document this as part of pluginpacks' public API documentation.
…(review) Addresses review on #11: - Rename the manifest field to additionalFiles: it reads clearly as files added on top of the component/static files pluginpack supports by default, vs. the generic "files". - Drop the inline schema comment; document the field in the README public API section ("Additional Plugin-Root Files") instead. Updates source.ts (field read + error messages), tests, and README. npm run test:all green (80 tests, docs in sync).
eshwar-sundar-glean
added a commit
to gleanwork/agent-plugins
that referenced
this pull request
Jul 27, 2026
Match the pluginpack review rename (gleanwork/pluginpack#11): the plugin-root files map key is now `additionalFiles`. npm test green (69/65/56).
Contributor
Author
|
Addressed in e3fda9b:
— sent via Glean Pi |
steve-calvert-glean
approved these changes
Jul 27, 2026
steve-calvert-glean
deleted the
eshwar/per-target-mcp-and-plugin-root-files
branch
July 27, 2026 20:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two capabilities pluginpack needs to host the glean-vnext runtime MCP server as a source plugin:
readMcpServers(target)appliesresolveTargetOverrideto.mcp.json, so a source plugin can shiptargets/<target>/.mcp.jsonthat fully replaces the base config for that target (e.g. codex uses./start.mjs+cwdinstead of${CLAUDE_PLUGIN_ROOT}/start.mjs).files—plugin.pluginpack.jsonaccepts afiles: { [dest]: source }map copied to the emitted plugin root (coversdist/index.js,start.mjs,package.jsonin one feature). Supports target overrides on source paths; guards against collisions, unsafe paths, and missing sources.Test screenshots
Check that the Plugin is merged and both glean run and top level skills are loaded.

Why
The glean-vnext plugin is a local stdio MCP server (bundled runtime + launcher) that can't be expressed with the current pluginpack model (no arbitrary plugin-root files; no way to vary the MCP invocation per target). These features let vnext live as a normal source plugin under
sources/glean-vnext/and be folded into the existinggleanemitted plugin.Tests
npm run test:allgreen: format:check, lint, typecheck, 32 tests, build, docs. 4 new tests cover per-target MCP override, plugin-root files (with target override + managed-manifest tracking), collision guard, and missing-source guard.Consumer
Depended on by gleanwork/agent-plugins
eshwar/glean-vnext-fold-into-glean(draft PR #3). agent-plugins must bump to@gleanwork/pluginpack@^0.8.0once this is published.Sequence diagrams
Feature 1 — per-target MCP config override (build time)
sequenceDiagram participant CLI as pluginpack build --target codex participant Eng as targets/engine.ts<br/>emitFromDefinition participant Rnd as render.ts<br/>resolveMcpServers participant Src as source.ts<br/>readMcpServers participant Ovr as source.ts<br/>resolveTargetOverride participant FS as filesystem CLI->>Eng: emit(project, target="codex") Eng->>Rnd: resolveMcpServers(project, from, "codex") loop each sourceId in from[] Rnd->>Src: readMcpServers(sourceId, "codex") Src->>Ovr: resolveTargetOverride(dir, ".mcp.json", "codex") Ovr->>FS: exists(targets/codex/.mcp.json)? alt override exists FS-->>Ovr: yes Ovr-->>Src: targets/codex/.mcp.json else no override FS-->>Ovr: no Ovr-->>Src: .mcp.json (base) end Src-->>Rnd: mcpServers (codex content) end Rnd-->>Eng: merged servers (dup-name = error) Eng->>FS: write plugins/<id>/.mcp.json + manifest mcpServers:"./.mcp.json"Feature 2 — plugin-root
filesmap (build time)sequenceDiagram participant Eng as targets/engine.ts participant Rnd as render.ts<br/>collectPluginFiles participant Src as source.ts<br/>readPluginFiles participant Ovr as resolveTargetOverride participant FS as filesystem Eng->>Rnd: collectPluginFiles(project, target, from, components) loop each sourceId in from[] Rnd->>Src: readPluginFiles(sourceId, target) Src->>Src: walk component dirs + static files (target-overridden) Note over Src: then the declared files map loop each dest -> source in manifest.files Src->>Src: guard: dest is safe relative path Src->>Src: guard: dest not already emitted (collision) Src->>Ovr: resolveTargetOverride(dir, source, target) Ovr-->>Src: resolved source path Src->>FS: read (throws if missing) FS-->>Src: bytes end Src-->>Rnd: file map (incl. dist/index.js, start.mjs, package.json) end Rnd-->>Eng: merged files (dup-path = error) -> tracked as managed output