claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] MCP servers from marketplace no longer available

Open stephanwesten opened this issue 1 month ago • 13 comments

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Bug Report: Plugin MCP servers not loaded after update to 2.0.64

Description

After updating to Claude Code 2.0.64, MCP servers defined in marketplace plugins are no longer available. The /mcp command shows "No MCP servers configured" even though the plugin is installed and enabled. Plugin commands and skills continue to work correctly.

Environment

  • Claude Code version: 2.0.64
  • OS: macOS (Darwin 24.6.0, ARM64)
  • Plugin source: Local directory marketplace

Steps to Reproduce

  1. Install a plugin from a local marketplace that includes .mcp.json with MCP server definitions
  2. Enable the plugin in settings.json: "enabledPlugins": { "plugin-name@marketplace": true }
  3. Start Claude Code
  4. Run /mcp command

Expected Behavior

MCP servers defined in the plugin's .mcp.json should be available and shown in /mcp output.

Actual Behavior

  • /mcp shows "No MCP servers configured"
  • Plugin commands (slash commands) work correctly
  • Plugin skills work correctly
  • Only MCP servers are missing

Technical Analysis

  1. .mcp.json not copied to cache

The plugin's .mcp.json file exists in the source directory but is NOT copied to the plugin cache:

Source has .mcp.json:

~/.claude/plugins/marketplaces/my-marketplace/my-plugin/.mcp.json

Cache only has commands/ and skills/:

~/.claude/plugins/cache/my-marketplace/my-plugin// ├── commands/ └── skills/

.mcp.json is MISSING

  1. Install path mismatch in installed_plugins.json

{ "installPath": ".../my-plugin/unknown" // This directory doesn't exist }

The unknown directory referenced doesn't exist. Cache has hash-named directories instead (e.g., 3e8d46c8013a/, b4139b6ea827/).

  1. Plugin .mcp.json contents (for reference)

{ "mcpServers": { "server1": { "type": "sse", "url": "https://example.com/sse" }, "server2": { "command": "npx", "args": ["-y", "some-mcp-server@latest"] } } }

Workaround Attempted

  • Reinstalling plugin (/plugin uninstall + /plugin install) - did not resolve
  • Plugin remains enabled in settings

Impact

  • Multiple users affected (confirmed by team members)
  • Breaks workflows that depend on plugin-provided MCP servers (e.g., Atlassian, browser tools)

Possible Root Cause

In version 2.0.64, the plugin caching mechanism appears to skip .mcp.json files, only copying commands/ and skills/ directories. Additionally, the install path tracking uses unknown as version string for local directory plugins, which doesn't match the actual cache directory structure.

What Should Happen?

/plugin should show me the MCP servers from the marketplace

Error Messages/Logs

n/a

Steps to Reproduce

see description

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.0.62

Claude Code Version

2.0.64

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

No response

stephanwesten avatar Dec 10 '25 11:12 stephanwesten

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/13471
  2. https://github.com/anthropics/claude-code/issues/11856
  3. https://github.com/anthropics/claude-code/issues/13509

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

github-actions[bot] avatar Dec 10 '25 11:12 github-actions[bot]

This is a different issue as the 3 above

stephanwesten avatar Dec 10 '25 15:12 stephanwesten

Similarly, hooks don't seem to be copied to the cache either, so hooks also have the same issue. Also - this regression seemed to have been added in v2.0.62 (last night)

This (temporary manual) workaround seems to have fixed the issue for me until CC officially fixes the bug:

  cp -r ~/.claude/plugins/marketplaces/<marketplace>/plugins/<plugin>/hooks/ \
        ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/<path-from-hook-command>/

dgalambos avatar Dec 10 '25 15:12 dgalambos

Thanks for reporting: .mcp.json, .lsp.json should be copied now when the plugin is installed. Could you try the today's Claude build.

whyuan-cc avatar Dec 11 '25 22:12 whyuan-cc

Thanks for reporting: .mcp.json, .lsp.json should be copied now when the plugin is installed. Could you try the today's Claude build.

@whyuan-cc - I am on v2.0.65 and hooks are still not being copied over correctly.

doron-sincere avatar Dec 11 '25 22:12 doron-sincere

@doron-sincere could you share the hooks structure?

my understanding is that you do not have a self-contained plugin, which has $plugin/.claude-plugin/plugin.json and $plugin/all_files. Instead, you have a marketplace.json that list all components of the plugin, like

{
      "name": "my-best-plugin",
      "version": "1.0.0",
      "commands": [
          $commands files
      ],
      "hooks": [
           $hooks files
       ]
    },

whyuan-cc avatar Dec 11 '25 23:12 whyuan-cc

@doron-sincere could you share the hooks structure?

my understanding is that you do not have a self-contained plugin, which has $plugin/.claude-plugin/plugin.json and $plugin/all_files. Instead, you have a marketplace.json that list all components of the plugin, like

{
      "name": "my-best-plugin",
      "version": "1.0.0",
      "commands": [
          $commands files
      ],
      "hooks": [
           $hooks files
       ]
    },

@whyuan-cc I have a private marketplace for our team's plugins. We have a "core" plugin, that everything is "required"/base agents/hooks/etc, then we have other plugins that are team-dependent, but build off of the "core" one as well - the only overlap is that the hooks are re-used but have different params passed in (and are defined in the marketplace.json file).

Directory structure:

.claude-plugin/
└── marketplace.json
plugins/
├── core/
│   ├── .claude-plugin/
│   │   └── plugin.json
│   ├── commands/
│   │   └── *.md
│   ├── agents/
│   │   └── *.md
│   └── hooks/
│       ├── session-start.sh
│       ├── user-prompt-submit.sh
│       └── pre-tool-use-bash.sh
└── my-second-plugin/
    ├── .claude-plugin/
    │   └── plugin.json
    └── agents/
        └── *.md

marketplace.json (.claude-plugin/marketplace.json):

{
  "name": "my-marketplace",
  "version": "1.0.0",
  "plugins": [
    {
      "name": "core",
      "source": "./plugins",
      "version": "1.0.0",
      "commands": [
        "./core/commands/commit.md",
        "./core/commands/create_plan.md"
      ],
      "agents": [
        "./core/agents/core-agent-1.md",
        "./core/agents/core-agent-2.md"
      ],
      "hooks": {
        "SessionStart": [
          {
            "description": "Provides namespace resolution at session start",
            "matcher": "*",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/session-start.sh core"
              }
            ]
          }
        ],
        "UserPromptSubmit": [
          {
            "description": "Intercepts user prompts for namespace resolution",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/user-prompt-submit.sh core"
              }
            ]
          }
        ],
        "PreToolUse": [
          {
            "description": "Pre-Bash hook for directory awareness",
            "toolNames": ["Bash"],
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/pre-tool-use-bash.sh"
              }
            ]
          }
        ]
      }
    },
    {
      "name": "my-second-plugin",
      "source": "./plugins",
      "version": "1.0.0",
      "agents": [
        "./my-second-plugin/agents/foo.md",
        "./my-second-plugin/agents/bar.md"
      ],
      "hooks": {
        "SessionStart": [
          {
            "description": "Provides namespace resolution at session start",
            "matcher": "*",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/session-start.sh my-second-plugin"
              }
            ]
          }
        ],
        "UserPromptSubmit": [
          {
            "description": "Intercepts user prompts for namespace resolution",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/user-prompt-submit.sh my-second-plugin"
              }
            ]
          }
        ]
      }
    }
  ]
}

^ Note that the hooks in "my-second-plugin" are from the "core" location & we're using CLAUDE_PLUGIN_ROOT var as well - so this could be part of the issue, as it's a mix of multiple plugin names.

This did work prior to v2.0.62, so I assumed what I was doing was legal (ie. shared files to reduce code duplication). I appreciate your help & tell me if there's something we're doing wrong here.

doron-sincere avatar Dec 11 '25 23:12 doron-sincere

Sorry for breaking your experience due to our change. I see that your hooks have "command": "${CLAUDE_PLUGIN_ROOT}/core/hooks/. I will make a fix.

Just double check: commands and agents are still working.

whyuan-cc avatar Dec 12 '25 00:12 whyuan-cc

Yes, correct - it's just hooks that doesn't work for me in my setup. Commands and Agents work as expected - it's just the Hooks that aren't working in the new update (in v2.0.62+) - thank you!

doron-sincere avatar Dec 12 '25 01:12 doron-sincere

Multi-Level Relative Paths Not Resolved During Plugin Installation

Experiencing issue in v2.0.67 (suspected since v2.0.62) where component files referenced by multi-level relative paths (../../) are not copied to cache during plugin installation.

Environment:

  • Claude Code: v2.0.67 (suspected since v2.0.62)
  • Platform: macOS (Darwin 24.4.0)
  • Marketplace: Local directory

Root Cause: Relative Paths Not Resolved from Source

Using component-based marketplace structure where plugins reference shared implementations outside pluginRoot:

marketplace/
├── .claude-plugin/
│   └── marketplace.json
├── cli-tool/
│   └── components/
│       ├── commands/
│       │   └── example-commands/  # Implementation here
│       ├── agents/
│       ├── skills/
│       └── mcps/
│           └── devtools/
│               └── ui-docs.json  # Implementation here
└── plugins/
    ├── example-commands/
    │   └── .claude-plugin/
    │       └── plugin.json  # References ../../cli-tool/components/
    └── example-mcp/
        └── .claude-plugin/
            └── plugin.json  # References ../../cli-tool/components/

marketplace.json (at marketplace root):

{
  "name": "my-marketplace",
  "metadata": {
    "pluginRoot": "./plugins"
  },
  "plugins": [
    {"name": "example-commands", "source": "./plugins/example-commands"},
    {"name": "example-mcp", "source": "./plugins/example-mcp"}
  ]
}

Example 1 - Commands plugin (at plugins/example-commands/.claude-plugin/plugin.json):

{
  "commands": "./../../cli-tool/components/commands/example-commands/"
}

Example 2 - MCP plugin (at plugins/example-mcp/.claude-plugin/plugin.json):

{
  "mcpServers": "./../../cli-tool/components/mcps/devtools/ui-docs.json"
}

Both use ../../ to reference components outside pluginRoot.

Observed Behavior

Source (correct):

cli-tool/components/commands/example-commands/
├── command-a.md
├── command-b.md
└── ...

cli-tool/components/mcps/devtools/
└── ui-docs.json

Cache after installation:

~/.claude/plugins/cache/my-marketplace/example-commands/1.0.0/
├── .claude-plugin/
│   └── plugin.json
└── README.md

~/.claude/plugins/cache/my-marketplace/example-mcp/1.0.0/
├── .claude-plugin/
│   └── plugin.json
└── README.md

Expected: Component files (commands/, mcps/) copied to cache Actual: Only plugin.json and README.md copied, component files missing

Error in Claude Code:

❯ example-commands from example-commands@my-marketplace
   commands path not found: /Users/admin/.claude/plugins/cache/my-marketplace/cli-tool/components/commands/example-commands/
   → Check that the path in your manifest or marketplace config is correct

Root Cause: Claude Code tries to resolve ../../cli-tool/components/ relative to the cache directory at runtime, instead of resolving it from the source and copying files during installation.

Tested Workarounds (Both Fail)

Directory reference:

"commands": "./../../cli-tool/components/commands/example-commands/"

Array of files:

"commands": [
  "./../../cli-tool/components/commands/example-commands/command-a.md",
  "./../../cli-tool/components/commands/example-commands/command-b.md"
]

Both fail - files not copied to cache.

Analysis

The Bug: Component files referenced by multi-level relative paths (../../) are NOT copied to cache during plugin installation.

What gets copied:

  • plugin.json (from plugin directory)
  • README.md (from plugin directory)

What does NOT get copied:

  • No commands/ directory created
  • No command .md files copied
  • No MCP .json files copied
  • No component files referenced by ../../ paths

Installer behavior:

  1. Copies files directly in the plugin directory (plugin.json, README.md)
  2. Ignores all component references with ../../ paths
  3. At runtime, tries to resolve ../../cli-tool/... from cache directory
  4. Fails because those files were never copied

Impact: All component types (commands, agents, skills, mcpServers) that use multi-level relative paths to reference shared implementations outside pluginRoot are completely non-functional.

KylinWu avatar Dec 12 '25 08:12 KylinWu

~This seems to be fixed and is working as-expected (for me) in v2.0.67 - thank you!~

Edit: I spoke too soon 🤦🏼 - looks like they still aren't properly being added

doron-sincere avatar Dec 12 '25 14:12 doron-sincere

~This seems to be fixed and is working as-expected (for me) in v2.0.67 - thank you!~

Edit: I spoke too soon 🤦🏼 - looks like they still aren't properly being added

PR merged and the next build should work.

whyuan-cc avatar Dec 12 '25 23:12 whyuan-cc

Hey everyone! Thanks for filing the bug. We kinda knew this was coming for a while, and I'm really sorry I didn't jump on top of this earlier. Basically, for security and verification reasons, we need plugins to be a bit more self-contained, so we started copying them to a cache instead of using them in-place. For @doron-sincere's case, this should work fine (none of the paths contain reverse traversals, and we'll just copy the whole ./plugins directory for each plugin because that's the path given in the marketplace—inefficient, but simple and not that big of a deal. We just had a bug for that one, which should be fixed soon. For @KylinWu, this is a bit messier. I originally avoided moving plugins to version-specific cache directories for exactly this reason, but it's become pretty unmanageable with the set of things we need to support.

So from now on, we're just going to copy the path you give us in the marketplace manifest, recursively, or in the case of a .claude-plugin/plugin.json the implicit root directory of the plugin (the one that contains the .claude-plugin/plugin.json). If you want to traverse to paths outside of that directory, you're on your own. @KylinWu, you should be able to use symlinks, and we'll honor those as we copy. Alternatively, you can just list the path to the plugin as the root of the marketplace and provide the rest of the plugin manifest directly in the marketplace.

There are definitely downsides to this approach, but hopefully at least this clarifies things. Sorry for the breaking changes, and thanks for the feedback!

dhollman avatar Dec 13 '25 00:12 dhollman

@whyuan-cc Hopefully unnecessarily to mention this, but please add automated regressions tests. This part is brittle and for enterprises this part is vital to their dev platform.

stephanwesten avatar Dec 13 '25 08:12 stephanwesten

Hey everyone! Thanks for filing the bug. We kinda knew this was coming for a while, and I'm really sorry I didn't jump on top of this earlier. Basically, for security and verification reasons, we need plugins to be a bit more self-contained, so we started copying them to a cache instead of using them in-place. For @doron-sincere's case, this should work fine (none of the paths contain reverse traversals, and we'll just copy the whole ./plugins directory for each plugin because that's the path given in the marketplace—inefficient, but simple and not that big of a deal. We just had a bug for that one, which should be fixed soon. For @KylinWu, this is a bit messier. I originally avoided moving plugins to version-specific cache directories for exactly this reason, but it's become pretty unmanageable with the set of things we need to support.

So from now on, we're just going to copy the path you give us in the marketplace manifest, recursively, or in the case of a .claude-plugin/plugin.json the implicit root directory of the plugin (the one that contains the .claude-plugin/plugin.json). If you want to traverse to paths outside of that directory, you're on your own. @KylinWu, you should be able to use symlinks, and we'll honor those as we copy. Alternatively, you can just list the path to the plugin as the root of the marketplace and provide the rest of the plugin manifest directly in the marketplace.

There are definitely downsides to this approach, but hopefully at least this clarifies things. Sorry for the breaking changes, and thanks for the feedback!

Thanks @dhollman for the quick response and clear explanation!

We've implemented the inline manifest approach, and it's working perfectly with Claude Code v2.0.62+. 👍

KylinWu avatar Dec 15 '25 04:12 KylinWu