Skip to content

fix: infer registry_name when MCP registry API returns empty values#181

Merged
sergio-sisternes-epam merged 5 commits intomicrosoft:mainfrom
sergio-sisternes-epam:fix/180-empty-registry-name
Mar 6, 2026
Merged

fix: infer registry_name when MCP registry API returns empty values#181
sergio-sisternes-epam merged 5 commits intomicrosoft:mainfrom
sergio-sisternes-epam:fix/180-empty-registry-name

Conversation

@sergio-sisternes-epam
Copy link
Collaborator

Description

The MCP registry API returns empty registry_name for the majority of packages, causing all three client adapters to fail when resolving stdio-based MCP servers. This PR adds registry type inference to each adapter so package selection and configuration work regardless of whether registry_name is populated.

Fixes #180

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Changes

Root cause

The live MCP registry API (api.mcp.github.com) returns "registry_name": "" for most packages. All three adapters (vscode.py, copilot.py, codex.py) match on this field directly in _select_best_package() and _format_server_config(), so package type resolution always fails.

Solution

Added _infer_registry_name() static method to each adapter that derives the package type through a fallback chain:

  1. Explicit registry_name (when non-empty)
  2. runtime_hint mapping (npx/npm → npm, uvx/pip → pypi, docker → docker, dotnet → nuget)
  3. Package name patterns (@scope/name → npm, ghcr.io/… → docker, PascalCase.Name → nuget, *.mcpb → mcpb)

Additionally for the VS Code adapter:

  • Added _extract_package_args() to normalize both package_arguments (current API: {type, value}) and runtime_arguments (legacy: {is_required, value_hint})
  • Added -y flag to npx commands for non-interactive installs

Files changed

File Change
src/apm_cli/adapters/client/vscode.py Added _infer_registry_name, _extract_package_args; updated selection and formatting
src/apm_cli/adapters/client/copilot.py Added _infer_registry_name; updated _select_best_package and registry_name usage
src/apm_cli/adapters/client/codex.py Added _infer_registry_name; updated _select_best_package and registry_name usage
tests/unit/test_vscode_adapter.py 15 new tests across 3 test classes (TestVSCodeInferRegistryName, TestVSCodeExtractPackageArgs, TestVSCodeRealApiFormat)
tests/unit/test_runtime_args.py Updated assertions for -y flag in npx args
tests/unit/test_env_variables.py Updated assertion for -y flag in npx args
docs/integrations.md Added "Package Type Inference" section

Testing

  • Tested locally
  • All existing tests pass (1039 passed)
  • Added tests for new functionality (15 new tests including real API format coverage)

…icrosoft#180)

All three client adapters (VS Code, Copilot, Codex) failed to resolve
MCP registry packages because the API returns empty registry_name for
most packages. Added _infer_registry_name() to each adapter that derives
the package type from runtime_hint and package name patterns. Also added
_extract_package_args() to the VS Code adapter to handle the
package_arguments API format alongside legacy runtime_arguments.

- VS Code adapter: added _infer_registry_name, _extract_package_args,
  -y flag for npx commands
- Copilot adapter: added _infer_registry_name, updated _select_best_package
- Codex adapter: added _infer_registry_name, updated _select_best_package
- Tests: 15 new tests covering inference, arg extraction, real API format
- Docs: added Package Type Inference section to integrations.md
Copilot AI review requested due to automatic review settings March 6, 2026 01:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes MCP registry package resolution when the registry API returns empty registry_name values, by adding registry type inference in the client adapters so stdio-based MCP servers can still be selected/configured.

Changes:

  • Added registry type inference (_infer_registry_name) to VS Code, Copilot CLI, and Codex adapters and updated package selection to use inferred types.
  • Enhanced VS Code adapter formatting to support both package_arguments (new API) and runtime_arguments (legacy), and added -y to npx args.
  • Added/updated unit tests and documented the new inference behavior in docs/integrations.md.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/apm_cli/adapters/client/vscode.py Selects best package using inferred registry type; extracts args from new/legacy registry formats; adds npx -y; improves error messaging.
