OneLinersCommand workbench
Guides
AI/ML / Software Engineering / Security

Package a Claude Code plugin with a skill, subagent, and local MCP server

Build and verify a default-off Claude Code plugin that packages a manually invoked review skill, a genuinely read-only plugin subagent, a local stdio MCP policy tool, exact runtime dependencies, and a distributable marketplace entry without embedding credentials or pretending that descriptive annotations enforce authorization.

210 min14 stepsChanges system stateRevision 1
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 14 steps completed
Goal

Produce a versioned extension bundle that a team can inspect before trust, validate mechanically, install in local scope for a canary, disable immediately, and later distribute through a reviewed marketplace while keeping plugin-agent limitations, MCP approval, component namespacing, version ownership, and supply-chain evidence explicit.

Supported environments
  • Claude Code 2.1.218 or later
  • Node.js 22 LTS
  • MCP TypeScript server package @modelcontextprotocol/server 2.0.0
  • Zod 4.4.3
Prerequisites
  • Disposable marketplace repository Use a clean test repository owned by the team. It must not contain production credentials, unpublished customer data, private signing material, or an existing marketplace whose behavior would be changed by this exercise.git status --short && git rev-parse --show-toplevel
  • Supported Claude Code and Node runtimes Confirm the tested Claude Code release understands defaultEnabled, current skill fields, plugin validation, plugin-agent field restrictions, and project MCP approvals. Use Node 22 LTS for the local ESM server.claude --version && claude doctor && node --version && npm --version
  • Human review owner Assign a maintainer who reviews every Markdown instruction, executable dependency, MCP tool, update, revocation, and marketplace source before another user installs it.
  • Independent recovery path Know how to disable or uninstall the plugin from outside the active session, reset project MCP approvals, revoke any separately issued credentials, and restore the last reviewed marketplace revision.
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A complete Claude Code marketplace repository containing a stable default-off plugin, a manually invoked SKILL.md workflow, a scoped read-only subagent, a local stdio MCP policy server, exact dependencies, and deterministic contract tests.
  • A three-layer validation and release process that separates static organization policy, Claude Code schema validation, and live canary behavior instead of presenting any one check as comprehensive proof.
  • An operational disable and recovery path that handles plugin state, MCP approval, marketplace registration, dependency provenance, active sessions, and external credentials as separate concerns.
Observable outcome
  • A reviewer can trace every discovered component to one documented path and one stable namespace.
  • The plugin does not run by default, the skill cannot auto-invoke, the delegated agent resolves only Read, Glob, and Grep, and the MCP server returns constant policy without file, network, shell, or secret access.
  • A canary operator can install version 1.0.0 locally, observe MCP approval, invoke one review on a public fixture, verify negative requests, and disable the bundle without modifying shared project settings.
  • A release owner can tie distribution to one commit, lockfile digest, matching manifest versions, validation record, and tested incident procedure.

Architecture

How the parts fit together

The marketplace catalog locates a versioned plugin. The plugin contributes three independent Claude Code extension surfaces: a manual skill orchestrates intent, a namespaced subagent performs bounded repository inspection, and a local MCP server returns static policy. Static tests validate files, Claude Code validates supported schemas, and a human canary validates discovery, approval, and observed refusals.

Marketplace manifestOwns the non-reserved company-tools catalog identity and resolves the local plugin source from the marketplace root.
Plugin manifestOwns the stable safe-repository-review namespace, version, metadata, and default-off installation behavior.
Repository-review skillRequires explicit user invocation, retrieves reviewed policy in the main context, delegates one approved scope, and defines stop behavior.
Read-only reviewer agentUses only Read, Glob, and Grep to collect repository-relative path-and-line evidence, with no mutation, shell, web, nested agent, or MCP capability.
Repository-policy MCP serverRuns as a local Node stdio process after approval and returns one of three immutable policy sections through a schema-validated read-only tool.
Contract and canary gatesCheck organization invariants, Claude-supported structure, dependency resolution, installed inventory, approval behavior, positive evidence, and negative boundaries.
  1. A maintainer reviews the source tree, exact dependencies, manifests, Markdown instructions, executable server, and rollback ownership.
  2. The semantic harness parses the marketplace and plugin files and rejects unsafe drift that generic schema validation would not understand.
  3. Claude Code validates the marketplace and plugin components in strict mode without installing them.
  4. An operator registers the marketplace and installs the plugin in local scope, reloads components, and makes a separate decision about the plugin MCP server.
  5. The user explicitly invokes the namespaced skill with a narrow public path or question.
  6. The main flow retrieves static boundary, evidence, and escalation policy from the approved local MCP tool, then delegates to the scoped read-only agent.
  7. The agent collects minimal repository evidence with Read, Glob, and Grep, returns facts and unknowns, and stops when the request requires another tool or protected source.
  8. A release owner reviews positive and negative canary evidence and either rejects the revision or publishes one immutable, recoverable version.

Assumptions

  • The marketplace and plugin are maintained by an identified team in a repository with protected review and release controls.
  • Claude Code 2.1.218 or later is used so documented plugin, skill, agent, default enablement, reload, and strict validation behavior matches the Guide.
  • Node 22 LTS is already installed from a trusted source and the approved npm registry is reachable only during dependency resolution.
  • The review target is a disposable or public fixture with explicit scope; production secrets, credential stores, generated keys, and customer data are excluded.
  • The operator understands that workspace trust, plugin enablement, skill invocation, agent tools, and MCP server approval are separate gates.
  • The local MCP server is not granted operating-system sandboxing by its annotations and therefore remains safe by having no file, network, shell, or credential code path.
  • A human can disable the plugin and reset MCP choices from outside a malfunctioning active session.

Key concepts

Marketplace source
The catalog location registered with Claude Code. It can be pinned to a branch or tag but is distinct from an individual plugin source.
Plugin source
The directory, repository, subdirectory, URL, or package an entry installs. Supported repository source objects can include a full commit SHA.
Component namespace
The stable plugin name prefixed to skills, agents, MCP server identities, and install references to prevent cross-plugin ambiguity.
SKILL.md
A lazily loaded Markdown workflow. Manual invocation can be enforced with disable-model-invocation, but its instructions are not an operating-system sandbox.
Plugin subagent
A namespaced agent definition shipped by a plugin. It supports tool reduction but ignores hooks, mcpServers, and permissionMode fields for security reasons.
MCP approval
The user's separate trust decision for a project or plugin-provided server. Installing or enabling a plugin does not make arbitrary server code inherently safe.
Tool annotation
Metadata such as readOnlyHint that helps clients present expected behavior. It does not enforce authorization or prove implementation behavior.
Semantic contract test
A deterministic test of organization-specific invariants, such as manual invocation and forbidden ignored fields, beyond generic schema correctness.

Before you copy

Values used in this guide

{{marketplaceName}}

Stable, non-reserved marketplace identifier used by install and lifecycle commands.

Example: company-tools
{{pluginName}}

Stable plugin identity used to namespace its skill, agent, MCP server, and settings.

Example: safe-repository-review
{{pluginVersion}}

Semantic release version changed whenever instruction or executable behavior changes.

Example: 1.0.0
{{pluginCommitSha}}

Full reviewed source commit recorded in release evidence or a remote plugin source object.

Example: 7f4a2e13c0190fdb22ec6908ed63e16b4d4288f1
{{reviewScope}}

Repository-relative public path or concrete question authorized for one manual review.

Example: src/config/public-options.ts

Security and production boundaries

  • Review every plugin as code. Skills and agents can change model behavior, while MCP servers and other executable components run with user privileges unless separately constrained.
  • The `defaultEnabled: false` field prevents automatic enablement only for supported clients with no overriding user state. It does not replace workspace trust, source review, or a kill switch.
  • Manual skill invocation expresses intent but does not restrict tools. The agent's three-tool allowlist is the concrete delegated reduction in this design.
  • Plugin-shipped agent fields `hooks`, `mcpServers`, and `permissionMode` are ignored. Their presence would create misleading documentation, so the contract test rejects them.
  • Read-only tools can disclose secrets. Scope selection and explicit protected-path refusal remain necessary even when no mutation tool is available.
  • The MCP server's annotations are hints. The implementation is safe only because the tool accepts a closed enum and returns constant text without filesystem, shell, network, or secret access.
  • Package lock integrity, npm audit output, a Git commit, and a checksum are useful evidence but are not code signatures unless a verified signing and identity system is separately deployed.
  • Disablement, uninstallation, MCP approval reset, marketplace removal, credential revocation, and active-session termination solve different parts of an incident.

Stop before continuing if

  • Any manifest, skill, agent, MCP config, server, package, lockfile, or marketplace source differs from the reviewed revision.
  • The target Claude Code release is too old to honor the documented fields or produces strict validation warnings.
  • The plugin agent contains an ignored security field or resolves a state-changing, web, nested-agent, or MCP tool.
  • The MCP server reads files, accepts arbitrary paths or URLs, uses environment credentials, spawns a process, reaches the network, or writes application output to stdout.
  • A dependency is unapproved, floating, unexpectedly changed, executes an install hook, or has an unresolved security finding outside policy.
  • The canary does not prompt for the expected MCP trust decision or a negative request finds a fallback path.
  • Distribution cannot be tied to one reviewed commit and version or cannot be disabled and recovered by an identified owner.
01

verification

Record the clean extension baseline

read-only

Start at the marketplace repository root and record source-control state plus the exact Claude Code, Node, and npm versions. The reference depends on recently documented plugin, skill, and MCP behavior, so an unrecorded older client is not an acceptable canary.

Why this step matters

A plugin mixes model instructions and executable code. Recording the clean root and runtime versions before any file is created makes later validation, review, rollback, and compatibility claims traceable to one known starting point.

What to understand

An empty first line from `git status --short` means the checkout is clean; the example therefore begins with the repository root.

Stop if Claude Code is older than the minimum documented by this Guide or if Node is outside the team-supported LTS line.

Do not run this procedure in a repository that Claude already trusts until its current plugins, settings, and MCP approvals are inventoried.

System changes

  • No files or Claude Code settings are changed by this baseline.

Syntax explained

git status --short
Produces a compact change list; no output is the expected clean state.
claude --version
Pins the client behavior used for component discovery and validation.
Command
git status --short && git rev-parse --show-toplevel && claude --version && node --version && npm --version
Example output / evidence
/work/claude-marketplace
2.1.220 (Claude Code)
v22.19.0
10.9.3

Checkpoint: Confirm a clean, supported canary root

git status --short && git rev-parse --show-toplevel && claude --version && node --version && npm --version

Continue whenThe checkout is clean, the top-level directory is correct, Claude Code is supported, and Node reports the approved LTS major.

Stop whenThe checkout contains unrelated work, a runtime is unsupported, or the repository already distributes unreviewed executable extensions.

If this step fails

The checkout is not clean.

Likely causeAnother task or generated file already changed the marketplace repository.

Safe checks
  • Run `git status --short`
  • Identify the owner of every path

ResolutionUse a fresh worktree or wait for the existing owner; do not fold unrelated files into this plugin.

Stop conditions

  • The checkout contains unrelated work, a runtime is unsupported, or the repository already distributes unreviewed executable extensions.
02

command

Create the marketplace and plugin layout

caution

Create only the documented default component directories. The marketplace manifest belongs at the repository root under `.claude-plugin`; the plugin manifest is inside the plugin; skills, agents, MCP configuration, server code, and tests live at the plugin root rather than inside its metadata directory.

Why this step matters

Claude Code discovers components by path. A plausible file in the wrong directory may be silently ignored, producing a plugin that passes an informal visual review but exposes none of the intended behavior.

What to understand

Only metadata files belong inside a component's `.claude-plugin` directory.

The skill uses the `<name>/SKILL.md` directory form recommended for new plugins.

The local marketplace source later resolves from the marketplace root, not from `.claude-plugin/marketplace.json`.

System changes

  • Creates the new `claude-marketplace/` tree and empty component directories.

Syntax explained

mkdir -p
Creates the complete reviewed directory set without failing when a parent already exists.
find ... -type d
Prints directory evidence without reading file contents or executing plugin code.
Command
mkdir -p claude-marketplace/.claude-plugin claude-marketplace/plugins/safe-repository-review/.claude-plugin claude-marketplace/plugins/safe-repository-review/skills/repository-review claude-marketplace/plugins/safe-repository-review/agents claude-marketplace/plugins/safe-repository-review/mcp claude-marketplace/plugins/safe-repository-review/test && find claude-marketplace -type d -print | sort
Example output / evidence
claude-marketplace
claude-marketplace/.claude-plugin
claude-marketplace/plugins
claude-marketplace/plugins/safe-repository-review
claude-marketplace/plugins/safe-repository-review/.claude-plugin
claude-marketplace/plugins/safe-repository-review/agents
claude-marketplace/plugins/safe-repository-review/mcp
claude-marketplace/plugins/safe-repository-review/skills
claude-marketplace/plugins/safe-repository-review/skills/repository-review
claude-marketplace/plugins/safe-repository-review/test

Checkpoint: Compare the tree with documented plugin locations

mkdir -p claude-marketplace/.claude-plugin claude-marketplace/plugins/safe-repository-review/.claude-plugin claude-marketplace/plugins/safe-repository-review/skills/repository-review claude-marketplace/plugins/safe-repository-review/agents claude-marketplace/plugins/safe-repository-review/mcp claude-marketplace/plugins/safe-repository-review/test && find claude-marketplace -type d -print | sort

Continue whenEvery listed directory is beneath the marketplace root and none of the component directories is nested inside the plugin metadata directory.

Stop whenA path escapes the intended repository, collides with an existing plugin, or places executable components under `.claude-plugin`.

If this step fails

Claude Code later reports a missing component.

Likely causeThe component was created in a plausible but unsupported directory.

Safe checks
  • Compare the printed tree with the step output
  • Check case and hyphen spelling

ResolutionMove the file to the documented plugin-root location and rerun strict validation.

Security notes

  • Do not copy an existing plugin tree until every executable and symlink target has been reviewed.

Alternatives

  • Use `claude plugin init` for a disposable scaffold, then compare and replace every generated example before review.

Stop conditions

  • A path escapes the intended repository, collides with an existing plugin, or places executable components under `.claude-plugin`.
03

config

Pin the local MCP runtime

caution

Save the complete package manifest at the plugin root. Exact versions and a committed lockfile make the executable portion reviewable; lifecycle scripts from dependencies remain disabled during the first installation step.

Why this step matters

A local MCP server is code executed with the user's privileges when the plugin starts. Floating dependencies or hidden install scripts turn a reviewed plugin into an unbounded supply-chain decision at install time.

What to understand

`private` prevents accidental npm publication from this directory.

`type: module` matches the ESM imports used by the current MCP server package.

The test scripts separate pure MCP policy behavior from the whole plugin contract.

System changes

  • Adds a package manifest but does not download or execute dependencies yet.

Syntax explained

@modelcontextprotocol/server: 2.0.0
Pins the current server package that supports the stdio serving entry used below.
zod: 4.4.3
Pins the schema implementation used to validate the MCP tool argument.
File claude-marketplace/plugins/safe-repository-review/package.json
Configuration
{
  "name": "safe-repository-review-plugin",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "test:contract": "node test/plugin-contract.mjs ../..",
    "test:mcp": "node mcp/repository-policy.mjs --self-test"
  },
  "dependencies": {
    "@modelcontextprotocol/server": "2.0.0",
    "zod": "4.4.3"
  }
}
Example output / evidence
package.json valid: module=esm server=2.0.0 zod=4.4.3 scripts=2

Checkpoint: Parse the package manifest

Continue whenA JSON parser reports ESM mode, two exact dependencies, and two explicit test scripts.

Stop whenAny dependency is floating, an install lifecycle script appears, or the selected packages are not approved by the team's dependency policy.

If this step fails

The package manifest does not parse.

Likely causeA manual edit introduced invalid JSON or a copied comment.

Safe checks
  • Run `node -e "JSON.parse(require('fs').readFileSync('package.json'))"`
  • Inspect only the reported line

ResolutionRestore the exact reviewed manifest and validate it before installing packages.

Security notes

  • The lockfile produced later is evidence of resolution, not proof that package code is safe.

Alternatives

  • Bundle a reviewed standalone executable when the organization cannot permit a Node dependency tree.

Stop conditions

  • Any dependency is floating, an install lifecycle script appears, or the selected packages are not approved by the team's dependency policy.
04

config

Declare a stable, default-off plugin

caution

Create the plugin manifest with one stable kebab-case identity and an explicit version. Keep executable component paths at their documented defaults so strict validation and human review can compare the on-disk tree directly.

Why this step matters

The plugin name becomes a persistent namespace for skills, agents, MCP servers, settings, and marketplace installs. Changing it later breaks references, while default-on behavior could start code before a user understands the added scope.

What to understand

The display name is presentation only; the stable `name` remains the installation identity.

The plugin version, not a marketing label, must change whenever executable or instruction behavior changes.

`defaultEnabled: false` is defense in depth for current clients; older unsupported clients are excluded rather than assumed to honor it.

System changes

  • Adds plugin metadata and makes the reviewed default state disabled.

Syntax explained

name
Defines the stable namespace used by installed components.
defaultEnabled: false
Requires an explicit enable decision when no existing user setting overrides it.
File claude-marketplace/plugins/safe-repository-review/.claude-plugin/plugin.json
Configuration
{
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
  "name": "safe-repository-review",
  "displayName": "Safe Repository Review",
  "version": "1.0.0",
  "description": "Manual, read-only repository review with a scoped agent and local policy lookup tool.",
  "author": {
    "name": "Platform Engineering"
  },
  "license": "MIT",
  "keywords": [
    "repository-review",
    "read-only",
    "mcp",
    "skill",
    "subagent"
  ],
  "defaultEnabled": false
}
Example output / evidence
plugin manifest valid: name=safe-repository-review version=1.0.0 defaultEnabled=false

Checkpoint: Confirm identity, version, and opt-in state

Continue whenThe manifest parses with the exact stable name, version 1.0.0, and defaultEnabled set to false.

Stop whenThe stable name conflicts with another plugin, the version was reused for different content, or the target Claude Code release ignores the opt-in field.

If this step fails

The plugin appears under an unexpected name.

Likely causeThe marketplace entry and plugin manifest use different identities or an old install remains cached.

Safe checks
  • Compare both `name` fields
  • Inspect `claude plugin list --json`

ResolutionChoose one stable identity, remove the canary install, clear only its reviewed cache through supported commands, and reinstall.

Security notes

  • A default-off manifest does not replace source review or the workspace trust and MCP approval gates.

Alternatives

  • Use a personal `@skills-dir` canary before publishing a marketplace when distribution is not yet required.

Stop conditions

  • The stable name conflicts with another plugin, the version was reused for different content, or the target Claude Code release ignores the opt-in field.
05

config

Implement a deterministic local MCP policy tool

caution

Add the complete stdio MCP server. It returns three constant policy sections, validates the requested topic, exposes only one read-only tool, performs no file or network access, writes protocol data only through the SDK, and sends its startup message to stderr.

Why this step matters

A tiny deterministic server makes the executable trust boundary inspectable. The tool annotations improve client presentation but the implementation itself must remain read-only because annotations are descriptive hints rather than authorization enforcement.

What to understand

`z.enum` rejects unsupported topics before the handler receives them.

`serveStdio` owns protocol input and output; application diagnostics go to stderr so stdout cannot corrupt JSON-RPC.

The self-test exercises the pure policy function without pretending to test Claude Code approval or a full MCP handshake.

System changes

  • Adds executable JavaScript that starts when the plugin MCP server is approved and connected.

Syntax explained

readOnlyHint: true
Describes expected tool behavior to the client but does not grant or enforce filesystem permissions.
serveStdio(createServer)
Creates a server instance for the negotiated stdio connection using the current MCP server package.
File claude-marketplace/plugins/safe-repository-review/mcp/repository-policy.mjs
Configuration
import assert from "node:assert/strict";
import { fileURLToPath } from "node:url";
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";

const POLICIES = Object.freeze({
  boundaries: [
    "Read only files inside the repository root.",
    "Never request, read, print, or summarize secrets.",
    "Do not edit files, run shell commands, or call network tools."
  ],
  evidence: [
    "Cite repository-relative paths and line numbers.",
    "Separate observed facts from inferences.",
    "Report uncertainty and missing evidence explicitly."
  ],
  escalation: [
    "Stop when evidence requires a protected path or external system.",
    "Ask the operator to collect approved evidence instead of widening access.",
    "Treat MCP annotations as hints, not an authorization boundary."
  ]
});

export function policyFor(topic) {
  if (!Object.hasOwn(POLICIES, topic)) {
    throw new Error("unsupported policy topic");
  }
  return POLICIES[topic].join("\n");
}

export function createServer() {
  const server = new McpServer(
    { name: "repository-policy", version: "1.0.0" },
    {
      instructions:
        "This server returns static review policy. It does not read files, use the network, or mutate state."
    }
  );

  server.registerTool(
    "repository_policy",
    {
      title: "Repository review policy",
      description:
        "Return one reviewed policy section for a read-only repository review.",
      inputSchema: z.object({
        topic: z.enum(["boundaries", "evidence", "escalation"])
      }),
      annotations: {
        readOnlyHint: true,
        destructiveHint: false,
        idempotentHint: true,
        openWorldHint: false
      }
    },
    async ({ topic }) => ({
      content: [{ type: "text", text: policyFor(topic) }]
    })
  );

  return server;
}

const isMain = process.argv[1] === fileURLToPath(import.meta.url);
if (isMain && process.argv.includes("--self-test")) {
  assert.match(policyFor("boundaries"), /Read only files/);
  assert.match(policyFor("evidence"), /line numbers/);
  assert.throws(() => policyFor("unknown"));
  console.log("MCP_POLICY_OK topics=3 network=none writes=none");
} else if (isMain) {
  console.error("repository-policy MCP server running on stdio");
  void serveStdio(createServer);
}
Example output / evidence
MCP_POLICY_OK topics=3 network=none writes=none

Checkpoint: Review implementation before dependency installation

Continue whenThe file contains one static tool, one enum input, no filesystem or fetch import, no stdout logging in server mode, and a deterministic self-test branch.

Stop whenThe server reads environment secrets, accepts paths or URLs, starts a shell, writes files, uses the network, or prints non-protocol text to stdout.

If this step fails

The MCP client reports malformed protocol output.

Likely causeApplication logging or another process wrote to stdout.

Safe checks
  • Run the self-test separately
  • Inspect server-mode logging calls

ResolutionMove diagnostics to stderr and leave stdout exclusively to the stdio transport.

Security notes

  • MCP tool descriptions and annotations are untrusted metadata from an authorization perspective; enforce boundaries in code and client policy.
  • Do not add elicitation for secrets. Obtain credentials out of band only when a future server genuinely requires them.

Alternatives

  • Store the same static policy in a skill reference file if no callable MCP tool is operationally necessary.

Stop conditions

  • The server reads environment secrets, accepts paths or URLs, starts a shell, writes files, uses the network, or prints non-protocol text to stdout.
06

config

Bind the plugin MCP server without embedded secrets

caution

Create `.mcp.json` at the plugin root. Use `node` as a fixed executable and the plugin-root substitution for the bundled server path. Do not include an `env` object because this policy tool needs no credential or user configuration.

Why this step matters

Marketplace plugins are copied into a versioned cache, so working-directory-relative paths are fragile. The documented plugin-root substitution resolves the bundled file inside the installed copy without hard-coded personal paths.

What to understand

Plugin-provided MCP configuration can substitute `${CLAUDE_PLUGIN_ROOT}` directly.

A project-scope plugin still requires the user's per-server MCP approval after workspace trust.

The server key contributes to the scoped MCP tool name and therefore becomes part of the extension interface.

System changes

  • Declares one local stdio process that Claude Code may start after plugin enablement and required approval.

Syntax explained

command: node
Invokes the reviewed Node runtime from PATH without a shell wrapper.
${CLAUDE_PLUGIN_ROOT}
Resolves the server path inside the installed plugin cache.
File claude-marketplace/plugins/safe-repository-review/.mcp.json
Configuration
{
  "mcpServers": {
    "repository-policy": {
      "command": "node",
      "args": [
        "${CLAUDE_PLUGIN_ROOT}/mcp/repository-policy.mjs"
      ]
    }
  }
}
Example output / evidence
MCP config valid: server=repository-policy command=node args=1 env=absent

Checkpoint: Parse and inspect the MCP entry

Continue whenThe config contains one server, a fixed executable, one plugin-local argument, and no headers, URLs, environment secrets, or shell string.

Stop whenThe command downloads a package at startup, embeds a token, depends on the caller's current directory, or points outside the plugin.

If this step fails

The server is missing from `/mcp`.

Likely causeThe config was misplaced, the plugin was not reloaded, approval was denied, or the runtime path failed.

Safe checks
  • Run `/reload-plugins`
  • Inspect `claude --debug` without copying secrets

ResolutionCorrect the reviewed path or approval state; do not bypass project MCP policy.

Security notes

  • Never commit `${TOKEN}` placeholders merely because expansion exists; missing variables can remain unexpanded and still produce confusing startup behavior.

Alternatives

  • Define an HTTP MCP server only when centralized operation, authentication, audit, transport security, and availability are separately engineered.

Stop conditions

  • The command downloads a package at startup, embeds a token, depends on the caller's current directory, or points outside the plugin.
07

config

Add a manually invoked review skill

caution

Create the namespaced `repository-review` skill. It is deliberately unavailable for model-initiated invocation, requires explicit user scope, checks MCP connection before delegation, names the packaged read-only agent, and forbids edits, commands, browsing, and secret requests.

Why this step matters

A review can expose sensitive repository content and spend substantial tokens. Manual invocation makes user intent explicit, while the skill supplies a repeatable orchestration contract instead of relying on an ambiguous natural-language prompt.

What to understand

`disable-model-invocation: true` prevents Claude from deciding to launch this workflow automatically.

Plugin skills are invoked under the installed plugin namespace, so users see `/safe-repository-review:repository-review`.

The instruction treats MCP connection and approval as prerequisites; it does not silently fall back to a different tool or invent policy text.

System changes

  • Adds persistent instructions that enter the conversation only when the user invokes the skill.

Syntax explained

disable-model-invocation: true
Restricts invocation to an explicit user action and removes automatic skill dispatch.
argument-hint
Shows the expected path or question without interpreting it as permission to widen scope.
File claude-marketplace/plugins/safe-repository-review/skills/repository-review/SKILL.md
Configuration
---
name: repository-review
description: Perform a manual, read-only review of repository code or configuration and return path-and-line evidence. Use only when the user explicitly asks for a repository review.
argument-hint: "[path-or-question]"
disable-model-invocation: true
---

Review $ARGUMENTS without changing the repository.

1. Confirm the requested scope and exclusions.
2. In the main conversation, inspect `/mcp` and call the plugin's
   `repository_policy` tool for `boundaries`, `evidence`, and
   `escalation`. Stop if the server is not connected or approval was denied.
3. Delegate the scoped inspection to
   `safe-repository-review:read-only-reviewer`.
4. Require repository-relative paths and line numbers for every finding.
5. Separate facts, inferences, unknowns, and suggested follow-up.
6. Do not edit files, execute commands, browse the network, or request secrets.
7. Return "No supported finding" when the available evidence does not support
   a concrete issue.

The MCP tool's read-only annotation is a client hint, not enforcement. The
agent's `tools` allowlist is the operative reduction for the delegated review.
Example output / evidence
skill valid: name=repository-review invocation=manual agent=safe-repository-review:read-only-reviewer

Checkpoint: Inspect the skill's invocation and failure behavior

Continue whenThe skill is manual, names one scoped plugin agent, requires the policy MCP tool, and states that missing connection or approval is a stop rather than a fallback.

Stop whenThe skill can auto-run, grants broad tools, treats an arbitrary argument as a shell command, or allows a review to continue without the required evidence boundary.

If this step fails

The skill does not appear under the expected command.

Likely causeIts path, frontmatter, namespace, or loaded plugin revision is wrong.

Safe checks
  • Inspect `/plugin` component inventory
  • Run strict plugin validation

ResolutionFix the file path or frontmatter, reload plugins, and confirm the installed revision before invoking it.

Security notes

  • The skill body is model instruction, not a sandbox. The delegated agent's actual tool set and the session's permission policy still matter.

Alternatives

  • Use a project-local `.claude/skills/` skill while the workflow is still specific to one repository and not ready for distribution.

Stop conditions

  • The skill can auto-run, grants broad tools, treats an arbitrary argument as a shell command, or allows a review to continue without the required evidence boundary.
08

config

Add a genuinely read-only plugin subagent

caution

Create the plugin agent with only Read, Glob, and Grep. Do not add `hooks`, `mcpServers`, or `permissionMode`: Claude Code ignores those fields for plugin-shipped agents. The MCP policy call remains in the main skill flow, while the delegated inspection receives a narrow built-in tool allowlist.

Why this step matters

A reassuring prompt cannot remove tools. The supported `tools` field creates the auditable reduction for this plugin agent, while explicitly omitting ignored security fields prevents reviewers from believing nonexistent enforcement is active.

What to understand

Plugin agents appear under a scoped name formed from the plugin and agent names.

The agent cannot run Bash or PowerShell, edit files, browse, spawn another agent, or call MCP tools because none are in its allowlist.

The body still defines protected-content behavior because read-only file access can disclose secrets even without mutations.

System changes

  • Adds a discoverable subagent definition with a three-tool read-only allowlist.

Syntax explained

tools: Read, Glob, Grep
Restricts the plugin agent to locating and reading approved repository evidence.
background: false
Returns the delegated result in the invoking turn and avoids a background edit path, though the tool allowlist remains the primary boundary.
File claude-marketplace/plugins/safe-repository-review/agents/read-only-reviewer.md
Configuration
---
name: read-only-reviewer
description: Inspect a user-approved repository scope and report evidence-backed correctness, reliability, or security concerns without editing files or running commands.
tools: Read, Glob, Grep
model: sonnet
effort: medium
maxTurns: 12
background: false
---

You are a read-only repository reviewer.

Boundaries:
- Stay inside the scope named in the delegation message.
- Never read common secret files, credential directories, generated key
  material, or paths outside the repository.
- Do not ask for Bash, PowerShell, Write, Edit, WebFetch, WebSearch, Agent, or
  MCP tools.
- Do not treat absence of evidence as proof of safety.

Method:
1. Restate scope and exclusions.
2. Locate only files needed for the stated question.
3. Read the smallest useful ranges.
4. For each candidate, cite a repository-relative path and line number,
   describe the observed behavior, and explain the concrete impact.
5. Reject speculative candidates that lack a traceable source-to-effect path.
6. Finish with findings ordered by severity, then unknowns and safe follow-up.

Do not modify the repository. If the evidence requires an unavailable tool,
protected file, external service, or runtime execution, stop and state exactly
what an authorized operator must collect.
Example output / evidence
agent valid: scoped-name=safe-repository-review:read-only-reviewer tools=Read,Glob,Grep unsupported-fields=0

Checkpoint: Reject unsupported security fields

Continue whenThe agent frontmatter contains the exact three-tool allowlist and no hooks, mcpServers, permissionMode, Write, Edit, shell, web, or Agent capability.

Stop whenValidation resolves zero tools, any state-changing capability appears, or a reviewer claims ignored plugin-agent fields enforce security.

If this step fails

The agent can access an unexpected tool.

Likely causeAnother definition won precedence, the installed revision is stale, or the review observed the parent session rather than the delegated agent.

Safe checks
  • Inspect the scoped agent in `/agents`
  • Check plugin source and installed version

ResolutionDisable the plugin, identify the active definition, correct the allowlist, reinstall the canary, and repeat the negative test.

Security notes

  • Read, Glob, and Grep can still expose secrets. The agent must stay in user-approved paths and stop at protected content.
  • Plugin-agent `permissionMode`, `mcpServers`, and `hooks` fields are unsupported and ignored; never use them as evidence.

Alternatives

  • Copy an agent into `.claude/agents/` only when project-specific MCP or permission fields are genuinely required and independently reviewed.

Stop conditions

  • Validation resolves zero tools, any state-changing capability appears, or a reviewer claims ignored plugin-agent fields enforce security.
09

config

Publish one locally resolvable marketplace entry

caution

Create the marketplace manifest at its required root location. The entry points to the plugin directory with a `./` relative source, repeats the public version for reviewer visibility, and uses a non-reserved marketplace identity owned by the team.

Why this step matters

The marketplace is a distribution catalog, not the plugin itself. Keeping the local canary source inside one repository makes the initial test reproducible, while stable identities and matching versions prevent ambiguous installs.

What to understand

Relative plugin sources resolve from the marketplace root and must begin with `./`.

A local path is appropriate for this canary and for a plugin stored in the same marketplace repository.

For a separately hosted production plugin, replace the source with a reviewed GitHub or Git URL object and a full forty-character `sha`; a marketplace source itself supports a ref, not a sha.

System changes

  • Adds a catalog entry that can be registered and installed through Claude Code's marketplace commands.

Syntax explained

name: company-tools
Defines the non-reserved marketplace namespace used by install commands.
source: ./plugins/safe-repository-review
Resolves the plugin from the same reviewed marketplace checkout.
File claude-marketplace/.claude-plugin/marketplace.json
Configuration
{
  "$schema": "https://json.schemastore.org/claude-code-marketplace.json",
  "name": "company-tools",
  "owner": {
    "name": "Platform Engineering"
  },
  "description": "Reviewed Claude Code extensions for internal engineering work.",
  "version": "1.0.0",
  "plugins": [
    {
      "name": "safe-repository-review",
      "source": "./plugins/safe-repository-review",
      "description": "Manual read-only repository review with explicit evidence boundaries.",
      "version": "1.0.0",
      "category": "development",
      "tags": [
        "review",
        "read-only",
        "mcp"
      ]
    }
  ]
}
Example output / evidence
marketplace valid: name=company-tools plugins=1 source=./plugins/safe-repository-review version=1.0.0

Checkpoint: Match marketplace and plugin identities

Continue whenThe marketplace has one plugin, the source stays inside its root, and both manifest versions are 1.0.0.

Stop whenThe marketplace name is reserved or misleading, a relative source traverses with `..`, or the marketplace and plugin versions disagree.

If this step fails

Marketplace validation cannot find the plugin.

Likely causeThe source was resolved relative to the metadata directory instead of the marketplace root.

Safe checks
  • Inspect the source beginning with `./`
  • Run validation from `claude-marketplace/`

ResolutionRestore the documented root-relative path and validate the marketplace plus the individual plugin.

Security notes

  • A branch or tag can move. Use an exact plugin-source SHA where immutable production provenance is required and record the reviewed commit separately.

Alternatives

  • Distribute one plugin repository directly during a private pilot, then add a marketplace only when multiple users need supported installation and updates.

Stop conditions

  • The marketplace name is reserved or misleading, a relative source traverses with `..`, or the marketplace and plugin versions disagree.
10

config

Add a deterministic extension contract test

caution

Save the complete Node harness inside the plugin. It parses both manifests and `.mcp.json`, verifies the manual skill and scoped agent contract, rejects ignored plugin-agent security fields, checks exact dependencies, imports the pure policy function, and never launches Claude Code or an MCP client.

Why this step matters

Claude's validator checks supported schemas, but it cannot express the team's semantic requirements. The local harness turns critical policy choices into repeatable assertions without claiming to prove runtime approval or model behavior.

What to understand

The test fails if an ignored `hooks`, `mcpServers`, or `permissionMode` field appears in the plugin agent.

It checks for absence of MCP `env`, exact runtime versions, and the literal installed-plugin root substitution.

Importing `policyFor` tests deterministic content without opening stdio or starting a long-lived server.

System changes

  • Adds a test file that reads plugin artifacts and imports only the pure MCP policy function.

Syntax explained

process.argv[2]
Accepts the marketplace root explicitly so the harness does not rely on a caller's implicit working directory.
assert.equal / assert.match
Fails closed when an identity, path, field, version, or policy invariant changes.
File claude-marketplace/plugins/safe-repository-review/test/plugin-contract.mjs
Configuration
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { policyFor } from "../mcp/repository-policy.mjs";

const marketplaceRoot = path.resolve(process.argv[2] ?? ".");
const pluginRoot = path.join(
  marketplaceRoot,
  "plugins",
  "safe-repository-review"
);

const read = (relative) =>
  fs.readFileSync(path.join(pluginRoot, relative), "utf8");
const json = (relative) => JSON.parse(read(relative));

const marketplace = JSON.parse(
  fs.readFileSync(
    path.join(marketplaceRoot, ".claude-plugin", "marketplace.json"),
    "utf8"
  )
);
assert.equal(marketplace.name, "company-tools");
assert.equal(marketplace.plugins.length, 1);
assert.equal(
  marketplace.plugins[0].source,
  "./plugins/safe-repository-review"
);

const manifest = json(".claude-plugin/plugin.json");
assert.equal(manifest.name, "safe-repository-review");
assert.equal(manifest.version, "1.0.0");
assert.equal(manifest.defaultEnabled, false);

const skill = read("skills/repository-review/SKILL.md");
assert.match(skill, /disable-model-invocation: true/);
assert.match(skill, /safe-repository-review:read-only-reviewer/);
assert.match(skill, /Do not edit files/);

const agent = read("agents/read-only-reviewer.md");
assert.match(agent, /tools: Read, Glob, Grep/);
for (const unsupported of ["hooks:", "mcpServers:", "permissionMode:"]) {
  assert.equal(
    agent.includes(unsupported),
    false,
    "plugin agent contains unsupported field: " + unsupported
  );
}

const mcp = json(".mcp.json");
const server = mcp.mcpServers["repository-policy"];
assert.equal(server.command, "node");
assert.deepEqual(server.args, [
  "${CLAUDE_PLUGIN_ROOT}/mcp/repository-policy.mjs"
]);
assert.equal(server.env, undefined);

const packageJson = json("package.json");
assert.equal(packageJson.dependencies["@modelcontextprotocol/server"], "2.0.0");
assert.equal(packageJson.dependencies.zod, "4.4.3");
assert.match(policyFor("escalation"), /annotations as hints/);

console.log(
  "PLUGIN_CONTRACT_OK marketplace=1 plugin=1 skill=manual agent=read-only " +
  "mcp=local secrets=none"
);
Example output / evidence
PLUGIN_CONTRACT_OK marketplace=1 plugin=1 skill=manual agent=read-only mcp=local secrets=none

Checkpoint: Review every asserted policy invariant

Continue whenThe harness covers marketplace source, default-off state, manual invocation, read-only tools, ignored-field absence, secret-free MCP config, exact dependencies, and escalation text.

Stop whenThe harness executes Claude, starts the server, reaches the network, writes fixtures into the repository, or asserts a property that the files do not actually enforce.

If this step fails

The contract test passes after a material change it should reject.

Likely causeThe relevant field or behavior was never asserted.

Safe checks
  • Compare the change with the threat model
  • Add one focused negative fixture

ResolutionExtend the semantic assertion before accepting the plugin change or bumping its version.

Security notes

  • A passing static contract does not attest dependency integrity, Claude runtime permission decisions, or model output quality.

Alternatives

  • Use a JSON Schema plus policy-as-code engine when many plugins share the same organizational contract.

Stop conditions

  • The harness executes Claude, starts the server, reaches the network, writes fixtures into the repository, or asserts a property that the files do not actually enforce.
11

command

Resolve exact dependencies without lifecycle scripts

caution

From the plugin root, install the exact package versions with dependency lifecycle scripts disabled, generate and review `package-lock.json`, then run the pure MCP self-test. Keep the registry response and integrity entries as review evidence.

Why this step matters

The server cannot run until its imports resolve. Disabling lifecycle scripts reduces installation-time execution, while an exact lockfile and immediate pure self-test provide concrete evidence for the reviewed dependency graph and server logic.

What to understand

`--ignore-scripts` blocks dependency preinstall, install, and postinstall hooks for this resolution step.

`--save-exact` preserves the exact versions already selected in the manifest.

Review the lockfile diff, package integrity values, license policy, and vulnerability result; zero reported vulnerabilities is not a security proof.

System changes

  • Creates `node_modules/` locally and a versioned `package-lock.json`; no Claude Code setting changes yet.

Syntax explained

--ignore-scripts
Prevents npm lifecycle hooks from executing during dependency installation.
--save-exact
Avoids converting the reviewed dependency versions into ranges.
Command
cd claude-marketplace/plugins/safe-repository-review && npm install --ignore-scripts --save-exact && npm run test:mcp
Example output / evidence
added 96 packages, and audited 97 packages in 4s
found 0 vulnerabilities
> safe-repository-review-plugin@1.0.0 test:mcp
> node mcp/repository-policy.mjs --self-test
MCP_POLICY_OK topics=3 network=none writes=none

Checkpoint: Inspect the exact lockfile and MCP self-test

cd claude-marketplace/plugins/safe-repository-review && npm install --ignore-scripts --save-exact && npm run test:mcp

Continue whenInstallation completes from the approved registry, the lockfile contains exact resolved artifacts with integrity data, and the self-test prints the exact MCP_POLICY_OK line.

Stop whenResolution uses an unapproved registry, a package changes unexpectedly, lifecycle execution occurs, audit reports an unaccepted vulnerability, or the self-test differs.

If this step fails

The dependency graph changes on a repeat install.

Likely causeThe lockfile was not committed, registry metadata changed, or a range remained.

Safe checks
  • Inspect `git diff -- package.json package-lock.json`
  • Run `npm ci --ignore-scripts` in a clean canary

ResolutionRestore exact versions and the reviewed lockfile; do not publish a nondeterministic graph.

Security notes

  • Dependency code runs later when the MCP server starts even though install scripts were disabled.

Alternatives

  • Vendor a reviewed standalone binary with a reproducible build and independent signature verification.

Stop conditions

  • Resolution uses an unapproved registry, a package changes unexpectedly, lifecycle execution occurs, audit reports an unaccepted vulnerability, or the self-test differs.
12

verification

Run semantic and Claude Code validation

read-only

Run the team contract test, validate the entire marketplace, then validate the plugin itself in strict mode. Marketplace validation checks source resolution and its local plugin; strict plugin validation makes unrecognized fields fail rather than remain warnings.

Why this step matters

No single validator covers distribution syntax, Claude component schemas, and organization-specific safety semantics. Running all three gates catches different failure classes before code is installed into an active Claude session.

What to understand

Marketplace validation resolves the local plugin source and checks catalog-level errors.

Strict plugin validation catches misspelled or unsupported manifest and frontmatter fields.

The semantic test specifically rejects security claims Claude's schema cannot infer.

System changes

  • Reads and validates extension files; it does not register, enable, or execute the plugin MCP server.

Syntax explained

claude plugin validate .
Validates the marketplace manifest and its local plugin source.
--strict
Treats otherwise non-fatal unrecognized plugin fields as validation failures.
Command
cd claude-marketplace/plugins/safe-repository-review && npm run test:contract && cd ../.. && claude plugin validate . && claude plugin validate ./plugins/safe-repository-review --strict
Example output / evidence
> safe-repository-review-plugin@1.0.0 test:contract
> node test/plugin-contract.mjs ../..
PLUGIN_CONTRACT_OK marketplace=1 plugin=1 skill=manual agent=read-only mcp=local secrets=none
Validation passed: marketplace company-tools (1 plugin)
Validation passed: safe-repository-review (strict)

