@sammorrowdrums/mcpi-ext 0.2.0 → 0.2.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 (208) hide show
  1. package/dist/code-mode/code-mode-integration.test.d.ts +2 -0
  2. package/dist/code-mode/code-mode-integration.test.d.ts.map +1 -0
  3. package/dist/code-mode/code-mode-integration.test.js +116 -0
  4. package/dist/code-mode/code-mode-integration.test.js.map +1 -0
  5. package/dist/code-mode/eligibility.d.ts +10 -0
  6. package/dist/code-mode/eligibility.d.ts.map +1 -0
  7. package/dist/code-mode/eligibility.js +14 -0
  8. package/dist/code-mode/eligibility.js.map +1 -0
  9. package/dist/code-mode/eligibility.test.d.ts +2 -0
  10. package/dist/code-mode/eligibility.test.d.ts.map +1 -0
  11. package/dist/code-mode/eligibility.test.js +53 -0
  12. package/dist/code-mode/eligibility.test.js.map +1 -0
  13. package/dist/code-mode/executor.d.ts +35 -0
  14. package/dist/code-mode/executor.d.ts.map +1 -0
  15. package/dist/code-mode/executor.js +120 -0
  16. package/dist/code-mode/executor.js.map +1 -0
  17. package/dist/code-mode/executor.test.d.ts +2 -0
  18. package/dist/code-mode/executor.test.d.ts.map +1 -0
  19. package/dist/code-mode/executor.test.js +130 -0
  20. package/dist/code-mode/executor.test.js.map +1 -0
  21. package/dist/code-mode/index.d.ts +65 -0
  22. package/dist/code-mode/index.d.ts.map +1 -0
  23. package/dist/code-mode/index.js +175 -0
  24. package/dist/code-mode/index.js.map +1 -0
  25. package/dist/code-mode/tools.d.ts +45 -0
  26. package/dist/code-mode/tools.d.ts.map +1 -0
  27. package/dist/code-mode/tools.js +70 -0
  28. package/dist/code-mode/tools.js.map +1 -0
  29. package/dist/code-mode/type-hints.d.ts +20 -0
  30. package/dist/code-mode/type-hints.d.ts.map +1 -0
  31. package/dist/code-mode/type-hints.js +189 -0
  32. package/dist/code-mode/type-hints.js.map +1 -0
  33. package/dist/code-mode/type-hints.test.d.ts +2 -0
  34. package/dist/code-mode/type-hints.test.d.ts.map +1 -0
  35. package/dist/code-mode/type-hints.test.js +157 -0
  36. package/dist/code-mode/type-hints.test.js.map +1 -0
  37. package/dist/docker-e2e.d.ts +55 -0
  38. package/dist/docker-e2e.d.ts.map +1 -0
  39. package/dist/docker-e2e.js +235 -0
  40. package/dist/docker-e2e.js.map +1 -0
  41. package/dist/docker-e2e.test.d.ts +2 -0
  42. package/dist/docker-e2e.test.d.ts.map +1 -0
  43. package/dist/docker-e2e.test.js +176 -0
  44. package/dist/docker-e2e.test.js.map +1 -0
  45. package/dist/index.d.ts +3 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +148 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/index.test.d.ts +2 -0
  50. package/dist/index.test.d.ts.map +1 -0
  51. package/dist/index.test.js +8 -0
  52. package/dist/index.test.js.map +1 -0
  53. package/dist/mcp/client-manager.d.ts +46 -0
  54. package/dist/mcp/client-manager.d.ts.map +1 -0
  55. package/dist/mcp/client-manager.js +148 -0
  56. package/dist/mcp/client-manager.js.map +1 -0
  57. package/dist/mcp/client-manager.test.d.ts +2 -0
  58. package/dist/mcp/client-manager.test.d.ts.map +1 -0
  59. package/dist/mcp/client-manager.test.js +204 -0
  60. package/dist/mcp/client-manager.test.js.map +1 -0
  61. package/dist/mcp/config-loader.d.ts +8 -0
  62. package/dist/mcp/config-loader.d.ts.map +1 -0
  63. package/dist/mcp/config-loader.js +43 -0
  64. package/dist/mcp/config-loader.js.map +1 -0
  65. package/dist/mcp/config-loader.test.d.ts +2 -0
  66. package/dist/mcp/config-loader.test.d.ts.map +1 -0
  67. package/dist/mcp/config-loader.test.js +93 -0
  68. package/dist/mcp/config-loader.test.js.map +1 -0
  69. package/dist/mcp/config.d.ts +46 -0
  70. package/dist/mcp/config.d.ts.map +1 -0
  71. package/dist/mcp/config.js +28 -0
  72. package/dist/mcp/config.js.map +1 -0
  73. package/{src/mcp/index.ts → dist/mcp/index.d.ts} +1 -0
  74. package/dist/mcp/index.d.ts.map +1 -0
  75. package/dist/mcp/index.js +4 -0
  76. package/dist/mcp/index.js.map +1 -0
  77. package/dist/skills/discover.d.ts +10 -0
  78. package/dist/skills/discover.d.ts.map +1 -0
  79. package/dist/skills/discover.js +60 -0
  80. package/dist/skills/discover.js.map +1 -0
  81. package/dist/skills/format.d.ts +10 -0
  82. package/dist/skills/format.d.ts.map +1 -0
  83. package/dist/skills/format.js +38 -0
  84. package/dist/skills/format.js.map +1 -0
  85. package/dist/skills/format.test.d.ts +2 -0
  86. package/dist/skills/format.test.d.ts.map +1 -0
  87. package/dist/skills/format.test.js +63 -0
  88. package/dist/skills/format.test.js.map +1 -0
  89. package/{src/skills/index.ts → dist/skills/index.d.ts} +2 -5
  90. package/dist/skills/index.d.ts.map +1 -0
  91. package/dist/skills/index.js +6 -0
  92. package/dist/skills/index.js.map +1 -0
  93. package/dist/skills/load-skill-tool.d.ts +40 -0
  94. package/dist/skills/load-skill-tool.d.ts.map +1 -0
  95. package/dist/skills/load-skill-tool.js +104 -0
  96. package/dist/skills/load-skill-tool.js.map +1 -0
  97. package/dist/skills/mcp-tool-proxy.d.ts +11 -0
  98. package/dist/skills/mcp-tool-proxy.d.ts.map +1 -0
  99. package/dist/skills/mcp-tool-proxy.js +116 -0
  100. package/dist/skills/mcp-tool-proxy.js.map +1 -0
  101. package/dist/skills/skill-integration.test.d.ts +2 -0
  102. package/dist/skills/skill-integration.test.d.ts.map +1 -0
  103. package/dist/skills/skill-integration.test.js +119 -0
  104. package/dist/skills/skill-integration.test.js.map +1 -0
  105. package/dist/skills/skill-registry.d.ts +39 -0
  106. package/dist/skills/skill-registry.d.ts.map +1 -0
  107. package/dist/skills/skill-registry.js +48 -0
  108. package/dist/skills/skill-registry.js.map +1 -0
  109. package/dist/skills/skill-registry.test.d.ts +2 -0
  110. package/dist/skills/skill-registry.test.d.ts.map +1 -0
  111. package/dist/skills/skill-registry.test.js +67 -0
  112. package/dist/skills/skill-registry.test.js.map +1 -0
  113. package/dist/test-servers/weather-server.d.ts +12 -0
  114. package/dist/test-servers/weather-server.d.ts.map +1 -0
  115. package/dist/test-servers/weather-server.js +139 -0
  116. package/dist/test-servers/weather-server.js.map +1 -0
  117. package/dist/test-servers/weather-stdio.d.ts +2 -0
  118. package/dist/test-servers/weather-stdio.d.ts.map +1 -0
  119. package/{src/test-servers/weather-stdio.ts → dist/test-servers/weather-stdio.js} +1 -1
  120. package/dist/test-servers/weather-stdio.js.map +1 -0
  121. package/dist/tool-cli/cli.d.ts +3 -0
  122. package/dist/tool-cli/cli.d.ts.map +1 -0
  123. package/dist/tool-cli/cli.js +179 -0
  124. package/dist/tool-cli/cli.js.map +1 -0
  125. package/dist/tool-cli/constants.d.ts +7 -0
  126. package/dist/tool-cli/constants.d.ts.map +1 -0
  127. package/dist/tool-cli/constants.js +15 -0
  128. package/dist/tool-cli/constants.js.map +1 -0
  129. package/dist/tool-cli/format.d.ts +8 -0
  130. package/dist/tool-cli/format.d.ts.map +1 -0
  131. package/{src/tool-cli/format.ts → dist/tool-cli/format.js} +5 -4
  132. package/dist/tool-cli/format.js.map +1 -0
  133. package/dist/tool-cli/format.test.d.ts +2 -0
  134. package/dist/tool-cli/format.test.d.ts.map +1 -0
  135. package/dist/tool-cli/format.test.js +30 -0
  136. package/dist/tool-cli/format.test.js.map +1 -0
  137. package/{src/tool-cli/index.ts → dist/tool-cli/index.d.ts} +1 -0
  138. package/dist/tool-cli/index.d.ts.map +1 -0
  139. package/dist/tool-cli/index.js +3 -0
  140. package/dist/tool-cli/index.js.map +1 -0
  141. package/dist/tool-cli/rpc-client.d.ts +6 -0
  142. package/dist/tool-cli/rpc-client.d.ts.map +1 -0
  143. package/dist/tool-cli/rpc-client.js +25 -0
  144. package/dist/tool-cli/rpc-client.js.map +1 -0
  145. package/dist/tool-cli/rpc-server.d.ts +48 -0
  146. package/dist/tool-cli/rpc-server.d.ts.map +1 -0
  147. package/dist/tool-cli/rpc-server.js +220 -0
  148. package/dist/tool-cli/rpc-server.js.map +1 -0
  149. package/dist/tool-cli/rpc-server.test.d.ts +2 -0
  150. package/dist/tool-cli/rpc-server.test.d.ts.map +1 -0
  151. package/dist/tool-cli/rpc-server.test.js +154 -0
  152. package/dist/tool-cli/rpc-server.test.js.map +1 -0
  153. package/package.json +5 -1
  154. package/.dockerignore +0 -6
  155. package/.github/dependabot.yml +0 -25
  156. package/.github/workflows/ci.yml +0 -50
  157. package/.hadolint.yaml +0 -6
  158. package/.prettierignore +0 -4
  159. package/.prettierrc +0 -7
  160. package/AGENTS.md +0 -118
  161. package/DECISIONS.md +0 -99
  162. package/Dockerfile +0 -39
  163. package/aube-lock.yaml +0 -4146
  164. package/docs/code-mode.md +0 -38
  165. package/docs/skills.md +0 -57
  166. package/docs/tool-cli.md +0 -54
  167. package/eslint.config.js +0 -27
  168. package/images/banner.webp +0 -0
  169. package/images/code-c-maude.webp +0 -0
  170. package/images/code-mode-histogram.png +0 -0
  171. package/images/nuclear-mcp-football.webp +0 -0
  172. package/images/skills-enabling-mcp-tools.png +0 -0
  173. package/images/the-skill-dealer.webp +0 -0
  174. package/images/tool-cli-grep.png +0 -0
  175. package/mise.toml +0 -53
  176. package/scripts/docker-entrypoint.sh +0 -29
  177. package/scripts/test-echo-server.mjs +0 -28
  178. package/scripts/test-mcp-integration.mjs +0 -59
  179. package/scripts/test-tool-cli-smoke.mjs +0 -93
  180. package/src/code-mode/code-mode-integration.test.ts +0 -135
  181. package/src/code-mode/eligibility.test.ts +0 -60
  182. package/src/code-mode/eligibility.ts +0 -16
  183. package/src/code-mode/executor.test.ts +0 -168
  184. package/src/code-mode/executor.ts +0 -163
  185. package/src/code-mode/index.ts +0 -208
  186. package/src/code-mode/tools.ts +0 -110
  187. package/src/code-mode/type-hints.test.ts +0 -187
  188. package/src/code-mode/type-hints.ts +0 -249
  189. package/src/docker-e2e.test.ts +0 -195
  190. package/src/docker-e2e.ts +0 -277
  191. package/src/index.test.ts +0 -8
  192. package/src/index.ts +0 -179
  193. package/src/mcp/client-manager.test.ts +0 -250
  194. package/src/mcp/client-manager.ts +0 -199
  195. package/src/mcp/config-loader.test.ts +0 -115
  196. package/src/mcp/config-loader.ts +0 -46
  197. package/src/mcp/config.ts +0 -40
  198. package/src/skills/discover.ts +0 -81
  199. package/src/skills/format.test.ts +0 -70
  200. package/src/skills/format.ts +0 -42
  201. package/src/skills/load-skill-tool.ts +0 -136
  202. package/src/skills/mcp-tool-proxy.ts +0 -143
  203. package/src/skills/skill-integration.test.ts +0 -139
  204. package/src/skills/skill-registry.test.ts +0 -83
  205. package/src/skills/skill-registry.ts +0 -69
  206. package/src/test-servers/weather-server.ts +0 -171
  207. package/src/tool-cli/format.test.ts +0 -33
  208. package/tsconfig.json +0 -21
@@ -0,0 +1,220 @@
1
+ import http from "node:http";
2
+ import { resolvePort } from "./constants.js";
3
+ /**
4
+ * JSON-RPC 2.0 server that exposes MCP tool discovery and execution.
5
+ *
6
+ * Methods:
7
+ * - listServers → server names + tool counts + random examples
8
+ * - listTools(server) → tool names + descriptions
9
+ * - describeTool(server, tool) → full schema
10
+ * - callTool(server, tool, arguments) → execute and return result
11
+ */
12
+ export class ToolCliRpcServer {
13
+ mcpManager;
14
+ server = null;
15
+ port;
16
+ constructor(mcpManager, port) {
17
+ this.mcpManager = mcpManager;
18
+ this.port = port ?? resolvePort();
19
+ }
20
+ /** Start the HTTP server. Resolves once listening. */
21
+ async start(log) {
22
+ if (this.server)
23
+ return;
24
+ const MAX_BODY_SIZE = 1024 * 1024; // 1 MB
25
+ const server = http.createServer((req, res) => {
26
+ if (req.method !== "POST") {
27
+ res.writeHead(405, { "Content-Type": "application/json" });
28
+ res.end(JSON.stringify(rpcError(null, -32600, "Only POST accepted")));
29
+ return;
30
+ }
31
+ let body = "";
32
+ let aborted = false;
33
+ req.on("error", () => {
34
+ aborted = true;
35
+ });
36
+ req.on("data", (chunk) => {
37
+ if (aborted)
38
+ return;
39
+ body += chunk.toString();
40
+ if (body.length > MAX_BODY_SIZE) {
41
+ aborted = true;
42
+ res.writeHead(413, { "Content-Type": "application/json" });
43
+ res.end(JSON.stringify(rpcError(null, -32600, "Request too large")));
44
+ req.destroy();
45
+ }
46
+ });
47
+ req.on("end", () => {
48
+ if (aborted)
49
+ return;
50
+ void this.handleBody(body)
51
+ .then((response) => {
52
+ res.writeHead(200, { "Content-Type": "application/json" });
53
+ res.end(JSON.stringify(response));
54
+ })
55
+ .catch(() => {
56
+ try {
57
+ res.writeHead(500, { "Content-Type": "application/json" });
58
+ res.end(JSON.stringify(rpcError(null, -32603, "Internal error")));
59
+ }
60
+ catch {
61
+ res.end();
62
+ }
63
+ });
64
+ });
65
+ });
66
+ return new Promise((resolve, reject) => {
67
+ server.once("error", (err) => {
68
+ this.server = null;
69
+ reject(err);
70
+ });
71
+ server.listen(this.port, "127.0.0.1", () => {
72
+ this.server = server;
73
+ log?.(`[tool-cli] RPC server listening on 127.0.0.1:${this.port}`);
74
+ resolve();
75
+ });
76
+ });
77
+ }
78
+ /** Stop the HTTP server. */
79
+ async stop() {
80
+ const server = this.server;
81
+ if (!server)
82
+ return;
83
+ this.server = null;
84
+ return new Promise((resolve) => {
85
+ server.close(() => resolve());
86
+ });
87
+ }
88
+ /** Returns the port the server is listening on (resolved after start for port 0). */
89
+ getPort() {
90
+ if (this.server) {
91
+ const addr = this.server.address();
92
+ if (addr && typeof addr === "object")
93
+ return addr.port;
94
+ }
95
+ return this.port;
96
+ }
97
+ async handleBody(body) {
98
+ let parsed;
99
+ try {
100
+ parsed = JSON.parse(body);
101
+ }
102
+ catch {
103
+ return rpcError(null, -32700, "Parse error");
104
+ }
105
+ if (parsed.jsonrpc !== "2.0" || !parsed.method) {
106
+ return rpcError(parsed.id ?? null, -32600, "Invalid Request");
107
+ }
108
+ try {
109
+ const result = await this.dispatch(parsed.method, parsed.params ?? {});
110
+ return { jsonrpc: "2.0", result, id: parsed.id ?? null };
111
+ }
112
+ catch (err) {
113
+ const message = err instanceof Error ? err.message : String(err);
114
+ const code = err instanceof RpcMethodError ? err.code : -32603;
115
+ return rpcError(parsed.id ?? null, code, message);
116
+ }
117
+ }
118
+ async dispatch(method, params) {
119
+ switch (method) {
120
+ case "listServers":
121
+ return this.listServers();
122
+ case "listTools":
123
+ return this.listTools(params);
124
+ case "describeTool":
125
+ return this.describeTool(params);
126
+ case "callTool":
127
+ return this.callTool(params);
128
+ default:
129
+ throw new RpcMethodError(-32601, `Method not found: ${method}`);
130
+ }
131
+ }
132
+ listServers() {
133
+ const serverNames = this.mcpManager.getConnectedServers();
134
+ const servers = serverNames.map((name) => {
135
+ const tools = this.mcpManager.getToolsForServer(name);
136
+ return {
137
+ name,
138
+ toolCount: tools.length,
139
+ examples: pickRandomExamples(tools, 3),
140
+ };
141
+ });
142
+ return { servers };
143
+ }
144
+ listTools(params) {
145
+ const server = requireString(params, "server");
146
+ this.assertServerExists(server);
147
+ const tools = this.mcpManager.getToolsForServer(server);
148
+ return {
149
+ server,
150
+ tools: tools.map((t) => ({
151
+ name: t.name,
152
+ description: t.description ?? "(no description)",
153
+ hasStructuredOutput: t.outputSchema != null,
154
+ })),
155
+ };
156
+ }
157
+ describeTool(params) {
158
+ const server = requireString(params, "server");
159
+ const toolName = requireString(params, "tool");
160
+ this.assertServerExists(server);
161
+ const tool = this.mcpManager.getToolsForServer(server).find((t) => t.name === toolName);
162
+ if (!tool) {
163
+ throw new RpcMethodError(-32602, `Tool "${toolName}" not found on server "${server}"`);
164
+ }
165
+ return {
166
+ name: tool.name,
167
+ description: tool.description ?? "(no description)",
168
+ inputSchema: tool.inputSchema,
169
+ outputSchema: tool.outputSchema,
170
+ annotations: tool.annotations,
171
+ };
172
+ }
173
+ async callTool(params) {
174
+ const server = requireString(params, "server");
175
+ const toolName = requireString(params, "tool");
176
+ this.assertServerExists(server);
177
+ const client = this.mcpManager.getClient(server);
178
+ if (!client) {
179
+ throw new RpcMethodError(-32603, `No client for server "${server}"`);
180
+ }
181
+ const toolArgs = params.arguments ?? {};
182
+ const result = await client.callTool({ name: toolName, arguments: toolArgs });
183
+ return {
184
+ content: result.content,
185
+ isError: result.isError === true ? true : undefined,
186
+ structuredContent: result.structuredContent,
187
+ };
188
+ }
189
+ assertServerExists(server) {
190
+ if (!this.mcpManager.getConnectedServers().includes(server)) {
191
+ throw new RpcMethodError(-32602, `Server "${server}" not found. Connected: ${this.mcpManager.getConnectedServers().join(", ") || "(none)"}`);
192
+ }
193
+ }
194
+ }
195
+ class RpcMethodError extends Error {
196
+ code;
197
+ constructor(code, message) {
198
+ super(message);
199
+ this.code = code;
200
+ this.name = "RpcMethodError";
201
+ }
202
+ }
203
+ function rpcError(id, code, message) {
204
+ return { jsonrpc: "2.0", error: { code, message }, id };
205
+ }
206
+ function requireString(params, key) {
207
+ const val = params[key];
208
+ if (typeof val !== "string" || val.length === 0) {
209
+ throw new RpcMethodError(-32602, `Missing or invalid parameter: "${key}" (string required)`);
210
+ }
211
+ return val;
212
+ }
213
+ /** Pick up to `n` random tool names from a list. */
214
+ function pickRandomExamples(tools, n) {
215
+ if (tools.length <= n)
216
+ return tools.map((t) => t.name);
217
+ const shuffled = [...tools].sort(() => Math.random() - 0.5);
218
+ return shuffled.slice(0, n).map((t) => t.name);
219
+ }
220
+ //# sourceMappingURL=rpc-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-server.js","sourceRoot":"","sources":["../../src/tool-cli/rpc-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rpc-server.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-server.test.d.ts","sourceRoot":"","sources":["../../src/tool-cli/rpc-server.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,154 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
+ import { ToolCliRpcServer } from "./rpc-server.js";
3
+ /** Minimal mock of McpClientManager for RPC server testing. */
4
+ function createMockManager() {
5
+ const tools = [
6
+ {
7
+ name: "get_weather",
8
+ description: "Get current weather for a city",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: { city: { type: "string", description: "City name" } },
12
+ required: ["city"],
13
+ },
14
+ annotations: { readOnlyHint: true },
15
+ serverName: "weather",
16
+ },
17
+ {
18
+ name: "set_alarm",
19
+ description: "Set a weather alarm",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ city: { type: "string" },
24
+ threshold: { type: "number" },
25
+ },
26
+ required: ["city", "threshold"],
27
+ },
28
+ annotations: { readOnlyHint: false, destructiveHint: false },
29
+ serverName: "weather",
30
+ },
31
+ {
32
+ name: "search_docs",
33
+ description: "Search documentation",
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: { query: { type: "string", description: "Search query" } },
37
+ required: ["query"],
38
+ },
39
+ outputSchema: {
40
+ type: "object",
41
+ properties: { results: { type: "array" } },
42
+ },
43
+ annotations: { readOnlyHint: true },
44
+ serverName: "docs",
45
+ },
46
+ ];
47
+ return {
48
+ getConnectedServers: () => ["weather", "docs"],
49
+ getToolsForServer: (name) => tools.filter((t) => t.serverName === name),
50
+ getTools: () => tools,
51
+ getClient: (name) => {
52
+ if (name === "weather" || name === "docs") {
53
+ return {
54
+ callTool: async (params) => ({
55
+ content: [{ type: "text", text: `Called ${params.name}` }],
56
+ }),
57
+ };
58
+ }
59
+ return undefined;
60
+ },
61
+ };
62
+ }
63
+ // Use port 0 so the OS assigns a free port — avoids collisions when src + dist tests run together
64
+ describe("ToolCliRpcServer", () => {
65
+ let server;
66
+ let port;
67
+ beforeAll(async () => {
68
+ const manager = createMockManager();
69
+ server = new ToolCliRpcServer(manager, 0);
70
+ await server.start();
71
+ port = server.getPort();
72
+ });
73
+ afterAll(async () => {
74
+ await server.stop();
75
+ });
76
+ async function rpc(method, params = {}) {
77
+ const res = await fetch(`http://127.0.0.1:${port}`, {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
81
+ });
82
+ return res.json();
83
+ }
84
+ it("lists connected servers with tool counts", async () => {
85
+ const resp = (await rpc("listServers"));
86
+ const { servers } = resp.result;
87
+ expect(servers).toHaveLength(2);
88
+ const weather = servers.find((s) => s.name === "weather");
89
+ expect(weather).toBeDefined();
90
+ expect(weather?.toolCount).toBe(2);
91
+ expect(weather?.examples.length).toBeGreaterThan(0);
92
+ const docs = servers.find((s) => s.name === "docs");
93
+ expect(docs).toBeDefined();
94
+ expect(docs?.toolCount).toBe(1);
95
+ });
96
+ it("lists tools for a specific server", async () => {
97
+ const resp = (await rpc("listTools", { server: "weather" }));
98
+ expect(resp.result.server).toBe("weather");
99
+ expect(resp.result.tools).toHaveLength(2);
100
+ expect(resp.result.tools[0].name).toBe("get_weather");
101
+ expect(resp.result.tools[1].name).toBe("set_alarm");
102
+ });
103
+ it("describes a tool with full schema", async () => {
104
+ const resp = (await rpc("describeTool", { server: "weather", tool: "get_weather" }));
105
+ expect(resp.result.name).toBe("get_weather");
106
+ expect(resp.result.description).toBe("Get current weather for a city");
107
+ expect(resp.result.inputSchema).toHaveProperty("properties");
108
+ expect(resp.result.annotations).toEqual({ readOnlyHint: true });
109
+ });
110
+ it("calls a tool and returns result", async () => {
111
+ const resp = (await rpc("callTool", {
112
+ server: "weather",
113
+ tool: "get_weather",
114
+ arguments: { city: "London" },
115
+ }));
116
+ expect(resp.result.content).toHaveLength(1);
117
+ expect(resp.result.content[0].text).toBe("Called get_weather");
118
+ });
119
+ it("returns error for unknown server", async () => {
120
+ const resp = (await rpc("listTools", { server: "nonexistent" }));
121
+ expect(resp.error).toBeDefined();
122
+ expect(resp.error.code).toBe(-32602);
123
+ expect(resp.error.message).toContain("not found");
124
+ });
125
+ it("returns error for unknown tool", async () => {
126
+ const resp = (await rpc("describeTool", { server: "weather", tool: "nonexistent" }));
127
+ expect(resp.error).toBeDefined();
128
+ expect(resp.error.message).toContain("not found");
129
+ });
130
+ it("returns error for unknown method", async () => {
131
+ const resp = (await rpc("unknownMethod"));
132
+ expect(resp.error).toBeDefined();
133
+ expect(resp.error.code).toBe(-32601);
134
+ });
135
+ it("returns error for missing required params", async () => {
136
+ const resp = (await rpc("listTools", {}));
137
+ expect(resp.error).toBeDefined();
138
+ expect(resp.error.code).toBe(-32602);
139
+ });
140
+ it("rejects non-POST requests", async () => {
141
+ const res = await fetch(`http://127.0.0.1:${port}`, { method: "GET" });
142
+ expect(res.status).toBe(405);
143
+ });
144
+ it("handles malformed JSON gracefully", async () => {
145
+ const res = await fetch(`http://127.0.0.1:${port}`, {
146
+ method: "POST",
147
+ headers: { "Content-Type": "application/json" },
148
+ body: "not json at all",
149
+ });
150
+ const json = (await res.json());
151
+ expect(json.error.code).toBe(-32700);
152
+ });
153
+ });
154
+ //# sourceMappingURL=rpc-server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-server.test.js","sourceRoot":"","sources":["../../src/tool-cli/rpc-server.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sammorrowdrums/mcpi-ext",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "dependencies": {
5
5
  "@modelcontextprotocol/sdk": "^1.29.0",