src/apm_cli/adapters/client/copilot.py Uses inferred registry type for package selection/formatting when registry_name is empty.
src/apm_cli/adapters/client/codex.py Uses inferred registry type for package selection/formatting when registry_name is empty.
tests/unit/test_vscode_adapter.py Updates existing npx assertions and adds new test coverage for inference/extraction and real API-shaped payloads.
tests/unit/test_runtime_args.py Updates expected npx args to include -y.
tests/unit/test_env_variables.py Updates expected npx args to include -y.
docs/integrations.md Documents package type inference behavior and supported package types per runtime.
Comments suppressed due to low confidence (1)

src/apm_cli/adapters/client/codex.py:214

  • Codex’s npm config path currently sets command to npx but builds args from runtime_arguments + package_arguments without ensuring the npm package name is included. With the real MCP registry API, npm packages often provide only package_arguments (e.g. ['server','start']) and no runtime_arguments, which would produce npx server start (treating server as the package). Consider prepending the package name (and optionally -y for non-interactive installs) when registry_name is (inferred as) npm and the processed args don’t already include it.
                registry_name = self._infer_registry_name(package)
                package_name = package.get("name", "")
                runtime_hint = package.get("runtime_hint", "")
                runtime_arguments = package.get("runtime_arguments", [])
                package_arguments = package.get("package_arguments", [])
                env_vars = package.get("environment_variables", [])
                
                # Resolve environment variables first
                resolved_env = self._process_environment_variables(env_vars, env_overrides)
                
                # Process arguments to extract simple string values
                processed_runtime_args = self._process_arguments(runtime_arguments, resolved_env, runtime_vars)
                processed_package_args = self._process_arguments(package_arguments, resolved_env, runtime_vars)
                
                # Generate command and args based on package type
                if registry_name == "npm":
                    config["command"] = runtime_hint or "npx"
                    # For npm packages, use runtime_arguments directly as they contain the complete npx command
                    config["args"] = processed_runtime_args + processed_package_args
                    # For NPM packages, also use env block for environment variables

You can also share your feedback on Copilot code review. Take the survey.

…e _infer_registry_name

- VS Code & Codex adapters now always include the package name in npx
  args (e.g. npx -y @azure/mcp server start), filtering duplicates from
  legacy runtime_arguments that already contain it
- Moved _infer_registry_name() to MCPClientAdapter base class to avoid
  identical copies across all three adapters
- Codex adapter npm handler now includes -y flag for consistency
- All 1039 tests pass
Copy link
Collaborator

@danielmeppiel danielmeppiel left a comment

Choose a reason for hiding this comment

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

LGTM — most impactful of the three PRs. Fixes a real production bug where most MCP registry packages fail to install because registry_name is empty.

What I verified:

  • _infer_registry_name() placed in base.py — correct, avoids triplication across adapters ✓
  • Inference chain is solid: explicit → runtime_hint → name pattern heuristics ✓
  • -y flag added to npx in VS Code + Codex adapters (Copilot adapter already had it) ✓
  • _extract_package_args() normalizes both package_arguments (current API) and runtime_arguments (legacy) — future-proofs against API evolution ✓
  • Generic elif package and runtime_hint: fallback in VS Code adapter catches nuget/dotnet and other runtimes ✓
  • Error messages now list available registries instead of generic "no package information" — good UX ✓
  • 15+ tests including real API format coverage with actual registry response shapes ✓
  • docs/integrations.md updated ✓

Non-blocking observations:

  1. Pre-existing edge case: If a package list exists but the selected package has no runtime_hint and doesn't match npm/docker/pypi, server_config would be undefined when the env var block tries to reference it. The new generic fallback reduces this risk significantly, but a server_config = {} initialization or an explicit else guard would be belt-and-suspenders. Pre-existing though, not introduced here.
  2. VS Code _select_best_package priority is ["npm", "pypi", "docker"] while Copilot/Codex use ["npm", "docker", "pypi", "homebrew"]. This seems intentional but worth a comment explaining the rationale.

Merge order: PR 3 of 3. Rebase onto main after #178 merges.

@sergio-sisternes-epam sergio-sisternes-epam merged commit 251fa5e into microsoft:main Mar 6, 2026
6 checks passed
@sergio-sisternes-epam sergio-sisternes-epam deleted the fix/180-empty-registry-name branch March 6, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] All client adapters fail to resolve MCP registry packages when registry_name is empty

3 participants