Skip to content

kellenff/argdown-mcp

Repository files navigation

@casualtheorics/argdown-mcp

argdown-mcp is a sandboxed stdio MCP server that parses Argdown documents and computes Dung grounded extensions — which arguments survive once every attack is resolved — for language-model agents. It runs under Deno with every runtime permission denied (no filesystem, no network, no subprocess), so a model-invoked tool cannot escalate beyond stdio. Reasoning is grounded in named primitives: Dung's abstract argumentation framework and Caminada's three-valued labelling. A companion Claude Code plugin extends this with Pollock's defeater frame and Walton's argument schemes.

At a glance

Surface stdio MCP server — three tools (parse, export_json, dung_extensions)
Sandbox Deno deny-by-default — file, network, subprocess, FFI, OS info, env all denied
Theory Dung (1995) abstract argumentation + Caminada (2006) three-valued labelling
Runtime Deno ≥2.0 (recommended) · Node ≥24 (fallback) · Linux + macOS only
Companion plugin @casualtheorics/argdown-plugin — 7 Claude Code skills routing natural language to the server
Out of scope Rendering (HTML / SVG / dot / PDF), non-grounded Dung semantics, statement-level attacks, Windows

Quickstart

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

That one command registers the server with Claude Code under the strict Deno permission sandbox. No yarn install, no node_modules, no local build. Deno fetches the npm bundle and runs it with every dangerous permission denied at launch.

Other MCP clients: see Install (per MCP client) below.

Sandbox

MCP servers run as long-lived child processes of an LLM client. A typical Node-launched MCP server inherits its parent's ambient permissions — full filesystem read, network egress, subprocess spawn — which means a tool the model can invoke also has those permissions. This server's blessed launch denies all of them upfront:

deno run --no-config --no-prompt
         --deny-read --deny-write --deny-net
         --ignore-env --deny-sys --deny-run --deny-ffi
         npm:@casualtheorics/argdown-mcp
Flag What it prevents
--deny-read Reading any host file
--deny-write Writing any host file
--deny-net Outbound network requests
--ignore-env Reading process environment variables
--deny-sys Querying OS info (uid, hostname, network interfaces)
--deny-run Spawning subprocesses
--deny-ffi Loading native libraries
--no-prompt Interactive permission elevation at runtime
--no-config Reading deno.json / project config from CWD

CI verifies the bundle works under this exact profile on every push to main: see scripts/smoke-deno.sh, invoked by the Deno runtime smoke job in .github/workflows/ci.yml. The deny set is not aspirational documentation; it is the runtime under which the parse / JSON-export / Dung tools are smoke-tested before release.

The MCP input kind: "file" (filesystem path) is deprecated for model use because honoring it requires loosening --deny-read. Pass Argdown as inline source instead. Operator-facing CLI use can still pass --path.

Tools

Tool readOnlyHint openWorldHint Side effects
parse true false None — pure function over inline source
export_json true false None
dung_extensions true false None

All three accept the same input shape:

{
  "kind": "inline",
  "source": "<argdown markup>"
}

parse

Parses an Argdown document and returns a structural summary plus diagnostics.

Returns:

  • A summary line with statement, argument, and section counts.
  • A diagnostic block listing any lexer/parser errors with line:col positions, and any plugin exceptions.
  • 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.

isError: true is set when any of the following hold: lexer or parser errors are present, a plugin threw an exception, or the document parses to only synthetic anonymous statements with no relations, arguments, or sections.

export_json

Same as parse, but also returns the full IArgdownResponse.json payload in a fenced JSON block. Statements, arguments, relations, and sections come through as structured data.

dung_extensions

Computes the grounded extension under Dung's abstract argumentation framework — which arguments survive once every attack has been resolved — using Caminada's three-valued labelling algorithm.

Returns:

  • A summary line: Grounded extension: N IN, M OUT, K UNDEC over A arguments and R attacks.
  • A fenced JSON block with the full partition:
{
  "extension": {
    "in": ["..."],
    "out": ["..."],
    "undec": ["..."]
  },
  "argumentCount": 0,
  "attackCount": 0
}

Label semantics:

  • IN — accepted: every attacker of this argument is OUT.
  • OUT — defeated: at least one attacker is IN.
  • UNDEC — undecided: caught in an unresolved cycle.

Scope:

  • 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.
  • Only the grounded semantics is computed. Preferred, stable, complete, semi-stable, and ideal semantics are out of scope for v0.2.
  • Undercuts (relationType: "undercut") target inference nodes, not arguments, and are filtered out.
  • A self-attacker with no external defeater is UNDEC; with an IN external defeater, it is OUT.

Worked example

A four-argument reinstatement chain — the classic test of whether a Dung implementation handles defeat propagation correctly.

Input:

<A>: claim a.
  - <B>

<B>: claim b.
  - <C>

<C>: claim c.
  - <D>: claim d.

The chain reads: D attacks C, C attacks B, B attacks A.

dung_extensions response:

Grounded extension: 2 IN, 2 OUT, 0 UNDEC over 4 arguments and 3 attacks.
Extension:
{
  "extension": {
    "in": ["B", "D"],
    "out": ["A", "C"],
    "undec": []
  },
  "argumentCount": 4,
  "attackCount": 3
}

D is unattacked → IN. C is attacked by D (IN) → OUT. B's only attacker C is now OUT → IN ( reinstated). A is attacked by B (IN) → OUT.

A three-argument odd cycle, by contrast, declines to decide:

Input:

<A>: claim a.
  - <B>

<B>: claim b.
  - <C>

<C>: claim c.
  - <A>

dung_extensions response:

Grounded extension: 0 IN, 0 OUT, 3 UNDEC over 3 arguments and 3 attacks.

No argument can be labelled without circularly depending on another. The grounded semantics leaves all three UNDEC — the honest answer for a cycle of mutually attacking arguments.

Theory

The server's dung_extensions tool implements Dung's grounded semantics from On the acceptability of arguments and its fundamental role in nonmonotonic reasoning, logic programming and n-person games (Phan Minh Dung, 1995). Labels are assigned by the iterative fixpoint described in Caminada's On the issue of reinstatement in argumentation (2006): IN, OUT, and UNDEC partition the argument set such that every IN argument has all attackers OUT, and every OUT argument has at least one IN attacker.

The companion plugin (next section) carries additional theoretical scaffolding:

  • Pollock — rebutting vs. undercutting defeaters. A rebutter attacks a conclusion directly; an undercutter attacks the inferential link between premises and conclusion. Used by rebut-argument.
  • Walton — argument schemes and critical questions. A catalogue of recurring inference patterns (expert opinion, cause-to-effect, analogy, etc.) each with associated critical questions that probe weak points. Used by rebut-argument and (planned) detect-fallacies.
  • Toulmin — claim / data / warrant / backing. Roles assigned to statements when converting prose to Argdown. Used by extract-argument.
  • Govier — the Acceptability / Relevance / Grounds triad. Three axes on which to audit a premise. Used by find-unsupported-premises.

Plugin skill documentation cites the primary sources directly: see argdown-plugin/skills/references/argumentation-theory.md.

Companion Claude Code plugin

@casualtheorics/argdown-plugin ships seven skills that route natural-language requests to the MCP tools above. Claude Code activates them automatically by trigger phrase.

Skill Triggers (excerpt)
validate-argdown "validate this argdown" · "check argdown syntax"
find-unsupported-premises "find weak points" · "find gaps in the support"
trace-argument "trace why X follows" · "what supports Y"
rebut-argument "rebut this argument" · "steelman a counter"
extract-argument "extract the argument from this prose" · "convert this to argdown"
argdown-to-prose "summarise this argdown" · "explain this argument map in words"
dung-extensions "compute the grounded extension" · "which arguments survive"

Install:

claude plugin install @casualtheorics/argdown-plugin

The plugin's bundled .mcp.json registers @casualtheorics/argdown-mcp through Deno with the deny-by-default sandbox shown above. No separate setup beyond having deno ≥2.0 on PATH. See MARKETPLACE.md for the full plugin documentation.

Install (per MCP client)

Claude Code

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

Claude Desktop

Edit claude_desktop_config.json:

