-
Notifications
You must be signed in to change notification settings - Fork 936
Expand file tree
/
Copy pathmcp-tools.ts
More file actions
114 lines (107 loc) · 3.58 KB
/
mcp-tools.ts
File metadata and controls
114 lines (107 loc) · 3.58 KB
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
106
107
108
109
110
111
112
113
114
import { z } from '@midscene/core';
import { getDebug } from '@midscene/shared/logger';
import { BaseMidsceneTools, type ToolDefinition } from '@midscene/shared/mcp';
import { type ComputerAgent, agentFromComputer } from './agent';
import { ComputerDevice } from './device';
const debug = getDebug('mcp:computer-tools');
/**
* Computer-specific tools manager
* Extends BaseMidsceneTools to provide desktop automation tools
*/
export class ComputerMidsceneTools extends BaseMidsceneTools<ComputerAgent> {
protected createTemporaryDevice() {
// Create minimal temporary instance
return new ComputerDevice({});
}
protected async ensureAgent(
displayId?: string,
headless?: boolean,
): Promise<ComputerAgent> {
if (this.agent && displayId) {
// If a specific displayId is requested and we have an agent,
// destroy it to create a new one with the new display
try {
await this.agent.destroy?.();
} catch (error) {
debug('Failed to destroy agent during cleanup:', error);
}
this.agent = undefined;
}
if (this.agent) {
return this.agent;
}
debug('Creating Computer agent with displayId:', displayId || 'primary');
const opts = {
...(displayId ? { displayId } : {}),
...(headless !== undefined ? { headless } : {}),
};
const agent = await agentFromComputer(
Object.keys(opts).length > 0
? { ...opts, reportFileName: this.getPersistedReportFileName() }
: { reportFileName: this.getPersistedReportFileName() },
);
this.agent = agent;
this.persistAgentReportFileName(this.agent);
return agent;
}
/**
* Provide Computer-specific platform tools
*/
protected preparePlatformTools(): ToolDefinition[] {
return [
{
name: 'computer_connect',
description:
'Connect to computer desktop. Provide displayId to connect to a specific display (use computer_list_displays to get available IDs). If not provided, uses the primary display.',
schema: {
displayId: z
.string()
.optional()
.describe('Display ID (from computer_list_displays)'),
headless: z
.boolean()
.optional()
.describe('Start virtual display via Xvfb (Linux only)'),
},
handler: async ({
displayId,
headless,
}: { displayId?: string; headless?: boolean }) => {
const agent = await this.ensureAgent(displayId, headless);
const screenshot = await agent.interface.screenshotBase64();
return {
content: [
{
type: 'text',
text: `Connected to computer${displayId ? ` (Display: ${displayId})` : ' (Primary display)'}`,
},
...this.buildScreenshotContent(screenshot),
],
};
},
},
{
name: 'computer_disconnect',
description: 'Disconnect from computer and release resources',
schema: {},
handler: this.createDisconnectHandler('computer'),
},
{
name: 'computer_list_displays',
description: 'List all available displays/monitors',
schema: {},
handler: async () => {
const displays = await ComputerDevice.listDisplays();
return {
content: [
{
type: 'text',
text: `Available displays:\n${displays.map((d) => `- ${d.name} (ID: ${d.id})${d.primary ? ' [PRIMARY]' : ''}`).join('\n')}`,
},
],
};
},
},
];
}
}