@deimoscloud/coreai 0.1.0

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 (216) hide show
  1. package/.prettierrc +9 -0
  2. package/AGENT_SPEC.md +347 -0
  3. package/ARCHITECTURE.md +547 -0
  4. package/DRAFT_PRD.md +1440 -0
  5. package/IMPLEMENTATION_PLAN.md +256 -0
  6. package/PRODUCT.md +473 -0
  7. package/README.md +303 -0
  8. package/WORKFLOWS.md +295 -0
  9. package/agents/_templates/ic-engineer.md +185 -0
  10. package/agents/_templates/reviewer.md +182 -0
  11. package/agents/backend-engineer.yaml +72 -0
  12. package/agents/devops-engineer.yaml +72 -0
  13. package/agents/engineering-manager.yaml +70 -0
  14. package/agents/examples/android-engineer.md +302 -0
  15. package/agents/examples/backend-engineer.md +320 -0
  16. package/agents/examples/devops-engineer.md +742 -0
  17. package/agents/examples/engineering-manager.md +469 -0
  18. package/agents/examples/frontend-engineer.md +58 -0
  19. package/agents/examples/product-manager.md +315 -0
  20. package/agents/examples/qa-engineer.md +371 -0
  21. package/agents/examples/security-engineer.md +525 -0
  22. package/agents/examples/solutions-architect.md +351 -0
  23. package/agents/examples/wearos-engineer.md +359 -0
  24. package/agents/frontend-engineer.yaml +72 -0
  25. package/commands/core/check-inbox.md +34 -0
  26. package/commands/core/delegate.md +30 -0
  27. package/commands/core/git-commit.md +144 -0
  28. package/commands/core/pr-create.md +193 -0
  29. package/commands/core/review.md +56 -0
  30. package/commands/core/sprint-status.md +65 -0
  31. package/commands/optional/docs-update.md +200 -0
  32. package/commands/optional/jira-create.md +200 -0
  33. package/commands/optional/jira-transition.md +184 -0
  34. package/commands/optional/worktree-cleanup.md +167 -0
  35. package/commands/optional/worktree-setup.md +110 -0
  36. package/dist/cli/index.js +4037 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/index.d.ts +2978 -0
  39. package/dist/index.js +3867 -0
  40. package/dist/index.js.map +1 -0
  41. package/eslint.config.js +29 -0
  42. package/jest.config.js +22 -0
  43. package/knowledge-library/README.md +118 -0
  44. package/knowledge-library/android-engineer/context/current.txt +42 -0
  45. package/knowledge-library/android-engineer/control/decisions.txt +9 -0
  46. package/knowledge-library/android-engineer/control/dependencies.txt +19 -0
  47. package/knowledge-library/android-engineer/control/objectives.txt +26 -0
  48. package/knowledge-library/android-engineer/history/.gitkeep +0 -0
  49. package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
  50. package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
  51. package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
  52. package/knowledge-library/architecture.txt +61 -0
  53. package/knowledge-library/backend-engineer/context/current.txt +42 -0
  54. package/knowledge-library/backend-engineer/control/decisions.txt +9 -0
  55. package/knowledge-library/backend-engineer/control/dependencies.txt +19 -0
  56. package/knowledge-library/backend-engineer/control/objectives.txt +26 -0
  57. package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
  58. package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
  59. package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
  60. package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
  61. package/knowledge-library/context.txt +52 -0
  62. package/knowledge-library/devops-engineer/context/current.txt +42 -0
  63. package/knowledge-library/devops-engineer/control/decisions.txt +9 -0
  64. package/knowledge-library/devops-engineer/control/dependencies.txt +19 -0
  65. package/knowledge-library/devops-engineer/control/objectives.txt +26 -0
  66. package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
  67. package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
  68. package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
  69. package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
  70. package/knowledge-library/engineering-manager/context/current.txt +40 -0
  71. package/knowledge-library/engineering-manager/control/decisions.txt +9 -0
  72. package/knowledge-library/engineering-manager/control/objectives.txt +27 -0
  73. package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
  74. package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
  75. package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
  76. package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
  77. package/knowledge-library/prd.txt +81 -0
  78. package/knowledge-library/product-manager/context/current.txt +42 -0
  79. package/knowledge-library/product-manager/control/decisions.txt +9 -0
  80. package/knowledge-library/product-manager/control/dependencies.txt +19 -0
  81. package/knowledge-library/product-manager/control/objectives.txt +26 -0
  82. package/knowledge-library/product-manager/history/.gitkeep +0 -0
  83. package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
  84. package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
  85. package/knowledge-library/product-manager/tech/.gitkeep +0 -0
  86. package/knowledge-library/qa-engineer/context/current.txt +42 -0
  87. package/knowledge-library/qa-engineer/control/decisions.txt +9 -0
  88. package/knowledge-library/qa-engineer/control/dependencies.txt +19 -0
  89. package/knowledge-library/qa-engineer/control/objectives.txt +26 -0
  90. package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
  91. package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
  92. package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
  93. package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
  94. package/knowledge-library/security-engineer/context/current.txt +42 -0
  95. package/knowledge-library/security-engineer/control/decisions.txt +9 -0
  96. package/knowledge-library/security-engineer/control/dependencies.txt +19 -0
  97. package/knowledge-library/security-engineer/control/objectives.txt +26 -0
  98. package/knowledge-library/security-engineer/history/.gitkeep +0 -0
  99. package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
  100. package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
  101. package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
  102. package/knowledge-library/solutions-architect/context/current.txt +42 -0
  103. package/knowledge-library/solutions-architect/control/decisions.txt +9 -0
  104. package/knowledge-library/solutions-architect/control/dependencies.txt +19 -0
  105. package/knowledge-library/solutions-architect/control/objectives.txt +26 -0
  106. package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
  107. package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
  108. package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
  109. package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
  110. package/knowledge-library/wearos-engineer/context/current.txt +42 -0
  111. package/knowledge-library/wearos-engineer/control/decisions.txt +9 -0
  112. package/knowledge-library/wearos-engineer/control/dependencies.txt +19 -0
  113. package/knowledge-library/wearos-engineer/control/objectives.txt +26 -0
  114. package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
  115. package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
  116. package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
  117. package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
  118. package/package.json +66 -0
  119. package/schemas/agent.schema.json +171 -0
  120. package/schemas/coreai.config.schema.json +257 -0
  121. package/scripts/add-agent.sh +323 -0
  122. package/scripts/install.sh +354 -0
  123. package/src/adapters/factory.test.ts +386 -0
  124. package/src/adapters/factory.ts +305 -0
  125. package/src/adapters/index.ts +113 -0
  126. package/src/adapters/interfaces.ts +268 -0
  127. package/src/adapters/mcp/client.test.ts +130 -0
  128. package/src/adapters/mcp/client.ts +451 -0
  129. package/src/adapters/mcp/discovery.test.ts +315 -0
  130. package/src/adapters/mcp/discovery.ts +340 -0
  131. package/src/adapters/mcp/index.ts +66 -0
  132. package/src/adapters/mcp/mapper.test.ts +218 -0
  133. package/src/adapters/mcp/mapper.ts +536 -0
  134. package/src/adapters/mcp/registry.test.ts +433 -0
  135. package/src/adapters/mcp/registry.ts +550 -0
  136. package/src/adapters/mcp/types.ts +258 -0
  137. package/src/adapters/native/filesystem.test.ts +350 -0
  138. package/src/adapters/native/filesystem.ts +393 -0
  139. package/src/adapters/native/github.test.ts +173 -0
  140. package/src/adapters/native/github.ts +627 -0
  141. package/src/adapters/native/index.ts +22 -0
  142. package/src/adapters/native/selector.test.ts +224 -0
  143. package/src/adapters/native/selector.ts +150 -0
  144. package/src/adapters/types.ts +270 -0
  145. package/src/agents/compiler.test.ts +399 -0
  146. package/src/agents/compiler.ts +359 -0
  147. package/src/agents/index.ts +36 -0
  148. package/src/agents/loader.test.ts +319 -0
  149. package/src/agents/loader.ts +143 -0
  150. package/src/agents/resolver.test.ts +282 -0
  151. package/src/agents/resolver.ts +262 -0
  152. package/src/agents/types.ts +87 -0
  153. package/src/cache/index.ts +38 -0
  154. package/src/cache/interfaces.ts +283 -0
  155. package/src/cache/manager.test.ts +266 -0
  156. package/src/cache/manager.ts +388 -0
  157. package/src/cache/provider.test.ts +485 -0
  158. package/src/cache/provider.ts +745 -0
  159. package/src/cache/types.test.ts +192 -0
  160. package/src/cache/types.ts +313 -0
  161. package/src/cli/commands/build.test.ts +248 -0
  162. package/src/cli/commands/build.ts +244 -0
  163. package/src/cli/commands/cache.test.ts +221 -0
  164. package/src/cli/commands/cache.ts +229 -0
  165. package/src/cli/commands/index.ts +63 -0
  166. package/src/cli/commands/init.test.ts +173 -0
  167. package/src/cli/commands/init.ts +296 -0
  168. package/src/cli/commands/skills.test.ts +272 -0
  169. package/src/cli/commands/skills.ts +348 -0
  170. package/src/cli/commands/status.test.ts +392 -0
  171. package/src/cli/commands/status.ts +332 -0
  172. package/src/cli/commands/sync.test.ts +213 -0
  173. package/src/cli/commands/sync.ts +251 -0
  174. package/src/cli/commands/validate.test.ts +216 -0
  175. package/src/cli/commands/validate.ts +340 -0
  176. package/src/cli/index.test.ts +190 -0
  177. package/src/cli/index.ts +493 -0
  178. package/src/commands/context.test.ts +163 -0
  179. package/src/commands/context.ts +111 -0
  180. package/src/commands/index.ts +56 -0
  181. package/src/commands/loader.test.ts +273 -0
  182. package/src/commands/loader.ts +355 -0
  183. package/src/commands/registry.test.ts +384 -0
  184. package/src/commands/registry.ts +248 -0
  185. package/src/commands/runner.test.ts +297 -0
  186. package/src/commands/runner.ts +222 -0
  187. package/src/commands/types.ts +361 -0
  188. package/src/config/index.ts +19 -0
  189. package/src/config/loader.test.ts +262 -0
  190. package/src/config/loader.ts +188 -0
  191. package/src/config/types.ts +154 -0
  192. package/src/context/index.ts +14 -0
  193. package/src/context/loader.test.ts +334 -0
  194. package/src/context/loader.ts +357 -0
  195. package/src/index.test.ts +13 -0
  196. package/src/index.ts +244 -0
  197. package/src/knowledge-library/index.ts +44 -0
  198. package/src/knowledge-library/manager.test.ts +536 -0
  199. package/src/knowledge-library/manager.ts +804 -0
  200. package/src/knowledge-library/types.ts +432 -0
  201. package/src/skills/generator.test.ts +602 -0
  202. package/src/skills/generator.ts +491 -0
  203. package/src/skills/index.ts +27 -0
  204. package/src/skills/templates.ts +520 -0
  205. package/src/skills/types.ts +251 -0
  206. package/templates/completion-report.md +72 -0
  207. package/templates/feedback.md +56 -0
  208. package/templates/project-files/CLAUDE.md.template +109 -0
  209. package/templates/project-files/coreai.json.example +47 -0
  210. package/templates/project-files/mcp.json.template +20 -0
  211. package/templates/review-complete.md +64 -0
  212. package/templates/review-request.md +67 -0
  213. package/templates/task-assignment.md +51 -0
  214. package/tsconfig.build.json +4 -0
  215. package/tsconfig.json +26 -0
  216. package/tsup.config.ts +23 -0
@@ -0,0 +1,451 @@
1
+ /**
2
+ * MCP Client Wrapper
3
+ *
4
+ * Provides a simplified interface for connecting to and communicating with MCP servers.
5
+ */
6
+
7
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
8
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
9
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
10
+ import type {
11
+ McpServerConfig,
12
+ McpServerInfo,
13
+ McpTool,
14
+ McpResource,
15
+ McpToolResult,
16
+ McpCapabilities,
17
+ McpContent,
18
+ StdioServerConfig,
19
+ } from './types.js';
20
+ import { McpError } from './types.js';
21
+
22
+ /**
23
+ * Options for creating an MCP client
24
+ */
25
+ export interface McpClientOptions {
26
+ /**
27
+ * Client name to report to servers
28
+ */
29
+ clientName?: string;
30
+
31
+ /**
32
+ * Client version to report to servers
33
+ */
34
+ clientVersion?: string;
35
+
36
+ /**
37
+ * Timeout for operations in milliseconds
38
+ */
39
+ timeout?: number;
40
+ }
41
+
42
+ const DEFAULT_OPTIONS: Required<McpClientOptions> = {
43
+ clientName: 'coreai',
44
+ clientVersion: '0.1.0',
45
+ timeout: 30000,
46
+ };
47
+
48
+ /**
49
+ * MCP Client Wrapper
50
+ *
51
+ * Manages a connection to a single MCP server and provides
52
+ * a simplified API for tool calls, resource access, etc.
53
+ */
54
+ export class McpClient {
55
+ private client: Client | null = null;
56
+ private transport: Transport | null = null;
57
+ private _serverInfo: McpServerInfo | null = null;
58
+ private options: Required<McpClientOptions>;
59
+ private serverName: string;
60
+ private config: McpServerConfig;
61
+
62
+ constructor(serverName: string, config: McpServerConfig, options?: McpClientOptions) {
63
+ this.serverName = serverName;
64
+ this.config = config;
65
+ this.options = { ...DEFAULT_OPTIONS, ...options };
66
+ }
67
+
68
+ /**
69
+ * Connect to the MCP server
70
+ */
71
+ async connect(): Promise<void> {
72
+ if (this.client && this.isConnected()) {
73
+ return;
74
+ }
75
+
76
+ try {
77
+ // Create the appropriate transport
78
+ this.transport = await this.createTransport();
79
+
80
+ // Create the MCP client
81
+ this.client = new Client(
82
+ {
83
+ name: this.options.clientName,
84
+ version: this.options.clientVersion,
85
+ },
86
+ {
87
+ capabilities: {
88
+ roots: { listChanged: true },
89
+ },
90
+ }
91
+ );
92
+
93
+ // Connect to the server
94
+ await this.client.connect(this.transport);
95
+
96
+ // Store server info
97
+ const serverVersion = this.client.getServerVersion();
98
+ const serverCapabilities = this.client.getServerCapabilities();
99
+
100
+ const info: McpServerInfo = {
101
+ name: this.serverName,
102
+ connected: true,
103
+ };
104
+
105
+ if (serverVersion?.version) {
106
+ info.version = serverVersion.version;
107
+ }
108
+
109
+ const caps = this.parseCapabilities(serverCapabilities);
110
+ if (caps) {
111
+ info.capabilities = caps;
112
+ }
113
+
114
+ const instructions = this.client.getInstructions();
115
+ if (instructions) {
116
+ info.instructions = instructions;
117
+ }
118
+
119
+ this._serverInfo = info;
120
+ } catch (error) {
121
+ throw new McpError(
122
+ `Failed to connect to MCP server "${this.serverName}": ${error instanceof Error ? error.message : String(error)}`,
123
+ 'connection_failed',
124
+ this.serverName,
125
+ error instanceof Error ? error : undefined
126
+ );
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Disconnect from the MCP server
132
+ */
133
+ async disconnect(): Promise<void> {
134
+ if (this.transport) {
135
+ await this.transport.close();
136
+ this.transport = null;
137
+ }
138
+
139
+ this.client = null;
140
+
141
+ if (this._serverInfo) {
142
+ this._serverInfo.connected = false;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Check if connected to the server
148
+ */
149
+ isConnected(): boolean {
150
+ return this._serverInfo?.connected ?? false;
151
+ }
152
+
153
+ /**
154
+ * Get server information
155
+ */
156
+ getServerInfo(): McpServerInfo | null {
157
+ return this._serverInfo;
158
+ }
159
+
160
+ /**
161
+ * List available tools from the server
162
+ */
163
+ async listTools(): Promise<McpTool[]> {
164
+ const client = this.ensureConnected();
165
+
166
+ const result = await client.listTools();
167
+
168
+ return result.tools.map((tool) => {
169
+ // Build inputSchema with only defined properties
170
+ const inputSchema: McpTool['inputSchema'] = { type: 'object' };
171
+ if (tool.inputSchema.properties) {
172
+ inputSchema.properties = tool.inputSchema.properties as Record<string, unknown>;
173
+ }
174
+ if (tool.inputSchema.required) {
175
+ inputSchema.required = tool.inputSchema.required;
176
+ }
177
+
178
+ const mapped: McpTool = {
179
+ name: tool.name,
180
+ inputSchema,
181
+ };
182
+
183
+ if (tool.description) {
184
+ mapped.description = tool.description;
185
+ }
186
+
187
+ if (tool.annotations) {
188
+ const annotations: McpTool['annotations'] = {};
189
+ if (tool.annotations.title) annotations.title = tool.annotations.title;
190
+ if (tool.annotations.readOnlyHint !== undefined)
191
+ annotations.readOnlyHint = tool.annotations.readOnlyHint;
192
+ if (tool.annotations.destructiveHint !== undefined)
193
+ annotations.destructiveHint = tool.annotations.destructiveHint;
194
+ if (tool.annotations.idempotentHint !== undefined)
195
+ annotations.idempotentHint = tool.annotations.idempotentHint;
196
+ if (Object.keys(annotations).length > 0) {
197
+ mapped.annotations = annotations;
198
+ }
199
+ }
200
+
201
+ return mapped;
202
+ });
203
+ }
204
+
205
+ /**
206
+ * Call a tool on the server
207
+ */
208
+ async callTool(name: string, args?: Record<string, unknown>): Promise<McpToolResult> {
209
+ const client = this.ensureConnected();
210
+
211
+ try {
212
+ const result = await client.callTool({
213
+ name,
214
+ arguments: args,
215
+ });
216
+
217
+ // Handle the different result formats
218
+ if ('content' in result && Array.isArray(result.content)) {
219
+ const content: McpContent[] = [];
220
+
221
+ for (const c of result.content) {
222
+ if (typeof c === 'object' && c !== null && 'type' in c) {
223
+ const item = c as { type: string; [key: string]: unknown };
224
+ if (item.type === 'text' && typeof item.text === 'string') {
225
+ content.push({ type: 'text', text: item.text });
226
+ } else if (
227
+ item.type === 'image' &&
228
+ typeof item.data === 'string' &&
229
+ typeof item.mimeType === 'string'
230
+ ) {
231
+ content.push({ type: 'image', data: item.data, mimeType: item.mimeType });
232
+ } else if (item.type === 'resource' && typeof item.resource === 'object') {
233
+ const res = item.resource as {
234
+ uri: string;
235
+ text?: string;
236
+ blob?: string;
237
+ mimeType?: string;
238
+ };
239
+ const resourceContent: {
240
+ uri: string;
241
+ text?: string;
242
+ blob?: string;
243
+ mimeType?: string;
244
+ } = {
245
+ uri: res.uri,
246
+ };
247
+ if (res.text) resourceContent.text = res.text;
248
+ if (res.blob) resourceContent.blob = res.blob;
249
+ if (res.mimeType) resourceContent.mimeType = res.mimeType;
250
+ content.push({
251
+ type: 'resource',
252
+ resource: resourceContent,
253
+ });
254
+ } else {
255
+ // Default to text for unknown types
256
+ content.push({ type: 'text', text: JSON.stringify(c) });
257
+ }
258
+ }
259
+ }
260
+
261
+ const toolResult: McpToolResult = { content };
262
+
263
+ if (typeof result.isError === 'boolean') {
264
+ toolResult.isError = result.isError;
265
+ }
266
+
267
+ if (typeof result.structuredContent === 'object' && result.structuredContent !== null) {
268
+ toolResult.structuredContent = result.structuredContent as Record<string, unknown>;
269
+ }
270
+
271
+ return toolResult;
272
+ }
273
+
274
+ // Handle legacy toolResult format
275
+ if ('toolResult' in result) {
276
+ return {
277
+ content: [{ type: 'text', text: JSON.stringify(result.toolResult) }],
278
+ };
279
+ }
280
+
281
+ return {
282
+ content: [],
283
+ };
284
+ } catch (error) {
285
+ throw new McpError(
286
+ `Failed to call tool "${name}": ${error instanceof Error ? error.message : String(error)}`,
287
+ 'protocol_error',
288
+ this.serverName,
289
+ error instanceof Error ? error : undefined
290
+ );
291
+ }
292
+ }
293
+
294
+ /**
295
+ * List available resources from the server
296
+ */
297
+ async listResources(): Promise<McpResource[]> {
298
+ const client = this.ensureConnected();
299
+
300
+ const result = await client.listResources();
301
+
302
+ return result.resources.map((resource) => {
303
+ const mapped: McpResource = {
304
+ uri: resource.uri,
305
+ name: resource.name,
306
+ };
307
+ if (resource.description) {
308
+ mapped.description = resource.description;
309
+ }
310
+ if (resource.mimeType) {
311
+ mapped.mimeType = resource.mimeType;
312
+ }
313
+ return mapped;
314
+ });
315
+ }
316
+
317
+ /**
318
+ * Read a resource from the server
319
+ */
320
+ async readResource(uri: string): Promise<string> {
321
+ const client = this.ensureConnected();
322
+
323
+ const result = await client.readResource({ uri });
324
+
325
+ // Return the first text content, or blob as base64
326
+ for (const content of result.contents) {
327
+ if ('text' in content) {
328
+ return content.text;
329
+ }
330
+ if ('blob' in content) {
331
+ return content.blob;
332
+ }
333
+ }
334
+
335
+ return '';
336
+ }
337
+
338
+ /**
339
+ * Create the appropriate transport for the server config
340
+ */
341
+ private async createTransport(): Promise<Transport> {
342
+ if (this.config.transport === 'stdio') {
343
+ return this.createStdioTransport(this.config);
344
+ }
345
+
346
+ // HTTP/SSE transports would be added here
347
+ throw new McpError(
348
+ `Unsupported transport type: ${this.config.transport}`,
349
+ 'invalid_config',
350
+ this.serverName
351
+ );
352
+ }
353
+
354
+ /**
355
+ * Create a stdio transport for local MCP servers
356
+ */
357
+ private createStdioTransport(config: StdioServerConfig): Transport {
358
+ const params: {
359
+ command: string;
360
+ args?: string[];
361
+ env?: Record<string, string>;
362
+ cwd?: string;
363
+ } = {
364
+ command: config.command,
365
+ };
366
+
367
+ if (config.args) {
368
+ params.args = config.args;
369
+ }
370
+ if (config.env) {
371
+ params.env = config.env;
372
+ }
373
+ if (config.cwd) {
374
+ params.cwd = config.cwd;
375
+ }
376
+
377
+ return new StdioClientTransport(params);
378
+ }
379
+
380
+ /**
381
+ * Parse server capabilities into our format
382
+ */
383
+ private parseCapabilities(capabilities?: Record<string, unknown>): McpCapabilities | undefined {
384
+ if (!capabilities) return undefined;
385
+
386
+ return {
387
+ tools: !!capabilities.tools,
388
+ resources: !!capabilities.resources,
389
+ prompts: !!capabilities.prompts,
390
+ logging: !!capabilities.logging,
391
+ };
392
+ }
393
+
394
+ /**
395
+ * Ensure the client is connected and return the client instance
396
+ */
397
+ private ensureConnected(): Client {
398
+ if (!this.client || !this.isConnected()) {
399
+ throw new McpError(
400
+ `Not connected to MCP server "${this.serverName}"`,
401
+ 'connection_closed',
402
+ this.serverName
403
+ );
404
+ }
405
+ return this.client;
406
+ }
407
+
408
+ /**
409
+ * Set server info (for mock/testing purposes)
410
+ */
411
+ protected setServerInfo(info: McpServerInfo): void {
412
+ this._serverInfo = info;
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Create a mock MCP client for testing
418
+ */
419
+ export function createMockMcpClient(
420
+ serverName: string,
421
+ tools: McpTool[] = [],
422
+ resources: McpResource[] = []
423
+ ): McpClient {
424
+ // Create a client with in-memory transport for testing
425
+ const client = new McpClient(serverName, { transport: 'stdio', command: 'mock' });
426
+
427
+ // Store mock data
428
+ const mockTools = tools;
429
+ const mockResources = resources;
430
+
431
+ // Override connect to set up mock state
432
+ client.connect = async function (this: McpClient) {
433
+ const info: McpServerInfo = {
434
+ name: serverName,
435
+ version: '1.0.0',
436
+ connected: true,
437
+ capabilities: { tools: true, resources: true },
438
+ };
439
+ (this as McpClient & { setServerInfo(info: McpServerInfo): void }).setServerInfo(info);
440
+ };
441
+
442
+ client.listTools = async function () {
443
+ return mockTools;
444
+ };
445
+
446
+ client.listResources = async function () {
447
+ return mockResources;
448
+ };
449
+
450
+ return client;
451
+ }