6
6
  "@sammorrowdrums/tool-cli": "^0.3.0",
@@ -30,6 +30,7 @@
30
30
  "format:check": "prettier --check .",
31
31
  "lint": "eslint .",
32
32
  "lint:fix": "eslint --fix .",
33
+ "prepublishOnly": "npm run build",
33
34
  "start": "node dist/index.js",
34
35
  "test": "vitest --run"
35
36
  },
@@ -37,6 +38,9 @@
37
38
  "node": ">=22.13.0"
38
39
  },
39
40
  "description": "MCP extension for mcpi — tiered progressive tool discovery",
41
+ "files": [
42
+ "dist"
43
+ ],
40
44
  "license": "MIT",
41
45
  "main": "./dist/index.js",
42
46
  "type": "module",
package/.dockerignore DELETED
@@ -1,6 +0,0 @@
1
- node_modules
2
- dist
3
- .git
4
- .gitignore
5
- *.md
6
- .pi
@@ -1,25 +0,0 @@
1
- version: 2
2
-
3
- updates:
4
- - package-ecosystem: npm
5
- directory: /
6
- schedule:
7
- interval: weekly
8
- open-pull-requests-limit: 10
9
- groups:
10
- dev-dependencies:
11
- dependency-type: development
12
- update-types:
13
- - minor
14
- - patch
15
- production-dependencies:
16
- dependency-type: production
17
- update-types:
18
- - minor
19
- - patch
20
-
21
- - package-ecosystem: github-actions
22
- directory: /
23
- schedule:
24
- interval: weekly
25
- open-pull-requests-limit: 5
@@ -1,50 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
-
9
- concurrency:
10
- group: ci-${{ github.ref }}
11
- cancel-in-progress: true
12
-
13
- permissions:
14
- contents: read
15
- models: read
16
-
17
- jobs:
18
- ci:
19
- name: Lint, Build & Test
20
- runs-on: ubuntu-latest
21
- steps:
22
- - uses: actions/checkout@v6
23
-
24
- - uses: jdx/mise-action@v4
25
-
26
- - name: Install dependencies
27
- run: npm install
28
-
29
- - name: Lint
30
- run: mise run lint
31
-
32
- - name: Lint Dockerfile
33
- uses: hadolint/hadolint-action@v3.3.0
34
- with:
35
- dockerfile: Dockerfile
36
-
37
- - name: Check formatting
38
- run: mise run format:check
39
-
40
- - name: Type-check
41
- run: mise run check
42
-
43
- - name: Build
44
- run: mise run build
45
-
46
- - name: Test
47
- run: mise run test
48
-
49
- - name: MCP integration smoke test
50
- run: mise run test:integration
package/.hadolint.yaml DELETED
@@ -1,6 +0,0 @@
1
- # hadolint configuration
2
- # DL3008: Pin versions in apt-get — not practical for a dev/e2e image
3
- # SC1091: Can't follow sourced file (/etc/os-release) — false positive
4
- ignored:
5
- - DL3008
6
- - SC1091
package/.prettierignore DELETED
@@ -1,4 +0,0 @@
1
- dist/
2
- node_modules/
3
- aube-lock.yaml
4
- *.tsbuildinfo
package/.prettierrc DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "semi": true,
3
- "singleQuote": false,
4
- "trailingComma": "all",
5
- "printWidth": 100,
6
- "tabWidth": 2
7
- }
package/AGENTS.md DELETED
@@ -1,118 +0,0 @@
1
- # AGENTS.md
2
-
3
- ## Tooling
4
-
5
- This project uses **mise** for tool version management and **npm** for package management. If you are an AI agent or new contributor, read this first.
6
-
7
- ### mise (tool version manager)
8
-
9
- - **What:** [mise](https://mise.jdx.dev/) manages tool versions (node) and project tasks. Think asdf + direnv + make in one tool.
10
- - **Why:** Reproducible dev environments. `mise.toml` pins exact tool versions so every contributor and CI run uses the same stack.
11
- - **Install:** `curl https://mise.run | sh` then activate: `eval "$(~/.local/bin/mise activate bash)"`
12
- - **Usage:**
13
- - `mise install` — install all tools from `mise.toml`
14
- - `mise run <task>` — run a project task (build, test, dev, check, start)
15
- - `mise use <tool>@<version>` — add/update a tool version
16
-
17
- ### mcpi (coding agent)
18
-
19
- - **What:** [mcpi](https://github.com/SamMorrowDrums/mcpi) is an extensible terminal coding agent (fork of pi). This project builds extensions for it.
20
- - **Extension pattern:** Export a default function receiving `ExtensionAPI`, register tools/commands/hooks.
21
- - **Load extension:** `mcpi --extension ./dist/index.js`
22
-
23
- ## Dev Loop
24
-
25
- ```sh
26
- mise install # one-time: install node
27
- npm install # install npm dependencies
28
- mise run build # compile TypeScript
29
- mise run test # run tests
30
- mise run dev # watch mode for development
31
- mise run check # type-check only
32
- mise run lint # lint TypeScript files
33
- mise run format # auto-format code with Prettier
34
- mise run format:check # check formatting (CI mode)
35
- ```
36
-
37
- ## Project Structure
38
-
39
- ```
40
- src/
41
- index.ts Extension entry point (lifecycle hooks, wiring)
42
- mcp/ MCP client management (connections, tool discovery)
43
- skills/ Skill registry, discovery, gating, tool proxies
44
- tool-cli/ tool-cli RPC server, client, CLI binary, prompt
45
- test-servers/ Test MCP servers (weather, echo)
46
- dist/ Compiled output (gitignored)
47
- scripts/ Integration and smoke test scripts
48
- mise.toml Tool versions and tasks
49
- package.json Dependencies and npm scripts
50
- tsconfig.json TypeScript configuration
51
- ```
52
-
53
- ## Architecture
54
-
55
- ### Tiered MCP Tool Access
56
-
57
- The extension provides three tiers for exposing MCP tools to the agent:
58
-
59
- | Tier | Mechanism | When Used |
60
- | ------------- | ------------------------------------------------------------------ | ------------------------------------------------ |
61
- | 1 — Skills | `deferred: true` + `tool_call` gate → tools unlocked by load_skill | MCP server ships skills |
62
- | 2 — tool-cli | CLI progressive discovery via shell | Ad-hoc exploration, no skills |
63
- | 3 — Code Mode | search+execute, no HITL | Read-only tools with structured output (planned) |
64
-
65
- ### tool-cli Architecture
66
-
67
- tool-cli is a thin CLI binary that communicates with the extension via JSON-RPC 2.0 over HTTP. The agent uses it as a standard shell command, composable with pipes, grep, jq, loops, etc.
68
-
69
- ```
70
- Agent (mcpi)
71
-
72
- │ shell exec
73
-
74
- tool-cli <server> <tool> '{"args"}'
75
-
76
- │ HTTP JSON-RPC (localhost:7179)
77
-
78
- ToolCliRpcServer (in extension process)
79
-
80
- │ MCP protocol (stdio/HTTP)
81
-
82
- MCP Server(s)
83
- ```
84
-
85
- **Key design points:**
86
-
87
- - **No auth (temporary)** — the RPC server binds to `127.0.0.1` only, limiting access to the local machine. This is acceptable for development but not a finished security posture — any local process can call the server and execute MCP tools. Future work should add a shared secret or token (e.g. passed via environment variable to the CLI) so only the intended agent process can make calls.
88
- - **Interception point for HITL** — the RPC server's `callTool` method is the single choke point for all tool execution. Future work can check tool annotations (`readOnlyHint`, `destructiveHint`) here and gate non-read-only calls through user confirmation before forwarding to the MCP server.
89
- - **Progressive discovery** — the agent discovers servers → tools → schemas incrementally, paying only the tokens it needs.
90
- - **Shell-native** — plain text output composes with grep, jq, xargs, pipes, loops. The agent can chain tool calls using standard bash idioms.
91
-
92
- ## Code Quality
93
-
94
- - **ESLint** — flat config with `typescript-eslint` (strict + stylistic) and Prettier compat
95
- - **Prettier** — auto-formatting (double quotes, semicolons, trailing commas, 100 char width)
96
- - **CI** — GitHub Actions runs lint → format:check → type-check → build → test on every PR
97
- - **Dependabot** — automated dependency updates (npm + GitHub Actions)
98
-
99
- Run `mise run lint` and `mise run format` before committing. CI will reject PRs that fail any check.
100
-
101
- **Before pushing**, always run:
102
-
103
- ```sh
104
- mise run lint # lint must pass
105
- mise run test # tests must pass
106
- mise run format:check # formatting must pass
107
- ```
108
-
109
- ## Decision Log
110
-
111
- We maintain a [DECISIONS.md](DECISIONS.md) file recording key architectural and design decisions. Keep it up to date when making significant choices — add a new numbered entry with date, context, decision, and rationale.
112
-
113
- ## Conventions
114
-
115
- - ESM (`"type": "module"`)
116
- - Target: ES2022, module: Node16
117
- - Strict TypeScript
118
- - Tests with vitest (co-located `*.test.ts` files)