{
  "mcpServers": {
    "argdown": {
      "command": "deno",
      "args": [
        "run",
        "--no-config",
        "--no-prompt",
        "--deny-read",
        "--deny-write",
        "--deny-net",
        "--ignore-env",
        "--deny-sys",
        "--deny-run",
        "--deny-ffi",
        "npm:@casualtheorics/argdown-mcp"
      ]
    }
  }
}

Cursor / VS Code / Cline / other MCP clients

Use the same command + args pair as the Claude Desktop block, transposed into the client's MCP server configuration format. The strict Deno profile is identical across clients.

Node fallback (compatibility only)

npx @casualtheorics/argdown-mcp

Node ≥24 runs the same bundle but provides no runtime permission sandbox. Reserve this for trusted local use; the recommended posture for model-attached MCP remains the Deno launch above.

CLI (no MCP required)

The package also ships an argdown-cli binary exposing the same three patterns directly from the shell.

# Inline source
argdown-cli parse --source "[a]: hello
  + [b]: world"

# Compute the Dung grounded extension
argdown-cli dung --path debate.argdown

# Stdin (use the bare `-` sentinel)
cat doc.argdown | argdown-cli export-json -
CLI command MCP tool
argdown-cli parse parse
argdown-cli export-json export_json
argdown-cli dung dung_extensions

Pass exactly one of --source <text>, --path <file>, or - (stdin). Add --json to emit the full MCP envelope ( { content, isError? }) verbatim — useful for piping into jq. The MCP path input is deprecated; the direct CLI still supports --path because the operator chose to invoke it.

Exit codes: 0 success · 1 the shaped result is flagged as an error · 2 argument-validation failure.

Architecture

flowchart LR
    Source["Argdown source<br/>(kind: inline)"] --> Parser["ParserPlugin"]
    Parser --> Model["ModelPlugin"]
    Model --> Route{"Tool"}
    Route -->|" parse "| Shape["shapeResponse"]
    Route -->|" export_json "| Export["JSONExportPlugin"]
    Export --> Shape
    Route -->|" dung_extensions "| Dung["dungGrounded<br/>(Caminada labelling)"]
    Dung --> ShapeDung["shapeDungResponse"]
    Shape --> Envelope["MCP tool result"]
    ShapeDung --> Envelope
Loading

The server registers three @argdown/core plugins: ParserPlugin, ModelPlugin, and JSONExportPlugin. Rendering plugins (html, svg, dot, pdf), selection/color/tag/group plugins, and argdown.config.json discovery are intentionally excluded. The goal is a minimal, deterministic parse surface.

The package ships as a single self-contained dist/server.js (~6 MB) with no runtime npm dependencies. @argdown/core, @argdown/node, the MCP SDK, and Zod are bundled by tsup; a createRequire ESM shim satisfies the CJS dependencies that @argdown/node pulls in transitively.

The wire input schema is a flat { kind, source?, path? } object rather than a discriminated union, because the MCP SDK's normalizeObjectSchema does not accept z.discriminatedUnion(...) — it silently emits an empty schema to clients. Handler-side validation enforces the kind / field invariant.

Non-goals

Excluded Why
Rendering (HTML, SVG, dot, PDF) This is a headless parse and reasoning surface. Rendering is @argdown/cli's job.
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.
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.
kind: "file" for model-invoked calls Requires loosening --deny-read. The CLI still accepts --path for operator use.
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.
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.

Platform & runtime support

Linux and macOS. Windows is not supported (package.json sets "os": ["!win32"] and will refuse to install).

The recommended runtime is Deno ≥2.0. Node ≥24 is supported as a fallback for trusted local use, not as the recommended MCP deployment mode.

Troubleshooting

  • @import through MCP path mode is deprecated. Strict Deno launches deny file reads, so kind: "file" cannot load importer files or imports. Expand imports outside MCP and pass the complete Argdown text as inline source.
  • @import cycles are detected by @argdown/node's IncludePlugin and surfaced in response.exceptions. The server will not hang.
  • (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".

Contributing

See CONTRIBUTING.md for prerequisites, workflow commands, and the release procedure.

License

MIT. See the LICENSE file.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors