Architecture Plugin / Extension Pattern See in Code Tour

Plugin Architecture

How Claude Code supports 45+ built-in tools plus unlimited external tools (via MCP) using a single extensible interface.

Plugin Architecture โ€” Architecture Diagram
graph TD
    A[Tool Registry] --> B[Built-in Tools]
    A --> C[MCP Tools]
    A --> D[Skill Tools]
    B --> E[BashTool]
    B --> F[FileReadTool]
    B --> G[AgentTool]
    C --> H[stdio server]
    C --> I[HTTP server]
    C --> J[WebSocket server]
    D --> K[User Skills]

Mermaid diagram definition

Deep Dive

The plugin architecture centers on a single generic Tool<Input, Output> interface. Any code that implements this interface becomes a first-class tool โ€” indistinguishable from built-in tools from Claude's perspective.

๐Ÿ”‘Key Insight

MCP (Model Context Protocol) extends this: external processes implement the MCP protocol, and Claude Code wraps their exposed tools in the same `Tool` interface. The AI never knows whether a tool is built-in or external.

โ„น๏ธInfo

Skills are a third tier: curated prompts packaged as user-installable extensions. They use the same dispatch path as tools but are prompt-based rather than code-based.

KEY TAKEAWAYS
  • โ†’One interface, unlimited implementations
  • โ†’External tools (MCP) are indistinguishable from built-ins at query time
  • โ†’Skills add a prompt-based tier without code changes
  • โ†’The registry is the only place tool enumeration happens

Source Code

The generic Tool interface โ€” the single contract all plugins must implement.

export type Tool<
  Input extends AnyObject = AnyObject,
  Output = unknown,
  P extends ToolProgressData = ToolProgressData,
> = {
  /**
   * Optional aliases for backwards compatibility when a tool is renamed.
   * The tool can be looked up by any of these names in addition to its primary name.
   */
  aliases?: string[]
  /**
   * One-line capability phrase used by ToolSearch for keyword matching.
   * Helps the model find this tool via keyword search when it's deferred.
   * 3โ€“10 words, no trailing period.
   * Prefer terms not already in the tool name (e.g. 'jupyter' for NotebookEdit).
   */
  searchHint?: string
  call(
    args: z.infer<Input>,
    context: ToolUseContext,
    canUseTool: CanUseToolFn,
    parentMessage: AssistantMessage,
    onProgress?: ToolCallProgress<P>,
  ): Promise<ToolResult<Output>>
  description(
    input: z.infer<Input>,
    options: {
      isNonInteractiveSession: boolean
      toolPermissionContext: ToolPermissionContext
      tools: Tools
    },
  ): Promise<string>
  readonly inputSchema: Input
  // Type for MCP tools that can specify their input schema directly in JSON Schema format
  // rather than converting from Zod schema
  readonly inputJSONSchema?: ToolInputJSONSchema
  // Optional because TungstenTool doesn't define this. TODO: Make it required.
  // When we do that, we can also go through and make this a bit more type-safe.
  outputSchema?: z.ZodType<unknown>
  inputsEquivalent?(a: z.infer<Input>, b: z.infer<Input>): boolean
  isConcurrencySafe(input: z.infer<Input>): boolean
  isEnabled(): boolean
  isReadOnly(input: z.infer<Input>): boolean
  /** Defaults to false. Only set when the tool performs irreversible operations (delete, overwrite, send). */
  isDestructive?(input: z.infer<Input>): boolean
  /**
   * What should happen when the user submits a new message while this tool
   * is running.
   *
   * - `'cancel'` โ€” stop the tool and discard its result
   * - `'block'`  โ€” keep running; the new message waits
   *
   * Defaults to `'block'` when not implemented.
   */
  interruptBehavior?(): 'cancel' | 'block'
  /**
   * Returns information about whether this tool use is a search or read operation
   * that should be collapsed into a condensed display in the UI. Examples include
   * file searching (Grep, Glob), file reading (Read), and bash commands like find,
AI Assistant

Ask anything about Plugin Architecture

Powered by Groq ยท Enter to send, Shift+Enter for newline