@casualtheorics/argdown-mcp 0.2.0 → 0.3.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.
Files changed (4) hide show
  1. package/README.md +317 -75
  2. package/dist/cli.js +220469 -0
  3. package/dist/server.js +658 -588
  4. package/package.json +48 -37
package/README.md CHANGED
@@ -1,84 +1,110 @@
1
- # @casualtheorics/argdown-mcp
1
+ # `@casualtheorics/argdown-mcp`
2
2
 
3
- An MCP server that exposes [Argdown](https://argdown.org/) parsing, JSON export, and Dung grounded-extension reasoning to language models. Give Claude (or any MCP-capable model) the ability to parse, validate, inspect, and resolve attacks within Argdown documents — including files with `@import` directives. This server does not render HTML, SVG, dot, or PDF; it is strictly a parse/validate/export/extension tool.
3
+ `argdown-mcp` is a sandboxed stdio MCP server that parses [Argdown](https://argdown.org/) documents and computes Dung
4
+ grounded extensions — which arguments survive once every attack is resolved — for language-model agents. It runs
5
+ under [Deno](https://deno.com) with every runtime permission denied (no filesystem, no network, no subprocess), so a
6
+ model-invoked tool cannot escalate beyond stdio. Reasoning is grounded in named primitives: Dung's abstract
7
+ argumentation framework and Caminada's three-valued labelling. A companion Claude Code plugin extends this with
8
+ Pollock's defeater frame and Walton's argument schemes.
4
9
 
5
- ## Install
10
+ ## At a glance
6
11
 
7
- **One-shot via npx:**
12
+ | | |
13
+ | -------------------- | ------------------------------------------------------------------------------------------------- |
14
+ | **Surface** | stdio MCP server — three tools (`parse`, `export_json`, `dung_extensions`) |
15
+ | **Sandbox** | Deno deny-by-default — file, network, subprocess, FFI, OS info, env all denied |
16
+ | **Theory** | Dung (1995) abstract argumentation + Caminada (2006) three-valued labelling |
17
+ | **Runtime** | Deno ≥2.0 (recommended) · Node ≥24 (fallback) · Linux + macOS only |
18
+ | **Companion plugin** | `@casualtheorics/argdown-plugin` — 7 Claude Code skills routing natural language to the server |
19
+ | **Out of scope** | Rendering (HTML / SVG / dot / PDF), non-grounded Dung semantics, statement-level attacks, Windows |
8
20
 
9
- ```bash
10
- npx -y @casualtheorics/argdown-mcp
11
- ```
12
-
13
- **One-shot via Yarn:**
21
+ ## Quickstart
14
22
 
15
23
  ```bash
16
- yarn dlx @casualtheorics/argdown-mcp
24
+ claude mcp add --scope user argdown -- deno run --no-config --no-prompt --deny-read --deny-write --deny-net --ignore-env --deny-sys --deny-run --deny-ffi npm:@casualtheorics/argdown-mcp
17
25
  ```
18
26
 
19
- **Claude Code (recommended for persistent access):**
27
+ That one command registers the server with Claude Code under the strict Deno permission sandbox. No `yarn install`, no
28
+ `node_modules`, no local build. Deno fetches the npm bundle and runs it with every dangerous permission denied at
29
+ launch.
20
30
 
21
- ```bash
22
- claude mcp add --scope user argdown -- npx -y @casualtheorics/argdown-mcp
23
- ```
31
+ Other MCP clients: see [Install (per MCP client)](#install-per-mcp-client) below.
24
32
 
25
- **Claude Desktop** — add to `claude_desktop_config.json`:
33
+ ## Sandbox
26
34
 
27
- ```json
28
- {
29
- "mcpServers": {
30
- "argdown": {
31
- "command": "npx",
32
- "args": ["-y", "@casualtheorics/argdown-mcp"]
33
- }
34
- }
35
- }
36
- ```
35
+ MCP servers run as long-lived child processes of an LLM client. A typical Node-launched MCP server inherits its parent's
36
+ ambient permissions — full filesystem read, network egress, subprocess spawn — which means a tool the model can invoke
37
+ also has those permissions. This server's blessed launch denies all of them upfront:
37
38
 
38
- ## What is Argdown?
39
+ ```
40
+ deno run --no-config --no-prompt
41
+ --deny-read --deny-write --deny-net
42
+ --ignore-env --deny-sys --deny-run --deny-ffi
43
+ npm:@casualtheorics/argdown-mcp
44
+ ```
39
45
 
40
- [Argdown](https://argdown.org/) is a plain-text markup language for argument mapping. It lets you write complex argumentation structures — statements, arguments, attacks, supports — in a human-readable format. This server lets a language model parse and inspect those documents without needing the Argdown desktop application or CLI.
46
+ | Flag | What it prevents |
47
+ | -------------- | ---------------------------------------------------- |
48
+ | `--deny-read` | Reading any host file |
49
+ | `--deny-write` | Writing any host file |
50
+ | `--deny-net` | Outbound network requests |
51
+ | `--ignore-env` | Reading process environment variables |
52
+ | `--deny-sys` | Querying OS info (uid, hostname, network interfaces) |
53
+ | `--deny-run` | Spawning subprocesses |
54
+ | `--deny-ffi` | Loading native libraries |
55
+ | `--no-prompt` | Interactive permission elevation at runtime |
56
+ | `--no-config` | Reading `deno.json` / project config from CWD |
57
+
58
+ CI verifies the bundle works under this exact profile on every push to `main`: see [
59
+ `scripts/smoke-deno.sh`](./scripts/smoke-deno.sh), invoked by the `Deno runtime smoke` job in [
60
+ `.github/workflows/ci.yml`](./.github/workflows/ci.yml). The deny set is not aspirational documentation; it is the
61
+ runtime under which the parse / JSON-export / Dung tools are smoke-tested before release.
62
+
63
+ The MCP input `kind: "file"` (filesystem path) is **deprecated for model use** because honoring it requires loosening
64
+ `--deny-read`. Pass Argdown as inline `source` instead. Operator-facing CLI use can still pass `--path`.
41
65
 
42
66
  ## Tools
43
67
 
44
- ### `parse`
68
+ | Tool | `readOnlyHint` | `openWorldHint` | Side effects |
69
+ | ----------------- | :------------: | :-------------: | --------------------------------------- |
70
+ | `parse` | `true` | `false` | None — pure function over inline source |
71
+ | `export_json` | `true` | `false` | None |
72
+ | `dung_extensions` | `true` | `false` | None |
45
73
 
46
- Parses an Argdown document and returns a structural summary plus diagnostics.
47
-
48
- **Input:**
74
+ All three accept the same input shape:
49
75
 
50
76
  ```json
51
- { "kind": "inline" | "file", "source": "...", "path": "..." }
77
+ {
78
+ "kind": "inline",
79
+ "source": "<argdown markup>"
80
+ }
52
81
  ```
53
82
 
54
- - `kind: "inline"` — pass the Argdown markup as `source`.
55
- - `kind: "file"` — pass the filesystem path as `path`. `@import` directives resolve relative to the importer file, not CWD.
83
+ ### `parse`
84
+
85
+ Parses an Argdown document and returns a structural summary plus diagnostics.
56
86
 
57
87
  **Returns:**
58
88
 
59
89
  - A summary line with statement, argument, and section counts.
60
90
  - A diagnostic block listing any lexer/parser errors with `line:col` positions, and any plugin exceptions.
61
- - A `(not valid Argdown)` hint when the input parses but contains only synthetic (`Untitled N`) statements with no relations, arguments, or sections — the Argdown parser is permissive, so this heuristic catches "definitely not Argdown" inputs.
91
+ - A `(not valid Argdown)` hint when the input parses but contains only synthetic (`Untitled N`) statements with no
92
+ relations, arguments, or sections — the Argdown parser is permissive, so this heuristic catches "definitely not
93
+ Argdown" inputs.
62
94
 
63
- **`isError: true`** when any of the following are true:
64
-
65
- - Lexer or parser errors are present.
66
- - A plugin threw an exception.
67
- - The document parses to only synthetic anonymous statements with no relations, arguments, or sections.
95
+ `isError: true` is set when any of the following hold: lexer or parser errors are present, a plugin threw an exception,
96
+ or the document parses to only synthetic anonymous statements with no relations, arguments, or sections.
68
97
 
69
98
  ### `export_json`
70
99
 
71
- Same as `parse`, but also returns the full `IArgdownResponse.json` payload in a fenced JSON block.
72
-
73
- **Input:** same shape as `parse`.
74
-
75
- **Returns:** everything `parse` returns, plus a JSON block containing statements, arguments, relations, and sections as structured data.
100
+ Same as `parse`, but also returns the full `IArgdownResponse.json` payload in a fenced JSON block. Statements,
101
+ arguments, relations, and sections come through as structured data.
76
102
 
77
103
  ### `dung_extensions`
78
104
 
79
- Computes the grounded extension under [Dung's abstract argumentation framework](https://plato.stanford.edu/entries/argument/) — i.e., which arguments survive once every attack has been resolved. Uses Caminada's three-valued labelling algorithm.
80
-
81
- **Input:** same shape as `parse` / `export_json`.
105
+ Computes the grounded extension
106
+ under [Dung's abstract argumentation framework](https://plato.stanford.edu/entries/argument/) — which arguments survive
107
+ once every attack has been resolved — using Caminada's three-valued labelling algorithm.
82
108
 
83
109
  **Returns:**
84
110
 
@@ -87,13 +113,17 @@ Computes the grounded extension under [Dung's abstract argumentation framework](
87
113
 
88
114
  ```json
89
115
  {
90
- "extension": { "in": ["..."], "out": ["..."], "undec": ["..."] },
116
+ "extension": {
117
+ "in": ["..."],
118
+ "out": ["..."],
119
+ "undec": ["..."]
120
+ },
91
121
  "argumentCount": 0,
92
122
  "attackCount": 0
93
123
  }
94
124
  ```
95
125
 
96
- **Semantics:**
126
+ **Label semantics:**
97
127
 
98
128
  - **IN** — accepted: every attacker of this argument is OUT.
99
129
  - **OUT** — defeated: at least one attacker is IN.
@@ -101,53 +131,265 @@ Computes the grounded extension under [Dung's abstract argumentation framework](
101
131
 
102
132
  **Scope:**
103
133
 
104
- - Only **argument-to-argument** attack relations are considered (written `<X>\n - <Y>` in Argdown). Statement-level attacks (`[s1]\n - [s2]`) are intentionally ignored — Dung's framework is abstract over arguments; lifting statement attacks belongs to a structured-argumentation layer (ASPIC+, ABA), which is out of scope.
105
- - Only the **grounded** semantics is computed. Preferred, stable, complete, semi-stable, and ideal semantics are out of scope for v0.2.
134
+ - Only **argument-to-argument** attack relations are considered (written `<X>\n - <Y>` in Argdown). Statement-level
135
+ attacks (`[s1]\n - [s2]`) are intentionally ignored Dung's framework is abstract over arguments; lifting statement
136
+ attacks belongs to a structured-argumentation layer (ASPIC+, ABA), which is out of scope.
137
+ - Only the **grounded** semantics is computed. Preferred, stable, complete, semi-stable, and ideal semantics are out of
138
+ scope for v0.2.
106
139
  - Undercuts (`relationType: "undercut"`) target inference nodes, not arguments, and are filtered out.
107
140
  - A self-attacker with no external defeater is UNDEC; with an IN external defeater, it is OUT.
108
141
 
109
- ## Architecture
142
+ ### Worked example
110
143
 
111
- **Plugin set:** The server runs three `@argdown/core` plugins: parse, model, and JSON export. Rendering plugins (html, svg, dot, pdf), selection/color/tag/group plugins, and `argdown.config.json` discovery are all intentionally excluded. The goal is a minimal, deterministic parse surface.
144
+ A four-argument reinstatement chain the classic test of whether a Dung implementation handles defeat propagation
145
+ correctly.
112
146
 
113
- **Bundle:** The package ships as a single self-contained `dist/server.js` (~6 MB) with no runtime npm dependencies. It bundles `@argdown/core`, `@argdown/node`, the MCP SDK, and Zod via tsup, using a `createRequire` ESM shim to satisfy `@argdown/node`'s CommonJS expectations.
147
+ **Input:**
114
148
 
115
- **Input schema:** The wire schema is a flat `{ kind, source?, path? }` object rather than a discriminated union, because the MCP SDK's `normalizeObjectSchema` does not accept `z.discriminatedUnion(...)`. Handler-side enforcement ensures the appropriate field (`source` or `path`) is present for each `kind` value.
149
+ ```argdown
150
+ <A>: claim a.
151
+ - <B>
116
152
 
117
- ## Troubleshooting
153
+ <B>: claim b.
154
+ - <C>
118
155
 
119
- - **`@import` paths are relative to the importer file, not CWD.** If `main.argdown` imports `imports/sub.argdown`, the path resolves from the directory containing `main.argdown`.
156
+ <C>: claim c.
157
+ - <D>: claim d.
158
+ ```
120
159
 
121
- - **`@import` cycles** are detected by `@argdown/node`'s IncludePlugin and surfaced in `response.exceptions`. The server will not hang.
160
+ The chain reads: `D` attacks `C`, `C` attacks `B`, `B` attacks `A`.
122
161
 
123
- - **`(not valid Argdown)` hint** appears when the input parses successfully but produces only synthetic `Untitled N` statements with no relations. This is the server's heuristic for catching non-Argdown content passed to `kind: "inline"`.
162
+ **`dung_extensions` response:**
124
163
 
125
- ## Security
164
+ ```
165
+ Grounded extension: 2 IN, 2 OUT, 0 UNDEC over 4 arguments and 3 attacks.
166
+ Extension:
167
+ ```
126
168
 
127
- Path mode (`kind: "file"`) reads any file the server process can read. There is no sandboxing. Do not run this server as root, and treat its filesystem access scope as equivalent to any other tool the model can invoke (e.g., Bash).
169
+ ```json
170
+ {
171
+ "extension": {
172
+ "in": ["B", "D"],
173
+ "out": ["A", "C"],
174
+ "undec": []
175
+ },
176
+ "argumentCount": 4,
177
+ "attackCount": 3
178
+ }
179
+ ```
128
180
 
129
- ## Platform support
181
+ `D` is unattacked → **IN**. `C` is attacked by `D` (IN) → **OUT**. `B`'s only attacker `C` is now OUT → **IN** _(
182
+ reinstated)_. `A` is attacked by `B` (IN) → **OUT**.
130
183
 
131
- Linux and macOS only. Windows is not supported (`package.json` sets `"os": ["!win32"]` and will refuse to install).
184
+ A three-argument odd cycle, by contrast, declines to decide:
132
185
 
133
- ## Contributing
186
+ **Input:**
187
+
188
+ ```argdown
189
+ <A>: claim a.
190
+ - <B>
191
+
192
+ <B>: claim b.
193
+ - <C>
194
+
195
+ <C>: claim c.
196
+ - <A>
197
+ ```
198
+
199
+ **`dung_extensions` response:**
200
+
201
+ ```
202
+ Grounded extension: 0 IN, 0 OUT, 3 UNDEC over 3 arguments and 3 attacks.
203
+ ```
204
+
205
+ No argument can be labelled without circularly depending on another. The grounded semantics leaves all three **UNDEC** —
206
+ the honest answer for a cycle of mutually attacking arguments.
207
+
208
+ ## Theory
209
+
210
+ The server's `dung_extensions` tool implements Dung's grounded semantics from _On the acceptability of arguments and its
211
+ fundamental role in nonmonotonic reasoning, logic programming and n-person games_ (Phan Minh Dung, 1995). Labels are
212
+ assigned by the iterative fixpoint described in Caminada's _On the issue of reinstatement in argumentation_ (2006): IN,
213
+ OUT, and UNDEC partition the argument set such that every IN argument has all attackers OUT, and every OUT argument has
214
+ at least one IN attacker.
215
+
216
+ The companion plugin (next section) carries additional theoretical scaffolding:
217
+
218
+ - **Pollock** — rebutting vs. undercutting defeaters. A rebutter attacks a conclusion directly; an undercutter attacks
219
+ the inferential link between premises and conclusion. Used by `rebut-argument`.
220
+ - **Walton** — argument schemes and critical questions. A catalogue of recurring inference patterns (expert opinion,
221
+ cause-to-effect, analogy, etc.) each with associated critical questions that probe weak points. Used by
222
+ `rebut-argument` and (planned) `detect-fallacies`.
223
+ - **Toulmin** — claim / data / warrant / backing. Roles assigned to statements when converting prose to Argdown. Used by
224
+ `extract-argument`.
225
+ - **Govier** — the **A**cceptability / **R**elevance / **G**rounds triad. Three axes on which to audit a premise. Used
226
+ by `find-unsupported-premises`.
227
+
228
+ Plugin skill documentation cites the primary sources directly: see [
229
+ `argdown-plugin/skills/references/argumentation-theory.md`](./argdown-plugin/skills/references/argumentation-theory.md).
230
+
231
+ ## Companion Claude Code plugin
232
+
233
+ [`@casualtheorics/argdown-plugin`](./argdown-plugin) ships seven skills that route natural-language requests to the MCP
234
+ tools above. Claude Code activates them automatically by trigger phrase.
235
+
236
+ | Skill | Triggers (excerpt) |
237
+ | --------------------------- | ------------------------------------------------------------------ |
238
+ | `validate-argdown` | "validate this argdown" · "check argdown syntax" |
239
+ | `find-unsupported-premises` | "find weak points" · "find gaps in the support" |
240
+ | `trace-argument` | "trace why X follows" · "what supports Y" |
241
+ | `rebut-argument` | "rebut this argument" · "steelman a counter" |
242
+ | `extract-argument` | "extract the argument from this prose" · "convert this to argdown" |
243
+ | `argdown-to-prose` | "summarise this argdown" · "explain this argument map in words" |
244
+ | `dung-extensions` | "compute the grounded extension" · "which arguments survive" |
245
+
246
+ Install:
134
247
 
135
248
  ```bash
136
- corepack enable # one-time
137
- git clone <repo>
138
- yarn install # no-op — zero-installs, PnP cache is committed
139
- yarn typecheck
140
- yarn test
141
- yarn build
142
- yarn smoke
249
+ claude plugin install @casualtheorics/argdown-plugin
143
250
  ```
144
251
 
145
- For editor PnP integration:
252
+ The plugin's bundled `.mcp.json` registers `@casualtheorics/argdown-mcp` through Deno with the deny-by-default sandbox
253
+ shown above. No separate setup beyond having `deno` ≥2.0 on `PATH`. See [`MARKETPLACE.md`](./MARKETPLACE.md) for the
254
+ full plugin documentation.
255
+
256
+ ## Install (per MCP client)
257
+
258
+ ### Claude Code
146
259
 
147
260
  ```bash
148
- yarn dlx @yarnpkg/sdks vscode # or: idea, vim, etc.
261
+ claude mcp add --scope user argdown -- deno run --no-config --no-prompt --deny-read --deny-write --deny-net --ignore-env --deny-sys --deny-run --deny-ffi npm:@casualtheorics/argdown-mcp
149
262
  ```
150
263
 
264
+ ### Claude Desktop
265
+
266
+ Edit `claude_desktop_config.json`:
267
+
268
+ ```json
269
+ {
270
+ "mcpServers": {
271
+ "argdown": {
272
+ "command": "deno",
273
+ "args": [
274
+ "run",
275
+ "--no-config",
276
+ "--no-prompt",
277
+ "--deny-read",
278
+ "--deny-write",
279
+ "--deny-net",
280
+ "--ignore-env",
281
+ "--deny-sys",
282
+ "--deny-run",
283
+ "--deny-ffi",
284
+ "npm:@casualtheorics/argdown-mcp"
285
+ ]
286
+ }
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Cursor / VS Code / Cline / other MCP clients
292
+
293
+ Use the same `command` + `args` pair as the Claude Desktop block, transposed into the client's MCP server configuration
294
+ format. The strict Deno profile is identical across clients.
295
+
296
+ ### Node fallback (compatibility only)
297
+
298
+ ```bash
299
+ npx @casualtheorics/argdown-mcp
300
+ ```
301
+
302
+ Node ≥24 runs the same bundle but provides no runtime permission sandbox. Reserve this for trusted local use; the
303
+ recommended posture for model-attached MCP remains the Deno launch above.
304
+
305
+ ## CLI (no MCP required)
306
+
307
+ The package also ships an `argdown-cli` binary exposing the same three patterns directly from the shell.
308
+
309
+ ```bash
310
+ # Inline source
311
+ argdown-cli parse --source "[a]: hello
312
+ + [b]: world"
313
+
314
+ # Compute the Dung grounded extension
315
+ argdown-cli dung --path debate.argdown
316
+
317
+ # Stdin (use the bare `-` sentinel)
318
+ cat doc.argdown | argdown-cli export-json -
319
+ ```
320
+
321
+ | CLI command | MCP tool |
322
+ | ------------------------- | ----------------- |
323
+ | `argdown-cli parse` | `parse` |
324
+ | `argdown-cli export-json` | `export_json` |
325
+ | `argdown-cli dung` | `dung_extensions` |
326
+
327
+ Pass exactly one of `--source <text>`, `--path <file>`, or `-` (stdin). Add `--json` to emit the full MCP envelope (
328
+ `{ content, isError? }`) verbatim — useful for piping into `jq`. The MCP path input is deprecated; the direct CLI still
329
+ supports `--path` because the operator chose to invoke it.
330
+
331
+ Exit codes: `0` success · `1` the shaped result is flagged as an error · `2` argument-validation failure.
332
+
333
+ ## Architecture
334
+
335
+ ```mermaid
336
+ flowchart LR
337
+ Source["Argdown source<br/>(kind: inline)"] --> Parser["ParserPlugin"]
338
+ Parser --> Model["ModelPlugin"]
339
+ Model --> Route{"Tool"}
340
+ Route -->|" parse "| Shape["shapeResponse"]
341
+ Route -->|" export_json "| Export["JSONExportPlugin"]
342
+ Export --> Shape
343
+ Route -->|" dung_extensions "| Dung["dungGrounded<br/>(Caminada labelling)"]
344
+ Dung --> ShapeDung["shapeDungResponse"]
345
+ Shape --> Envelope["MCP tool result"]
346
+ ShapeDung --> Envelope
347
+ ```
348
+
349
+ The server registers three `@argdown/core` plugins: `ParserPlugin`, `ModelPlugin`, and `JSONExportPlugin`. Rendering
350
+ plugins (`html`, `svg`, `dot`, `pdf`), selection/color/tag/group plugins, and `argdown.config.json` discovery are
351
+ intentionally excluded. The goal is a minimal, deterministic parse surface.
352
+
353
+ The package ships as a single self-contained `dist/server.js` (~6 MB) with no runtime npm dependencies. `@argdown/core`,
354
+ `@argdown/node`, the MCP SDK, and Zod are bundled by tsup; a `createRequire` ESM shim satisfies the CJS dependencies
355
+ that `@argdown/node` pulls in transitively.
356
+
357
+ The wire input schema is a flat `{ kind, source?, path? }` object rather than a discriminated union, because the MCP
358
+ SDK's `normalizeObjectSchema` does not accept `z.discriminatedUnion(...)` — it silently emits an empty schema to
359
+ clients. Handler-side validation enforces the kind / field invariant.
360
+
361
+ ## Non-goals
362
+
363
+ | Excluded | Why |
364
+ | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
365
+ | Rendering (HTML, SVG, dot, PDF) | This is a _headless_ parse and reasoning surface. Rendering is `@argdown/cli`'s job. |
366
+ | Preferred / stable / complete / semi-stable / ideal extensions | Out of scope for v0.2. Grounded is sufficient for the unique-acceptance case that motivates LLM tool use. |
367
+ | Statement-level attack lifting | Argdown's `[s1] - [s2]` syntax is not auto-lifted to argument attacks. Lifting belongs to a structured-argumentation layer (ASPIC+, ABA), not to Dung. |
368
+ | `kind: "file"` for model-invoked calls | Requires loosening `--deny-read`. The CLI still accepts `--path` for operator use. |
369
+ | Ambient permissions | The blessed runtime denies file, network, subprocess, FFI, OS info, and env. Re-enabling any of them re-introduces the risk the project exists to eliminate. |
370
+ | Windows | `package.json` sets `"os": ["!win32"]`. Cross-platform Deno support exists, but the Node compatibility path has not been verified on Windows and the CI matrix does not cover it. |
371
+
372
+ ## Platform & runtime support
373
+
374
+ Linux and macOS. Windows is not supported (`package.json` sets `"os": ["!win32"]` and will refuse to install).
375
+
376
+ The recommended runtime is Deno ≥2.0. Node ≥24 is supported as a fallback for trusted local use, not as the recommended
377
+ MCP deployment mode.
378
+
379
+ ## Troubleshooting
380
+
381
+ - **`@import` through MCP path mode is deprecated.** Strict Deno launches deny file reads, so `kind: "file"` cannot load
382
+ importer files or imports. Expand imports outside MCP and pass the complete Argdown text as inline `source`.
383
+ - **`@import` cycles** are detected by `@argdown/node`'s `IncludePlugin` and surfaced in `response.exceptions`. The
384
+ server will not hang.
385
+ - **`(not valid Argdown)` hint** appears when the input parses successfully but produces only synthetic `Untitled N`
386
+ statements with no relations. This is the server's heuristic for catching non-Argdown content passed to
387
+ `kind: "inline"`.
388
+
389
+ ## Contributing
390
+
391
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md) for prerequisites, workflow commands, and the release procedure.
392
+
151
393
  ## License
152
394
 
153
- MIT. See the `LICENSE` file.
395
+ MIT. See the [`LICENSE`](./LICENSE) file.