-
Notifications
You must be signed in to change notification settings - Fork 36.8k
Description
Does this issue occur when all extensions are disabled?: Yes
- VS Code Version: 1.107.0-insider
- OS Version: Windows 11
Summary
The AbstractCommonMcpManagementService.getMcpServerConfigurationFromManifest() method in VS Code's MCP management service has hardcoded package name/version insertion behavior that:
- Always auto-inserts
package@versionwhen bothnameandversionfields exist in package configuration - Always adds
--yesflag for NuGet packages, creating duplicates if already specified
This prevents external MCP registries (like private enterprise registries) from having full control over command-line argument construction, leading to duplicate arguments and incorrect command generation.
Issue 1: Mandatory Auto-Insert of Package Name@Version
Location
File: src/vs/platform/mcp/common/mcpManagement.ts (or similar path)
Class: AbstractCommonMcpManagementService
Method: getMcpServerConfigurationFromManifest()
Lines: 177-184 (approximate)
Current Behavior
switch (serverPackage.registryType) {
case RegistryType.NODE:
args.push(serverPackage.version ? `${serverPackage.identifier}@${serverPackage.version}` : serverPackage.identifier);
break;
case RegistryType.PYTHON:
args.push(serverPackage.version ? `${serverPackage.identifier}==${serverPackage.version}` : serverPackage.identifier);
break;
case RegistryType.DOCKER:
args.push(serverPackage.version ? `${serverPackage.identifier}:${serverPackage.version}` : serverPackage.identifier);
break;
case RegistryType.NUGET:
args.push(serverPackage.version ? `${serverPackage.identifier}@${serverPackage.version}` : serverPackage.identifier);
args.push('--yes');
if (serverPackage.packageArguments?.length) {
args.push('--');
}
break;
}Problem: This code unconditionally inserts the package identifier between runtimeArguments and packageArguments, with no way to disable this behavior.
Reproduction Case: npm Package with Custom Registry
Gallery Package Configuration:
{
"packages": [
{
"registryType": "npm",
"identifier": "@myorg/mcp-server",
"version": "latest",
"runtimeArguments": [
{ "type": "positional", "value": "exec" },
{ "type": "positional", "value": "-y" }
],
"packageArguments": [
{ "type": "named", "name": "--registry", "value": "https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/npm/registry/" },
{ "type": "named", "name": "--package", "value": "@myorg/mcp-server@latest" },
{ "type": "positional", "value": "mcp-server-memory" }
]
}
]
}Expected VS Code Output:
{
"command": "npx",
"args": [
"exec",
"-y",
"--registry",
"https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/npm/registry/",
"--package",
"@myorg/mcp-server@latest",
"my-mcp-server"
]
}Actual VS Code Output:
{
"command": "npx",
"args": [
"exec",
"-y",
"@myorg/mcp-server@latest", // ← AUTO-INSERTED (duplicate!)
"--registry",
"https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/npm/registry/",
"--package",
"@myorg/mcp-server@latest", // ← EXPECTED (from packageArguments)
"my-mcp-server"
]
}Expected Command:
npx exec -y --registry https://... --package @myorg/mcp-server@latest my-mcp-serverActual Command:
npx exec -y @myorg/mcp-server@latest --registry https://... --package @myorg/mcp-server@latest my-mcp-serverWhy This Breaks
For custom package registries (Azure DevOps, GitHub Packages, private npm registries), the package specification must be passed with the --package flag to npm exec:
npm exec --registry <url> --package <name@version> <command>The auto-inserted @myorg/mcp-server@latest (without --package flag) is interpreted as:
- A command to execute (npm tries to find and run this as a binary)
- Creates incorrect argument order that fails validation
Issue 2: Hardcoded --yes Flag for NuGet Packages
Location
File: src/vs/platform/mcp/common/mcpManagement.ts
Class: AbstractCommonMcpManagementService
Method: getMcpServerConfigurationFromManifest()
Line: 184 (approximate)
Current Behavior
case RegistryType.NUGET:
args.push(serverPackage.version ? `${serverPackage.identifier}@${serverPackage.version}` : serverPackage.identifier);
args.push('--yes'); // ← ALWAYS ADDED
if (serverPackage.packageArguments?.length) {
args.push('--');
}
break;Problem: The --yes flag is unconditionally added even if already present in runtimeArguments, creating duplicates.
Reproduction Case: NuGet Package with --yes in Arguments
Gallery Package Configuration:
{
"packages": [
{
"registryType": "nuget",
"identifier": "MyOrg.McpServer",
"version": "latest",
"runtimeArguments": [
{ "type": "positional", "value": "MyOrg.McpServer" },
{ "type": "named", "name": "--source", "value": "https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/nuget/v3/index.json" },
{ "type": "positional", "value": "--yes" }
],
"packageArguments": []
}
]
}Expected VS Code Output:
{
"command": "dnx",
"args": [
"MyOrg.McpServer",
"--source",
"https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/nuget/v3/index.json",
"--yes"
]
}Actual VS Code Output:
{
"command": "dnx",
"args": [
"MyOrg.McpServer",
"--source",
"https://pkgs.dev.azure.com/myorg/myproject/_packaging/my-feed/nuget/v3/index.json",
"--yes", // ← From runtimeArguments
"MyOrg.McpServer@latest", // ← Auto-inserted
"--yes" // ← Auto-inserted (duplicate!)
]
}Impact
Affected Use Cases
- Private Package Registries - Azure DevOps Artifacts, GitHub Packages, JFrog Artifactory
- Custom npm/NuGet Configurations - Organizations with internal package feeds
- Non-Standard Package Managers - Custom tooling that wraps standard package managers
- External MCP Registry Providers - Third-party services hosting MCP server catalogs
Environment
- VS Code Version: 1.107.0-insider
- OS: Windows 11
- MCP Registry: Private Enterprise MCP Registry (third-party external registry)
- Package Managers Affected: npm, NuGet
Additional Context
Code References
Main transformation method:
export abstract class AbstractCommonMcpManagementService extends Disposable implements IMcpManagementService {
getMcpServerConfigurationFromManifest(manifest: IGalleryMcpServerConfiguration, packageType: RegistryType): McpServerConfigurationParseResult {
// Lines 157-166: Process runtimeArguments
if (serverPackage.runtimeArguments?.length) {
const result = this.processArguments(serverPackage.runtimeArguments ?? []);
args.push(...result.args);
}
// Lines 177-184: AUTO-INSERT (Issue 1)
switch (serverPackage.registryType) {
case RegistryType.NODE:
args.push(serverPackage.version ? `${serverPackage.identifier}@${serverPackage.version}` : serverPackage.identifier);
break;
case RegistryType.NUGET:
args.push(serverPackage.version ? `${serverPackage.identifier}@${serverPackage.version}` : serverPackage.identifier);
args.push('--yes'); // Issue 2: Hardcoded --yes
break;
}
// Lines 186-191: Process packageArguments (too late, duplicate already exists)
if (serverPackage.packageArguments?.length) {
const result = this.processArguments(serverPackage.packageArguments);
args.push(...result.args);
}
}
}