File size: 3,210 Bytes
529090e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { Router } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { MCPMessage } from '@widget-tdc/mcp-types';
import { mcpRegistry } from './mcpRegistry.js';
import { unifiedMemorySystem } from './cognitive/UnifiedMemorySystem.js';
import { eventBus } from './EventBus.js';

export const mcpRouter = Router();

// Route MCP messages
mcpRouter.post('/route', async (req, res) => {
  const startTime = Date.now();
  let success = false;

  try {
    console.log('📨 MCP Router received request:', JSON.stringify(req.body));
    const message: MCPMessage = req.body;
    // Context for memory enrichment
    const ctx = {
      userId: (req as any).user?.id ?? 'anonymous',
      orgId: (req as any).user?.orgId ?? 'default',
      timestamp: new Date()
    };
    // Enrich message with memory context
    const enrichedMessage = await unifiedMemorySystem.enrichMCPRequest(message, ctx);
    // Ensure ID/timestamp
    if (!enrichedMessage.id) enrichedMessage.id = uuidv4();
    if (!enrichedMessage.createdAt) enrichedMessage.createdAt = new Date().toISOString();
    // Route the enriched message
    const result = await mcpRegistry.route(enrichedMessage);
    // Persist result in working memory for future context
    await unifiedMemorySystem.updateWorkingMemory(ctx, result);

    success = true;
    const duration = Date.now() - startTime;

    // Emit event for TaskRecorder observation
    eventBus.emit('mcp.tool.executed', {
      tool: enrichedMessage.tool,
      payload: enrichedMessage.payload,
      userId: ctx.userId,
      orgId: ctx.orgId,
      success: true,
      result,
      duration
    });

    res.json({
      success: true,
      messageId: enrichedMessage.id,
      result,
    });
  } catch (error: any) {
    const duration = Date.now() - startTime;

    // Emit event for TaskRecorder observation (failure)
    eventBus.emit('mcp.tool.executed', {
      tool: req.body?.tool || 'unknown',
      payload: req.body?.payload || {},
      userId: (req as any).user?.id ?? 'anonymous',
      orgId: (req as any).user?.orgId ?? 'default',
      success: false,
      error: error.message,
      duration
    });

    console.error('MCP routing error:', error);
    res.status(500).json({ success: false, error: error.message || 'Internal server error' });
  }
});

// Get list of available tools
mcpRouter.get('/tools', (req, res) => {
  const tools = mcpRegistry.getRegisteredTools();
  res.json({
    tools,
    count: tools.length,
  });
});

// Get resource content
mcpRouter.get('/resources', async (req, res) => {
  const uri = req.query.uri as string;

  if (!uri) {
    return res.status(400).json({ error: 'Missing uri parameter' });
  }

  try {
    const content = await mcpRegistry.readResource(uri);
    // If content is a string (JSON), try to parse it to return proper JSON object
    try {
      if (typeof content === 'string') {
        const jsonContent = JSON.parse(content);
        return res.json({ success: true, data: jsonContent });
      }
    } catch (e) {
      // Not JSON, return as is
    }
    res.json({ success: true, content });
  } catch (error: any) {
    res.status(404).json({ success: false, error: error.message });
  }
});