{
  "markdown": "# @intent-driven/mcp-server\n\n[![CI](https://github.com/intent-driven-software/idf-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/intent-driven-software/idf-mcp/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/@intent-driven/mcp-server.svg)](https://www.npmjs.com/package/@intent-driven/mcp-server)\n[![npm downloads](https://img.shields.io/npm/dm/@intent-driven/mcp-server.svg)](https://www.npmjs.com/package/@intent-driven/mcp-server)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n**Stop giving AI agents API keys. Give them a domain.**\n\n`@intent-driven/mcp-server` exposes any [IDF](https://github.com/DubovskiyIM/idf) domain\nto Claude Desktop / Cursor / Zed as a Model Context Protocol server &mdash; with\n**domain semantics in tool descriptions** (preconditions, invariants,\nirreversibility, role scopes) and **structured rejections** when the agent\ntries something it shouldn't. Not a 500. Not a string. A JSON shape the\nLLM can read and adapt to.\n\n→ Landing &amp; demo: **[fold.intent-design.tech](https://fold.intent-design.tech)**\n→ 5-min quickstart: **[github.com/intent-driven-software/fold-runtime-quickstart](https://github.com/intent-driven-software/fold-runtime-quickstart)**\n\n### 70-second walkthrough\n\n[![Watch the demo on Loom](https://cdn.loom.com/sessions/thumbnails/2ca4a40e3b9245feb86a74a998e42cb8-with-play.gif)](https://www.loom.com/share/2ca4a40e3b9245feb86a74a998e42cb8)\n\n→ **[Watch on Loom →](https://www.loom.com/share/2ca4a40e3b9245feb86a74a998e42cb8)**\n\n---\n\n## Why this exists\n\nOn April 25 2026 a Cursor agent powered by Claude Opus 4.6, working on a\ncredential mismatch in PocketOS staging, found an unrelated API token,\ndecided to delete a Railway volume to fix things, and wiped the production\ndatabase **and all volume-level backups** in 9 seconds. The agent's own\npost-mortem:\n\n> \"I guessed that deleting a staging volume via the API would be scoped\n> to staging only. I didn't verify. I didn't check if the volume ID was\n> shared across environments.\"\n\n30-hour outage. PocketOS rolled back to a 3-month-old backup.\n([The Register](https://www.theregister.com/2026/04/27/cursoropus_agent_snuffs_out_pocketos/) ·\n[FastCompany](https://www.fastcompany.com/91533544/cursor-claude-ai-agent-deleted-software-company-pocket-os-database-jer-crane) ·\n[OECD AI Incident #6153](https://oecd.ai/en/incidents/2026-04-27-6153))\n\nThis isn't an alignment problem. The system never told the agent what\nwas allowed, why it shouldn't, or what would happen if it tried. Existing\nMCP servers don't either &mdash; tool descriptions carry endpoint shape\nand not much else. The agent learns by colliding with 500s.\n\nThis package fixes that. The MCP tool descriptions carry the **why** the\ncall might fail; the rejection carries the **what** failed, structured.\n\n## How it plugs into your stack\n\n`@intent-driven/mcp-server` is a **stdio MCP adapter** that talks to a\n**Fold runtime** over an HTTP API. The runtime is a sibling service —\nnot middleware in your existing app, not codegen at runtime. Your current\nbackend stays where it is; the IDF artifact *describes* the agent-facing\nsurface, and the runtime serves it on its own port (default `:3001`).\n\n```\n┌──────────────────┐   stdio    ┌──────────────────┐   HTTP   ┌────────────────────┐\n│ Claude Desktop   │ ◀─────────▶│ @intent-driven/  │ ◀───────▶│ Fold runtime       │\n│ Cursor / Zed     │            │ mcp-server       │          │ (idf host :3001)   │\n└──────────────────┘            └──────────────────┘          └────────┬───────────┘\n                                                                       │ reads\n                                                                       ▼\n                                                              ┌────────────────────┐\n                                                              │ IDF artifact       │\n                                                              │ (entities + intents│\n                                                              │  + invariants +    │\n                                                              │  roles + __irr)    │\n                                                              └────────────────────┘\n```\n\nThe **MCP server** is what Claude/Cursor connects to. The **runtime** is\nwhat enforces the rejection. The **IDF artifact** is what you author.\n\n**Who this is for.** You're the engineer at a 5–30-person team putting\nan AI agent into production this quarter — on top of a real backend,\nwith real customers, real SOC2 review on the horizon. You don't want a\nguardrail layer that reviews after the fact. You want the system itself\nto refuse the wrong action — before the call, with a structured reason\nthe agent can read.\n\n## What the agent actually sees\n\n`submit_response` in the freelance domain:\n\n```\nExecutor публикует Response на Task в status=published; Response.status=pending; +1 в Task.responsesCount\n\nCreates: Response(pending)\n\nPreconditions: task.status = \"published\"\n\nMay fail on (domain invariants):\n  - Response.taskId must reference existing Task.id\n  - Response: max 1 per taskId where (status=\"selected\")\n  - Response: row count rule per taskId where (status=\"pending\") [info]\n```\n\n`release_payment` in the same domain:\n\n```\nCustomer releases escrow to executor. After confirmation, money is gone — forward-correction only.\n\n⚠️ Irreversible action (point-of-no-return: high). Forward-correction only after this effect is confirmed.\n\nMay fail on (domain invariants):\n  - Deal.status transitions allowed: in_progress→completed, on_review→completed, ...\n```\n\nNone of this is hand-written for the MCP server. It's all derived from\none declarative IDF artifact (entities + intents + invariants + roles\n+ irreversibility points).\n\n## What a structured rejection looks like\n\nAgent submits a $50,000 BTC long without preapproval. The runtime\nintercepts **before** any effect lands in storage:\n\n```json\nHTTP 403\n{\n  \"error\": \"preapproval_denied\",\n  \"intentId\": \"agent_execute_preapproved_order\",\n  \"reason\": \"no_preapproval\",\n  \"details\": {\n    \"entity\": \"AgentPreapproval\",\n    \"ownerField\": \"userId\",\n    \"viewerId\": \"user_5f57c252\"\n  }\n}\n```\n\nThe next move for any sane agent: stop, ask the human for a preapproval,\nretry. Not a 500. Not a string. A JSON shape the LLM can read and adapt to.\n\n---\n\n## Quickstart\n\nThe fastest path is the [**fold-runtime-quickstart**](https://github.com/intent-driven-software/fold-runtime-quickstart)\n&mdash; two commands, Docker-bundled, no path configuration:\n\n```bash\ngit clone https://github.com/intent-driven-software/fold-runtime-quickstart && cd $_\ndocker compose up                  # ~3 min first time, ~5 sec after\n\n# in another terminal\nnpm install\nnpm run demo:rogue   && \\          # Act 1: $50K trade → 403 with structured rejection\n  npm run demo:grant && \\          # Act 2: investor issues $1K cap (one declarative effect)\n  npm run demo:smart               # Act 3: agent reads cap, scales to $950, executes 200 OK\n```\n\nIf you'd rather drive the host yourself (e.g. for development against your\nown ontologies), see the next section.\n\n## Drive the MCP server directly\n\nYou need a running IDF host on `localhost:3001` (the quickstart's\ndocker-compose gives you that, or run [`idf`](https://github.com/DubovskiyIM/idf)\nmanually) and a bootstrapped domain.\n\n### CLI\n\n```bash\n# bootstrap from local FS (ontology + intents)\nmcp-idf --domain=invest --ontology-path=/abs/path/to/idf/src/domains/invest\n\n# skip bootstrap (domain already loaded by another client / docker)\nmcp-idf --domain=invest --no-bootstrap\n```\n\nFlags / env vars:\n\n| Flag                | Env var                | Default                         |\n|---------------------|------------------------|---------------------------------|\n| `--domain`          | `IDF_DOMAIN`           | `booking`                       |\n| `--server`          | `IDF_SERVER`           | `http://localhost:3001`         |\n| `--ontology-path`   | `IDF_ONTOLOGY_PATH`    | `./src/domains/<domain>`        |\n| `--agent-email`     | `IDF_AGENT_EMAIL`      | `mcp-agent@local`               |\n| `--no-bootstrap`    | `IDF_BOOTSTRAP=0`      | bootstrap on (load FS ontology) |\n\n### Claude Desktop\n\n`~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"invest\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@intent-driven/mcp-server\"],\n      \"env\": {\n        \"IDF_SERVER\": \"http://localhost:3001\",\n        \"IDF_DOMAIN\": \"invest\",\n        \"IDF_BOOTSTRAP\": \"0\",\n        \"IDF_AGENT_EMAIL\": \"claude@local\"\n      }\n    }\n  }\n}\n```\n\n`IDF_BOOTSTRAP=0` if the host already has the domain loaded (the quickstart\ncontainer does this on `docker compose up`). Restart Claude Desktop fully\n(⌘Q + relaunch &mdash; closing the window isn't enough). All\nagent-callable intents appear in the **Tools** menu.\n\n---\n\n## Schema mapping\n\n```\nIDF intent.canExecute              ─→  MCP tool\nintent.parameters                  ─→  JSON Schema inputSchema\nintent.conditions                  ─→  description hint for LLM\nontology.invariants (relevant)     ─→  description block \"May fail on\"\nintent.irreversibility:high        ─→  annotations.destructiveHint + warning\nrole.visibleFields                 ─→  resource per collection\npreapproval guard                  ─→  automatic scope/limits\ncheckOwnership                     ─→  automatic access control\n```\n\n### Tools\n\nOne tool per intent in `ontology.roles.agent.canExecute`.\n\n- `name` — `intentId`\n- `title` — `intent.name`\n- `description` — `intent.description` + `Creates: …` + preconditions +\n  `May fail on (domain invariants)` block + irreversibility warning when\n  `irreversibility: \"high\"`\n- `inputSchema` — JSON Schema from `particles.parameters`:\n  - `entityRef` / `id` / `text` / `textarea` / `select` → `string`\n  - `number` → `number`\n  - `boolean` → `boolean`\n  - `datetime` → `string` + `format: \"date-time\"`\n  - `email` → `string` + `format: \"email\"`\n- `annotations.destructiveHint` — `true` when\n  `intent.irreversibility === \"high\"` (§23 IDF: effect-level point of no return)\n\n### Resources\n\nOne resource per collection in `role.visibleFields[entity]`. URI scheme:\n`idf://<domain>/<collection>`.\n\n`resources/read` returns the filtered world from\n`/api/agent/:domain/world` &mdash; already scoped per viewer (single-owner\n+ m2m via `role.scope`).\n\n---\n\n## What this gets you that hand-rolled MCP doesn't\n\nThe MCP community solves these by hand in every server:\n\n1. **Scope / visibility.** Decorators or middleware. → IDF declares `role.visibleFields`.\n2. **Permissions.** OAuth scopes, custom ACL. → IDF declares `roles.agent.canExecute`.\n3. **Rate limits / spending caps.** Bespoke per server. → IDF declares `preapproval.requiredFor` with `maxAmount` / `dailySum`.\n4. **Destructive hints.** Manual, often forgotten. → IDF: `effect.context.__irr.point === \"high\"` → `destructiveHint: true` automatic.\n5. **Business rules as LLM hint.** Usually not transmitted. → IDF: `intent.conditions` land in tool description as `Preconditions:`.\n6. **Domain invariants in descriptions.** Almost never. → IDF computes the relevant invariants per intent (alpha × entity match) and injects them as `May fail on (domain invariants)`. Closes the #1 complaint about hand-rolled MCP servers: *\"the server doesn't carry domain semantics — the LLM knows what to call but not why it'll fail.\"*\n\n---\n\n## How long does authoring an IDF artifact take\n\nThree reference points from the public IDF host runtime:\n\n| Domain      | Shape                                                          | Time                                |\n|-------------|----------------------------------------------------------------|-------------------------------------|\n| `invest`    | 14 entities · 61 intents · 5 invariants · ~600 lines           | a weekend, hand-written             |\n| `gravitino` | 253 entities (Apache catalog OpenAPI) · 120 intents            | imported in <1h, enriched in 2 days |\n| `workflow`  | 9 entities · 47 intents · timer queue · cascade rules          | a day                               |\n\nWhere the speed comes from (all in `@intent-driven/cli`):\n\n- `idf import postgres` — reads your live schema, generates entity\n  baseline with FKs and column types as `fieldRole`.\n- `idf import openapi` — reads your existing API spec, generates intents\n  + parameter shapes + reference fields. *This is how a 253-entity\n  domain gets bootstrapped.*\n- `idf import prisma` — same story for ORM-driven backends.\n- `idf enrich` — LLM pass to fill `label`, `fieldRole`, `compositions`,\n  suggested `roles.agent.preapproval` predicates from your existing\n  code comments.\n\nThe author-once-then-forget loop is the whole point. Once the artifact\nexists, you don't regenerate scaffolding on schema change — the runtime\nre-reads and serves four readers (UI, voice, agent, document) off the\nsame file.\n\n---\n\n## Domain prerequisites\n\nThe protocol is reliable, but it needs the IDF domain to be authored\ncorrectly. Without these, `tools/list` may return empty,\n`tools/call` may return `domain_not_supported`, resources may be empty:\n\n1. **`ontology.roles.agent`** must be declared. No agent role → no tools, no resources.\n2. **`role.agent.canExecute`** — list of safe intents. Avoid `__irr:high` without preapproval.\n3. **`role.agent.visibleFields`** — array of fields or `\"own\"` / `\"all\"` / `\"aggregated\"` markers.\n4. **Server-side effect builder** (`server/schema/effectBuildersRegistry.cjs` in `idf`) must include your domain. Without it `tools/call` returns `domain_not_supported`.\n5. **Public catalogs without `ownerField`.** When an entity has `ownerField`, the SDK `filterWorldForRole` filters out rows where `row[ownerField] !== viewer.id`. For public catalogs (e.g. `Task` with `status: \"published\"`) use `role.scope` with a via-collection or a separate agent-roleable projection (roadmap).\n\n---\n\n## Limitations (1.0)\n\n- `tools` and `resources` only. `prompts` / `completion` — roadmap.\n- Bootstrap reads ontology from local FS. SaaS variant (ontology from DB/API) — next.\n- Auth: email/password login. PAT / OAuth2 — next.\n- Sync only (`POST /exec`). Long-running via MCP tasks API — next.\n\n## Links\n\n- **Landing &amp; demo:** [fold.intent-design.tech](https://fold.intent-design.tech)\n- **Quickstart:** [intent-driven-software/fold-runtime-quickstart](https://github.com/intent-driven-software/fold-runtime-quickstart)\n- **Host runtime:** [DubovskiyIM/idf](https://github.com/DubovskiyIM/idf)\n- **Why a runtime layer:** [paper](https://fold.intent-design.tech/paper/why-runtime-layer/) — ~1800-word essay on the agent-safety class question this answers\n- **MCP spec:** [modelcontextprotocol.io](https://modelcontextprotocol.io)\n\n## License\n\nMIT\n",
  "bytes": 14754,
  "sha": "4939ca4f346706ca6ba25fceb2a9c0cf4ea2b8eb06833315efe4c27dfd427037",
  "repo_slug": "intent-driven-software/idf-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_intent_driven_software_idf_mcp_7e2ccd92/readme"
}