forma-dsl-mcp 0.1.4
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 +97 -0
- package/package.json +52 -0
- package/src/bin.js +30 -0
- package/src/catalogue.js +703 -0
- package/src/document.js +285 -0
- package/src/examples.js +212 -0
- package/src/guide.js +313 -0
- package/src/reference/README.md +153 -0
- package/src/reference/api/describe-parameters.md +167 -0
- package/src/reference/api/evaluation-context.md +221 -0
- package/src/reference/api/export.md +185 -0
- package/src/reference/api/geometry-node.md +215 -0
- package/src/reference/api/kernel.md +182 -0
- package/src/reference/api/low-level.md +239 -0
- package/src/reference/api/render.md +217 -0
- package/src/reference/api/values.md +223 -0
- package/src/reference/errors.md +253 -0
- package/src/reference/language/control-flow.md +160 -0
- package/src/reference/language/expressions.md +206 -0
- package/src/reference/language/overview.md +156 -0
- package/src/reference/language/scope.md +184 -0
- package/src/reference/language/syntax.md +210 -0
- package/src/reference/reference/align.md +189 -0
- package/src/reference/reference/booleans.md +231 -0
- package/src/reference/reference/component.md +248 -0
- package/src/reference/reference/conversions.md +269 -0
- package/src/reference/reference/functions.md +314 -0
- package/src/reference/reference/local.md +197 -0
- package/src/reference/reference/model.md +213 -0
- package/src/reference/reference/param.md +230 -0
- package/src/reference/reference/part.md +229 -0
- package/src/reference/reference/refinement.md +284 -0
- package/src/reference/reference/shapes-2d.md +309 -0
- package/src/reference/reference/shapes-3d.md +279 -0
- package/src/reference/reference/transforms.md +246 -0
- package/src/reference.js +160 -0
- package/src/server.js +219 -0
- package/src/tools.js +523 -0
- package/src/workspace.js +204 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kalpak44
|
|
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
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# forma-dsl-mcp
|
|
2
|
+
|
|
3
|
+
[](https://github.com/kalpak44/forma-dsl/actions/workflows/release.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/forma-dsl-mcp)
|
|
5
|
+
|
|
6
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server that knows
|
|
7
|
+
[forma](https://www.npmjs.com/package/forma-dsl) — the declarative DSL for 3D solids — and
|
|
8
|
+
writes `.forma` documents that render.
|
|
9
|
+
|
|
10
|
+
It speaks over stdio, so any MCP client can launch it:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"forma": {
|
|
16
|
+
"command": "npx",
|
|
17
|
+
"args": ["-y", "forma-dsl-mcp"],
|
|
18
|
+
"env": { "FORMA_MCP_ROOT": "/absolute/path/to/your/models" }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`FORMA_MCP_ROOT` is the only configuration. It defaults to the working directory the client
|
|
25
|
+
launches the server in, and **every path the file tools accept is confined to it** — an
|
|
26
|
+
absolute path, a `..` that climbs out, or a symlink pointing out of the tree is refused
|
|
27
|
+
rather than followed.
|
|
28
|
+
|
|
29
|
+
## Why it is not just a prompt
|
|
30
|
+
|
|
31
|
+
A model that has read the language's documentation still writes forma that does not build.
|
|
32
|
+
The difference this server makes is that it **runs the geometry kernel**. `forma_check`
|
|
33
|
+
compiles the document, solves it with [Manifold](https://github.com/elalish/manifold) and
|
|
34
|
+
reports back the bounding box, the volume, the triangle count and the genus of every part —
|
|
35
|
+
so the question "is this the size that was asked for, and is it actually a solid?" is
|
|
36
|
+
answered before anyone is told the work is done. A part that silently solved to nothing is
|
|
37
|
+
called out by name.
|
|
38
|
+
|
|
39
|
+
`forma_write` runs that same check and **refuses to write a document that does not render**.
|
|
40
|
+
|
|
41
|
+
Everything the server says about the language is answerable to the language. The block and
|
|
42
|
+
function catalogue is merged with the library's own registries at load time, and the tests
|
|
43
|
+
assert that the two agree: a block added, renamed or given a new dimensionality in
|
|
44
|
+
`forma-dsl` fails this package's build rather than becoming a confident wrong answer. Every
|
|
45
|
+
worked example is rendered by the test suite, at both ends of every parameter's declared
|
|
46
|
+
range.
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
| Tool | What it does |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `forma_guide` | The language in one page: structure, nesting, dimensionality, units, syntax, the mistakes that cost the most time |
|
|
53
|
+
| `forma_blocks` | Every block with its attributes, defaults, dimensionality and caveats |
|
|
54
|
+
| `forma_functions` | Every builtin function and constant, with arity |
|
|
55
|
+
| `forma_reference` | The full reference manual, searchable and readable page by page |
|
|
56
|
+
| `forma_examples` | Complete documents that render, each showing one way of building a real part |
|
|
57
|
+
| `forma_check` | Parse, build and **measure** — errors with a line, a column and an excerpt with a caret; parts with their boxes, volumes and triangle counts |
|
|
58
|
+
| `forma_write` | Check, then write a `.forma` file into the workspace |
|
|
59
|
+
| `forma_read` | Read a document back, checked |
|
|
60
|
+
| `forma_list` | Every `.forma` file under the root |
|
|
61
|
+
| `forma_export_stl` | Render and write a binary STL |
|
|
62
|
+
|
|
63
|
+
## Resources and prompts
|
|
64
|
+
|
|
65
|
+
Resources carry the same knowledge in a form a person can attach by hand:
|
|
66
|
+
|
|
67
|
+
- `forma://guide` — the language in brief
|
|
68
|
+
- `forma://catalogue` — every block and function, as JSON
|
|
69
|
+
- `forma://reference/{path}` — one page of the manual
|
|
70
|
+
- `forma://example/{name}` — one worked document
|
|
71
|
+
|
|
72
|
+
Two prompts name the workflows worth having a name for: `model_a_part`, which walks from a
|
|
73
|
+
description of a physical object to a checked document, and `review_a_document`, which reads
|
|
74
|
+
an existing one and looks for the failures that are silent.
|
|
75
|
+
|
|
76
|
+
## Running it from source
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install
|
|
80
|
+
npm test -w forma-dsl-mcp # 140+ tests, including the protocol end to end
|
|
81
|
+
node packages/forma-dsl-mcp/src/bin.js # the server, on stdio
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Point a client at `node /absolute/path/to/packages/forma-dsl-mcp/src/bin.js` to use the
|
|
85
|
+
working tree rather than the published package.
|
|
86
|
+
|
|
87
|
+
## The bundled manual
|
|
88
|
+
|
|
89
|
+
`src/reference/` is a copy of [`apps/docs/content`](../../apps/docs/content/README.md), which
|
|
90
|
+
is a private workspace and cannot be depended on from something that ships to npm. The copy
|
|
91
|
+
is what lets the server answer offline. It is made by `npm run sync:reference -w
|
|
92
|
+
forma-dsl-mcp` and compared byte for byte against the original by the tests, so it cannot
|
|
93
|
+
drift: edit the manual, re-run the sync, and the test passes again.
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT — see [LICENSE](LICENSE).
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "forma-dsl-mcp",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "A stdio MCP server that knows the forma DSL and writes .forma documents that render.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"forma",
|
|
9
|
+
"forma-dsl",
|
|
10
|
+
"cad",
|
|
11
|
+
"csg",
|
|
12
|
+
"3d",
|
|
13
|
+
"parametric",
|
|
14
|
+
"stl"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/kalpak44/forma-dsl/tree/main/packages/forma-dsl-mcp#readme",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/kalpak44/forma-dsl.git",
|
|
20
|
+
"directory": "packages/forma-dsl-mcp"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/kalpak44/forma-dsl/issues"
|
|
24
|
+
},
|
|
25
|
+
"author": "Pavel Usanli",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"bin": {
|
|
29
|
+
"forma-dsl-mcp": "./src/bin.js"
|
|
30
|
+
},
|
|
31
|
+
"exports": {
|
|
32
|
+
".": "./src/server.js",
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"src"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22.13.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"start": "node src/bin.js",
|
|
43
|
+
"test": "node --test",
|
|
44
|
+
"sync:reference": "node scripts/sync-reference.mjs",
|
|
45
|
+
"check:package": "node scripts/check-package.mjs"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
49
|
+
"forma-dsl": "^0.1.4",
|
|
50
|
+
"zod": "^4.1.13"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/bin.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The executable: one MCP server, speaking over stdin and stdout.
|
|
4
|
+
*
|
|
5
|
+
* Nothing may be written to stdout but the protocol — a stray `console.log` corrupts the
|
|
6
|
+
* JSON-RPC stream and the client disconnects with an error that names nothing. Everything
|
|
7
|
+
* this file has to say goes to stderr, which clients collect as the server's log.
|
|
8
|
+
*/
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
|
|
11
|
+
import { Workspace } from './workspace.js';
|
|
12
|
+
import { VERSION, createServer } from './server.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Where the file tools are allowed to read and write.
|
|
16
|
+
*
|
|
17
|
+
* Defaults to the working directory, which is what a client that launches the server inside
|
|
18
|
+
* a project gives it. `FORMA_MCP_ROOT` overrides it.
|
|
19
|
+
*/
|
|
20
|
+
const root = process.env.FORMA_MCP_ROOT ?? process.cwd();
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const workspace = await Workspace.open(root);
|
|
24
|
+
const server = createServer(workspace);
|
|
25
|
+
await server.connect(new StdioServerTransport());
|
|
26
|
+
console.error(`forma-dsl-mcp ${VERSION} ready — workspace ${workspace.root}`);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(`forma-dsl-mcp failed to start: ${error?.message ?? error}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|