Skip to content

feat: per-target MCP config overrides + plugin-root files - #11

Merged
steve-calvert-glean merged 2 commits into
mainfrom
eshwar/per-target-mcp-and-plugin-root-files
Jul 27, 2026
Merged

feat: per-target MCP config overrides + plugin-root files#11
steve-calvert-glean merged 2 commits into
mainfrom
eshwar/per-target-mcp-and-plugin-root-files

Conversation

@eshwar-sundar-glean

@eshwar-sundar-glean eshwar-sundar-glean commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds two capabilities pluginpack needs to host the glean-vnext runtime MCP server as a source plugin:

  1. Per-target MCP config overridereadMcpServers(target) applies resolveTargetOverride to .mcp.json, so a source plugin can ship targets/<target>/.mcp.json that fully replaces the base config for that target (e.g. codex uses ./start.mjs + cwd instead of ${CLAUDE_PLUGIN_ROOT}/start.mjs).
  2. Plugin-root filesplugin.pluginpack.json accepts a files: { [dest]: source } map copied to the emitted plugin root (covers dist/index.js, start.mjs, package.json in 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.
image

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 existing glean emitted plugin.

Tests

npm run test:all green: 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.0 once 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"
Loading

Feature 2 — plugin-root files map (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
Loading

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
eshwar-sundar-glean force-pushed the eshwar/per-target-mcp-and-plugin-root-files branch from 82cc4ca to 444d6fe Compare July 27, 2026 10:59

@eshwar-sundar-glean eshwar-sundar-glean left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread src/schema.ts Outdated
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(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).
@eshwar-sundar-glean

Copy link
Copy Markdown
Contributor Author

Addressed in e3fda9b:

  • Renamed filesadditionalFiles across the schema, source.ts (field read + error messages), and tests. Agree it reads more clearly as "files added on top of the components pluginpack supports by default."
  • Removed the inline schema comment; documented the field in the README public-API section instead (renamed to "Additional Plugin-Root Files").

npm run test:all green (80 tests, docs:check in sync). The consumer (gleanwork/agent-plugins#3) is updated to match — build stays green (69/65/56).

— sent via Glean Pi

@steve-calvert-glean
steve-calvert-glean merged commit d77295b into main Jul 27, 2026
1 check passed
@steve-calvert-glean
steve-calvert-glean deleted the eshwar/per-target-mcp-and-plugin-root-files branch July 27, 2026 20:24
@steve-calvert-glean steve-calvert-glean added the enhancement New feature or request label Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants