Skip to content

Marketplace clone loads .mcp.json over documented mcp.json when both exist in a dual Cursor + Claude Code plugin repo #252

Description

@adriannoes

Summary

A repository that is both a Cursor plugin and a Claude Code plugin often ships two MCP config filenames:

  • mcp.json — Cursor’s documented plugin default (Plugins reference: auto-discover mcp.json; mcpServers in .cursor-plugin/plugin.json only for a custom path or inline config)
  • .mcp.json — Claude Code’s documented plugin default

The Marketplace scan already looks for both names (see #43: “.mcp.json or mcp.json”). The runtime on a Marketplace clone is not documented when both files exist and contain different servers. In our case the clone started the Claude Code file (local stdio / uvx) instead of the Cursor file (hosted HTTP + OAuth).

That is a different failure from #43 (scanner ignoring manifest paths / inline mcpServers). This issue is precedence when both files are present.

Why we ship both (adoption, not a quirk)

We publish one git repository as two first-class plugins:

  • a Cursor Marketplace plugin (.cursor-plugin/), and
  • a Claude Code plugin (.claude-plugin/).

That is deliberate distribution: the same skills + hosted MCP for whoever the user already lives in, without a second repo or a second source of truth. Cursor’s public contract puts MCP in mcp.json. Claude Code’s public contract puts MCP in .mcp.json. Following both docs in one repo is how dual-client vendors will keep packaging this — Figma’s mcp-server-guide is the same shape (Cursor + Claude in one git tree).

Anyone else aiming for adoption on both IDEs will hit the same filename pair. If those two files ever diverge (hosted vs local stdio, different env, a leftover uvx on the Claude side), the Cursor Marketplace clone can start the wrong server while the listing still describes the hosted one. This is not unique to us; it is the default layout two public plugin specs produce when they share a repo.

Expected

Per the plugins reference:

  1. Default discovery for a Cursor plugin is mcp.json at the plugin root.
  2. .mcp.json is not the Cursor plugin contract (it is Claude Code’s).
  3. If both files exist, Cursor should either:
    • load mcp.json only, or
    • document a deterministic precedence (and warn when the two payloads differ).

The submit scanner and the authoring docs should name the same files and the same precedence.

Actual

Installing from the Marketplace cloned the entire GitHub repo into the plugin cache. Both files sat at the plugin root. With no mcpServers pin (we followed the docs: omit the field so mcp.json is auto-discovered), Cursor connected to the server in .mcp.json, not mcp.json.

A local plugin copy that only included mcp.json behaved as documented (hosted URL). The Marketplace clone did not.

Reproduction

Minimal dual-client plugin root (the layout two marketplaces independently document):

.cursor-plugin/plugin.json — no mcpServers (rely on default discovery):

{
  "name": "example",
  "displayName": "Example",
  "version": "0.1.0"
}

.claude-plugin/plugin.json — Claude Code plugin in the same repo (MCP is not inlined; it auto-discovers .mcp.json).

mcp.json (Cursor / hosted — what the listing should run):

{
  "mcpServers": {
    "example": {
      "url": "https://mcp.example.com/mcp",
      "auth": { "CLIENT_ID": "example-mcp" }
    }
  }
}

.mcp.json (Claude Code / local stdio — different payload on purpose):

{
  "mcpServers": {
    "example": {
      "command": "uvx",
      "args": ["example-mcp-server"]
    }
  }
}

Steps:

  1. Submit or install this repo as a Cursor Marketplace plugin (clone of the GitHub root).
  2. Open the installed plugin’s MCP server.
  3. Observe which config was used.

Result: the clone started uvx example-mcp-server from .mcp.json.
Expected: hosted https://mcp.example.com/mcp from mcp.json.

Workaround that unblocked us

  1. One hosted payload in .mcp.json only (same file Claude Code auto-discovers).
  2. Explicit pin: "mcpServers": "./.mcp.json" in .cursor-plugin/plugin.json.
  3. Do not leave a sibling mcp.json with a different server.

This matches the documented custom-path override, and is what figma/mcp-server-guide does (single .mcp.json + pin; no root mcp.json).

Request

  1. Document precedence when mcp.json and .mcp.json both exist at the plugin root.
  2. Align the Marketplace scanner text (Bug Report: Marketplace scanner ignores .plugin/plugin.json manifest and custom component paths #43) with the plugins reference (today the scanner lists both names; the reference only documents mcp.json).
  3. In the authoring / submit docs, warn dual Cursor + Claude Code authors: shipping both filenames is the natural adoption layout; different payloads can make the Marketplace clone start the wrong server. Pin mcpServers or keep a single shared file.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions