Skip to content

Claude Code Plugin - Architecture

Overview

The LCP plugin packages lcp serve-all as a Claude Code plugin, enabling the agent to access real-time Python library documentation via MCP without any per-project configuration. The plugin is distributed through the Claude Code marketplace, which governs how it is discovered, installed, and configured.

Repository Structure

The plugin spans two locations within the zazza123/lcp repository:

lcp/                               # repository root
├── .claude-plugin/
│   └── marketplace.json           # Marketplace catalog: declares the repo as a marketplace
│                                  # and lists available plugins with their source paths
└── plugin/lcp/                    # Plugin root (source for the lcp@lcp plugin)
    ├── .claude-plugin/
    │   └── plugin.json            # Plugin manifest: id, name, version, keywords, userConfig schema
    ├── .mcp.json                  # MCP server declaration pointing to bin/serve.sh
    ├── agents/
    │   └── library-explorer.md   # Read-only haiku subagent for deep library research
    ├── bin/
    │   └── serve.sh              # Startup wrapper: validates lcp, injects registries
    ├── commands/
    │   ├── resolve.md            # /lcp:resolve <package> shortcut
    │   └── scan.md               # /lcp:scan <package> shortcut
    ├── hooks/
    │   └── hooks.json            # SessionStart lifecycle hook
    ├── skills/
    │   ├── lcp-universal/
    │   │   └── SKILL.md          # Proactive library resolution skill
    │   └── lcp-usage/
    │       └── SKILL.md          # General LCP usage guidance skill
    └── README.md

Marketplace Distribution

The Claude Code plugin marketplace uses a two-layer file structure. The root /.claude-plugin/marketplace.json is the marketplace catalog — it registers the GitHub repository as a marketplace and declares which plugins are available within it, each with a source path pointing to a subdirectory. The plugin/lcp/.claude-plugin/plugin.json is the plugin manifest — it contains the plugin's metadata, keywords, and the userConfig schema that Claude Code presents during installation.

When a user runs /plugin marketplace add zazza123/lcp, Claude Code fetches the repository's marketplace catalog. When they subsequently run /plugin install lcp@lcp, Claude Code reads the plugin manifest from the path declared in the catalog (./plugin/lcp), registers the MCP server, skills, commands, hooks, and subagent, and exposes the userConfig inputs.

The userConfig.registries field lets users provide a comma-separated list of LCP registry URLs. Claude Code injects the configured value as the CLAUDE_PLUGIN_OPTION_registries environment variable at runtime, which bin/serve.sh picks up to pass the first registry URL to lcp serve-all --registry.

flowchart LR
    A["GitHub repo\nzazza123/lcp"] --> B["/.claude-plugin/\nmarketplace.json"]
    B --> C["/plugin marketplace add\nzazza123/lcp"]
    C --> D["/plugin install lcp@lcp"]
    D --> E["Claude Code reads\nplugin/lcp/.claude-plugin/plugin.json\n+ .mcp.json"]
    E --> F["Plugin active in session"]

MCP Server Startup Flow

When Claude Code opens a session with the plugin installed, it reads .mcp.json and starts the declared MCP server. The startup sequence runs through bin/serve.sh:

flowchart TD
    A["Claude Code session starts"] --> B["Read .mcp.json"]
    B --> C["Start bin/serve.sh via ${CLAUDE_PLUGIN_ROOT}"]
    C --> D{"lcp on PATH?"}
    D -- no --> E["Exit 1: print install instructions"]
    D -- yes --> F{"userConfig.registries set?"}
    F -- yes --> G["Pass first registry as --registry arg"]
    F -- no --> H["Start lcp serve-all (no registry)"]
    G --> H
    H --> I["FastMCP universal server running"]
    I --> J["SessionStart hook checks lcp independently"]
    J --> K{"lcp found?"}
    K -- no --> L["Print warning message to session"]
    K -- yes --> M["Session ready"]

The SessionStart hook in hooks/hooks.json is independent of the wrapper — it runs as a shell command at the start of every session to provide a human-readable warning if lcp is missing, even when the MCP server has already failed silently.

Skills Design

Skills are auto-invoked by Claude Code based on their description frontmatter. Both skills accept $ARGUMENTS for direct invocation:

Skill Invocation mode Description match
lcp-universal Automatic + /lcp:lcp-universal <library> Triggers when implementing code against any third-party Python library
lcp-usage Automatic + /lcp:lcp-usage <library> Triggers on LCP tool usage guidance requests

lcp-universal is the primary skill. It instructs the agent to call resolve_library("package") before writing any code that uses an external library, then follow the structured exploration workflow defined in the MCP server's get_usage_guide tool.

Commands Design

Commands are user-invoked /lcp:<name> <args> shortcuts that route $ARGUMENTS to a specific workflow:

Command User invokes Behaviour
resolve /lcp:resolve requests Resolves the library and summarises its public API
scan /lcp:scan requests Scans the package and produces a human-readable module and symbol summary

Commands are lighter than skills — they don't trigger automatically and don't modify agent behaviour globally. They are user-controlled entry points for explicit, one-shot library operations.

Library Explorer Agent

agents/library-explorer.md defines a subagent with the following constraints:

Parameter Value Rationale
model haiku Fast and cheap for read-only tool calls
effort low No reasoning needed for structured tool traversal
maxTurns 15 Bounded exploration; prevents runaway tool chains
disallowedTools Write, Edit, MultiEdit Read-only — never modifies project files

The agent is invoked by the parent agent to delegate deep library research without consuming the parent's context budget.

userConfig: Registry List

plugin.json declares a userConfig.registries field (string, comma-separated) to let teams configure one or more LCP registry URLs. bin/serve.sh reads CLAUDE_PLUGIN_CONFIG_REGISTRIES and passes the first URL to lcp serve-all --registry.

This supports the pattern of teams hosting a private lcp-registry containing pre-built manifests for internal packages that cannot be pip-installed in a CI/agent environment.

Relationship to the MCP Server

The plugin is a packaging and configuration layer. All library resolution, caching, tool dispatch, and registry fallback logic lives in src/lcp/mcp_server.py. The plugin itself adds nothing to the MCP server's behaviour — it provides the lifecycle wiring (startup, hooks), the agent guidance layer (skills, commands, subagent), and the marketplace metadata.

flowchart LR
    subgraph Repo root
        CAT[".claude-plugin/\nmarketplace.json\ncatalog"]
    end
    subgraph Plugin
        MP["plugin/lcp/.claude-plugin/\nplugin.json\nmetadata + userConfig"]
        A[".mcp.json"] --> B["bin/serve.sh"]
        C["hooks/hooks.json"]
        D["skills/"]
        E["commands/"]
        F["agents/"]
    end
    subgraph SDK
        B --> G["lcp serve-all"]
        G --> H["mcp_server.py\ncreate_universal_server()"]
    end
    CAT --> |"marketplace add\n→ plugin install"| MP
    MP --> |"installed via marketplace"| A
    D --> |"guides agent"| H
    E --> |"user shortcut"| H
    F --> |"subagent calls"| H

Last Updated: May 2026 (updated: marketplace catalog) Status: Implemented