@mlightcad/cad-mcp-server 0.0.0-stage → 1.7.8-preview.1
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/LICENSE +21 -0
- package/README.md +146 -2
- package/dist/catalogTools.d.ts +51 -0
- package/dist/catalogTools.js +104 -0
- package/dist/catalogTools.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +19 -0
- package/dist/cli.js.map +1 -0
- package/dist/headlessGpu.d.ts +32 -0
- package/dist/headlessGpu.js +122 -0
- package/dist/headlessGpu.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +29 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +37 -0
- package/dist/session.js +213 -0
- package/dist/session.js.map +1 -0
- package/dist/toolResult.d.ts +22 -0
- package/dist/toolResult.js +40 -0
- package/dist/toolResult.js.map +1 -0
- package/dist-runner/assets/index-2iXkmn03.js +7916 -0
- package/dist-runner/index.html +25 -0
- package/dist-runner/workers/libredwg-parser-worker.js +35 -0
- package/dist-runner/workers/libredwg-web.wasm +0 -0
- package/dist-runner/workers/mtext-renderer-worker.js +42780 -0
- package/package.json +67 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mlightcad
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,147 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @mlightcad/cad-mcp-server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
stdio [Model Context Protocol](https://modelcontextprotocol.io) server that lets
|
|
4
|
+
third-party agents (Claude Code, Cursor, Codex, …) drive CAD drawings through
|
|
5
|
+
the same **script-first** API as the in-app CAD Agent.
|
|
6
|
+
|
|
7
|
+
## Why scripts, not hundreds of tools?
|
|
8
|
+
|
|
9
|
+
MCP is a great way to connect agents to CAD. It is a poor place to re-export
|
|
10
|
+
every drawing primitive as its own tool. A catalog of `draw_line`,
|
|
11
|
+
`draw_circle`, `set_entity_layer`, … never finishes, burns tokens on every
|
|
12
|
+
request, and still cannot cover one-off analysis (“find bolt-hole outliers by
|
|
13
|
+
layer and report them”).
|
|
14
|
+
|
|
15
|
+
This server follows the design in
|
|
16
|
+
[Building a CAD Agent: MCP, Tools, or Let AI Write Code?](https://dev.to/mlightcad/building-a-cad-agent-mcp-tools-or-let-ai-write-code-2nc4):
|
|
17
|
+
|
|
18
|
+
- **Tools** for clear lifecycle steps (open / blank drawing)
|
|
19
|
+
- **Scripts** for combining the CAD API into analysis, edits, and verification
|
|
20
|
+
|
|
21
|
+
The model writes a `cad.*` function body; the headless viewer runs it. Same
|
|
22
|
+
runtime as the in-app CAD Agent (`@mlightcad/cad-agent-core`), so external
|
|
23
|
+
agents (Claude Code, Cursor, Codex, …) get flexibility without a ballooning
|
|
24
|
+
tool list — and with lower token and round-trip cost for bulk work.
|
|
25
|
+
|
|
26
|
+
## Tools (intentionally small)
|
|
27
|
+
|
|
28
|
+
| Tool | Purpose |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `open_drawing` | Open a local/remote DXF/DWG, or omit `path` for a blank ISO template |
|
|
31
|
+
| `execute_cad_script` | Run a `cad.*` JavaScript function body ([script API](https://mlightcad.github.io/cad-viewer/guide/script/overview.html)) |
|
|
32
|
+
|
|
33
|
+
There are **no** per-entity `draw_line` / `draw_circle` tools. All drawing,
|
|
34
|
+
queries, edits, and context live inside one script call.
|
|
35
|
+
|
|
36
|
+
## Works with cad-simple-viewer and cad-viewer
|
|
37
|
+
|
|
38
|
+
Both products share `AcApDocManager` from `@mlightcad/cad-simple-viewer`. This
|
|
39
|
+
server’s headless runner boots that kernel (not the Vue UI package). Scripts
|
|
40
|
+
you write for the Script panel or CAD Agent in either product are valid here,
|
|
41
|
+
and the reverse is true.
|
|
42
|
+
|
|
43
|
+
This package does **not** depend on `@mlightcad/cad-viewer`.
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Node.js ≥ 20
|
|
48
|
+
- Chromium for Playwright (`pnpm --filter @mlightcad/cad-mcp-server install-browser`)
|
|
49
|
+
|
|
50
|
+
## Install / run
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm --filter @mlightcad/cad-mcp-server build
|
|
54
|
+
pnpm --filter @mlightcad/cad-mcp-server install-browser
|
|
55
|
+
cad-mcp-server
|
|
56
|
+
# or: node packages/cad-mcp-server/dist/cli.js
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## MCP client config
|
|
60
|
+
|
|
61
|
+
### Cursor (`.cursor/mcp.json`)
|
|
62
|
+
|
|
63
|
+
Prefer `${workspaceFolder}` over a hardcoded absolute path or a bare
|
|
64
|
+
relative path (MCP cwd is not always the repo root):
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"cad": {
|
|
70
|
+
"command": "node",
|
|
71
|
+
"args": [
|
|
72
|
+
"${workspaceFolder}/packages/cad-mcp-server/dist/cli.js"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Claude Code / Claude Desktop
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"cad": {
|
|
85
|
+
"command": "npx",
|
|
86
|
+
"args": ["-y", "@mlightcad/cad-mcp-server"]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
(After the package is published; for local monorepo use the `node …/dist/cli.js` form.)
|
|
93
|
+
|
|
94
|
+
## Typical flow
|
|
95
|
+
|
|
96
|
+
1. `open_drawing` with `{ "path": "./plan.dxf", "mode": "write" }`
|
|
97
|
+
(local path or http(s) URL; omit `path` to start blank).
|
|
98
|
+
2. `execute_cad_script` with a function body:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
let id
|
|
102
|
+
cad.edit.transaction('circle', tx => {
|
|
103
|
+
id = tx.drawCircle({ center: { x: 0, y: 0 }, radius: 100 })
|
|
104
|
+
})
|
|
105
|
+
cad.view.zoomExtents()
|
|
106
|
+
return cad.measure.report([
|
|
107
|
+
cad.measure.check('r', 100, cad.measure.radius(id))
|
|
108
|
+
])
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`cad.view.capturePreview` is enabled; screenshots are returned as MCP image
|
|
112
|
+
content.
|
|
113
|
+
|
|
114
|
+
## Architecture
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
MCP client --stdio--> cad-mcp-server (Node)
|
|
118
|
+
|
|
|
119
|
+
| Playwright (lazy)
|
|
120
|
+
v
|
|
121
|
+
headless Chromium
|
|
122
|
+
cad-simple-viewer + cad-agent-core
|
|
123
|
+
createCadToolCatalog / execute_cad_script
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The browser session stays alive for the process lifetime so drawing state
|
|
127
|
+
persists across tool calls.
|
|
128
|
+
|
|
129
|
+
## Library API
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import {
|
|
133
|
+
createCadMcpServer,
|
|
134
|
+
registerCadMcpTools,
|
|
135
|
+
CadMcpSession
|
|
136
|
+
} from '@mlightcad/cad-mcp-server'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`registerCadMcpTools` maps the same tool surface for a custom `McpServer`
|
|
140
|
+
(e.g. a future in-page WebMCP host that already has `AcApDocManager`).
|
|
141
|
+
|
|
142
|
+
## Related packages
|
|
143
|
+
|
|
144
|
+
- `@mlightcad/cad-agent-core` — script host and tool catalog
|
|
145
|
+
- `@mlightcad/cad-agent-plugin` — in-app chat agent
|
|
146
|
+
- `@mlightcad/cad-script-plugin` — manual script console
|
|
147
|
+
- `@mlightcad/cad-simple-viewer-cli` — AutoCAD `.scr` headless CLI (different script model)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Input schema for `execute_cad_script`.
|
|
5
|
+
*
|
|
6
|
+
* Kept in sync with {@link createCadToolCatalog} in `@mlightcad/cad-agent-core`
|
|
7
|
+
* (`code` first so streaming providers do not finalize on `intent` alone).
|
|
8
|
+
*/
|
|
9
|
+
export declare const executeCadScriptInputSchema: {
|
|
10
|
+
code: z.ZodString;
|
|
11
|
+
intent: z.ZodOptional<z.ZodString>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Input schema for MCP-only document lifecycle tool `open_drawing`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const openDrawingInputSchema: {
|
|
17
|
+
path: z.ZodOptional<z.ZodString>;
|
|
18
|
+
mode: z.ZodOptional<z.ZodEnum<["read", "write"]>>;
|
|
19
|
+
};
|
|
20
|
+
export interface RegisterCadMcpToolsOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Opens a drawing (or blank template) in the CAD session.
|
|
23
|
+
*/
|
|
24
|
+
openDrawing: (input: {
|
|
25
|
+
path?: string;
|
|
26
|
+
mode?: 'read' | 'write';
|
|
27
|
+
}) => Promise<{
|
|
28
|
+
ok: true;
|
|
29
|
+
title: string;
|
|
30
|
+
mode: 'read' | 'write';
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Runs `execute_cad_script` against the live CadSession (typically in-page).
|
|
34
|
+
*/
|
|
35
|
+
executeCadScript: (input: {
|
|
36
|
+
code: string;
|
|
37
|
+
intent?: string;
|
|
38
|
+
}) => Promise<unknown>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Registers the script-first CAD tool surface on an MCP server.
|
|
42
|
+
*
|
|
43
|
+
* Tools:
|
|
44
|
+
* - `open_drawing` — document lifecycle (not part of agent-core catalog)
|
|
45
|
+
* - `execute_cad_script` — same catalog tool as the in-app CAD Agent / Script
|
|
46
|
+
* panel on both cad-simple-viewer and cad-viewer hosts
|
|
47
|
+
*
|
|
48
|
+
* @param server - MCP server instance
|
|
49
|
+
* @param options - Session-backed executors
|
|
50
|
+
*/
|
|
51
|
+
export declare function registerCadMcpTools(server: McpServer, options: RegisterCadMcpToolsOptions): void;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { CAD_SCRIPT_API_SUMMARY } from '@mlightcad/cad-agent-core/script-api';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { toolResultToMcpContent } from './toolResult.js';
|
|
4
|
+
/**
|
|
5
|
+
* Input schema for `execute_cad_script`.
|
|
6
|
+
*
|
|
7
|
+
* Kept in sync with {@link createCadToolCatalog} in `@mlightcad/cad-agent-core`
|
|
8
|
+
* (`code` first so streaming providers do not finalize on `intent` alone).
|
|
9
|
+
*/
|
|
10
|
+
export const executeCadScriptInputSchema = {
|
|
11
|
+
code: z
|
|
12
|
+
.string()
|
|
13
|
+
.min(1)
|
|
14
|
+
.describe('JavaScript function body using cad.* (required). Prefer short scripts; for complex drawings use multiple calls.'),
|
|
15
|
+
intent: z
|
|
16
|
+
.string()
|
|
17
|
+
.max(200)
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Optional short label for the tool result. Never send intent alone — code is required. Prefer emitting code before intent.')
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Input schema for MCP-only document lifecycle tool `open_drawing`.
|
|
23
|
+
*/
|
|
24
|
+
export const openDrawingInputSchema = {
|
|
25
|
+
path: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Local .dxf/.dwg path or http(s) URL. Omit to create a blank ISO template drawing.'),
|
|
29
|
+
mode: z
|
|
30
|
+
.enum(['read', 'write'])
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Open mode. Default: write when path is omitted, read when path is set. Use write to edit an existing file.')
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Registers the script-first CAD tool surface on an MCP server.
|
|
36
|
+
*
|
|
37
|
+
* Tools:
|
|
38
|
+
* - `open_drawing` — document lifecycle (not part of agent-core catalog)
|
|
39
|
+
* - `execute_cad_script` — same catalog tool as the in-app CAD Agent / Script
|
|
40
|
+
* panel on both cad-simple-viewer and cad-viewer hosts
|
|
41
|
+
*
|
|
42
|
+
* @param server - MCP server instance
|
|
43
|
+
* @param options - Session-backed executors
|
|
44
|
+
*/
|
|
45
|
+
export function registerCadMcpTools(server, options) {
|
|
46
|
+
// MCP SDK + zod generics often hit TS2589; register via a loose shim.
|
|
47
|
+
const register = server.registerTool.bind(server);
|
|
48
|
+
register('open_drawing', {
|
|
49
|
+
description: 'Open a DXF/DWG drawing (local path or http(s) URL), or omit path to create a blank ISO template. Call before editing an existing file. Drawing ops use execute_cad_script.',
|
|
50
|
+
inputSchema: openDrawingInputSchema
|
|
51
|
+
}, async (input) => {
|
|
52
|
+
try {
|
|
53
|
+
const result = await options.openDrawing({
|
|
54
|
+
path: input.path,
|
|
55
|
+
mode: input.mode
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: 'text', text: JSON.stringify(result) }]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: JSON.stringify({
|
|
67
|
+
ok: false,
|
|
68
|
+
error: error instanceof Error ? error.message : String(error)
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
isError: true
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
register('execute_cad_script', {
|
|
77
|
+
description: CAD_SCRIPT_API_SUMMARY,
|
|
78
|
+
inputSchema: executeCadScriptInputSchema
|
|
79
|
+
}, async (input) => {
|
|
80
|
+
try {
|
|
81
|
+
const raw = await options.executeCadScript({
|
|
82
|
+
code: input.code,
|
|
83
|
+
intent: input.intent
|
|
84
|
+
});
|
|
85
|
+
return toolResultToMcpContent(raw);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: 'text',
|
|
92
|
+
text: JSON.stringify({
|
|
93
|
+
success: false,
|
|
94
|
+
message: 'Script execution failed',
|
|
95
|
+
error: error instanceof Error ? error.message : String(error)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
isError: true
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=catalogTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalogTools.js","sourceRoot":"","sources":["../src/catalogTools.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createCadMcpServer } from './server.js';
|
|
4
|
+
/**
|
|
5
|
+
* stdio entry for `@mlightcad/cad-mcp-server`.
|
|
6
|
+
*
|
|
7
|
+
* stdout is reserved for MCP JSON-RPC — log only to stderr.
|
|
8
|
+
*/
|
|
9
|
+
async function main() {
|
|
10
|
+
const server = createCadMcpServer();
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
console.error('[cad-mcp-server] listening on stdio');
|
|
14
|
+
}
|
|
15
|
+
main().catch(error => {
|
|
16
|
+
console.error('[cad-mcp-server] fatal:', error instanceof Error ? error.message : error);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD;;;;GAIG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAA;IACnC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/B,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAA;AACtD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;IACnB,OAAO,CAAC,KAAK,CACX,yBAAyB,EACzB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC/C,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Browser } from 'playwright';
|
|
2
|
+
/**
|
|
3
|
+
* ANGLE / GL backend tried for headless WebGL, in preference order.
|
|
4
|
+
* `swiftshader` is the software renderer used when no hardware backend works.
|
|
5
|
+
*/
|
|
6
|
+
type GpuBackend = 'd3d11' | 'd3d9' | 'metal' | 'vulkan' | 'gl' | 'egl' | 'gles' | 'swiftshader';
|
|
7
|
+
export interface HeadlessGpuLaunch {
|
|
8
|
+
browser: Browser;
|
|
9
|
+
/** UNMASKED_RENDERER_WEBGL string, or `unavailable`. */
|
|
10
|
+
renderer: string;
|
|
11
|
+
backend: GpuBackend;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Hardware backends for this OS, then SwiftShader.
|
|
15
|
+
*/
|
|
16
|
+
export declare function gpuBackendOrder(platform?: NodeJS.Platform): GpuBackend[];
|
|
17
|
+
/** True for CPU rasterizers (SwiftShader, llvmpipe, WARP, …). */
|
|
18
|
+
export declare function isSoftwareWebGlRenderer(renderer: string): boolean;
|
|
19
|
+
export interface LaunchHeadlessChromiumOptions {
|
|
20
|
+
channel?: string;
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
/**
|
|
23
|
+
* Prefer hardware GPU WebGL. Default `true`.
|
|
24
|
+
* When hardware is unavailable, falls back to SwiftShader.
|
|
25
|
+
*/
|
|
26
|
+
useGpu?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Launches headless Chromium for WebGL (same strategy as cad-simple-viewer-cli).
|
|
30
|
+
*/
|
|
31
|
+
export declare function launchHeadlessChromium(options?: LaunchHeadlessChromiumOptions): Promise<HeadlessGpuLaunch>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
/**
|
|
3
|
+
* Hardware backends for this OS, then SwiftShader.
|
|
4
|
+
*/
|
|
5
|
+
export function gpuBackendOrder(platform = process.platform) {
|
|
6
|
+
switch (platform) {
|
|
7
|
+
case 'win32':
|
|
8
|
+
return ['d3d11', 'd3d9', 'swiftshader'];
|
|
9
|
+
case 'darwin':
|
|
10
|
+
return ['metal', 'gl', 'swiftshader'];
|
|
11
|
+
default:
|
|
12
|
+
return ['vulkan', 'gl', 'egl', 'gles', 'swiftshader'];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** True for CPU rasterizers (SwiftShader, llvmpipe, WARP, …). */
|
|
16
|
+
export function isSoftwareWebGlRenderer(renderer) {
|
|
17
|
+
return /swiftshader|llvmpipe|softpipe|lavapipe|microsoft basic render|software raster/i.test(renderer);
|
|
18
|
+
}
|
|
19
|
+
function chromiumArgsForBackend(backend) {
|
|
20
|
+
const shared = ['--ignore-gpu-blocklist', '--enable-gpu', '--enable-webgl'];
|
|
21
|
+
if (backend === 'swiftshader') {
|
|
22
|
+
return [
|
|
23
|
+
...shared,
|
|
24
|
+
'--use-gl=angle',
|
|
25
|
+
'--use-angle=swiftshader',
|
|
26
|
+
'--enable-unsafe-swiftshader'
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
if (backend === 'egl') {
|
|
30
|
+
return [...shared, '--use-gl=egl'];
|
|
31
|
+
}
|
|
32
|
+
return [...shared, '--use-gl=angle', `--use-angle=${backend}`];
|
|
33
|
+
}
|
|
34
|
+
async function probeWebGlRenderer(browser) {
|
|
35
|
+
const page = await browser.newPage();
|
|
36
|
+
try {
|
|
37
|
+
return await page.evaluate(() => {
|
|
38
|
+
const canvas = document.createElement('canvas');
|
|
39
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
40
|
+
if (!gl)
|
|
41
|
+
return 'unavailable';
|
|
42
|
+
const ext = gl.getExtension('WEBGL_debug_renderer_info');
|
|
43
|
+
const renderer = ext
|
|
44
|
+
? gl.getParameter(ext.UNMASKED_RENDERER_WEBGL)
|
|
45
|
+
: gl.getParameter(gl.RENDERER);
|
|
46
|
+
return renderer ? String(renderer) : 'unavailable';
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return 'unavailable';
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await page.close().catch(() => undefined);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function launchSwiftShader(base) {
|
|
57
|
+
const browser = await chromium.launch({
|
|
58
|
+
...base,
|
|
59
|
+
args: chromiumArgsForBackend('swiftshader')
|
|
60
|
+
});
|
|
61
|
+
const renderer = await probeWebGlRenderer(browser);
|
|
62
|
+
return { browser, renderer, backend: 'swiftshader' };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Launches headless Chromium for WebGL (same strategy as cad-simple-viewer-cli).
|
|
66
|
+
*/
|
|
67
|
+
export async function launchHeadlessChromium(options = {}) {
|
|
68
|
+
const channel = options.channel;
|
|
69
|
+
const platform = options.platform ?? process.platform;
|
|
70
|
+
const useGpu = options.useGpu !== false;
|
|
71
|
+
const base = {
|
|
72
|
+
headless: true,
|
|
73
|
+
...(channel ? { channel } : {})
|
|
74
|
+
};
|
|
75
|
+
if (!useGpu) {
|
|
76
|
+
console.error('[cad-mcp-server] GPU disabled; using software renderer (SwiftShader)');
|
|
77
|
+
return launchSwiftShader(base);
|
|
78
|
+
}
|
|
79
|
+
let software;
|
|
80
|
+
const skipped = [];
|
|
81
|
+
for (const backend of gpuBackendOrder(platform)) {
|
|
82
|
+
let browser;
|
|
83
|
+
try {
|
|
84
|
+
browser = await chromium.launch({
|
|
85
|
+
...base,
|
|
86
|
+
args: chromiumArgsForBackend(backend)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
skipped.push(`${backend} (${error instanceof Error ? error.message : String(error)})`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const renderer = await probeWebGlRenderer(browser);
|
|
94
|
+
if (renderer === 'unavailable') {
|
|
95
|
+
skipped.push(`${backend} (no WebGL)`);
|
|
96
|
+
await browser.close().catch(() => undefined);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (!isSoftwareWebGlRenderer(renderer)) {
|
|
100
|
+
if (software) {
|
|
101
|
+
await software.browser.close().catch(() => undefined);
|
|
102
|
+
}
|
|
103
|
+
return { browser, renderer, backend };
|
|
104
|
+
}
|
|
105
|
+
skipped.push(`${backend} (${renderer})`);
|
|
106
|
+
if (!software) {
|
|
107
|
+
software = { browser, renderer, backend };
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
await browser.close().catch(() => undefined);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (software) {
|
|
114
|
+
if (skipped.length > 0) {
|
|
115
|
+
console.error(`[cad-mcp-server] no hardware WebGL; using software renderer. Tried ${skipped.join('; ')}`);
|
|
116
|
+
}
|
|
117
|
+
return software;
|
|
118
|
+
}
|
|
119
|
+
console.error('[cad-mcp-server] no hardware WebGL; falling back to SwiftShader');
|
|
120
|
+
return launchSwiftShader(base);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=headlessGpu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headlessGpu.js","sourceRoot":"","sources":["../src/headlessGpu.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for embedding or testing the CAD MCP server.
|
|
3
|
+
*
|
|
4
|
+
* The CLI entry is {@link ./cli.ts}; most hosts run `cad-mcp-server` via stdio.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export { executeCadScriptInputSchema, openDrawingInputSchema, registerCadMcpTools, type RegisterCadMcpToolsOptions } from './catalogTools.js';
|
|
9
|
+
export { createCadMcpServer } from './server.js';
|
|
10
|
+
export { CadMcpSession, type CadMcpOpenMode, type CadMcpSessionCreateOptions } from './session.js';
|
|
11
|
+
export { toolResultToMcpContent, type McpContentBlock } from './toolResult.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for embedding or testing the CAD MCP server.
|
|
3
|
+
*
|
|
4
|
+
* The CLI entry is {@link ./cli.ts}; most hosts run `cad-mcp-server` via stdio.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export { executeCadScriptInputSchema, openDrawingInputSchema, registerCadMcpTools } from './catalogTools.js';
|
|
9
|
+
export { createCadMcpServer } from './server.js';
|
|
10
|
+
export { CadMcpSession } from './session.js';
|
|
11
|
+
export { toolResultToMcpContent } from './toolResult.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,mBAAmB,EAEpB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EACL,aAAa,EAGd,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,sBAAsB,EAEvB,MAAM,iBAAiB,CAAA"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the stdio MCP server that exposes CAD script tools.
|
|
4
|
+
*
|
|
5
|
+
* The headless Chromium session is started lazily on the first tool call.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createCadMcpServer(): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { registerCadMcpTools } from './catalogTools.js';
|
|
4
|
+
import { CadMcpSession } from './session.js';
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const { version: packageVersion } = require('../package.json');
|
|
7
|
+
/**
|
|
8
|
+
* Builds the stdio MCP server that exposes CAD script tools.
|
|
9
|
+
*
|
|
10
|
+
* The headless Chromium session is started lazily on the first tool call.
|
|
11
|
+
*/
|
|
12
|
+
export function createCadMcpServer() {
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: 'cad-mcp-server',
|
|
15
|
+
version: packageVersion
|
|
16
|
+
});
|
|
17
|
+
registerCadMcpTools(server, {
|
|
18
|
+
openDrawing: async (input) => {
|
|
19
|
+
const session = await CadMcpSession.shared();
|
|
20
|
+
return session.openDrawing(input);
|
|
21
|
+
},
|
|
22
|
+
executeCadScript: async (input) => {
|
|
23
|
+
const session = await CadMcpSession.shared();
|
|
24
|
+
return session.executeCadScript(input);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return server;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAE5D,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAA;IAEF,mBAAmB,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;YACzB,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,CAAA;YAC5C,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;QACnC,CAAC;QACD,gBAAgB,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;YAC9B,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,CAAA;YAC5C,OAAO,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;QACxC,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ToolResult } from '@mlightcad/cad-agent-core';
|
|
2
|
+
export type CadMcpOpenMode = 'read' | 'write';
|
|
3
|
+
export interface CadMcpSessionCreateOptions {
|
|
4
|
+
/** Prefer hardware GPU WebGL. Default `true`. */
|
|
5
|
+
useGpu?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Long-lived headless Chromium session hosting cad-simple-viewer + agent-core.
|
|
9
|
+
*
|
|
10
|
+
* Started lazily on the first tool call and kept for the process lifetime so
|
|
11
|
+
* drawing state persists across MCP tool invocations.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CadMcpSession {
|
|
14
|
+
private readonly browser;
|
|
15
|
+
private readonly page;
|
|
16
|
+
private readonly server;
|
|
17
|
+
private constructor();
|
|
18
|
+
private static instance;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the shared session, creating it on first call.
|
|
21
|
+
*/
|
|
22
|
+
static shared(options?: CadMcpSessionCreateOptions): Promise<CadMcpSession>;
|
|
23
|
+
static create(options?: CadMcpSessionCreateOptions): Promise<CadMcpSession>;
|
|
24
|
+
openDrawing(input: {
|
|
25
|
+
path?: string;
|
|
26
|
+
mode?: CadMcpOpenMode;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
ok: true;
|
|
29
|
+
title: string;
|
|
30
|
+
mode: CadMcpOpenMode;
|
|
31
|
+
}>;
|
|
32
|
+
executeCadScript(input: {
|
|
33
|
+
code: string;
|
|
34
|
+
intent?: string;
|
|
35
|
+
}): Promise<ToolResult>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
}
|