Agent Plugins format: ${PLUGIN_ROOT} / ${PLUGIN_DATA} not expanded in plugin mcp.json and hooks.json (stdio MCP server cannot start)
@sandy081 is already working on this.
Since Sep 19, 2026.
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.7k
- PR merge metrics
- PR metrics pending
Description
Summary
For plugins in the Agent Plugins 1.0.0 format (root plugin.json with "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"), VS Code does not expand ${PLUGIN_ROOT} (nor ${PLUGIN_DATA}) in mcp.json args/env/cwd, does not set PLUGIN_ROOT/PLUGIN_DATA in the server environment, and does not use the plugin root as the default working directory. The literal string reaches the spawned process, so a stdio MCP server that references a bundled file cannot start. The same plugin works in Copilot CLI, which does expand the placeholder.
The Agent Plugins specification requires this expansion (§9.1, §9.2, §11.1 items 6–7): https://agent-plugins.org/specification#9-environment-variables-and-placeholder-expansion
Steps to reproduce
-
Install a plugin with this
mcp.json(e.g.neqsimfrom the marketplace https://github.com/equinor/neqsim-copilot-plugin, or any minimal Agent Plugins-format plugin):{ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json", "mcpServers": { "neqsim": { "type": "stdio", "command": "java", "args": ["${PLUGIN_ROOT}/servers/NeqsimMcpLauncher.java"] } } } -
Start a chat so the server is launched.
-
Open Output → MCP: neqsim.
Actual
Starting server from LocalProcess extension host
[server stderr] Error: Could not find or load main class ${PLUGIN_ROOT}.servers.NeqsimMcpLauncher.java
[server stderr] Caused by: java.lang.ClassNotFoundException: ${PLUGIN_ROOT}.servers.NeqsimMcpLauncher.java
Connection state: Error Process exited with code 1
The plugin's com.github.copilot/hooks/hooks.json SessionStart command containing ${PLUGIN_ROOT} fails the same way.
Expected
${PLUGIN_ROOT} replaced by the absolute plugin directory in args, env and cwd; PLUGIN_ROOT and PLUGIN_DATA present in the subprocess environment; plugin root used as the default cwd (spec §7.2.1). Same behaviour as for the Copilot / Claude / OpenPlugin formats, which already substitute the token.
Cause
src/vs/platform/agentPlugins/common/pluginParsers.ts — AGENT_PLUGIN_FORMAT is declared with
pluginRootTokens: [],
pluginRootEnvVars: [],
and parseMcpServerDefinitionMap only sets defaultCwd and applies interpolateMcpPluginRoot / convertBareEnvVarsToVsCodeSyntax when formatConfig.format !== PluginFormat.AgentPlugin. COPILOT_FORMAT, CLAUDE_FORMAT and OPEN_PLUGIN_FORMAT all list ['${PLUGIN_ROOT}', '${CLAUDE_PLUGIN_ROOT}']. The exporter for this format (Lhn/s_r in the bundle) does accept ${PLUGIN_ROOT}/${PLUGIN_DATA} in cwd, so the token is recognised on the way out but never resolved on the way in.
Presumably the intent was to defer to the agent host / Copilot SDK, which knows CLAUDE_PLUGIN_ROOT / COPILOT_PLUGIN_ROOT / PLUGIN_ROOT — but plugin MCP servers are started by the LocalProcess extension host, so nothing in the chain performs the substitution.
Environment
- VS Code 1.138.0 (stable), commit 7debcd0e2acdea1c52de81bf9ee1620444407dda, Windows 11
- Still present in
main(pluginParsers.tsas of 2026-09-19) - Plugin: https://github.com/equinor/neqsim-copilot-plugin (
neqsim/mcp.json,neqsim/com.github.copilot/hooks/hooks.json)
Workaround
Register the server in the user mcp.json with the absolute path of the installed plugin (~/.vscode/agent-plugins/github.com/<owner>/<marketplace>/<plugin>/...). Not viable for a distributed plugin, since the install location differs per client and install method.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.