Checkpoint: Require three independent green gates

cd claude-marketplace/plugins/safe-repository-review && npm run test:contract && cd ../.. && claude plugin validate . && claude plugin validate ./plugins/safe-repository-review --strict

Continue whenThe exact PLUGIN_CONTRACT_OK line appears and both Claude Code validation commands pass without warnings.

Stop whenAny gate warns, skips the local plugin, resolves a different path, or reports unsupported frontmatter.

If this step fails

Marketplace validation passes but strict plugin validation fails.

Likely causeThe catalog is structurally valid while an individual component has an unsupported or misspelled field.

Safe checks
  • Read the exact component path in the error
  • Compare it with current official reference

ResolutionFix the component and rerun all three gates; never downgrade strict mode to hide the warning.

Stop conditions

  • Any gate warns, skips the local plugin, resolves a different path, or reports unsupported frontmatter.
13

command

Install a local-scope canary and exercise boundaries

caution

Register the local marketplace and install the plugin only in local scope. Reload plugins, approve only the reviewed `repository-policy` server, inspect the component inventory, invoke the skill on a public fixture, and try negative requests for an edit, shell command, protected file, and unsupported evidence source.

Why this step matters

Static validation cannot demonstrate discovery, namespacing, per-server approval, agent tool resolution, or refusal behavior. A local canary limits configuration impact while a human observes the exact installed revision and negative paths.

What to understand

Run `/reload-plugins`, inspect `/plugin`, `/agents`, and `/mcp`, then approve only the local policy server.

Invoke `/safe-repository-review:repository-review src/public-fixture.ts` and require path-and-line evidence.

Ask the delegated agent to edit a file, run `git status`, browse a URL, or read `.env`; each unsupported action must stop without another tool silently taking its place.

System changes

  • Adds a local marketplace declaration, local plugin installation state, cached plugin files, and a project MCP approval decision.

Syntax explained

--scope local
Keeps the canary out of the shared repository settings and other projects.
plugin list --json
Provides machine-readable evidence of exact name, version, scope, and enable state.
Command
claude plugin marketplace add ./claude-marketplace --scope local && claude plugin install safe-repository-review@company-tools --scope local && claude plugin list --json
Example output / evidence
Marketplace company-tools added at local scope
Installed safe-repository-review@company-tools at local scope
[{"name":"safe-repository-review@company-tools","version":"1.0.0","scope":"local","enabled":true}]

Checkpoint: Observe positive and negative live behavior

claude plugin marketplace add ./claude-marketplace --scope local && claude plugin install safe-repository-review@company-tools --scope local && claude plugin list --json

Continue whenThe installed revision is 1.0.0, the skill and scoped agent appear, the MCP server requires approval, the public fixture review cites lines, and write, shell, web, protected-file, and unsupported-evidence attempts stop.

Stop whenThe plugin starts before opt-in, an unreviewed MCP server is approved, the agent gains another tool, a protected read succeeds, or output claims evidence it did not inspect.

If this step fails

The plugin works only before `/reload-plugins` or only from its source checkout.

Likely causeA component references files outside the cached plugin or relies on the development working directory.

Safe checks
  • Inspect installed component inventory
  • Run from a different repository directory

ResolutionReplace external or relative references with plugin-root paths, reinstall, and repeat the canary.

Security notes

  • Project MCP approval is separate from plugin installation. Review the command and args before accepting it.
  • A successful refusal is evidence for this tested version and flow, not a universal claim about model behavior.

Alternatives

  • Use `claude --plugin-dir` for an even more temporary development session before writing local installation state.

Stop conditions

  • The plugin starts before opt-in, an unreviewed MCP server is approved, the agent gains another tool, a protected read succeeds, or output claims evidence it did not inspect.
14

decision

Choose a versioned distribution and revocation plan

caution

Publish only after a human compares the exact canary commit, lockfile, validator output, live negative evidence, and release notes. For a separate plugin repository, use a full forty-character plugin-source SHA. Record how to disable, uninstall, reset MCP approvals, revoke external credentials, and restore the previous version before notifying users.

Why this step matters

A plugin update changes both model instructions and executable code. Release approval needs immutable evidence and an operational kill path; a version string alone neither proves provenance nor revokes a running or already approved integration.

What to understand

The local monorepo source is tied to the reviewed marketplace revision; separately hosted production plugin sources can add an exact `sha`.

Disabling a plugin stops future loading after reload or restart but does not revoke credentials held by an external service.

Uninstall behavior, cached revisions, active sessions, dependencies, and persistent plugin data must be reviewed before removal is used as incident response.

System changes

  • This decision does not publish by itself; it creates release evidence and an approved distribution or rejection record.

Syntax explained

git rev-parse HEAD
Records the exact reviewed marketplace source revision.
plugin details
Confirms the user-visible component inventory and estimated context cost for the installed plugin.
Command
git status --short && git rev-parse HEAD && sha256sum plugins/safe-repository-review/package-lock.json && claude plugin details safe-repository-review@company-tools
Example output / evidence
7f4a2e13c0190fdb22ec6908ed63e16b4d4288f1
6a85087c481fd8cd56e5f2f7cdb8b3d42c00e6a563c59490c4f40ad4ecbc9d54  plugins/safe-repository-review/package-lock.json
safe-repository-review@company-tools  version 1.0.0  Skills 1  Agents 1  MCP servers 1

Checkpoint: Approve or reject one immutable release

git status --short && git rev-parse HEAD && sha256sum plugins/safe-repository-review/package-lock.json && claude plugin details safe-repository-review@company-tools

Continue whenA human-approved record ties version 1.0.0 to one commit, one lockfile digest, three validation gates, live boundary evidence, release notes, and tested disable and recovery commands.

Stop whenThe release source can move without review, evidence refers to another commit, ownership is missing, the kill switch is untested, or external credentials cannot be revoked independently.

If this step fails

A released plugin must be disabled urgently.

Likely causeA boundary regression, compromised dependency, malicious source, or incorrect instruction reached users.

Safe checks
  • Run `claude plugin disable safe-repository-review@company-tools --scope local` for the canary
  • Run `/reload-plugins` or restart and inspect `/mcp`

ResolutionDisable the affected scope, reset project MCP choices if trust changed, revoke external credentials separately, preserve sanitized evidence, and publish a reviewed fixed version or removal notice.

Security notes

  • Do not claim a marketplace branch, tag, version label, or checksum is a signature unless a separate verified signing system exists.
  • Do not store API keys in marketplace URLs, `.mcp.json`, git configuration examples, release notes, or test output.

Alternatives

  • Keep the plugin local-only until immutable source, update ownership, health monitoring, and incident revocation are operational.

Stop conditions

  • The release source can move without review, evidence refers to another commit, ownership is missing, the kill switch is untested, or external credentials cannot be revoked independently.

Finish line

Verification checklist

Verify the semantic extension contractcd claude-marketplace/plugins/safe-repository-review && npm run test:contractThe exact PLUGIN_CONTRACT_OK line reports one marketplace, one default-off plugin, a manual skill, a read-only agent, one local MCP server, and no embedded secrets.
Verify the MCP policy functioncd claude-marketplace/plugins/safe-repository-review && npm run test:mcpThe exact MCP_POLICY_OK line reports three supported topics with no network or write behavior.
Verify Claude Code schemas strictlycd claude-marketplace && claude plugin validate . && claude plugin validate ./plugins/safe-repository-review --strictBoth the marketplace and individual plugin pass, with no warning about unsupported or unrecognized fields.
Verify the installed component inventoryclaude plugin list --json && claude plugin details safe-repository-review@company-toolsThe local canary reports version 1.0.0, enabled state chosen by the operator, one skill, one agent, and one MCP server from company-tools.
Verify live refusal boundariesclaude --debugAfter explicit skill invocation, the scoped agent can cite approved public files but has no Write, Edit, shell, web, Agent, or MCP tool; protected-file and unsupported-evidence requests stop without fallback.

