@sammorrowdrums/mcpi-ext 0.2.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +426 -151
  3. package/dist/code-mode/eligibility.d.ts +29 -4
  4. package/dist/code-mode/eligibility.js +56 -6
  5. package/dist/code-mode/executor.d.ts +19 -1
  6. package/dist/code-mode/executor.js +73 -8
  7. package/dist/code-mode/index.d.ts +54 -12
  8. package/dist/code-mode/index.js +157 -65
  9. package/dist/code-mode/isolated-vm.d.ts +65 -0
  10. package/dist/code-mode/isolated-vm.js +116 -0
  11. package/dist/code-mode/tools.d.ts +4 -1
  12. package/dist/code-mode/tools.js +7 -4
  13. package/dist/code-mode/type-hints.d.ts +2 -2
  14. package/dist/code-mode/type-hints.js +24 -8
  15. package/dist/docker-e2e.d.ts +0 -1
  16. package/dist/docker-e2e.js +0 -1
  17. package/dist/index.d.ts +9 -1
  18. package/dist/index.js +146 -67
  19. package/dist/mcp/call-tool-result.d.ts +10 -0
  20. package/dist/mcp/call-tool-result.js +70 -0
  21. package/dist/mcp/client-factory.d.ts +59 -0
  22. package/dist/mcp/client-factory.js +76 -0
  23. package/dist/mcp/client-manager.d.ts +61 -19
  24. package/dist/mcp/client-manager.js +223 -64
  25. package/dist/mcp/config-loader.d.ts +0 -1
  26. package/dist/mcp/config-loader.js +0 -1
  27. package/dist/mcp/config.d.ts +11 -1
  28. package/dist/mcp/config.js +15 -1
  29. package/dist/mcp/gateway-defaults.d.ts +14 -0
  30. package/dist/mcp/gateway-defaults.js +21 -0
  31. package/dist/mcp/host-approval.d.ts +16 -0
  32. package/dist/mcp/host-approval.js +19 -0
  33. package/dist/mcp/host-elicitation.d.ts +19 -0
  34. package/dist/mcp/host-elicitation.js +94 -0
  35. package/dist/mcp/index.d.ts +4 -1
  36. package/dist/mcp/index.js +4 -1
  37. package/dist/mcp/policy.d.ts +314 -0
  38. package/dist/mcp/policy.js +848 -0
  39. package/dist/routing/facilities.d.ts +109 -0
  40. package/dist/routing/facilities.js +175 -0
  41. package/dist/routing/format.d.ts +24 -0
  42. package/dist/routing/format.js +64 -0
  43. package/dist/routing/index.d.ts +4 -0
  44. package/dist/routing/index.js +4 -0
  45. package/dist/routing/seam.d.ts +35 -0
  46. package/dist/routing/seam.js +28 -0
  47. package/dist/routing/tripwire.d.ts +42 -0
  48. package/dist/routing/tripwire.js +80 -0
  49. package/dist/skills/discover.d.ts +5 -3
  50. package/dist/skills/discover.js +37 -12
  51. package/dist/skills/format.d.ts +4 -1
  52. package/dist/skills/format.js +8 -4
  53. package/dist/skills/index.d.ts +2 -2
  54. package/dist/skills/index.js +1 -1
  55. package/dist/skills/load-skill-tool.d.ts +23 -7
  56. package/dist/skills/load-skill-tool.js +112 -33
  57. package/dist/skills/mcp-tool-proxy.d.ts +4 -8
  58. package/dist/skills/mcp-tool-proxy.js +22 -97
  59. package/dist/skills/sep2640/client.d.ts +91 -0
  60. package/dist/skills/sep2640/client.js +160 -0
  61. package/dist/skills/sep2640/discover.d.ts +33 -0
  62. package/dist/skills/sep2640/discover.js +82 -0
  63. package/dist/skills/sep2640/index.d.ts +13 -0
  64. package/dist/skills/sep2640/index.js +13 -0
  65. package/dist/skills/sep2640/integrity.d.ts +58 -0
  66. package/dist/skills/sep2640/integrity.js +185 -0
  67. package/dist/skills/sep2640/load.d.ts +61 -0
  68. package/dist/skills/sep2640/load.js +90 -0
  69. package/dist/skills/sep2640/protocol.d.ts +146 -0
  70. package/dist/skills/sep2640/protocol.js +214 -0
  71. package/dist/skills/sep2640/spec.d.ts +76 -0
  72. package/dist/skills/sep2640/spec.js +88 -0
  73. package/dist/skills/skill-registry.d.ts +48 -2
  74. package/dist/skills/skill-registry.js +40 -3
  75. package/dist/tool-cli/bridge.d.ts +14 -0
  76. package/dist/tool-cli/bridge.js +196 -0
  77. package/dist/tool-cli/format.d.ts +17 -5
  78. package/dist/tool-cli/format.js +36 -20
  79. package/dist/tool-cli/index.d.ts +5 -2
  80. package/dist/tool-cli/index.js +3 -1
  81. package/dist/tool-cli/provider.d.ts +21 -0
  82. package/dist/tool-cli/provider.js +114 -0
  83. package/dist/tool-cli/startup.d.ts +22 -0
  84. package/dist/tool-cli/startup.js +47 -0
  85. package/package.json +78 -30
  86. package/dist/code-mode/code-mode-integration.test.d.ts +0 -2
  87. package/dist/code-mode/code-mode-integration.test.d.ts.map +0 -1
  88. package/dist/code-mode/code-mode-integration.test.js +0 -116
  89. package/dist/code-mode/code-mode-integration.test.js.map +0 -1
  90. package/dist/code-mode/eligibility.d.ts.map +0 -1
  91. package/dist/code-mode/eligibility.js.map +0 -1
  92. package/dist/code-mode/eligibility.test.d.ts +0 -2
  93. package/dist/code-mode/eligibility.test.d.ts.map +0 -1
  94. package/dist/code-mode/eligibility.test.js +0 -53
  95. package/dist/code-mode/eligibility.test.js.map +0 -1
  96. package/dist/code-mode/executor.d.ts.map +0 -1
  97. package/dist/code-mode/executor.js.map +0 -1
  98. package/dist/code-mode/executor.test.d.ts +0 -2
  99. package/dist/code-mode/executor.test.d.ts.map +0 -1
  100. package/dist/code-mode/executor.test.js +0 -130
  101. package/dist/code-mode/executor.test.js.map +0 -1
  102. package/dist/code-mode/index.d.ts.map +0 -1
  103. package/dist/code-mode/index.js.map +0 -1
  104. package/dist/code-mode/tools.d.ts.map +0 -1
  105. package/dist/code-mode/tools.js.map +0 -1
  106. package/dist/code-mode/type-hints.d.ts.map +0 -1
  107. package/dist/code-mode/type-hints.js.map +0 -1
  108. package/dist/code-mode/type-hints.test.d.ts +0 -2
  109. package/dist/code-mode/type-hints.test.d.ts.map +0 -1
  110. package/dist/code-mode/type-hints.test.js +0 -157
  111. package/dist/code-mode/type-hints.test.js.map +0 -1
  112. package/dist/docker-e2e.d.ts.map +0 -1
  113. package/dist/docker-e2e.js.map +0 -1
  114. package/dist/docker-e2e.test.d.ts +0 -2
  115. package/dist/docker-e2e.test.d.ts.map +0 -1
  116. package/dist/docker-e2e.test.js +0 -176
  117. package/dist/docker-e2e.test.js.map +0 -1
  118. package/dist/index.d.ts.map +0 -1
  119. package/dist/index.js.map +0 -1
  120. package/dist/index.test.d.ts +0 -2
  121. package/dist/index.test.d.ts.map +0 -1
  122. package/dist/index.test.js +0 -8
  123. package/dist/index.test.js.map +0 -1
  124. package/dist/mcp/client-manager.d.ts.map +0 -1
  125. package/dist/mcp/client-manager.js.map +0 -1
  126. package/dist/mcp/client-manager.test.d.ts +0 -2
  127. package/dist/mcp/client-manager.test.d.ts.map +0 -1
  128. package/dist/mcp/client-manager.test.js +0 -204
  129. package/dist/mcp/client-manager.test.js.map +0 -1
  130. package/dist/mcp/config-loader.d.ts.map +0 -1
  131. package/dist/mcp/config-loader.js.map +0 -1
  132. package/dist/mcp/config-loader.test.d.ts +0 -2
  133. package/dist/mcp/config-loader.test.d.ts.map +0 -1
  134. package/dist/mcp/config-loader.test.js +0 -93
  135. package/dist/mcp/config-loader.test.js.map +0 -1
  136. package/dist/mcp/config.d.ts.map +0 -1
  137. package/dist/mcp/config.js.map +0 -1
  138. package/dist/mcp/index.d.ts.map +0 -1
  139. package/dist/mcp/index.js.map +0 -1
  140. package/dist/skills/discover.d.ts.map +0 -1
  141. package/dist/skills/discover.js.map +0 -1
  142. package/dist/skills/format.d.ts.map +0 -1
  143. package/dist/skills/format.js.map +0 -1
  144. package/dist/skills/format.test.d.ts +0 -2
  145. package/dist/skills/format.test.d.ts.map +0 -1
  146. package/dist/skills/format.test.js +0 -63
  147. package/dist/skills/format.test.js.map +0 -1
  148. package/dist/skills/index.d.ts.map +0 -1
  149. package/dist/skills/index.js.map +0 -1
  150. package/dist/skills/load-skill-tool.d.ts.map +0 -1
  151. package/dist/skills/load-skill-tool.js.map +0 -1
  152. package/dist/skills/mcp-tool-proxy.d.ts.map +0 -1
  153. package/dist/skills/mcp-tool-proxy.js.map +0 -1
  154. package/dist/skills/skill-integration.test.d.ts +0 -2
  155. package/dist/skills/skill-integration.test.d.ts.map +0 -1
  156. package/dist/skills/skill-integration.test.js +0 -119
  157. package/dist/skills/skill-integration.test.js.map +0 -1
  158. package/dist/skills/skill-registry.d.ts.map +0 -1
  159. package/dist/skills/skill-registry.js.map +0 -1
  160. package/dist/skills/skill-registry.test.d.ts +0 -2
  161. package/dist/skills/skill-registry.test.d.ts.map +0 -1
  162. package/dist/skills/skill-registry.test.js +0 -67
  163. package/dist/skills/skill-registry.test.js.map +0 -1
  164. package/dist/test-servers/weather-server.d.ts +0 -12
  165. package/dist/test-servers/weather-server.d.ts.map +0 -1
  166. package/dist/test-servers/weather-server.js +0 -139
  167. package/dist/test-servers/weather-server.js.map +0 -1
  168. package/dist/test-servers/weather-stdio.d.ts +0 -2
  169. package/dist/test-servers/weather-stdio.d.ts.map +0 -1
  170. package/dist/test-servers/weather-stdio.js +0 -11
  171. package/dist/test-servers/weather-stdio.js.map +0 -1
  172. package/dist/tool-cli/cli.d.ts +0 -3
  173. package/dist/tool-cli/cli.d.ts.map +0 -1
  174. package/dist/tool-cli/cli.js +0 -179
  175. package/dist/tool-cli/cli.js.map +0 -1
  176. package/dist/tool-cli/constants.d.ts +0 -7
  177. package/dist/tool-cli/constants.d.ts.map +0 -1
  178. package/dist/tool-cli/constants.js +0 -15
  179. package/dist/tool-cli/constants.js.map +0 -1
  180. package/dist/tool-cli/format.d.ts.map +0 -1
  181. package/dist/tool-cli/format.js.map +0 -1
  182. package/dist/tool-cli/format.test.d.ts +0 -2
  183. package/dist/tool-cli/format.test.d.ts.map +0 -1
  184. package/dist/tool-cli/format.test.js +0 -30
  185. package/dist/tool-cli/format.test.js.map +0 -1
  186. package/dist/tool-cli/index.d.ts.map +0 -1
  187. package/dist/tool-cli/index.js.map +0 -1
  188. package/dist/tool-cli/rpc-client.d.ts +0 -6
  189. package/dist/tool-cli/rpc-client.d.ts.map +0 -1
  190. package/dist/tool-cli/rpc-client.js +0 -25
  191. package/dist/tool-cli/rpc-client.js.map +0 -1
  192. package/dist/tool-cli/rpc-server.d.ts +0 -48
  193. package/dist/tool-cli/rpc-server.d.ts.map +0 -1
  194. package/dist/tool-cli/rpc-server.js +0 -220
  195. package/dist/tool-cli/rpc-server.js.map +0 -1
  196. package/dist/tool-cli/rpc-server.test.d.ts +0 -2
  197. package/dist/tool-cli/rpc-server.test.d.ts.map +0 -1
  198. package/dist/tool-cli/rpc-server.test.js +0 -154
  199. package/dist/tool-cli/rpc-server.test.js.map +0 -1
package/README.md CHANGED
@@ -1,217 +1,479 @@
1
1
  # mcpi-ext
2
2
 
3
- > **Experimental.** This extension implements progressive MCP tool discovery via skills for [mcpi](https://github.com/SamMorrowDrums/mcpi) (an experimental pi fork). See the [skills-as-groups proposal](https://github.com/modelcontextprotocol/experimental-ext-grouping/pull/13) for the proposed MCP spec addition, and the [progressive tool discovery docs](https://github.com/SamMorrowDrums/mcpi/blob/main/docs/progressive-tool-discovery.md) for implementation details.
3
+ [![npm](https://img.shields.io/npm/v/@sammorrowdrums/mcpi-ext)](https://www.npmjs.com/package/@sammorrowdrums/mcpi-ext)
4
+ [![npm](https://img.shields.io/npm/v/@sammorrowdrums/mcpi)](https://www.npmjs.com/package/@sammorrowdrums/mcpi)
5
+ [![npm](https://img.shields.io/npm/v/@sammorrowdrums/tool-cli)](https://www.npmjs.com/package/@sammorrowdrums/tool-cli)
6
+
7
+ An extension for [mcpi](https://github.com/SamMorrowDrums/mcpi) that gives an agent three ways to
8
+ reach [MCP](https://modelcontextprotocol.io/) servers — **skills**, **tool-cli**, and **code mode** —
9
+ behind a single authorization boundary, so every call is authorized, audited, and gated in one place.
10
+
11
+ Each mechanism exists to spend only the context tokens a task actually needs. A large MCP server can
12
+ publish hundreds of tools; loading all of their schemas into every request is expensive and degrades
13
+ tool selection. These three mechanisms let the agent discover and call tools progressively instead.
14
+
15
+ - **[Skills](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/skills.md)** — the server
16
+ publishes a documented workflow that unlocks a curated tool set on demand.
17
+ - **[tool-cli](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/tool-cli.md)** — a shell
18
+ on-ramp for progressive discovery: servers → tools → schema → call.
19
+ - **[Code mode](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/code-mode.md)** —
20
+ sandboxed JavaScript that chains read-only tool calls inside a V8 isolate.
21
+
22
+ ---
23
+
24
+ ## Quick start
25
+
26
+ Verified against **mcpi 0.85.0** and **tool-cli 1.0.2** — the current releases, and also the
27
+ minimum supported versions: mcpi-ext declares a peer floor of `@sammorrowdrums/mcpi >=0.85.0
28
+ <1.0.0`, and requires `@sammorrowdrums/tool-cli` v1 for the bridge contract. Any mcpi-ext `1.x`
29
+ works; the commands below pin the current one.
30
+
31
+ ### 1. Check Node
32
+
33
+ Node.js `>=22.13.0`. Node 22 and 24 are both covered by CI.
4
34
 
5
35
  ```sh
6
- npm install -g @sammorrowdrums/mcpi@latest @sammorrowdrums/mcpi-ext@latest @sammorrowdrums/tool-cli@latest
7
- mcpi --extension $(npm root -g)/@sammorrowdrums/mcpi-ext/dist/index.js \
8
- --mcp-config ~/.config/mcpi-ext/mcp.json
36
+ node --version
9
37
  ```
10
38
 
11
- See [Quick Start](#quick-start) for MCP server configuration.
39
+ ### 2. Install mcpi and tool-cli globally
12
40
 
13
- ---
41
+ `mcpi` and `tool-cli` are commands you run, so they belong on your `PATH`:
14
42
 
15
- ![Three figures in a dark, Sandman-esque realm — The Skill Dealer, The Nuclear Football, and Codey C. Maude — standing before swirling constellations of MCP tool connections](images/banner.webp)
43
+ ```sh
44
+ npm install -g @sammorrowdrums/mcpi@0.85.0 @sammorrowdrums/tool-cli@1.0.2
45
+ ```
16
46
 
17
- > _They will tell you that MCP has a context problem. That the protocol gives too many tools, that the model drowns in schemas it doesn't need, that the cost of knowing everything is losing the ability to do anything well._
18
- >
19
- > _They are wrong._
47
+ To track the newest releases instead of the pinned pair, use `@latest`:
48
+
49
+ ```sh
50
+ npm install -g @sammorrowdrums/mcpi@latest @sammorrowdrums/tool-cli@latest
51
+ ```
52
+
53
+ ### 3. Install the extension through mcpi
54
+
55
+ Do **not** install mcpi-ext globally and point `--extension` at it by hand. mcpi manages extension
56
+ packages itself, records them in its settings, and can update them later:
57
+
58
+ ```sh
59
+ mcpi install npm:@sammorrowdrums/mcpi-ext
60
+ ```
61
+
62
+ That takes the newest `1.x`, which is what most people want. To pin an exact version for a
63
+ reproducible setup, name it — this page documents `1.0.1`:
64
+
65
+ ```sh
66
+ mcpi install npm:@sammorrowdrums/mcpi-ext@1.0.1
67
+ ```
68
+
69
+ Confirm it registered:
70
+
71
+ ```sh
72
+ mcpi list
73
+ ```
74
+
75
+ ```
76
+ User packages:
77
+ npm:@sammorrowdrums/mcpi-ext@1.0.1
78
+ ~/.cache/mcpi/npm/node_modules/@sammorrowdrums/mcpi-ext
79
+ ```
80
+
81
+ `mcpi install` writes to `~/.config/mcpi/settings.json`. Add `-l` to install into the current
82
+ project's `.mcpi/settings.json` instead. Once a package is listed there, mcpi loads it on every
83
+ run — you never pass `--extension` for it again.
84
+
85
+ ### 4. Configure MCP servers
86
+
87
+ Create `~/.config/mcpi-ext/mcp.json`. That is the default path; `--mcp-config <path>` overrides it,
88
+ and a missing file is not an error — mcpi-ext simply starts with zero servers.
89
+
90
+ Keep your token **out of this file**. Write it to a private env file instead, created with
91
+ restrictive permissions from the start so the token is never briefly world-readable:
92
+
93
+ ```sh
94
+ mkdir -p ~/.config/mcpi-ext
95
+ chmod 700 ~/.config/mcpi-ext
96
+ (umask 077 && gh auth token | sed 's/^/GITHUB_PERSONAL_ACCESS_TOKEN=/' > ~/.config/mcpi-ext/github-mcp.env)
97
+ chmod 600 ~/.config/mcpi-ext/github-mcp.env
98
+ ls -l ~/.config/mcpi-ext/github-mcp.env # expect -rw-------
99
+ ```
100
+
101
+ Substitute your own token for `gh auth token` if you are not using the GitHub CLI. The file is plain
102
+ `KEY=VALUE` lines, read by Docker itself — never parsed by mcpi-ext.
103
+
104
+ Then have Docker read it, substituting your real home directory for `/home/you` — arguments are
105
+ passed to the process directly and are **not** shell-expanded, so `~` and `$HOME` will not work
106
+ here:
107
+
108
+ ```json
109
+ {
110
+ "mcpServers": {
111
+ "github": {
112
+ "type": "stdio",
113
+ "command": "docker",
114
+ "args": [
115
+ "run",
116
+ "--rm",
117
+ "-i",
118
+ "--env-file",
119
+ "/home/you/.config/mcpi-ext/github-mcp.env",
120
+ "ghcr.io/github/github-mcp-server:latest",
121
+ "stdio"
122
+ ]
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ > **Why not just `export` the token?** MCP stdio servers do not inherit your shell environment. The
129
+ > MCP SDK spawns them with a fixed safe set — `HOME`, `LOGNAME`, `PATH`, `SHELL`, `TERM`, `USER` on
130
+ > POSIX — plus whatever the server entry declares explicitly. An exported
131
+ > `GITHUB_PERSONAL_ACCESS_TOKEN` never reaches the server. `mcp.json` also performs no `${VAR}`
132
+ > expansion: values are used literally. `--env-file` is therefore the way to supply a secret without
133
+ > writing it into `mcp.json`, and it keeps the token in one `chmod 600` file you can rotate.
20
134
  >
21
- > _MCP doesn't have a context problem. It has an imagination problem. The protocol already contains everything you need — `skill://` resources, tool annotations, `outputSchema`, progressive discovery. The pieces are all there, lying in the open like runes on a hillside. You just have to read them._
135
+ > An `"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "..." }` block does work, but it puts a live
136
+ > credential in a config file that is easy to copy, sync, or commit by accident.
22
137
  >
23
- > _What follows is the story of three who did._
138
+ > **Not using Docker?** A server you run directly gets the same restricted environment, so it cannot
139
+ > read an exported token either. Supply credentials through whatever mechanism that server already
140
+ > supports for reading a secret from a file. If you need a wrapper script for local development, see
141
+ > the [server developer guide](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/server-developer-guide.md#supplying-credentials-to-a-local-server).
24
142
 
25
- ---
143
+ Both `stdio` (spawns a process) and `remote` (Streamable HTTP) servers are supported:
144
+
145
+ ```json
146
+ {
147
+ "mcpServers": {
148
+ "github": { "...": "..." },
149
+ "my-remote-server": {
150
+ "type": "remote",
151
+ "url": "https://my-mcp-server.example.com/mcp",
152
+ "headers": { "Authorization": "Bearer ..." }
153
+ }
154
+ }
155
+ }
156
+ ```
26
157
 
27
- Building custom [MCP](https://modelcontextprotocol.io/) support as [mcpi](https://github.com/SamMorrowDrums/mcpi) extensions. This project implements **tiered progressive discovery** three complementary strategies for exposing MCP tools to an AI agent, each paying only the context tokens it needs.
158
+ A `stdio` entry takes `command`, optional `args`, `env`, and `cwd`. A `remote` entry takes `url` and
159
+ optional `headers`. Any other shape is rejected at startup with the offending path.
28
160
 
29
- | Tier | Aspect | Mechanism |
30
- | ------------- | ------------------------ | ----------------------------------------------------- |
31
- | 1 — Skills | **The Skill Dealer** | `skill://` resources gate tools via `allowed-tools` |
32
- | 2 — tool-cli | **The Nuclear Football** | CLI progressive discovery via shell |
33
- | 3 — Code Mode | **Codey C. Maude** | Sandboxed JS over read-only tools with `outputSchema` |
161
+ ### 5. Run
34
162
 
35
- ---
163
+ ```sh
164
+ mcpi --provider github-copilot --model claude-opus-5 \
165
+ --mcp-config ~/.config/mcpi-ext/mcp.json \
166
+ --mcp-skills-extension
167
+ ```
36
168
 
37
- ## I. The Skill Dealer
169
+ `--mcp-config` and `--mcp-skills-extension` are registered by mcpi-ext, so they exist only once the
170
+ extension is installed. `--mcp-skills-extension` is **opt-in** and off by default; see
171
+ [Skills support](#skills-support) before enabling it. Drop it unless you are talking to a server that
172
+ implements the draft.
38
173
 
39
- ![A shadowy figure behind a table of glowing cards, each card inscribed with the name of an MCP tool](images/the-skill-dealer.webp)
174
+ ### 6. Authenticate the model provider
40
175
 
41
- > _The Skill Dealer does not give you what you ask for. The Skill Dealer gives you what you need — and nothing more._
176
+ Providers are authenticated inside mcpi, not through this extension. On first run, use the `/login`
177
+ slash command:
42
178
 
43
- MCP servers ship `skill://` resources — SKILL.md files declaring which tools a skill gates. The extension discovers skills on connection and registers their tools with `deferred: true`: present in the registry for dispatch but hidden from the model and the prompt. **Cache is preserved** — neither the tools array nor the system prompt ever changes.
179
+ ```
180
+ /login github-copilot
181
+ ```
44
182
 
45
- When the model calls `load_skill`, the skill's instructions arrive and its tools are unblocked. The model discovers tools from the skill body and can call them immediately. The MCP server itself declares how its tools should be discovered.
183
+ `/login` opens mcpi's provider authentication flow OAuth where the provider supports it, otherwise
184
+ an API key prompt — and stores the credential for later sessions. Run bare `/login` to pick a
185
+ provider from a list. If a session later reports an expired credential, mcpi tells you to run
186
+ `/login <provider>` again. `github-copilot` defaults to the `claude-opus-5` model, so
187
+ `--model claude-opus-5` above is explicit rather than required.
46
188
 
47
- 📖 [**How it works →**](docs/skills.md) deferred gating, `defer_loading` provider support, `tool_call` hook enforcement.
189
+ ### Upgrading from pi or from mcpi before 0.85
48
190
 
49
- > _"What you do not need to know," said the Skill Dealer, shuffling the deck, "you will not be burdened with knowing."_
191
+ mcpi 0.85.0 no longer reads the legacy `~/.pi/agent` directory, and it **refuses to start** while
192
+ that directory exists rather than silently ignoring your history:
50
193
 
51
- ![Skills enabling MCP tools — the model loads a skill and gains access to gated tools](images/skills-enabling-mcp-tools.png)
194
+ ```
195
+ Error: mcpi no longer reads legacy pi config paths.
196
+ ```
197
+
198
+ Nothing is moved for you. Migrate by hand:
199
+
200
+ | Legacy | New |
201
+ | ----------------------- | ------------------------------------------------------------------ |
202
+ | `~/.pi/agent` | `~/.local/state/mcpi` (sessions in `~/.local/state/mcpi/sessions`) |
203
+ | package / binary caches | recreate under `~/.cache/mcpi` |
204
+
205
+ Caches are disposable — delete rather than move them. Alternatively set `MCPI_CODING_AGENT_DIR` to an
206
+ already-migrated directory. Settings live at `~/.config/mcpi/settings.json`; mcpi-ext's own MCP
207
+ config is separate, at `~/.config/mcpi-ext/mcp.json`.
52
208
 
53
209
  ---
54
210
 
55
- ## II. The Nuclear Football
211
+ ## What your MCP server actually gives you
212
+
213
+ The three mechanisms have different requirements. Only one of them depends on the server, so it is
214
+ worth being precise about which you get.
215
+
216
+ | Mechanism | Requires | Works with the official GitHub MCP server? |
217
+ | ------------- | ----------------------------------------------------- | ------------------------------------------ |
218
+ | **tool-cli** | any MCP server | **Yes** |
219
+ | **Code mode** | tools annotated `readOnlyHint: true`, not destructive | **Yes**, for the read-only subset |
220
+ | **Skills** | a server that publishes skills (see below) | **No** — it publishes none today |
221
+
222
+ Measured against `ghcr.io/github/github-mcp-server:latest` (server `v1.12.0`, protocol `2026-07-28`)
223
+ with the default toolset: **45 tools**, of which **26** are read-only and non-destructive and so
224
+ dispatchable from code mode. None declare an `outputSchema`, so code mode gives each one a permissive
225
+ internal survival schema and an `unknown` return type. The server does **not** declare the
226
+ `io.modelcontextprotocol/skills` extension, so it contributes **no skills** — mcpi-ext logs the
227
+ negotiation result and falls back to legacy `skill://` discovery, which also finds none.
228
+
229
+ > **Image tags.** Use `ghcr.io/github/github-mcp-server:latest`. A `skill-discovery` tag was
230
+ > referenced by earlier revisions of this document; **it does not exist** on the registry. Published
231
+ > tags are `latest`, `main`, `nightly`, and `v0.1.0`. The trailing `stdio` argument above is correct
232
+ > for `:latest`, which has an entrypoint; `:v0.1.0` has none and already includes `stdio` in its
233
+ > command, so passing it again fails to start.
234
+
235
+ ### Skills support
236
+
237
+ Skills require an MCP server that publishes them by one of two contracts:
238
+
239
+ 1. **[SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640)** — the
240
+ server declares the `io.modelcontextprotocol/skills` extension and serves `skills/list`. This is
241
+ a **live Draft** on the MCP Extensions Track: open, unratified, and still changing. mcpi-ext pins
242
+ revision `753b9f2be43e07fdd070e535d75f190cff14beea` and is gated **off** by default, which is why
243
+ `--mcp-skills-extension` (or `{"experimental": {"skillsExtension": true}}` in `mcp.json`) is
244
+ required to enable it. With the gate off, the extension is never advertised at `initialize`, so
245
+ no server can negotiate it.
246
+ 2. **Legacy `skill://` resources** — the server lists `skill://` URIs among its resources. This is
247
+ the compatibility fallback, used only when a server declares no extension.
248
+
249
+ The two are never mixed on one server. A server that declares the extension is served by the
250
+ extension path alone, even when its listing is empty.
251
+
252
+ The eight-skill GitHub reference implementation used to develop and test this client — 8 skills over
253
+ a 31-tool schema set — is **not a public distribution**. It is not published to GHCR, the MCP
254
+ Registry, or any other registry or public image tag, and there is no branch or SHA you can pull. It
255
+ remains local-only and can only be produced from the exact compatible source checkout. Treat it as
256
+ the tested reference implementation pending upstream adoption and public distribution; the official
257
+ server may implement skills in future, at which point they will work here with no change to this
258
+ extension.
259
+
260
+ If you already have a compatible GitHub MCP server checkout, you can build and tag it locally and
261
+ point `mcp.json` at that local tag — see
262
+ [running a custom server from a local image](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/server-developer-guide.md#running-a-custom-server-from-a-local-image)
263
+ in the developer guide. That path is for contributors with the source in hand; it does not make any
264
+ custom image available to pull.
265
+
266
+ To use skills today, point mcpi-ext at your own server implementing either contract. The
267
+ [server developer guide](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/server-developer-guide.md)
268
+ covers what to publish.
56
269
 
57
- ![A glowing briefcase marked 'tool-cli' being passed between hands in a dark corridor, trailing sparks of shell commands](images/nuclear-mcp-football.webp)
270
+ ---
58
271
 
59
- > _The Football is not a weapon. The Football is the authority to use weapons. Whoever holds it can reach any server, call any tool, chain any result — but they must do so deliberately, one command at a time._
272
+ ## Verifying your install
60
273
 
61
- [`tool-cli`](https://github.com/SamMorrowDrums/tool-cli) is a thin CLI binary that speaks JSON-RPC to the extension. The agent uses it like any shell command — composable with pipes, grep, jq, loops. Discovery is progressive: server list → tool list schema call. Each step pays only the tokens it needs.
274
+ Three prompts, one per mechanism. Each names the tool call you should actually see in the agent's
275
+ transcript — if you see prose describing a call instead of the call itself, the mechanism is not
276
+ working.
62
277
 
63
- 📖 [**How it works →**](docs/tool-cli.md) architecture, progressive discovery, shell composability.
64
- 📦 [**Standalone package →**](https://github.com/SamMorrowDrums/tool-cli) — `ToolProvider` interface, server, and implementor guidance for other languages.
278
+ ### Code modeworks with zero MCP servers
65
279
 
66
- > _They pass the Football from hand to hand. It is heavy with potential. Every tool on every server is one command away — but you must type the command yourself._
280
+ > Using code mode, compute the number of days between 2026-01-01 and 2026-09-07.
67
281
 
68
- ![tool-cli in action progressive discovery piped through grep](images/tool-cli-grep.png)
282
+ Expect a **`code_execute`** tool call returning `249`. This needs no MCP server at all, so it is the
283
+ fastest check that the extension loaded. If it reports code mode unavailable, see
284
+ [isolated-vm](#code-mode-needs-isolated-vm).
69
285
 
70
- ---
286
+ With servers connected, exercise MCP dispatch:
287
+
288
+ > Using code mode, list the open issues on github/github-mcp-server and count how many carry each
289
+ > label.
290
+
291
+ Expect **`code_search`** (finding dispatchable tools) then **`code_execute`** looping over paginated
292
+ results.
71
293
 
72
- ## III. Codey C. Maude
294
+ ### tool-cli works with any MCP server
73
295
 
74
- ![A luminous figure composed of flowing code, sitting cross-legged in a V8 isolate bubble, reading structured data from floating JSON schemas](images/code-c-maude.webp)
296
+ > Use tool-cli to list the MCP servers available, then show the schema for the GitHub server's
297
+ > `search_repositories` tool.
75
298
 
76
- > _Codey does not ask permission. Codey does not need to. Everything Codey touches is read-only, every result is typed, and the sandbox cannot be escaped. Codey is safe by construction._
299
+ Expect **`bash`** tool calls running `tool-cli` for example `tool-cli --help`, then
300
+ `tool-cli github`, then `tool-cli github search_repositories`. There is no `tool-cli` entry in the
301
+ agent's tool registry: it is a program invoked through mcpi's bash tool. A response containing
302
+ `<tool_cli>` markup, or a transcript of a command that no bash call ran, is a hallucination.
77
303
 
78
- Code Mode targets **read-only** tools with **structured output**. The model writes JavaScript that chains MCP tool calls inside a V8 isolate — memory-limited, time-limited, no filesystem or network access. Perfect for pagination loops, aggregation, and joins across many calls.
304
+ ### Skills needs a server that publishes them
79
305
 
80
- 📖 [**How it works →**](docs/code-mode.md) sandbox isolation, eligibility, tool dispatch.
306
+ > List the skills available, then load the one for issue triage.
81
307
 
82
- > _"I can see everything," Codey said, eyes reflecting infinite JSON. "I just can't touch it. That's the point. That's why they trust me."_
308
+ Expect a **`load_skill`** tool call. Loading prompts you to approve the skill's tool grant; the
309
+ declared tools stay locked until you approve. With no skills discovered, the agent should tell you
310
+ so — the routing section reports skills as unavailable with the reason rather than omitting them.
83
311
 
84
- ![Code Mode in action — chaining MCP tools in a V8 sandbox to build a histogram](images/code-mode-histogram.png)
312
+ ### Confirming what loaded
313
+
314
+ At startup mcpi-ext reports connected servers and discovered tool counts, and — when
315
+ `--mcp-skills-extension` is on — logs the pinned draft revision and the per-server negotiation
316
+ result. It always emits an `<execution_routing>` prompt section stating each facility's availability
317
+ and, when unavailable, why.
85
318
 
86
319
  ---
87
320
 
88
- ## When to Use Each Tier
321
+ ## Four facilities, three MCP mechanisms
89
322
 
90
- > _They asked the three: "Why are there three of you? Isn't one enough?"_
91
- >
92
- > _The Skill Dealer laid down a card. "When you know the ritual the steps, the order, the tools that belong together — you come to me. I give you the ceremony whole."_
93
- >
94
- > _The Football's briefcase clicked open. "When you need one answer, quickly, and you know what you're looking for — you reach for me. I'm a shell command. I compose."_
95
- >
96
- > _Codey smiled, cross-legged in the isolate. "And when the answer is buried in nine pages of data, when you need loops and math and joins across a thousand records — you write the code, and I run it. Safely."_
97
- >
98
- > _"Three is not redundancy," said the Skill Dealer. "Three is completeness."_
323
+ Skills, tool-cli, and code mode are the three ways this extension reaches MCP. The
324
+ `<execution_routing>` section describes a **fourth** facility alongside them — the host's own
325
+ **bash** toolbecause most real tasks need it and mis-routing to a sandbox that cannot write files
326
+ is a common failure.
99
327
 
100
- **The Skill Dealer** when there's a curated workflow for the domain task. "Triage these 20 issues" means loading the triage skill, which gives you the right tools _plus_ the workflow instructions (dedup checks, labeling conventions, close criteria). Re-deriving that from raw tool calls is wasteful and error-prone.
328
+ bash is not an MCP mechanism. It is the substrate: the only facility that can create, modify, or
329
+ inspect files, run the host's real programs, and leave artifacts behind. It is also how tool-cli is
330
+ invoked, which is why the two compose so closely — fetching MCP data and then filtering it with `jq`
331
+ or writing it to disk is one bash command, not two rival approaches.
101
332
 
102
- **The Nuclear Football** one-shot or exploratory calls, especially when piping through Unix tools. `tool-cli github search_code '{"query":"auth"}' | jq '.items[].path'` — one call, pipe to jq, done. Also perfect for discovering what's on a server you haven't used before.
333
+ | Facility | Suits work that is… |
334
+ | --------- | ------------------------------------------------------------------------------------------- |
335
+ | bash | touching the real machine: files, git, build tools, data pipelines, artifacts that persist |
336
+ | Code mode | exact computation or control flow, sandboxed with no filesystem, network, or process access |
337
+ | Skills | a documented domain workflow — sequencing, conventions, and a curated tool set |
338
+ | tool-cli | reaching a specific MCP tool, or discovering what exists — run through the host bash tool |
103
339
 
104
- **Codey C. Maude** when you need real computation across many calls: pagination loops, aggregation, joining results, math. 876 issues across 9 pages, counting labels per issue, summing into a histogram — that's a loop with state. Doing it via tool-cli would mean 9 separate calls plus shell-side aggregation. Fragile. Codey does it in one sandbox execution.
340
+ The section sorts facilities **by task shape, not by rank**. None is a default, none outranks
341
+ another, and there is no order to try them in. The list is alphabetical by identifier purely so the
342
+ emitted bytes stay stable between turns and never invalidate the prompt cache.
105
343
 
106
- ### A single task using all three
344
+ Every facility states its own availability. An unavailable one is listed **with its reason** rather
345
+ than silently dropped, and "we could not tell" is reported as `unknown` rather than collapsed into
346
+ "absent".
107
347
 
108
- > _"Triage the backlog of github/github-mcp-server: find stale bugs older than 90 days with no recent activity, summarize patterns, and close obvious duplicates."_
348
+ ### With zero MCP servers connected
109
349
 
110
- 1. **Codey** paginated all open bug issues, filtered by `updated < 90d ago`, grouped by label and keyword to find clusters. Computation across many pages — this is what sandboxes are for.
350
+ The extension still loads and still emits `<execution_routing>`. Code mode remains available, because
351
+ pure computation needs no server. Skills report as unavailable with the reason that none were
352
+ discovered. tool-cli starts its bridge but has no upstream to reach. Nothing errors, and a missing
353
+ `mcp.json` is treated as an empty server list rather than a failure.
111
354
 
112
- 2. **The Football** spot-checked suspect issues. `tool-cli github get_issue '{"number":42}'` piped through `jq` to eyeball specific fields. Quick, ad-hoc, composable.
355
+ ### Code mode needs isolated-vm
113
356
 
114
- 3. **The Skill Dealer** loaded `triage-issues` to actually close the duplicates — following the project's triage workflow with correct labels, comment templates, and close reasons. The ceremony, performed correctly.
357
+ Code mode uses the optional [`isolated-vm`](https://github.com/laverdet/isolated-vm) native addon. It
358
+ ships prebuilt binaries for Linux (x64, arm64), macOS (Apple Silicon), and Windows (x64), so the
359
+ usual install is a download. Where no prebuild matches — Intel macOS, for instance — npm compiles it
360
+ from source and needs a C++ toolchain.
115
361
 
116
- > _The rule of thumb is simple: skill for workflows, tool-cli for one-shots, code_execute for computation. The three are not competing. They are collaborating._
362
+ If the addon is unavailable for any reason, **installation still succeeds and the extension still
363
+ loads**. Code mode reports itself unavailable with the specific cause, and skills, tool-cli, and
364
+ execution routing continue to work. Code mode never falls back to `node:vm`: that would silently
365
+ downgrade an isolate boundary to same-process execution and hand sandboxed code the host realm.
366
+
367
+ To skip the addon deliberately: `npm install --omit=optional`.
117
368
 
118
369
  ---
119
370
 
120
- ## The Architecture
371
+ ## Architecture
121
372
 
122
373
  ```mermaid
123
374
  flowchart TD
124
375
  subgraph mcpi["mcpi (agent)"]
125
- T1["load_skill\n(Tier 1 — Skills)"]
126
- T2["tool-cli\n(Tier 2 — Football)"]
127
- T3["code_search / code_execute\n(Tier 3 — Code Mode)"]
128
- MCM["McpClientManager\n(MCP SDK — stdio & Streamable HTTP)"]
129
- T1 --> MCM
130
- T2 --> MCM
131
- T3 --> MCM
376
+ LS["load_skill<br/>(skills)"]
377
+ BASH["bash → tool-cli<br/>(tool-cli)"]
378
+ CM["code_search / code_execute<br/>(code mode)"]
132
379
  end
380
+ LS --> POL["McpPolicy<br/>(authorization boundary)"]
381
+ BASH --> POL
382
+ CM --> POL
383
+ POL --> MCM["McpClientManager<br/>(MCP client — stdio &amp; Streamable HTTP)"]
133
384
  MCM --> S1["MCP Server"]
134
385
  MCM --> S2["MCP Server"]
135
- MCM --> S3["MCP Server"]
136
386
  ```
137
387
 
138
- The harness controls what the model sees. MCP servers just expose their tools and skills. The extension decides _when_ and _how_ to reveal them.
139
-
140
- ### Every call flows through the harness
141
-
142
- All three tiers route MCP tool calls back through the extension process. This is a subtle but important property: even when the model writes sandboxed JavaScript (Code Mode) or shells out to `tool-cli`, the actual MCP call happens in the harness. This means:
143
-
144
- - **Every tool invocation appears in the agent log** — skills, tool-cli one-shots, and Code Mode sandbox calls alike. Full observability without instrumentation.
145
- - **Human-in-the-loop can be added at one point** — the `McpClientManager` is the single choke point. Future work can check tool annotations (`readOnlyHint`, `destructiveHint`) and gate destructive calls through user confirmation, regardless of which tier initiated them.
146
-
147
- > _MCP doesn't have a context problem. It never did. It was just waiting for someone to imagine the right way to read the runes._
388
+ All three mechanisms route back through the extension process, and every one of them crosses the same
389
+ authorization boundary — `McpPolicy` — exactly once. Even when the model writes sandboxed JavaScript
390
+ or shells out to `tool-cli`, the actual MCP call is authorized and dispatched by that one object.
391
+
392
+ - **Every tool invocation appears in the agent log** skills, tool-cli one-shots, and code mode
393
+ sandbox calls alike. Full observability without instrumentation.
394
+ - **Human-in-the-loop happens at one point.** `McpPolicy` reads tool annotations and gates
395
+ non-read-only calls through user confirmation, whichever mechanism initiated them. A tool unlocked
396
+ by an approved skill grant is not re-prompted.
397
+ - **Code mode is refused, not prompted.** A non-read-only tool called from the sandbox is denied
398
+ outright rather than escalated to a confirmation. Visibility is not authority.
399
+ - **Undiscovered and gated tools never reach upstream.** The policy verifies the tool exists in the
400
+ discovered set and is not skill-gated _before_ contacting the server, so naming a hidden tool over
401
+ the authenticated bridge socket fails at the boundary.
402
+ - **Resource reads use the same policy.** tool-cli can list templates and read ordinary text and
403
+ binary resources, while every `skill://` URI and SEP-2640-declared skill resource stays isolated.
404
+ Skill reads are origin-bound, and a discovery pass cannot authorize a skill-load read.
405
+ - **Every decision is audited** — allowed and denied alike, recorded with the source that made it
406
+ (`proxy`, `code-mode`, `tool-cli`, `skill-discovery`, `skill-load`, `skills-extension`).
407
+
408
+ ### Skills never execute anything
409
+
410
+ Nothing in a skill is executed. A SKILL.md body is content, not commands: helper code and
411
+ instructions telling the host to run something are text the model reads, never actions the extension
412
+ performs. A skill's declared tools stay **inert until you approve the grant**, and the grant is bound
413
+ to the server, the resource URI, and a hash of the tool list — so a server that widens `allowed-tools`
414
+ or rotates its content after approval is re-prompted rather than inheriting the old answer.
415
+
416
+ ### tool-cli bridge credentials are session-scoped
417
+
418
+ tool-cli reaches the extension over an authenticated local bridge, not a shared service. On
419
+ `session_start` the bridge binds a **random port** and generates a fresh **32-byte session token**;
420
+ both are torn down on `session_shutdown`. `TOOL_CLI_PORT` and `TOOL_CLI_TOKEN` are exposed to the
421
+ agent's bash environment **only after** an authenticated, compatible bridge-v1 handshake succeeds —
422
+ inherited values are masked until then, and startup, auth, timeout, or major-version failures
423
+ withhold the usage docs entirely and report an actionable reason.
424
+
425
+ Stdio MCP child servers are spawned with the SDK's safe environment plus their explicit
426
+ configuration, with every `TOOL_CLI_*` variable stripped — so a child server cannot inherit this
427
+ session's bridge credentials, even when mcpi was started from another mcpi session.
428
+
429
+ ### Protocol and defaults
430
+
431
+ mcpi-ext uses `@modelcontextprotocol/client@2.0.0` in automatic version-negotiation mode. It probes
432
+ the released **`2026-07-28`** protocol with `server/discover`, then falls back to the legacy
433
+ `initialize` handshake for servers that predate it. The connection log reports the negotiated era.
434
+
435
+ - Tool and skill-resource lists follow cursors automatically, with a 64-page safety limit.
436
+ - Results without a server-provided `ttlMs` are immediately stale (`defaultCacheTtlMs: 0`). Explicit
437
+ server cache hints are honoured in the SDK's in-memory cache; no persistent or shared cache is
438
+ configured.
439
+ - Tool-list change handling is enabled. Modern servers may use a `subscriptions/listen` stream where
440
+ advertised; legacy servers use list-changed notifications. Durable subscription resume and live
441
+ skill-resource refresh are not exposed.
442
+ - Modern `input_required` flows support explicit form input, decline, and cancel in interactive
443
+ sessions. Headless and URL elicitation fail with an actionable error rather than auto-approving.
148
444
 
149
445
  ---
150
446
 
151
- ## Quick Start
152
-
153
- ### 1. Install
154
-
155
- ```sh
156
- npm install -g @sammorrowdrums/mcpi@latest @sammorrowdrums/mcpi-ext@latest @sammorrowdrums/tool-cli@latest
157
- ```
158
-
159
- ### 2. Configure MCP servers
160
-
161
- Create `~/.config/mcpi-ext/mcp.json`:
162
-
163
- ```json
164
- {
165
- "mcpServers": {
166
- "github": {
167
- "type": "stdio",
168
- "command": "docker",
169
- "args": [
170
- "run",
171
- "--rm",
172
- "-i",
173
- "-e",
174
- "GITHUB_PERSONAL_ACCESS_TOKEN",
175
- "ghcr.io/github/github-mcp-server:skill-discovery",
176
- "stdio"
177
- ],
178
- "env": {
179
- "GITHUB_PERSONAL_ACCESS_TOKEN": "xxx"
180
- }
181
- }
182
- }
183
- }
184
- ```
447
+ ## Documentation
448
+
449
+ - [Skills](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/skills.md) — deferred gating,
450
+ the two discovery contracts, SEP-2640 integrity model, approval binding.
451
+ - [tool-cli](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/tool-cli.md) — bridge
452
+ architecture, progressive discovery, resources, shell composability.
453
+ - [Code mode](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/code-mode.md) — sandbox
454
+ isolation, catalog provenance, dispatch eligibility.
455
+ - [Server developer guide](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/server-developer-guide.md)
456
+ — what to publish so your MCP server works well with all three mechanisms.
457
+ - [Releasing](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/releasing.md) — trusted
458
+ publishing and release preflight.
459
+ - [AGENTS.md](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/AGENTS.md) — contributor tooling,
460
+ dev loop, and architecture detail.
461
+ - [DECISIONS.md](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/DECISIONS.md) — the decision
462
+ log behind these mechanisms.
185
463
 
186
- Replace `xxx` with your [GitHub personal access token](https://github.com/settings/tokens). See [github/github-mcp-server](https://github.com/github/github-mcp-server) for the standard server.
464
+ ---
187
465
 
188
- > **Note:** The `skill-discovery` tag includes experimental `skill://` resources that enable Tier 1 progressive discovery. The standard `ghcr.io/github/github-mcp-server` image works too — tool-cli (Tier 2) and Code Mode (Tier 3) function with any MCP server, but skill-gated tool activation requires `skill://` resources.
466
+ ## Screenshots
189
467
 
190
- You can add more servers both `stdio` (spawns a process) and `remote` (Streamable HTTP) are supported:
468
+ ![Skills enabling MCP toolsthe model loads a skill and gains access to gated tools](https://raw.githubusercontent.com/SamMorrowDrums/mcpi-ext/main/images/skills-enabling-mcp-tools.png)
191
469
 
192
- ```json
193
- {
194
- "mcpServers": {
195
- "github": { "...": "..." },
196
- "my-remote-server": {
197
- "type": "remote",
198
- "url": "https://my-mcp-server.example.com/mcp",
199
- "headers": {
200
- "Authorization": "Bearer xxx"
201
- }
202
- }
203
- }
204
- }
205
- ```
470
+ ![tool-cli in action — progressive discovery piped through grep](https://raw.githubusercontent.com/SamMorrowDrums/mcpi-ext/main/images/tool-cli-grep.png)
206
471
 
207
- ### 3. Run
472
+ ![Code mode in action — chaining MCP tools in a V8 sandbox to build a histogram](https://raw.githubusercontent.com/SamMorrowDrums/mcpi-ext/main/images/code-mode-histogram.png)
208
473
 
209
- ```sh
210
- mcpi --extension $(npm root -g)/@sammorrowdrums/mcpi-ext/dist/index.js \
211
- --mcp-config ~/.config/mcpi-ext/mcp.json
212
- ```
474
+ ---
213
475
 
214
- ### Local development
476
+ ## Local development
215
477
 
216
478
  ```sh
217
479
  git clone https://github.com/SamMorrowDrums/mcpi-ext.git
@@ -221,28 +483,41 @@ npm run build
221
483
  npm test
222
484
  ```
223
485
 
224
- Then run with your local build:
486
+ Run mcpi against your local build with `--extension`, which loads a file directly and bypasses the
487
+ settings-managed package above. This is the one case where `--extension` is the right tool:
225
488
 
226
489
  ```sh
227
490
  mcpi --extension ./dist/index.js --mcp-config ~/.config/mcpi-ext/mcp.json
228
491
  ```
229
492
 
230
- See [AGENTS.md](AGENTS.md) for full tooling docs, dev loop, and architecture details.
231
-
232
- ## Project Structure
493
+ ### Project structure
233
494
 
234
495
  ```
235
496
  src/
236
497
  index.ts Extension entry point (lifecycle hooks, wiring)
237
- mcp/ MCP client management (connections, tool discovery)
238
- skills/ Skill registry, discovery, gating, tool proxies
239
- tool-cli/ tool-cli RPC server, client, CLI binary, prompt
240
- code-mode/ V8 sandbox executor, eligibility, type hints
241
- test-servers/ Test MCP servers (weather, echo)
242
- docs/ Detailed mechanism documentation
243
- images/ Banner, character art, and screenshots
498
+ mcp/ MCP client management (connections, discovery) + McpPolicy
499
+ routing/ Execution-facility descriptors, prompt section, host seam
500
+ skills/ Skill registry, discovery, gating, tool proxies, SEP-2640
501
+ tool-cli/ tool-cli RPC server, provider, bridge handshake, prompt
502
+ code-mode/ V8 sandbox executor, lazy isolated-vm adapter, type hints
503
+ test-servers/ Test MCP servers (weather, echo, skills fixtures)
504
+ docs/ Mechanism documentation
505
+ images/ Screenshots
506
+ scripts/ Integration, smoke, and release-check scripts
507
+ tsconfig.json Development build (compiles tests and fixture servers)
508
+ tsconfig.build.json Published build (no tests, fixtures, or source maps)
244
509
  ```
245
510
 
511
+ See [AGENTS.md](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/AGENTS.md) for the full dev loop.
512
+
513
+ ## Releasing
514
+
515
+ Published to npm by
516
+ [`.github/workflows/publish.yml`](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/.github/workflows/publish.yml)
517
+ using npm trusted publishing — a GitHub Release triggers it, OIDC authenticates it, and no
518
+ `NPM_TOKEN` exists anywhere in this repository. See
519
+ [docs/releasing.md](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/docs/releasing.md).
520
+
246
521
  ## License
247
522
 
248
- See repository for license details.
523
+ [MIT](https://github.com/SamMorrowDrums/mcpi-ext/blob/main/LICENSE)