miadi 1.0.14

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 (53) hide show
  1. package/.env.example +28 -0
  2. package/ARCHITECTURE.md +290 -0
  3. package/CLAUDE.md +269 -0
  4. package/GEMINI.md +80 -0
  5. package/MCP_CONNECTOR_READY.md +219 -0
  6. package/MCP_LEARNING_NOTES.md +178 -0
  7. package/MCP_REBUILD_PLAN.md +159 -0
  8. package/MCP_REMOTE_SERVER_SPEC.md +373 -0
  9. package/MIA.md +344 -0
  10. package/MIETTE.md +195 -0
  11. package/README.md +264 -0
  12. package/REMOTE_MCP_TRANSFORMATION_GUIDE.md +384 -0
  13. package/STATUS.md +191 -0
  14. package/TOOL_SELECTION_PLAN.md +340 -0
  15. package/WAKE_UP_SUMMARY.md +102 -0
  16. package/__PUBLISH.sh +1 -0
  17. package/book/_/ledgers/ledger_miadi_mcp_analysis_250730.md +0 -0
  18. package/conversations/2507301433.claude.issue.11.2025-07-30-this-mcp-is-not-working-another-instance-of-yours.txt +756 -0
  19. package/conversations/2507301601.cursor.reverse_engineer_mcp_service_for.md +808 -0
  20. package/conversations/2508050125.llmcon.claude.MIADI_TOOLS-implement-what-is-in-toolselectionplanmd.txt +1235 -0
  21. package/conversations/2508051939.llmcon.claude.issue-14.TransitionToPlanningIT.implement-what-is-in-toolselectionplanmd.txt +1424 -0
  22. package/conversations/2508082352.llmcon.claude.MCP-Remote-Take-II.txt +1658 -0
  23. package/dist/index-remote.js +54736 -0
  24. package/dist/index.js +32363 -0
  25. package/mcp.sample.json +14 -0
  26. package/openapi.yml +2161 -0
  27. package/package.json +56 -0
  28. package/research/MCP_Research_Perplexity_2508060045.md +410 -0
  29. package/samples/README.md +2 -0
  30. package/scripts/ngrokserve.sh +6 -0
  31. package/scripts/start-remote.sh +141 -0
  32. package/scripts/start-with-ngrok.sh +140 -0
  33. package/src/api-client.ts +254 -0
  34. package/src/index-remote.ts +406 -0
  35. package/src/index-simple.ts +232 -0
  36. package/src/index.ts +510 -0
  37. package/src/tool-registry.ts +223 -0
  38. package/src/tools/ai-tools.ts +69 -0
  39. package/src/tools/capability-tools.ts +79 -0
  40. package/src/tools/forge-tools.ts +51 -0
  41. package/src/tools/memory-tools.ts +137 -0
  42. package/src/tools/session-tools.ts +135 -0
  43. package/src/tools/workflow-tools.ts +65 -0
  44. package/src/types.ts +291 -0
  45. package/src/utils.ts +279 -0
  46. package/tests/quick-test.sh +116 -0
  47. package/tests/run-all-tests.sh +167 -0
  48. package/tests/test-agent-capabilities.sh +364 -0
  49. package/tests/test-connectivity.sh +90 -0
  50. package/tests/test-memory-operations.sh +236 -0
  51. package/tests/test-session-management.sh +320 -0
  52. package/tests/test-tool-discovery.sh +151 -0
  53. package/tsconfig.json +24 -0
