File size: 4,068 Bytes
11f4e50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { Server, Socket } from 'socket.io';
import { Project, Video, User } from '../models';

// This is the MCP-like Hub for the workspace.
// It exposes "tools" to the connected Google Antigravity CLI (the agent)
// and broadcasts state changes to connected web browser clients (the humans observing).

export function setupMCPServer(io: Server) {
  // We use namespaces to separate human browsers from the AI CLI agent
  const agentNamespace = io.of('/mcp');
  const browserNamespace = io.of('/browser');

  agentNamespace.on('connection', (socket: Socket) => {
    console.log(`[MCP Server] AI Agent connected: ${socket.id}`);

    // Tool: Read Workspace State
    socket.on('mcp:read_state', async (callback) => {
      try {
        const projects = await Project.find().lean();
        // Return minimal readable state to the agent
        callback({ status: 'success', data: { projects, count: projects.length } });
      } catch (error: any) {
        callback({ status: 'error', message: error.message });
      }
    });

    // Tool: Navigate Browser UI
    socket.on('mcp:navigate', (data: { path: string }, callback) => {
      console.log(`[MCP Server] Agent forcing navigation to: ${data.path}`);
      // Broadcast to humans looking at the browser
      browserNamespace.emit('agent:navigate', data.path);
      callback({ status: 'success' });
    });

    // Tool: Create Project
    socket.on('mcp:create_project', async (data: { name: string, defaultPlatform: string, defaultFormat: string }, callback) => {
      try {
        // Find a default user to associate with agent actions
        const defaultUser = await User.findOne();
        if (!defaultUser) {
          throw new Error('No users found in database to associate project with.');
        }

        const project = await Project.create({
          userId: defaultUser._id,
          name: data.name,
          defaultPlatform: data.defaultPlatform,
          defaultFormat: data.defaultFormat,
        });

        // Notify the frontend that a project was created autonomously
        browserNamespace.emit('agent:project_created', project);

        // Force navigation to the newly created project
        browserNamespace.emit('agent:navigate', `/project/${project._id}`);

        callback({ status: 'success', data: project });
      } catch (error: any) {
        callback({ status: 'error', message: error.message });
      }
    });

    // Tool: Update Video Draft
    socket.on('mcp:update_video_draft', (data: { projectId: string, script?: string, voiceType?: string }, callback) => {
      // Broadcast the real-time AI typing/updating to the frontend VideoCreate wizard
      browserNamespace.emit('agent:video_draft_updated', data);
      callback({ status: 'success' });
    });

    // Tool: Send Activity Log
    socket.on('mcp:activity_log', (data: { message: string, type?: 'info' | 'success' | 'warning' | 'error' }) => {
      // The CLI agent reports what it is doing. Frontend displays this in AITerminal.
      browserNamespace.emit('agent:activity_log', {
        message: data.message,
        type: data.type || 'info',
        timestamp: new Date().toISOString()
      });
    });

    socket.on('disconnect', () => {
      console.log(`[MCP Server] AI Agent disconnected: ${socket.id}`);
      browserNamespace.emit('agent:activity_log', {
        message: 'Google Antigravity CLI disconnected from workspace.',
        type: 'error',
        timestamp: new Date().toISOString()
      });
    });
  });

  browserNamespace.on('connection', (socket: Socket) => {
    console.log(`[Browser] Human connected to workspace viewport: ${socket.id}`);

    // Humans can also send activity logs manually if needed
    socket.on('browser:activity_log', (data) => {
      browserNamespace.emit('agent:activity_log', {
        message: `User typed: ${data.message}`,
        type: 'info',
        timestamp: new Date().toISOString()
      });
    });
  });
}