@vitalops/opendesk-sdk 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.
- package/README.md +176 -0
- package/bin/opendesk-mcp.js +14 -0
- package/bin/opendesk.js +40 -0
- package/dist/client.d.ts +74 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +55 -0
- package/dist/client.js.map +1 -0
- package/dist/computer/sandbox.d.ts +31 -0
- package/dist/computer/sandbox.d.ts.map +1 -0
- package/dist/computer/sandbox.js +65 -0
- package/dist/computer/sandbox.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +10 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +49 -0
- package/dist/install.js.map +1 -0
- package/dist/mcp.d.ts +18 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +56 -0
- package/dist/mcp.js.map +1 -0
- package/dist/registry.d.ts +9 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +41 -0
- package/dist/registry.js.map +1 -0
- package/dist/tools/app.d.ts +21 -0
- package/dist/tools/app.d.ts.map +1 -0
- package/dist/tools/app.js +101 -0
- package/dist/tools/app.js.map +1 -0
- package/dist/tools/audit.d.ts +21 -0
- package/dist/tools/audit.d.ts.map +1 -0
- package/dist/tools/audit.js +34 -0
- package/dist/tools/audit.js.map +1 -0
- package/dist/tools/base.d.ts +33 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +22 -0
- package/dist/tools/base.js.map +1 -0
- package/dist/tools/clipboard.d.ts +21 -0
- package/dist/tools/clipboard.d.ts.map +1 -0
- package/dist/tools/clipboard.js +39 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/keyboard.d.ts +37 -0
- package/dist/tools/keyboard.d.ts.map +1 -0
- package/dist/tools/keyboard.js +62 -0
- package/dist/tools/keyboard.js.map +1 -0
- package/dist/tools/mouse.d.ts +37 -0
- package/dist/tools/mouse.d.ts.map +1 -0
- package/dist/tools/mouse.js +77 -0
- package/dist/tools/mouse.js.map +1 -0
- package/dist/tools/ocr.d.ts +19 -0
- package/dist/tools/ocr.d.ts.map +1 -0
- package/dist/tools/ocr.js +39 -0
- package/dist/tools/ocr.js.map +1 -0
- package/dist/tools/screenshot.d.ts +28 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +41 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/ui.d.ts +55 -0
- package/dist/tools/ui.d.ts.map +1 -0
- package/dist/tools/ui.js +173 -0
- package/dist/tools/ui.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# @vitalops/opendesk-sdk — JavaScript/TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Give any JavaScript or TypeScript AI agent eyes and hands on your desktop.
|
|
4
|
+
|
|
5
|
+
No Python required. All desktop automation runs natively in Node.js — screenshot capture, mouse/keyboard control, accessibility APIs, OCR, clipboard, and audit logging.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Node.js 18+
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @vitalops/opendesk-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Claude Code / Claude Desktop
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx opendesk-js install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This registers the native MCP server with Claude Code. The tools (`screenshot`, `mouse`, `keyboard`, `ui`, etc.) are then available in every Claude Code conversation.
|
|
28
|
+
|
|
29
|
+
To remove:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx opendesk-js uninstall
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Claude Desktop
|
|
36
|
+
|
|
37
|
+
Add to your config file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"opendesk": {
|
|
43
|
+
"command": "node",
|
|
44
|
+
"args": ["/path/to/node_modules/@vitalops/opendesk-sdk/bin/opendesk-mcp.js"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Programmatic (agent loop)
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { OpenDeskClient } from "@vitalops/opendesk-sdk";
|
|
58
|
+
|
|
59
|
+
const client = new OpenDeskClient();
|
|
60
|
+
|
|
61
|
+
// Take a screenshot with Set-of-Marks
|
|
62
|
+
const shot = await client.screenshot({ marks: true });
|
|
63
|
+
console.log(shot.output);
|
|
64
|
+
|
|
65
|
+
// Click a button by name — no coordinates needed
|
|
66
|
+
await client.ui({ action: "click", app: "Safari", title: "Go" });
|
|
67
|
+
|
|
68
|
+
// Type text
|
|
69
|
+
await client.keyboard({ action: "type", text: "Hello from JS" });
|
|
70
|
+
|
|
71
|
+
// Open an app
|
|
72
|
+
await client.app({ action: "open", name: "Spotify" });
|
|
73
|
+
|
|
74
|
+
// Read clipboard
|
|
75
|
+
const clip = await client.clipboard({ action: "read" });
|
|
76
|
+
console.log(clip.output);
|
|
77
|
+
|
|
78
|
+
// OCR a region
|
|
79
|
+
const text = await client.ocr({ region: [0, 0, 800, 400] });
|
|
80
|
+
|
|
81
|
+
// Show audit log
|
|
82
|
+
const log = await client.audit({ format: "summary" });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### With Vercel AI SDK
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { OpenDeskClient } from "@vitalops/opendesk-sdk";
|
|
89
|
+
import { generateText } from "ai";
|
|
90
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
91
|
+
|
|
92
|
+
const client = new OpenDeskClient();
|
|
93
|
+
|
|
94
|
+
const shot = await client.screenshot({ marks: true });
|
|
95
|
+
const response = await generateText({
|
|
96
|
+
model: anthropic("claude-opus-4-6"),
|
|
97
|
+
messages: [
|
|
98
|
+
{
|
|
99
|
+
role: "user",
|
|
100
|
+
content: [
|
|
101
|
+
{ type: "text", text: "What do you see on screen? Click the most prominent button." },
|
|
102
|
+
{ type: "image", image: shot.attachments[0].content },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Expose as MCP server
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { createMcpServer } from "@vitalops/opendesk-sdk";
|
|
113
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
114
|
+
|
|
115
|
+
const server = createMcpServer();
|
|
116
|
+
const transport = new StdioServerTransport();
|
|
117
|
+
await server.connect(transport);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Custom session ID or permission handler
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { OpenDeskClient } from "@vitalops/opendesk-sdk";
|
|
124
|
+
|
|
125
|
+
const client = new OpenDeskClient({
|
|
126
|
+
sessionId: "my-agent-session",
|
|
127
|
+
permissionHandler: async (tool, action, description) => {
|
|
128
|
+
console.log(`Allow ${description}? [y/n]`);
|
|
129
|
+
// return true to allow, false to deny
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Tools
|
|
138
|
+
|
|
139
|
+
Full reference: [docs/tools.md](../docs/tools.md)
|
|
140
|
+
|
|
141
|
+
| Tool | Method | Description |
|
|
142
|
+
|------|--------|-------------|
|
|
143
|
+
| `screenshot` | `client.screenshot(params?)` | Capture screen, optional SoM marks |
|
|
144
|
+
| `ui` | `client.ui(params)` | Click/type by element name — no coordinates |
|
|
145
|
+
| `mouse` | `client.mouse(params)` | Pixel-level mouse control |
|
|
146
|
+
| `keyboard` | `client.keyboard(params)` | Type, press keys, hotkeys |
|
|
147
|
+
| `app` | `client.app(params)` | Open, close, focus applications |
|
|
148
|
+
| `clipboard` | `client.clipboard(params)` | Read/write system clipboard |
|
|
149
|
+
| `ocr` | `client.ocr(params?)` | Extract text from screen |
|
|
150
|
+
| `audit` | `client.audit(params?)` | Show session audit log |
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## How it works
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
Your JS/TS code
|
|
158
|
+
│
|
|
159
|
+
▼
|
|
160
|
+
@vitalops/opendesk-sdk (Node.js)
|
|
161
|
+
│
|
|
162
|
+
├── screenshot (screenshot-desktop)
|
|
163
|
+
├── mouse/keyboard (@nut-tree-fork/nut-js)
|
|
164
|
+
├── ui (osascript / PowerShell UI Automation / xdotool)
|
|
165
|
+
├── ocr (tesseract.js)
|
|
166
|
+
├── clipboard (clipboardy)
|
|
167
|
+
└── audit (in-process session log)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
All platform-specific automation runs directly in Node.js. No external process is required.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* opendesk native MCP server — run over stdio.
|
|
4
|
+
* Used by Claude Code / Claude Desktop as the MCP command.
|
|
5
|
+
*
|
|
6
|
+
* Registered automatically by: npx opendesk-js install
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { runMcpStdio } from "../dist/mcp.js";
|
|
10
|
+
|
|
11
|
+
runMcpStdio().catch((err) => {
|
|
12
|
+
console.error(err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
package/bin/opendesk.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* opendesk-js CLI
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* install [--scope=user|project] — register native MCP server with Claude Code
|
|
7
|
+
* uninstall — remove MCP server from Claude Code
|
|
8
|
+
* mcp — run the native MCP server over stdio
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { install, uninstall } from "../dist/install.js";
|
|
12
|
+
import { runMcpStdio } from "../dist/mcp.js";
|
|
13
|
+
|
|
14
|
+
const [, , command, ...rest] = process.argv;
|
|
15
|
+
|
|
16
|
+
switch (command) {
|
|
17
|
+
case "install": {
|
|
18
|
+
const scopeArg = rest.find((a) => a.startsWith("--scope="));
|
|
19
|
+
const scope = scopeArg ? scopeArg.split("=")[1] : "user";
|
|
20
|
+
install(scope);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case "uninstall":
|
|
24
|
+
uninstall();
|
|
25
|
+
break;
|
|
26
|
+
case "mcp":
|
|
27
|
+
runMcpStdio().catch((err) => {
|
|
28
|
+
console.error(err);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
console.log(`opendesk-js — JavaScript SDK for opendesk
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
opendesk-js install [--scope=user|project] Register native MCP server with Claude Code
|
|
37
|
+
opendesk-js uninstall Remove MCP server from Claude Code
|
|
38
|
+
opendesk-js mcp Run native MCP server over stdio
|
|
39
|
+
`);
|
|
40
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenDeskClient — programmatic interface to all native opendesk tools.
|
|
3
|
+
* No Python required. All desktop automation runs in Node.js.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* import { OpenDeskClient } from "@opendesk/sdk";
|
|
8
|
+
*
|
|
9
|
+
* const client = new OpenDeskClient();
|
|
10
|
+
* const result = await client.screenshot({ marks: true });
|
|
11
|
+
* console.log(result.output);
|
|
12
|
+
*/
|
|
13
|
+
import { ToolRegistry } from "./registry.js";
|
|
14
|
+
import { ToolResult, PermissionHandler } from "./tools/base.js";
|
|
15
|
+
export interface OpenDeskClientOptions {
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
permissionHandler?: PermissionHandler;
|
|
18
|
+
registry?: ToolRegistry;
|
|
19
|
+
}
|
|
20
|
+
export declare class OpenDeskClient {
|
|
21
|
+
private registry;
|
|
22
|
+
private ctx;
|
|
23
|
+
constructor(options?: OpenDeskClientOptions);
|
|
24
|
+
private call;
|
|
25
|
+
screenshot(params?: {
|
|
26
|
+
marks?: boolean;
|
|
27
|
+
savePath?: string;
|
|
28
|
+
region?: number[];
|
|
29
|
+
}): Promise<ToolResult>;
|
|
30
|
+
mouse(params: {
|
|
31
|
+
action: string;
|
|
32
|
+
x?: number;
|
|
33
|
+
y?: number;
|
|
34
|
+
endX?: number;
|
|
35
|
+
endY?: number;
|
|
36
|
+
direction?: string;
|
|
37
|
+
amount?: number;
|
|
38
|
+
}): Promise<ToolResult>;
|
|
39
|
+
keyboard(params: {
|
|
40
|
+
action: string;
|
|
41
|
+
text?: string;
|
|
42
|
+
key?: string;
|
|
43
|
+
keys?: string[];
|
|
44
|
+
holdDuration?: number;
|
|
45
|
+
}): Promise<ToolResult>;
|
|
46
|
+
app(params: {
|
|
47
|
+
action: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
}): Promise<ToolResult>;
|
|
50
|
+
ui(params: {
|
|
51
|
+
action: string;
|
|
52
|
+
app: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
role?: string;
|
|
55
|
+
menu?: string;
|
|
56
|
+
menuItem?: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
key?: string;
|
|
59
|
+
modifiers?: string[];
|
|
60
|
+
}): Promise<ToolResult>;
|
|
61
|
+
clipboard(params: {
|
|
62
|
+
action: string;
|
|
63
|
+
text?: string;
|
|
64
|
+
}): Promise<ToolResult>;
|
|
65
|
+
ocr(params?: {
|
|
66
|
+
region?: number[];
|
|
67
|
+
}): Promise<ToolResult>;
|
|
68
|
+
audit(params?: {
|
|
69
|
+
format?: "summary" | "full";
|
|
70
|
+
sessionId?: string;
|
|
71
|
+
}): Promise<ToolResult>;
|
|
72
|
+
listTools(): string[];
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAkB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAgC,UAAU,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE9F,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,GAAG,CAAc;gBAEb,OAAO,GAAE,qBAA0B;IAQ/C,OAAO,CAAC,IAAI;IAIZ,UAAU,CAAC,MAAM,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvG,KAAK,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIjJ,QAAQ,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9H,GAAG,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAInE,EAAE,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIpL,SAAS,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIzE,GAAG,CAAC,MAAM,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5D,KAAK,CAAC,MAAM,GAAE;QAAE,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5F,SAAS,IAAI,MAAM,EAAE;CAGtB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenDeskClient — programmatic interface to all native opendesk tools.
|
|
3
|
+
* No Python required. All desktop automation runs in Node.js.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* import { OpenDeskClient } from "@opendesk/sdk";
|
|
8
|
+
*
|
|
9
|
+
* const client = new OpenDeskClient();
|
|
10
|
+
* const result = await client.screenshot({ marks: true });
|
|
11
|
+
* console.log(result.output);
|
|
12
|
+
*/
|
|
13
|
+
import { createRegistry } from "./registry.js";
|
|
14
|
+
export class OpenDeskClient {
|
|
15
|
+
registry;
|
|
16
|
+
ctx;
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.registry = options.registry ?? createRegistry();
|
|
19
|
+
this.ctx = {
|
|
20
|
+
sessionId: options.sessionId ?? "default",
|
|
21
|
+
permissionHandler: options.permissionHandler,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
call(name, params = {}) {
|
|
25
|
+
return this.registry.get(name).execute(this.ctx, params);
|
|
26
|
+
}
|
|
27
|
+
screenshot(params = {}) {
|
|
28
|
+
return this.call("screenshot", params);
|
|
29
|
+
}
|
|
30
|
+
mouse(params) {
|
|
31
|
+
return this.call("mouse", params);
|
|
32
|
+
}
|
|
33
|
+
keyboard(params) {
|
|
34
|
+
return this.call("keyboard", params);
|
|
35
|
+
}
|
|
36
|
+
app(params) {
|
|
37
|
+
return this.call("app", params);
|
|
38
|
+
}
|
|
39
|
+
ui(params) {
|
|
40
|
+
return this.call("ui", params);
|
|
41
|
+
}
|
|
42
|
+
clipboard(params) {
|
|
43
|
+
return this.call("clipboard", params);
|
|
44
|
+
}
|
|
45
|
+
ocr(params = {}) {
|
|
46
|
+
return this.call("ocr", params);
|
|
47
|
+
}
|
|
48
|
+
audit(params = {}) {
|
|
49
|
+
return this.call("audit", params);
|
|
50
|
+
}
|
|
51
|
+
listTools() {
|
|
52
|
+
return this.registry.all().map((t) => t.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAgB,MAAM,eAAe,CAAC;AAS7D,MAAM,OAAO,cAAc;IACjB,QAAQ,CAAe;IACvB,GAAG,CAAc;IAEzB,YAAY,UAAiC,EAAE;QAC7C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,cAAc,EAAE,CAAC;QACrD,IAAI,CAAC,GAAG,GAAG;YACT,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;YACzC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;SAC7C,CAAC;IACJ,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,SAAkC,EAAE;QAC7D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IAED,UAAU,CAAC,SAAoE,EAAE;QAC/E,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAiC,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,MAAqH;QACzH,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAiC,CAAC,CAAC;IAC/D,CAAC;IAED,QAAQ,CAAC,MAA+F;QACtG,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAiC,CAAC,CAAC;IAClE,CAAC;IAED,GAAG,CAAC,MAAyC;QAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAiC,CAAC,CAAC;IAC7D,CAAC;IAED,EAAE,CAAC,MAA2J;QAC5J,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAiC,CAAC,CAAC;IAC5D,CAAC;IAED,SAAS,CAAC,MAAyC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAiC,CAAC,CAAC;IACnE,CAAC;IAED,GAAG,CAAC,SAAgC,EAAE;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAiC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,SAA8D,EAAE;QACpE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAiC,CAAC,CAAC;IAC/D,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session audit sandbox — mirrors Python's computer/sandbox.py.
|
|
3
|
+
*/
|
|
4
|
+
export interface AuditEntry {
|
|
5
|
+
id: string;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
action: string;
|
|
8
|
+
params: Record<string, unknown>;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
result?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ComputerSandbox {
|
|
14
|
+
readonly sessionId: string;
|
|
15
|
+
allowedApps: string[];
|
|
16
|
+
screenRegion?: [number, number, number, number];
|
|
17
|
+
lastScreenshot?: Buffer;
|
|
18
|
+
private log;
|
|
19
|
+
constructor(sessionId: string);
|
|
20
|
+
isAppAllowed(appName: string): boolean;
|
|
21
|
+
isCoordinateAllowed(x: number, y: number): boolean;
|
|
22
|
+
recordAction(action: string, params: Record<string, unknown>, result?: string, error?: string): AuditEntry;
|
|
23
|
+
exportAuditLog(): AuditEntry[];
|
|
24
|
+
summary(): string;
|
|
25
|
+
}
|
|
26
|
+
export declare function getSandbox(sessionId: string): ComputerSandbox;
|
|
27
|
+
export declare function configureSandbox(sessionId: string, opts: {
|
|
28
|
+
allowedApps?: string[];
|
|
29
|
+
screenRegion?: [number, number, number, number];
|
|
30
|
+
}): ComputerSandbox;
|
|
31
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/computer/sandbox.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,eAAe;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAM;IAC3B,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,GAAG,CAAoB;gBAEnB,SAAS,EAAE,MAAM;IAI7B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtC,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAMlD,YAAY,CACV,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,UAAU;IAcb,cAAc,IAAI,UAAU,EAAE;IAI9B,OAAO,IAAI,MAAM;CASlB;AAID,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAG7D;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChF,eAAe,CAKjB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session audit sandbox — mirrors Python's computer/sandbox.py.
|
|
3
|
+
*/
|
|
4
|
+
export class ComputerSandbox {
|
|
5
|
+
sessionId;
|
|
6
|
+
allowedApps = [];
|
|
7
|
+
screenRegion;
|
|
8
|
+
lastScreenshot;
|
|
9
|
+
log = [];
|
|
10
|
+
constructor(sessionId) {
|
|
11
|
+
this.sessionId = sessionId;
|
|
12
|
+
}
|
|
13
|
+
isAppAllowed(appName) {
|
|
14
|
+
if (this.allowedApps.length === 0)
|
|
15
|
+
return true;
|
|
16
|
+
return this.allowedApps.some((a) => appName.toLowerCase().includes(a.toLowerCase()));
|
|
17
|
+
}
|
|
18
|
+
isCoordinateAllowed(x, y) {
|
|
19
|
+
if (!this.screenRegion)
|
|
20
|
+
return true;
|
|
21
|
+
const [rx, ry, rw, rh] = this.screenRegion;
|
|
22
|
+
return x >= rx && x <= rx + rw && y >= ry && y <= ry + rh;
|
|
23
|
+
}
|
|
24
|
+
recordAction(action, params, result, error) {
|
|
25
|
+
const entry = {
|
|
26
|
+
id: crypto.randomUUID(),
|
|
27
|
+
timestamp: Date.now() / 1000,
|
|
28
|
+
action,
|
|
29
|
+
params,
|
|
30
|
+
sessionId: this.sessionId,
|
|
31
|
+
result,
|
|
32
|
+
error,
|
|
33
|
+
};
|
|
34
|
+
this.log.push(entry);
|
|
35
|
+
return entry;
|
|
36
|
+
}
|
|
37
|
+
exportAuditLog() {
|
|
38
|
+
return [...this.log];
|
|
39
|
+
}
|
|
40
|
+
summary() {
|
|
41
|
+
const counts = {};
|
|
42
|
+
for (const e of this.log)
|
|
43
|
+
counts[e.action] = (counts[e.action] ?? 0) + 1;
|
|
44
|
+
const parts = Object.entries(counts)
|
|
45
|
+
.sort()
|
|
46
|
+
.map(([k, v]) => `${v}x ${k}`)
|
|
47
|
+
.join(", ");
|
|
48
|
+
return `session=${this.sessionId.slice(0, 12)}… | ${this.log.length} actions: ${parts || "none"}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const sandboxes = new Map();
|
|
52
|
+
export function getSandbox(sessionId) {
|
|
53
|
+
if (!sandboxes.has(sessionId))
|
|
54
|
+
sandboxes.set(sessionId, new ComputerSandbox(sessionId));
|
|
55
|
+
return sandboxes.get(sessionId);
|
|
56
|
+
}
|
|
57
|
+
export function configureSandbox(sessionId, opts) {
|
|
58
|
+
const sandbox = getSandbox(sessionId);
|
|
59
|
+
if (opts.allowedApps)
|
|
60
|
+
sandbox.allowedApps = opts.allowedApps;
|
|
61
|
+
if (opts.screenRegion)
|
|
62
|
+
sandbox.screenRegion = opts.screenRegion;
|
|
63
|
+
return sandbox;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/computer/sandbox.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @opendesk/sdk — public API surface
|
|
3
|
+
*/
|
|
4
|
+
export { OpenDeskClient, type OpenDeskClientOptions } from "./client.js";
|
|
5
|
+
export { createMcpServer, runMcpStdio } from "./mcp.js";
|
|
6
|
+
export { ToolRegistry, createRegistry } from "./registry.js";
|
|
7
|
+
export { Tool, type ToolResult, type ToolContext, type PermissionHandler, type Attachment, allowAllContext, checkPermission, PermissionDeniedError, } from "./tools/base.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EACL,IAAI,EACJ,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,eAAe,EACf,eAAe,EACf,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @opendesk/sdk — public API surface
|
|
3
|
+
*/
|
|
4
|
+
export { OpenDeskClient } from "./client.js";
|
|
5
|
+
export { createMcpServer, runMcpStdio } from "./mcp.js";
|
|
6
|
+
export { ToolRegistry, createRegistry } from "./registry.js";
|
|
7
|
+
export { Tool, allowAllContext, checkPermission, PermissionDeniedError, } from "./tools/base.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAA8B,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EACL,IAAI,EAKJ,eAAe,EACf,eAAe,EACf,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI install/uninstall commands — register the JS MCP bridge with Claude Code.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx opendesk-js install
|
|
6
|
+
* npx opendesk-js uninstall
|
|
7
|
+
*/
|
|
8
|
+
export declare function install(scope?: "user" | "project"): void;
|
|
9
|
+
export declare function uninstall(): void;
|
|
10
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyBH,wBAAgB,OAAO,CAAC,KAAK,GAAE,MAAM,GAAG,SAAkB,GAAG,IAAI,CAoBhE;AAED,wBAAgB,SAAS,IAAI,IAAI,CAIhC"}
|
package/dist/install.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI install/uninstall commands — register the JS MCP bridge with Claude Code.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx opendesk-js install
|
|
6
|
+
* npx opendesk-js uninstall
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
function findClaude() {
|
|
12
|
+
try {
|
|
13
|
+
const cmd = process.platform === "win32" ? "where claude" : "which claude";
|
|
14
|
+
const result = execSync(cmd, { encoding: "utf-8" }).trim().split("\n")[0].replace(/\r/g, "");
|
|
15
|
+
if (result)
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// fall through
|
|
20
|
+
}
|
|
21
|
+
throw new Error("claude command not found.\n" +
|
|
22
|
+
"Install Claude Code first: https://claude.ai/code");
|
|
23
|
+
}
|
|
24
|
+
function findMcpBin() {
|
|
25
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
26
|
+
const pkgRoot = path.resolve(path.dirname(thisFile), "..");
|
|
27
|
+
return path.join(pkgRoot, "bin", "opendesk-mcp.js");
|
|
28
|
+
}
|
|
29
|
+
export function install(scope = "user") {
|
|
30
|
+
const claude = findClaude();
|
|
31
|
+
const mcpBin = findMcpBin();
|
|
32
|
+
// Remove existing entry if any
|
|
33
|
+
try {
|
|
34
|
+
execFileSync(claude, ["mcp", "remove", "opendesk-js"], { stdio: "pipe" });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Not registered yet — fine
|
|
38
|
+
}
|
|
39
|
+
execFileSync(claude, ["mcp", "add", "opendesk-js", `--scope=${scope}`, "--", "node", mcpBin], { stdio: "inherit", shell: process.platform === "win32" });
|
|
40
|
+
console.log(`opendesk JS MCP server registered (${scope}).`);
|
|
41
|
+
console.log(` Server: ${mcpBin}`);
|
|
42
|
+
console.log("Start a Claude Code conversation and say 'take a screenshot' to verify.");
|
|
43
|
+
}
|
|
44
|
+
export function uninstall() {
|
|
45
|
+
const claude = findClaude();
|
|
46
|
+
execFileSync(claude, ["mcp", "remove", "opendesk-js"], { stdio: "inherit", shell: process.platform === "win32" });
|
|
47
|
+
console.log("opendesk JS MCP server removed from Claude Code.");
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC;QAC3E,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7F,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,6BAA6B;QAC7B,mDAAmD,CACpD,CAAC;AACJ,CAAC;AACD,SAAS,UAAU;IACjB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAA4B,MAAM;IACxD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,+BAA+B;IAC/B,IAAI,CAAC;QACH,YAAY,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,4BAA4B;IAC9B,CAAC;IAED,YAAY,CACV,MAAM,EACN,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EACvE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAC1D,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,sCAAsC,KAAK,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,YAAY,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;IAClH,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;AAClE,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone MCP server — exposes all native opendesk tools over the
|
|
3
|
+
* Model Context Protocol. No Python required.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx opendesk-js mcp — run over stdio (for Claude Code / Claude Desktop)
|
|
7
|
+
*
|
|
8
|
+
* Or programmatically:
|
|
9
|
+
* import { createMcpServer, runMcpStdio } from "@opendesk/sdk";
|
|
10
|
+
* const server = createMcpServer();
|
|
11
|
+
* // connect your own transport
|
|
12
|
+
*/
|
|
13
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
14
|
+
import { ToolRegistry } from "./registry.js";
|
|
15
|
+
import { ToolContext } from "./tools/base.js";
|
|
16
|
+
export declare function createMcpServer(registry?: ToolRegistry, ctx?: ToolContext): Server;
|
|
17
|
+
export declare function runMcpStdio(registry?: ToolRegistry, ctx?: ToolContext): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGnE,OAAO,EAAkB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAmB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE/D,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,CA0ClF;AAED,wBAAsB,WAAW,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3F"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone MCP server — exposes all native opendesk tools over the
|
|
3
|
+
* Model Context Protocol. No Python required.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx opendesk-js mcp — run over stdio (for Claude Code / Claude Desktop)
|
|
7
|
+
*
|
|
8
|
+
* Or programmatically:
|
|
9
|
+
* import { createMcpServer, runMcpStdio } from "@opendesk/sdk";
|
|
10
|
+
* const server = createMcpServer();
|
|
11
|
+
* // connect your own transport
|
|
12
|
+
*/
|
|
13
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
14
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
16
|
+
import { createRegistry } from "./registry.js";
|
|
17
|
+
import { allowAllContext } from "./tools/base.js";
|
|
18
|
+
export function createMcpServer(registry, ctx) {
|
|
19
|
+
const reg = registry ?? createRegistry();
|
|
20
|
+
const context = ctx ?? allowAllContext();
|
|
21
|
+
const server = new Server({ name: "opendesk", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
22
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
23
|
+
tools: reg.all().map((t) => ({
|
|
24
|
+
name: t.name,
|
|
25
|
+
description: t.description,
|
|
26
|
+
inputSchema: t.schema,
|
|
27
|
+
})),
|
|
28
|
+
}));
|
|
29
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
30
|
+
const { name, arguments: args = {} } = request.params;
|
|
31
|
+
const tool = reg.get(name);
|
|
32
|
+
const result = await tool.execute(context, args);
|
|
33
|
+
const contents = [];
|
|
34
|
+
if (result.output) {
|
|
35
|
+
contents.push({ type: "text", text: result.output });
|
|
36
|
+
}
|
|
37
|
+
for (const att of result.attachments) {
|
|
38
|
+
if (att.mediaType.startsWith("image/")) {
|
|
39
|
+
contents.push({ type: "image", data: att.content.toString("base64"), mimeType: att.mediaType });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
contents.push({ type: "text", text: `[Attachment: ${att.filename}]\ndata:${att.mediaType};base64,${att.content.toString("base64")}` });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!contents.length)
|
|
46
|
+
contents.push({ type: "text", text: "(no output)" });
|
|
47
|
+
return { content: contents };
|
|
48
|
+
});
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
export async function runMcpStdio(registry, ctx) {
|
|
52
|
+
const server = createMcpServer(registry, ctx);
|
|
53
|
+
const transport = new StdioServerTransport();
|
|
54
|
+
await server.connect(transport);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,cAAc,EAAgB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAe,MAAM,iBAAiB,CAAC;AAE/D,MAAM,UAAU,eAAe,CAAC,QAAuB,EAAE,GAAiB;IACxE,MAAM,GAAG,GAAG,QAAQ,IAAI,cAAc,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EACtC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,MAAM;SACtB,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACtD,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAA+B,CAAC,CAAC;QAE5E,MAAM,QAAQ,GAA6E,EAAE,CAAC;QAE9F,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YAClG,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,CAAC,QAAQ,WAAW,GAAG,CAAC,SAAS,WAAW,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YACzI,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAE3E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAuB,EAAE,GAAiB;IAC1E,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
|