package/src/index.ts ADDED
@@ -0,0 +1,510 @@
1
+ #!/usr/bin/env node
2
+
3
+ import dotenv from 'dotenv';
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { getEnvVar, logToolUsage, createMCPResponse, parseToolSelection, loadEnvironmentVariables } from './utils';
7
+ import { ToolRegistry, ToolDefinition } from './tool-registry';
8
+ import { memoryTools } from './tools/memory-tools';
9
+ import { sessionTools } from './tools/session-tools';
10
+ import { capabilityTools } from './tools/capability-tools';
11
+ import { aiTools } from './tools/ai-tools';
12
+ import { workflowTools } from './tools/workflow-tools';
13
+ import { forgeTools } from './tools/forge-tools';
14
+ import { z } from "zod";
15
+
16
+ // Enhanced environment loading with fallback to $HOME/.env
17
+ loadEnvironmentVariables();
18
+
19
+ // Load environment variables from current directory .env (if it exists)
20
+ dotenv.config();
21
+
22
+ /**
23
+ * Miadi MCP Server
24
+ *
25
+ * This server exposes the Miadi Three-Pathway Agent System API as MCP tools
26
+ * that Claude can use for agent session management, memory operations, and AI integration.
27
+ */
28
+
29
+ // Validate required environment variables
30
+ try {
31
+ getEnvVar('EH_TOKEN');
32
+ getEnvVar('EH_API_URL');
33
+ console.error('✅ Environment variables validated');
34
+ } catch (error: any) {
35
+ console.error('❌ Environment validation failed:', error.message);
36
+ process.exit(1);
37
+ }
38
+
39
+ // Initialize tool registry with environment configuration
40
+ const toolRegistry = new ToolRegistry(parseToolSelection());
41
+
42
+ // Create MCP server instance
43
+ const server = new McpServer(
44
+ {
45
+ name: "miadi-mcp-server",
46
+ version: "1.0.0",
47
+ },
48
+ {
49
+ capabilities: {
50
+ // Define capabilities if needed, e.g., "prompts": {}
51
+ },
52
+ }
53
+ );
54
+
55
+ /**
56
+ * Define all available tools with the registry
57
+ */
58
+ function defineAllTools(): void {
59
+ // Memory Operations
60
+ toolRegistry.register({
61
+ name: 'miadi-get-memory',
62
+ category: 'memory',
63
+ description: 'Retrieve memory data from Redis',
64
+ schema: {
65
+ key: z.string().optional().describe('The key to retrieve from memory'),
66
+ list: z.boolean().optional().describe('Set to true to list all keys'),
67
+ pattern: z.string().optional().describe('Pattern to match when listing keys'),
68
+ type: z.enum(['auto', 'string', 'hash', 'list', 'set', 'zset']).optional().describe('Redis data type to retrieve')
69
+ },
70
+ handler: async (args: any) => {
71
+ logToolUsage('miadi-get-memory', args);
72
+ const { key, list, pattern, type } = args;
73
+ const result = await memoryTools.getMemory(key, list, pattern, type);
74
+ return createMCPResponse(result, 'miadi-get-memory');
75
+ }
76
+ });
77
+
78
+ toolRegistry.register({
79
+ name: 'miadi-store-memory',
80
+ category: 'memory',
81
+ description: 'Store data in memory with TTL',
82
+ schema: {
83
+ key: z.string().describe('The key to store the memory under'),
84
+ value: z.string().describe('The value to store'),
85
+ ttl: z.number().optional().describe('Time to live for the memory in seconds'),
86
+ type: z.enum(['string', 'hash', 'list']).optional().describe('Type of memory to store'),
87
+ },
88
+ handler: async (args: any) => {
89
+ logToolUsage('miadi-store-memory', args);
90
+ const { key, value, ttl, type } = args;
91
+ const result = await memoryTools.storeMemory(key, value, ttl, type);
92
+ return createMCPResponse(result, 'miadi-store-memory');
93
+ }
94
+ });
95
+
96
+ toolRegistry.register({
97
+ name: 'miadi-update-memory-ttl',
98
+ category: 'memory',
99
+ description: 'Update memory TTL',
100
+ schema: {
101
+ key: z.string().describe('The key to update TTL for'),
102
+ ttl: z.number().describe('Time to live in seconds')
103
+ },
104
+ handler: async (args: any) => {
105
+ logToolUsage('miadi-update-memory-ttl', args);
106
+ const { key, ttl } = args;
107
+ const result = await memoryTools.updateMemoryTTL(key, ttl);
108
+ return createMCPResponse(result, 'miadi-update-memory-ttl');
109
+ }
110
+ });
111
+
112
+ toolRegistry.register({
113
+ name: 'miadi-get-memory-meta',
114
+ category: 'memory',
115
+ description: 'Get memory meta',
116
+ schema: {
117
+ key: z.string().describe('The key to get metadata for')
118
+ },
119
+ handler: async (args: any) => {
120
+ logToolUsage('miadi-get-memory-meta', args);
121
+ const { key } = args;
122
+ const result = await memoryTools.getMemoryMeta(key);
123
+ return createMCPResponse(result, 'miadi-get-memory-meta');
124
+ }
125
+ });
126
+
127
+ toolRegistry.register({
128
+ name: 'miadi-scan-keys',
129
+ category: 'memory',
130
+ description: 'Scan Redis keys',
131
+ schema: {
132
+ pattern: z.string().optional().describe('Redis glob pattern for key matching (default: "*")'),
133
+ regex: z.string().optional().describe('Regular expression for key matching'),
134
+ limit: z.number().optional().describe('Maximum number of keys to return')
135
+ },
136
+ handler: async (args: any) => {
137
+ logToolUsage('miadi-scan-keys', args);
138
+ const { pattern, regex, limit } = args;
139
+ const result = await memoryTools.scanKeys(pattern, regex, limit);
140
+ return createMCPResponse(result, 'miadi-scan-keys');
141
+ }
142
+ });
143
+
144
+ toolRegistry.register({
145
+ name: 'miadi-gather-memory-values',
146
+ category: 'memory',
147
+ description: 'Gather memory values',
148
+ schema: {
149
+ pattern: z.string().optional().describe('Pattern to match when gathering keys'),
150
+ regex: z.string().optional().describe('Regular expression for key matching'),
151
+ limit: z.number().optional().describe('Maximum number of values to return'),
152
+ scanLimit: z.number().optional().describe('Maximum number of keys to scan')
153
+ },
154
+ handler: async (args: any) => {
155
+ logToolUsage('miadi-gather-memory-values', args);
156
+ const { pattern, regex, limit, scanLimit } = args;
157
+ const result = await memoryTools.gatherMemoryValues(pattern, regex, limit, scanLimit);
158
+ return createMCPResponse(result, 'miadi-gather-memory-values');
159
+ }
160
+ });
161
+
162
+ toolRegistry.register({
163
+ name: 'miadi-collect-memory',
164
+ category: 'memory',
165
+ description: 'Collect memory',
166
+ schema: {
167
+ keys: z.array(z.string()).describe('Array of keys to collect memory from')
168
+ },
169
+ handler: async (args: any) => {
170
+ logToolUsage('miadi-collect-memory', args);
171
+ const { keys } = args;
172
+ const result = await memoryTools.collectMemory(keys);
173
+ return createMCPResponse(result, 'miadi-collect-memory');
174
+ }
175
+ });
176
+
177
+ toolRegistry.register({
178
+ name: 'miadi-view-key-content',
179
+ category: 'memory',
180
+ description: 'View key content',
181
+ schema: {
182
+ key: z.string().describe('The key to view content for')
183
+ },
184
+ handler: async (args: any) => {
185
+ logToolUsage('miadi-view-key-content', args);
186
+ const { key } = args;
187
+ const result = await memoryTools.viewKeyContent(key);
188
+ return createMCPResponse(result, 'miadi-view-key-content');
189
+ }
190
+ });
191
+
192
+ toolRegistry.register({
193
+ name: 'miadi-search-cluster',
194
+ category: 'memory',
195
+ description: 'Search cluster',
196
+ schema: {
197
+ term: z.string().describe('Search term to find in cluster')
198
+ },
199
+ handler: async (args: any) => {
200
+ logToolUsage('miadi-search-cluster', args);
201
+ const { term } = args;
202
+ const result = await memoryTools.searchCluster(term);
203
+ return createMCPResponse(result, 'miadi-search-cluster');
204
+ }
205
+ });
206
+
207
+ // Session Management
208
+ toolRegistry.register({
209
+ name: 'miadi-start-session',
210
+ category: 'session',
211
+ description: 'Start new agent session',
212
+ schema: {
213
+ persona: z.string().describe('Persona ID to activate (e.g., "mia-recursive-architect")'),
214
+ mode: z.string().describe('Mode ID to activate (e.g., "desktop", "walking")'),
215
+ userId: z.string().optional().describe('User identifier'),
216
+ contextOverrides: z.array(z.object({
217
+ name: z.string(),
218
+ type: z.enum(['location', 'device', 'activity', 'time', 'custom']),
219
+ value: z.union([z.string(), z.number(), z.boolean(), z.record(z.any())]),
220
+ description: z.string().optional()
221
+ })).optional().describe('Context variable overrides')
222
+ },
223
+ handler: async (args: any) => {
224
+ logToolUsage('miadi-start-session', args);
225
+ const { persona, mode, userId, contextOverrides } = args;
226
+ const result = await sessionTools.startSession(persona, mode, userId, contextOverrides);
227
+ return createMCPResponse(result, 'miadi-start-session');
228
+ }
229
+ });
230
+
231
+ toolRegistry.register({
232
+ name: 'miadi-get-current-session',
233
+ category: 'session',
234
+ description: 'Get current session details',
235
+ schema: {
236
+ sessionId: z.string().optional().describe('Session ID to retrieve details for')
237
+ },
238
+ handler: async (args: any) => {
239
+ logToolUsage('miadi-get-current-session', args);
240
+ const { sessionId } = args;
241
+ const result = await sessionTools.getCurrentSession(sessionId);
242
+ return createMCPResponse(result, 'miadi-get-current-session');
243
+ }
244
+ });
245
+
246
+ toolRegistry.register({
247
+ name: 'miadi-switch-mode',
248
+ category: 'session',
249
+ description: 'Switch mode in existing session',
250
+ schema: {
251
+ sessionId: z.string().describe('Session ID to switch mode for'),
252
+ newMode: z.string().describe('New mode ID to activate'),
253
+ contextOverrides: z.array(z.object({
254
+ name: z.string(),
255
+ type: z.enum(['location', 'device', 'activity', 'time', 'custom']),
256
+ value: z.union([z.string(), z.number(), z.boolean(), z.record(z.any())]),
257
+ description: z.string().optional()
258
+ })).optional().describe('Context variable overrides')
259
+ },
260
+ handler: async (args: any) => {
261
+ logToolUsage('miadi-switch-mode', args);
262
+ const { sessionId, newMode, contextOverrides } = args;
263
+ const result = await sessionTools.switchMode(sessionId, newMode, contextOverrides);
264
+ return createMCPResponse(result, 'miadi-switch-mode');
265
+ }
266
+ });
267
+
268
+ toolRegistry.register({
269
+ name: 'miadi-switch-persona',
270
+ category: 'session',
271
+ description: 'Switch persona in session',
272
+ schema: {
273
+ sessionId: z.string().describe('Session ID to switch persona for'),
274
+ newPersona: z.string().describe('New persona ID to activate'),
275
+ preserveMode: z.boolean().optional().describe('Whether to preserve current mode')
276
+ },
277
+ handler: async (args: any) => {
278
+ logToolUsage('miadi-switch-persona', args);
279
+ const { sessionId, newPersona, preserveMode } = args;
280
+ const result = await sessionTools.switchPersona(sessionId, newPersona, preserveMode);
281
+ return createMCPResponse(result, 'miadi-switch-persona');
282
+ }
283
+ });
284
+
285
+ toolRegistry.register({
286
+ name: 'miadi-end-session',
287
+ category: 'session',
288
+ description: 'End active session',
289
+ schema: {
290
+ sessionId: z.string().describe('Session ID to end')
291
+ },
292
+ handler: async (args: any) => {
293
+ logToolUsage('miadi-end-session', args);
294
+ const { sessionId } = args;
295
+ const result = await sessionTools.endSession(sessionId);
296
+ return createMCPResponse(result, 'miadi-end-session');
297
+ }
298
+ });
299
+
300
+ toolRegistry.register({
301
+ name: 'miadi-list-sessions',
302
+ category: 'session',
303
+ description: 'List active sessions',
304
+ schema: {
305
+ userId: z.string().optional().describe('User ID to filter sessions by'),
306
+ limit: z.number().optional().describe('Maximum number of sessions to return'),
307
+ offset: z.number().optional().describe('Offset for pagination')
308
+ },
309
+ handler: async (args: any) => {
310
+ logToolUsage('miadi-list-sessions', args);
311
+ const { userId, limit, offset } = args;
312
+ const result = await sessionTools.listSessions(userId, limit, offset);
313
+ return createMCPResponse(result, 'miadi-list-sessions');
314
+ }
315
+ });
316
+
317
+ // Capability Resolution
318
+ toolRegistry.register({
319
+ name: 'miadi-resolve-capabilities',
320
+ category: 'capability',
321
+ description: 'Resolve capabilities for persona/mode',
322
+ schema: {
323
+ persona: z.string().describe('Persona ID to resolve capabilities for'),
324
+ mode: z.string().describe('Mode ID to resolve capabilities for'),
325
+ context: z.record(z.any()).optional().describe('Context variables for capability resolution')
326
+ },
327
+ handler: async (args: any) => {
328
+ logToolUsage('miadi-resolve-capabilities', args);
329
+ const { persona, mode, context } = args;
330
+ const result = await capabilityTools.resolveCapabilities(persona, mode, context);
331
+ return createMCPResponse(result, 'miadi-resolve-capabilities');
332
+ }
333
+ });
334
+
335
+ toolRegistry.register({
336
+ name: 'miadi-get-agent-info',
337
+ category: 'capability',
338
+ description: 'Get comprehensive agent system info',
339
+ schema: {},
340
+ handler: async (args: any) => {
341
+ logToolUsage('miadi-get-agent-info', args);
342
+ const result = await capabilityTools.getAgentInfo();
343
+ return createMCPResponse(result, 'miadi-get-agent-info');
344
+ }
345
+ });
346
+
347
+ toolRegistry.register({
348
+ name: 'miadi-detect-cues',
349
+ category: 'capability',
350
+ description: 'Detect mode/persona switch cues from text',
351
+ schema: {
352
+ text: z.string().describe('Text to analyze for cues'),
353
+ currentSession: z.record(z.any()).optional().describe('Current session context'),
354
+ availableModes: z.array(z.string()).optional().describe('Available modes to detect cues for'),
355
+ availablePersonas: z.array(z.string()).optional().describe('Available personas to detect cues for')
356
+ },
357
+ handler: async (args: any) => {
358
+ logToolUsage('miadi-detect-cues', args);
359
+ const { text, currentSession, availableModes, availablePersonas } = args;
360
+ const result = await capabilityTools.detectCues(text, currentSession, availableModes, availablePersonas);
361
+ return createMCPResponse(result, 'miadi-detect-cues');
362
+ }
363
+ });
364
+
365
+ // AI Integration
366
+ toolRegistry.register({
367
+ name: 'miadi-openai-request',
368
+ category: 'ai',
369
+ description: 'Make OpenAI API requests',
370
+ schema: {
371
+ prompt: z.string().describe('Prompt to send to OpenAI'),
372
+ modelId: z.string().optional().describe('OpenAI model ID to use'),
373
+ maxTokens: z.number().optional().describe('Maximum tokens to generate'),
374
+ temperature: z.number().optional().describe('Temperature for response generation'),
375
+ stream: z.boolean().optional().describe('Whether to stream the response')
376
+ },
377
+ handler: async (args: any) => {
378
+ logToolUsage('miadi-openai-request', args);
379
+ const { prompt, modelId, maxTokens, temperature, stream } = args;
380
+ const result = await aiTools.openaiRequest(prompt, modelId, maxTokens, temperature, stream);
381
+ return createMCPResponse(result, 'miadi-openai-request');
382
+ }
383
+ });
384
+
385
+ toolRegistry.register({
386
+ name: 'miadi-ai-request',
387
+ category: 'ai',
388
+ description: 'Make generic AI requests',
389
+ schema: {
390
+ prompt: z.string().describe('Prompt to send to AI model'),
391
+ modelId: z.string().optional().describe('AI model ID to use'),
392
+ maxTokens: z.number().optional().describe('Maximum tokens to generate'),
393
+ temperature: z.number().optional().describe('Temperature for response generation')
394
+ },
395
+ handler: async (args: any) => {
396
+ logToolUsage('miadi-ai-request', args);
397
+ const { prompt, modelId, maxTokens, temperature } = args;
398
+ const result = await aiTools.aiRequest(prompt, modelId, maxTokens, temperature);
399
+ return createMCPResponse(result, 'miadi-ai-request');
400
+ }
401
+ });
402
+
403
+ // Workflow Management
404
+ toolRegistry.register({
405
+ name: 'miadi-register-agent',
406
+ category: 'workflow',
407
+ description: 'Register agent for GitHub events',
408
+ schema: {
409
+ agentId: z.string().describe('Agent ID to register'),
410
+ eventTypes: z.array(z.string()).describe('Event types to register for'),
411
+ callbackUrl: z.string().describe('Callback URL for events')
412
+ },
413
+ handler: async (args: any) => {
414
+ logToolUsage('miadi-register-agent', args);
415
+ const { agentId, eventTypes, callbackUrl } = args;
416
+ const result = await workflowTools.registerAgent(agentId, eventTypes, callbackUrl);
417
+ return createMCPResponse(result, 'miadi-register-agent');
418
+ }
419
+ });
420
+
421
+ toolRegistry.register({
422
+ name: 'miadi-get-agent-events',
423
+ category: 'workflow',
424
+ description: 'Check for agent events',
425
+ schema: {
426
+ agentId: z.string().describe('Agent ID to check events for')
427
+ },
428
+ handler: async (args: any) => {
429
+ logToolUsage('miadi-get-agent-events', args);
430
+ const { agentId } = args;
431
+ const result = await workflowTools.getAgentEvents(agentId);
432
+ return createMCPResponse(result, 'miadi-get-agent-events');
433
+ }
434
+ });
435
+
436
+ toolRegistry.register({
437
+ name: 'miadi-get-workflow-howto',
438
+ category: 'workflow',
439
+ description: 'Get workflow setup guides',
440
+ schema: {
441
+ topic: z.string().describe('Topic to get workflow guide for')
442
+ },
443
+ handler: async (args: any) => {
444
+ logToolUsage('miadi-get-workflow-howto', args);
445
+ const { topic } = args;
446
+ const result = await workflowTools.getWorkflowHowto(topic);
447
+ return createMCPResponse(result, 'miadi-get-workflow-howto');
448
+ }
449
+ });
450
+
451
+ // Forge Operations
452
+ toolRegistry.register({
453
+ name: 'miadi-get-forge-state',
454
+ category: 'forge',
455
+ description: 'Get current forge state',
456
+ schema: {},
457
+ handler: async (args: any) => {
458
+ logToolUsage('miadi-get-forge-state', args);
459
+ const result = await forgeTools.getForgeState();
460
+ return createMCPResponse(result, 'miadi-get-forge-state');
461
+ }
462
+ });
463
+
464
+ toolRegistry.register({
465
+ name: 'miadi-update-forge-state',
466
+ category: 'forge',
467
+ description: 'Update forge state',
468
+ schema: {
469
+ state: z.record(z.any()).describe('New forge state data')
470
+ },
471
+ handler: async (args: any) => {
472
+ logToolUsage('miadi-update-forge-state', args);
473
+ const { state } = args;
474
+ const result = await forgeTools.updateForgeState(state);
475
+ return createMCPResponse(result, 'miadi-update-forge-state');
476
+ }
477
+ });
478
+
479
+ toolRegistry.register({
480
+ name: 'miadi-get-glyph-map',
481
+ category: 'forge',
482
+ description: 'Get glyph map information',
483
+ schema: {},
484
+ handler: async (args: any) => {
485
+ logToolUsage('miadi-get-glyph-map', args);
486
+ const result = await forgeTools.getGlyphMap();
487
+ return createMCPResponse(result, 'miadi-get-glyph-map');
488
+ }
489
+ });
490
+ }
491
+
492
+ async function main() {
493
+ // Define all tools
494
+ defineAllTools();
495
+
496
+ // Log configuration summary
497
+ console.error(toolRegistry.getConfigSummary());
498
+
499
+ // Register enabled tools with MCP server
500
+ toolRegistry.registerAllEnabledTools(server);
501
+
502
+ const transport = new StdioServerTransport();
503
+ await server.connect(transport);
504
+ console.error("✅ Miadi MCP Server is ready and listening!");
505
+ }
506
+
507
+ main().catch((error) => {
508
+ console.error("❌ Failed to start MCP server:", error);
509
+ process.exit(1);
510
+ });