Recovery guidance

Common problems and safe checks

The plugin validates but no skill or agent appears.

Likely causeThe installed revision is stale, the component is in the wrong directory, the plugin is disabled, or the session has not reloaded plugin components.

Safe checks
  • Inspect `claude plugin details safe-repository-review@company-tools`
  • Run `/reload-plugins` and inspect debug component registration

ResolutionCorrect the documented root-level component path, reinstall the canary revision, and verify its scoped names.

The repository-policy server is unavailable.

Likely causeNode or a dependency is missing, the plugin-root path did not resolve, project approval was denied, or server startup wrote invalid stdout.

Safe checks
  • Run the pure `npm run test:mcp` self-test
  • Inspect `/mcp` and sanitized `claude --debug` startup reason

ResolutionFix the reviewed runtime or approval issue; do not let the skill invent policy or silently continue without the server.

The scoped agent has more than Read, Glob, and Grep.

Likely causeAnother agent definition won precedence, an installed cache is stale, or the observation came from the parent conversation rather than the delegated agent.

Safe checks
  • Inspect `/agents` for the fully scoped plugin name
  • Compare installed plugin version and source with release evidence

ResolutionDisable the plugin, correct identity or cache state through supported commands, reinstall locally, and repeat all negative tests.

The skill runs without explicit user invocation.

Likely causeThe installed SKILL.md lacks disable-model-invocation, an older revision is active, or a different skill with a similar name was invoked.

Safe checks
  • Inspect the loaded skill frontmatter in plugin details
  • Confirm the namespace and installed version

ResolutionDisable the affected revision and restore the reviewed manual-only skill before any further canary.

Marketplace validation skips the local plugin.

Likely causeValidation ran from the wrong directory or the source is not a valid root-relative `./` path.

Safe checks
  • Run validation from `claude-marketplace/`
  • Compare the marketplace source with the printed tree

ResolutionRestore `./plugins/safe-repository-review`, then validate both marketplace and plugin explicitly.

A repeat dependency install changes the lockfile.

Likely causeThe lockfile was not committed, a version range remained, the registry changed, or a different npm version rewrote metadata.

Safe checks
  • Compare package and lockfile diffs
  • Run `npm ci --ignore-scripts` in a fresh canary

ResolutionReject the release until exact versions, approved registry, lockfile format, and reproducible resolution are restored.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use a repository-local `.claude/skills/` workflow when the instructions are not yet stable or reusable enough to justify executable distribution.
  • Use a personal `@skills-dir` plugin for a single operator canary before creating a shared marketplace.
  • Keep static policy as a skill reference file and omit MCP entirely when a callable tool offers no operational benefit.
  • Use a centrally operated HTTP MCP service only after authentication, tenant isolation, transport security, rate limits, audit, retention, revocation, and availability are engineered.
  • Use a project-local subagent rather than a plugin agent when supported `mcpServers` or `permissionMode` behavior is required and the scope-specific policy can be reviewed in that repository.

Operate it safely

  • Add a CI job that installs with scripts disabled, runs both tests, invokes strict validation, and archives only sanitized evidence for each version.
  • Create a public, secret-free fixture repository with positive findings, false-positive traps, protected-path traps, and unsupported-runtime questions.
  • Measure skill and agent token cost through plugin details and keep instructions concise without removing safety boundaries.
  • Add a health process for dependency advisories, source ownership changes, stale official documentation, and Claude Code compatibility review every ninety days.
  • If the plugin moves to its own repository, replace the local source with an exact remote plugin-source SHA and test update plus rollback across two signed organizational release records.

Reference

Frequently asked questions

Does readOnlyHint make the MCP tool read-only?

No. It is descriptive metadata. This reference tool is read-only because its input is a closed enum and its implementation returns constant text without file, network, shell, environment, or mutation code paths.

Why does the plugin agent not declare permissionMode or mcpServers?

Claude Code ignores hooks, mcpServers, and permissionMode on plugin-shipped agents. The Guide keeps the MCP call in the main skill flow and uses the supported tools allowlist for delegated reduction.

Why is the skill manual if the agent already has read-only tools?

Repository review can expose data and consume resources. Manual invocation records user intent and scope, while the agent allowlist controls capability. They address different risks.

Does disabling the plugin terminate every risk?

No. Reload or restart to remove components and disconnect unchanged processes, reset MCP approval if trust changed, revoke external credentials separately, and inspect active sessions and persistent data.

Should a production marketplace use the local relative source?

It can when the plugin lives inside the same reviewed marketplace repository. A separately hosted plugin should use a supported remote source object with an exact forty-character SHA when immutable provenance is required.

Is a package-lock checksum a software signature?

No. It detects a byte change relative to recorded evidence. Authenticity requires a separately verified signer identity and signing policy.

Can the plugin subagent inspect runtime behavior?

Not in this design. It has no shell, browser, network, or MCP tools. It must report the missing evidence and ask an authorized operator to collect a reviewed fixture or runtime trace.

Recovery

Rollback

Disable the affected plugin at the installed scope, reload or restart so its components and MCP server disconnect, reset project MCP choices when the approval itself is no longer trusted, remove the local marketplace only after checking dependent plugins, revoke any separately managed credentials, and restore the previously reviewed marketplace revision.

  1. Preserve the plugin name, version, source commit, lockfile digest, validator output, sanitized debug reason, and affected scope without copying prompts, repository content, credentials, or full personal paths.
  2. Run `claude plugin disable safe-repository-review@company-tools --scope local`, then `/reload-plugins` or restart Claude Code and confirm the skill, agent, and MCP server are unavailable.
  3. Run `claude mcp reset-project-choices` if the project MCP approval must be reconsidered; this resets choices rather than proving that an external process stopped.
  4. Use `claude plugin uninstall safe-repository-review@company-tools --scope local` only after checking plugin dependencies and persistent data behavior. Keep data when incident evidence or rollback requires it.
  5. Remove the local marketplace declaration only when no installed plugin depends on it. Removing the last marketplace scope also uninstalls plugins installed from it.
  6. Revoke external service credentials and tokens independently. Disabling or uninstalling a plugin does not revoke secrets that another system already accepted.
  7. Restore the last reviewed marketplace and plugin revision, reinstall in local scope, rerun the contract, MCP self-test, strict validation, and live negative canary, then require a new human approval before wider distribution.

Evidence

Sources and review

Verified 2026-07-29Review due 2026-10-27
Claude Code plugins reference: skills, agents, MCP servers, validation, and component paths | AnthropicofficialClaude Code plugin marketplaces: sources, versions, local testing, and validation | AnthropicofficialClaude Code skills and SKILL.md invocation controls | AnthropicofficialClaude Code subagents: tool allowlists and plugin-agent limits | AnthropicofficialClaude Code MCP servers: project approval, scopes, and plugin paths | AnthropicofficialBuild an MCP server with registerTool and stdio | Model Context Protocolofficial