From b5a35563b6ddb916a2ab04546370d814e90b7a25 Mon Sep 17 00:00:00 2001 From: Blomios Date: Wed, 9 Sep 2026 16:24:16 +0200 Subject: [PATCH] =?UTF-8?q?docs(sdk):=20lancement=20des=20serveurs=20MCP?= =?UTF-8?q?=20JavaScript=20packag=C3=A9s=20=E2=80=94=20#294=20(manifest:?= =?UTF-8?q?=20aucune=20substitution=20${node}/${runtimeNode}/${hostNode}?= =?UTF-8?q?=20ni=20champ=20runtime,=20IdeA=20ne=20fournit=20pas=20de=20run?= =?UTF-8?q?time=20Node=20plugin-scoped;=20command=20n'est=20pas=20du=20she?= =?UTF-8?q?ll=20=E2=80=94=20d=C3=A9marrage=20direct=20avec=20args=20s?= =?UTF-8?q?=C3=A9par=C3=A9s,=20pas=20de=20fichiers=20de=20startup/alias/PA?= =?UTF-8?q?TH=20du=20shell=20de=20login;=20command=20relatif=20r=C3=A9solu?= =?UTF-8?q?=20sous=20pluginRoot=20=E2=80=94=20command:"node"=20sans=20allo?= =?UTF-8?q?wAbsoluteCommand=20devient=20${pluginRoot}/node=20(cause=20ENOE?= =?UTF-8?q?NT=20UnityPlugin=20#12);=20absolu=20litt=C3=A9ral=20refus=C3=A9?= =?UTF-8?q?=20sans=20allowAbsoluteCommand=3Dtrue,=20command=20devenu=20abs?= =?UTF-8?q?olu=20apr=C3=A8s=20substitution=20${pluginRoot}/${appDataDir}?= =?UTF-8?q?=20pass=C3=A9=20tel=20quel;=20shebang=20#!/usr/bin/env=20node?= =?UTF-8?q?=20d=C3=A9pend=20du=20node=20visible=20du=20process=20app=20Ide?= =?UTF-8?q?A;=20recommandations:=20ex=C3=A9cutable=20packag=C3=A9=20inclua?= =?UTF-8?q?nt=20son=20runtime=20ou=20runtime=20g=C3=A9r=C3=A9=20sous=20sto?= =?UTF-8?q?ckage=20plugin/app=20point=C3=A9=20via=20${pluginRoot}/${appDat?= =?UTF-8?q?aDir},=20sinon=20d=C3=A9pendance=20h=C3=B4te=20explicite=20abso?= =?UTF-8?q?lue=20/usr/bin/node=20avec=20allowAbsoluteCommand=3Dtrue=20et?= =?UTF-8?q?=20scripts=20dans=20args;=20m=C3=AAme=20r=C3=A8gle=20pour=20com?= =?UTF-8?q?mand:"bash";=20packaging-distribution:=20section=20Packaged=20E?= =?UTF-8?q?xecutables=20And=20Runtimes=20=E2=80=94=20bit=20ex=C3=A9cutable?= =?UTF-8?q?=20et=20shebang=20valides=20dans=20le=20package=20install=C3=A9?= =?UTF-8?q?,=20=C3=A9viter=20le=20bare=20command:"node"=20en=20plugins=20d?= =?UTF-8?q?istribu=C3=A9s/multi-harness;=20services:=20distinction=20runCo?= =?UTF-8?q?mmand()=20(ex=C3=A9cutable=20h=C3=B4te=20de=20l'environnement?= =?UTF-8?q?=20task,=20aucune=20substitution)=20vs=20r=C3=A8gles=20manifest?= =?UTF-8?q?=20mcpServers=20avec=20lien=20crois=C3=A9;=20affirmations=20v?= =?UTF-8?q?=C3=A9rifi=C3=A9es=20par=20Git=20contre=20l'h=C3=B4te=20crates/?= =?UTF-8?q?application/src/plugin/mod.rs:3199=20substitution=20puis=20look?= =?UTF-8?q?s=5Fabsolute/allow=5Fabsolute=5Fcommand=20sinon=20pr=C3=A9fixag?= =?UTF-8?q?e=20pluginRoot,=20et=20validation=20:3637=20absolu=20litt=C3=A9?= =?UTF-8?q?ral=20sans=20flag=20rejet=C3=A9;=20QA=20verte=20reconfirm=C3=A9?= =?UTF-8?q?e=20par=20Git:=20npm=20run=20check=20=E2=80=94=20build,=20typec?= =?UTF-8?q?heck:examples,=20package:hello-plugin)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/manifest.md | 56 +++++++++++++++++++++++++++++----- docs/packaging-distribution.md | 19 ++++++++++++ docs/services.md | 9 +++++- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/docs/manifest.md b/docs/manifest.md index 892bb96..657b736 100644 --- a/docs/manifest.md +++ b/docs/manifest.md @@ -283,8 +283,10 @@ MCP server contribution rules: - `autoStart: true` is required for IdeA to start the server during plugin MCP reconciliation. Non-auto-start servers are manifest metadata only today. - A relative `command` is resolved under the installed plugin package root. -- An absolute `command` is rejected unless `allowAbsoluteCommand: true` is set. - Use this only for an intentional dependency on a host binary. +- A literal absolute `command` is rejected unless `allowAbsoluteCommand: true` + is set. Use this only for an intentional dependency on a host binary. +- A `command` that becomes absolute after `${pluginRoot}` or `${appDataDir}` + substitution is allowed and is passed through as substituted. - `cwd` defaults to `${pluginRoot}` when omitted. The tools an agent can call are assigned with the triplet @@ -307,16 +309,56 @@ declared MCP server. In `command`, `args`, `env` and `cwd`, the host expands: - `${pluginRoot}` to the installed plugin package root. - `${appDataDir}` to the host-owned application data directory. +There is currently no `${node}`, `${runtimeNode}`, `${hostNode}` substitution +and no `runtime` field. IdeA does not provide a plugin-scoped Node.js runtime +for MCP servers. + This string substitution is limited to manifest-declared MCP server startup. Runtime handlers receive the same installed package location separately as `ctx.pluginRoot`; `ctx.services.tasks.runCommand()` does not perform placeholder substitution, and workspace APIs remain project-confined. -Prefer a packaged executable script for plugin-owned MCP servers, for example -`command: "scripts/unity-mcp-server.mjs"` with an appropriate shebang and file -mode. If the server must be launched through a host executable such as Node, -use an absolute command with `allowAbsoluteCommand: true` and keep plugin-owned -paths in `args`, for example `${pluginRoot}/scripts/unity-mcp-server.mjs`. +`command` is not shell syntax. IdeA starts it directly and passes `args` +separately. Do not rely on shell startup files, shell aliases, or a user's login +shell `PATH`. + +Prefer a packaged executable for plugin-owned MCP servers: + +```json +{ + "command": "scripts/unity-mcp-server", + "transport": "stdio", + "autoStart": true +} +``` + +Because the command is package-relative, IdeA resolves it to +`${pluginRoot}/scripts/unity-mcp-server`. If this file is a script, its shebang +and executable bit must be valid in the installed package. A JavaScript shebang +such as `#!/usr/bin/env node` still depends on a `node` binary visible to the +IdeA app process, not necessarily the user's interactive shell. + +For JavaScript MCP servers that must not depend on the user's shell `PATH`, use +one of these approaches: + +- Ship an executable server that includes its runtime, or install a managed + runtime under plugin/app-owned storage and point `command` at that executable + with `${pluginRoot}` or `${appDataDir}`. +- Declare an explicit host dependency with an absolute command such as + `/usr/bin/node`, set `allowAbsoluteCommand: true`, and keep plugin-owned + script paths in `args`. + +Avoid `command: "node"` for a packaged MCP server. With +`allowAbsoluteCommand: false`, it is treated as package-relative and resolves to +`${pluginRoot}/node`. With `allowAbsoluteCommand: true`, it is passed as a host +command name and depends on the environment inherited by IdeA, which may differ +from an interactive shell. + +The same rule applies to shell wrappers. `command: "bash"` resolves to +`${pluginRoot}/bash` unless absolute-command handling is explicitly enabled. Use +a package-relative wrapper executable, or use an absolute shell such as +`/bin/bash` with `allowAbsoluteCommand: true` when that host dependency is +intentional. ## Validation diff --git a/docs/packaging-distribution.md b/docs/packaging-distribution.md index 71c21eb..e774e5b 100644 --- a/docs/packaging-distribution.md +++ b/docs/packaging-distribution.md @@ -43,6 +43,25 @@ IdeA resolves React/ReactDOM bare imports to the host instance. Other bare dependencies are not host-resolved. Bundle or vendor third-party dependencies other than React/ReactDOM into package-relative files. +## Packaged Executables And Runtimes + +Manifest-declared MCP servers are launched from `contributes.mcpServers` by +starting the declared `command` directly. IdeA does not inject a shell and does +not provide a plugin-scoped Node.js runtime. + +For a packaged MCP server, prefer a package-relative executable such as +`scripts/my-plugin-mcp-server`. The installed file must keep the executable bit +and, when it is a script, a valid shebang. A JavaScript server with +`#!/usr/bin/env node` still requires `node` in the environment inherited by the +IdeA app process; this is not guaranteed to match the user's interactive shell, +especially when Node is provided by shell startup tooling. + +For reproducible JavaScript MCP servers, either ship/install a runtime under the +plugin package or app-owned storage and point the manifest at that executable, +or declare an explicit absolute host dependency with `allowAbsoluteCommand: +true`. Avoid relying on a bare `command: "node"` in distributed or multi-harness +plugins. + ## TypeScript Build The hello plugin uses plain `tsc`: diff --git a/docs/services.md b/docs/services.md index 282a93b..5db0ec7 100644 --- a/docs/services.md +++ b/docs/services.md @@ -42,7 +42,8 @@ path under the project root. The host does not implicitly resolve `command` or `args` against the plugin package. Use the absolute `ctx.pluginRoot` supplied at activation time to construct an explicit path to a packaged script, and pass that path as `command` or as an argument to its interpreter. Treat package files -as read-only. +as read-only. Unlike manifest-declared MCP servers, `runCommand()` does not +substitute `${pluginRoot}` or `${appDataDir}`. ```ts const script = `${ctx.pluginRoot.replace(/[\\/]+$/, "")}/scripts/check.mjs`; @@ -56,6 +57,12 @@ await ctx.services.tasks.runCommand({ }); ``` +This task example uses `node` as a host executable visible to the task +environment. That is not the contract for `contributes.mcpServers`: MCP server +`command` values are resolved by the plugin manifest rules documented in +[Manifest](manifest.md), where a bare `command: "node"` is package-relative +unless external host-command handling is explicitly enabled. + ## Tooling `services.tooling.diagnose()` checks executables, environment values and files