diff --git a/README.md b/README.md index 4f1b536..439e4ca 100644 --- a/README.md +++ b/README.md @@ -149,29 +149,46 @@ mcpctl apply -f state.yaml ## Plugin System (ProxyModel) -ProxyModel is mcpctl's plugin system. Each project is assigned a **plugin** that controls how Claude interacts with its servers. Plugins are composed from two layers: **TypeScript plugins** (MCP middleware hooks) and **YAML pipelines** (content transformation stages). +ProxyModel is mcpctl's plugin system. Each project is assigned a **plugin** that controls how Claude interacts with its servers. + +There are two layers: +- **Plugins** — TypeScript hooks that intercept MCP requests/responses (gating, tool filtering, etc.) +- **Pipelines** — YAML-defined content transformation stages (pagination, summarization, etc.) ### Built-in Plugins -| Plugin | Includes gating | Content pipeline | Description | +Plugins compose through inheritance. A plugin can `extend` another plugin and inherit all its hooks: + +``` +gate → gating only (begin_session + prompt delivery) +content-pipeline → content transformation only (pagination, section-split) +default → extends both gate AND content-pipeline (inherits all hooks from both) +``` + +| Plugin | Gating | Content pipeline | Description | |--------|:-:|:-:|---| -| **default** | Yes | Yes | Gate + content pipeline. The default for all projects. | -| **gate** | Yes | No | Gating only — `begin_session` gate with prompt delivery. | -| **content-pipeline** | No | No | Content transformation only — no gating. | +| **gate** | Yes | No | `begin_session` gate with prompt delivery | +| **content-pipeline** | No | Yes | Content transformation (paginate, section-split) | +| **default** | Yes | Yes | Extends both — gate + content pipeline combined | + +The `default` plugin doesn't reimplement anything — it inherits the gating hooks from `gate` and the content hooks from `content-pipeline`. Custom plugins can extend built-in ones the same way. **Gating** means Claude initially sees only a `begin_session` tool. After calling it with a task description, relevant prompts are delivered and the full tool list is revealed. This keeps Claude's context focused. ```bash -# Create a gated project (default behavior) +# Gated with content pipeline (default — extends gate + content-pipeline) mcpctl create project home --server my-ha --proxy-model default -# Create an ungated project (direct tool access, no gate) -mcpctl create project tools --server grafana --proxy-model content-pipeline +# Ungated, content pipeline only +mcpctl create project tools --server my-grafana --proxy-model content-pipeline + +# Gated only, no content transformation +mcpctl create project docs --server my-docs --proxy-model gate ``` ### Plugin Hooks -TypeScript plugins intercept MCP requests/responses at specific lifecycle points: +Plugins intercept MCP requests/responses at specific lifecycle points. When a plugin extends another, it inherits all the parent's hooks. If both parent and child define the same hook, the child's version wins. | Hook | When it fires | |------|--------------| @@ -186,7 +203,7 @@ TypeScript plugins intercept MCP requests/responses at specific lifecycle points | `onPromptsList` | `prompts/list` — can filter prompts | | `onPromptGet` | `prompts/get` — can intercept prompt reads | -Plugins compose via `extends` — the `default` plugin extends both `gate` and `content-pipeline`, inheriting all their hooks. +When multiple parents define the same hook, lifecycle hooks (`onSessionCreate`, `onSessionDestroy`) chain sequentially. All other hooks require the child to override — otherwise it's a conflict error. ### Content Pipelines