@directive-run/mcp
v0.6.10
Published
Model Context Protocol server that exposes Directive to AI clients — knowledge files, code examples, and Claude Code skill bundles today, with room to grow into runtime introspection and tooling. stdio for local clients (Claude Desktop, Cursor, MCP Inspec
Maintainers
Readme
@directive-run/mcp
Run a Model Context Protocol (MCP) server that lets AI assistants – Claude Desktop, Cursor, Windsurf, or any MCP client – query Directive's knowledge base, code examples, lint rules, and scaffolding tools live. No pre-bundling, no stale snapshots: the assistant asks, the server answers from the current package contents.
Most readers want this package. Install it if you use Claude Desktop, Cursor, or another MCP-speaking client – or if you're hosting Directive's knowledge as a service for your team's agents.
Which side are you on? This package is the server: it exposes Directive's knowledge so AI clients can read it. If instead you're building a Directive AI agent that needs to call external MCP servers (filesystem, GitHub, Slack), use
@directive-run/ai/mcpand itscreateMCPAdapter.
Install
The fastest path is zero-install via npx. Claude Desktop, Cursor, and other MCP clients will spawn it for you when their config block points here:
npx -y @directive-run/mcp --helpFor environments that pin binaries, install globally instead:
npm install -g @directive-run/mcp
directive-mcp --helpTry it (3 steps)
// 1. Paste into your AI client's MCP config and restart it.
// Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
// Cursor: .cursor/mcp.json
{
"mcpServers": {
"directive": {
"command": "npx",
"args": ["-y", "@directive-run/mcp"]
}
}
}2. Verify the server is loaded.
Claude Desktop: click the tools/hammer icon – you should see `directive`
with 22 tools. Or ask Claude:
"Use the directive MCP server's get_server_info tool."
Cursor: open Settings → MCP → look for `directive` (status: connected).
MCP Inspector: npx @modelcontextprotocol/inspector npx -y @directive-run/mcp
→ connect → /tools should list 20 entries.3. Send your first prompt. Any of these will fire a tool round-trip:
• "Using the directive MCP server, list the knowledge files,
then read the one about constraints."
• "Generate a Directive module named 'cart' with constraints + resolvers
using the directive MCP server."
• "Review this code with directive's review_source tool, then call
fix_code on any fixable findings:
createModule('Cart', { schema: {} });"How it works
Every Directive MCP request follows the same shape: an AI client (Claude Desktop, Cursor, your own agent) speaks JSON-RPC to one of two transports – stdio for local subprocess clients, SSE for the hosted gateway. The server dispatches to a tool handler, which reads from one of three in-process data sources: the bundled @directive-run/knowledge package (markdown + extracted examples), the lazy-loaded @directive-run/lint registry (ts-morph rules, loaded on first call so the ~25 MB ts-morph cost only hits when review_source or fix_code actually runs), or the pure-string @directive-run/scaffold generators. Nothing touches disk; nothing calls out over the network – except get_package_info, which fetches latest from npm with a 1-hour cache.
┌────────────────────────────────────────────────────────────────────────────────┐
│ Claude Desktop / Cursor / Windsurf / MCP Inspector │
│ │
│ Reads ~/Library/Application Support/Claude/claude_desktop_config.json on │
│ launch. For each mcpServers entry, spawns the subprocess and pipes JSON-RPC │
│ over its stdin/stdout. │
└────────────────────────────┬───────────────────────────────────────────────────┘
│ stdio (or SSE for hosted)
▼
┌────────────────────────────────────────────────────────────────────────────────┐
│ @directive-run/[email protected] (`npx -y @directive-run/mcp` subprocess) │
│ │
│ src/cli.ts: │
│ parseArgs() → { sse: false (default) } │
│ setServerInfo({ transport: "stdio", authEnabled: false }) │
│ createDirectiveServer() → McpServer with 22 tools registered │
│ │
│ Tool surface (22): │
│ Knowledge: list_knowledge, get_knowledge, search_knowledge, │
│ list_examples, get_example, search_examples │
│ Packages: list_packages, get_package_info, get_composable_packages │
│ Generate: generate_module, list_module_sections │
│ Review: list_review_rules, get_review_rule, review_source, fix_code │
│ Migration: list_migration_sources, get_migration_pattern │
│ Skills: list_skills, get_skill │
│ Server: get_server_info │
└──────┬─────────────────┬──────────────────┬──────────────────┬─────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌───────────────────┐
│knowledge │ │claude-plug-│ │ scaffold │ │ lint │
│ │ │ in │ │ │ │ (lazy-loaded │
│ • core/* │ │ • skills/* │ │ pure │ │ via separate │
│ • ai/* │ │ bundled │ │ functions│ │ tsup entry) │
│ • compo- │ │ from │ │ in / │ │ │
│ sitions│ │ knowledge │ │ strings │ │ • 10 ts-morph │
│ .json │ │ at build │ │ out │ │ rules │
│ • migra- │ │ │ │ │ │ • 6 fixable │
│ tion. │ │ │ │ Zero │ │ • Worker_threads │
│ json │ │ │ │ runtime │ │ ON by default │
│ • Lazy + │ │ │ │ deps │ │ • 5-second │
│ cached │ │ │ │ │ │ parse budget │
│ parsers│ │ │ │ │ └──────┬────────────┘
└──────────┘ └────────────┘ └──────────┘ │
▼
┌────────────────────────┐
│ ts-morph (lazy) │
│ TypeScript compiler │
│ API wrapper. Spins up │
│ in-memory Project, │
│ parses src → AST. │
│ Each rule walks the │
│ AST via │
│ getDescendantsOfKind │
└────────────────────────┘Caching & limits. First call to list_knowledge warms the knowledge cache (~700 KB markdown). First call to review_source spins up a worker thread + the ts-morph project, then keeps both for the process lifetime. Built-in caps: 200 KB max source for review_source/fix_code, 5-second parse budget, 1 MB body cap on SSE, 64 concurrent SSE sessions, 5-minute idle pruning. See get_server_info for the live counts.
For the request-flow trace in code, see src/server.ts (tool registration) and src/lint-runner.ts (worker dispatch).
stdio transport (local clients)
Add to your AI client's MCP config (Claude Desktop's claude_desktop_config.json, Cursor's .cursor/mcp.json, etc.) and restart it:
{
"mcpServers": {
"directive": {
"command": "npx",
"args": ["-y", "@directive-run/mcp"]
}
}
}Or run the MCP Inspector for a browser-based UI:
npx @modelcontextprotocol/inspector npx -y @directive-run/mcpSSE transport (hosted)
# Loopback (local dev) – no token required
directive-mcp --sse --port 3000
# Public host – token is mandatory
directive-mcp --sse --port 3000 --host 0.0.0.0 \
--token "$DIRECTIVE_MCP_TOKEN" \
--allow-origin https://app.example.comSecurity defaults. A public bind (--host 0.0.0.0) without --token exits with error: --token is required when binding to a non-loopback host. With a token set, every /sse and /messages request must send Authorization: Bearer <token>. Defaults: 1 MB body cap, 64 concurrent sessions, 5-minute idle timeout. Token can also come from the DIRECTIVE_MCP_TOKEN environment variable.
Endpoints:
GET /sse– establish the SSE stream.POST /messages?sessionId=…– client→server JSON-RPC messages.GET /healthz– liveness probe.
Tools (22)
Knowledge
| Tool | Purpose |
|---|---|
| list_knowledge | Every knowledge file name (core + AI + skeleton). |
| get_knowledge | Read one knowledge file by name. |
| search_knowledge | Case-insensitive substring search across every knowledge file. |
| list_examples | Every code example name. |
| get_example | Read one example by name (returned as a TypeScript code block). |
| search_examples | Case-insensitive substring search across the 37 bundled example .ts files. |
Packages
| Tool | Purpose |
|---|---|
| list_packages | Every @directive-run/* package with one-line description. |
| get_package_info | Single-package detail (baked metadata + live npm version, 1 h cache, 3 s timeout, falls back to baked on failure). |
| get_composable_packages | Outgoing and incoming composition edges for one package. Returns isError: true with NOT_FOUND prefix when the package isn't known. |
Generate
| Tool | Purpose |
|---|---|
| generate_module | Generate NEW Directive module or AI orchestrator source. Returns the source string + suggested filenames + required-packages list; the caller writes to disk via its own file tool. |
| list_module_sections | Enumerate the valid sections values for generate_module (autodiscovery – no hallucinated enum values). |
Review
| Tool | Purpose |
|---|---|
| list_review_rules | All 10 ts-morph rules as structured data (id, severity, category, title). |
| get_review_rule | One rule's full detail: WRONG/CORRECT example pair + explanation. |
| review_source | Run the rule registry against a TypeScript source string. Pre-parse 200 KB cap, 5-second budget enforced via worker.terminate(). Returns structured findings. |
| fix_code | Apply a rule's mechanical fix; returns diff + fixed source. 6 of 10 rules ship a fix; the rest return { ok: false, reason }. |
Migration
| Tool | Purpose |
|---|---|
| list_migration_sources | Source libraries get_migration_pattern accepts. |
| get_migration_pattern | Concept map + steps + before/after for migrating from Redux / Zustand / XState / MobX / Jotai / Recoil. |
Skills
| Tool | Purpose |
|---|---|
| list_skills | Every Claude Code skill bundled in @directive-run/claude-plugin. |
| get_skill | One skill's SKILL.md + supporting knowledge files as a single document. |
Server
| Tool | Purpose |
|---|---|
| get_server_info | Version + transport + auth state + bundled-knowledge hash + session count + package-registry timestamp. |
Playground
| Tool | Purpose |
|---|---|
| playground_link | Turn TypeScript source into a clickable URL that boots a real Directive project in StackBlitz. Two shapes: pass source (single string) for already-runnable snippets from get_example / fix_code, OR pass files: [{path, source}, …] for the paired library + runner output from generate_module. Optional mode: "preview" \| "instant" – "preview" (default) lands on directive.run/playground with code + Open-in-StackBlitz button; "instant" lands on directive.run/run which auto-submits the StackBlitz form (no preview UI). 8 KB cap on raw input. Payload travels in the URL hash so it never reaches server logs. |
| run_in_sandbox | Execute a Directive snippet inside a bounded worker_threads sandbox and return its observed behavior – captured console.log/warn/error lines, the post-settle() facts snapshot, structured errors, plus a playgroundUrl for click-through editing in StackBlitz. Pair with generate_module to show the user what the generated module ACTUALLY DID when it ran. v0.3.0 boundary: AST allowlist permits @directive-run/{core, ai, query, react, vue, svelte, solid, lit, el, optimistic, timeline, mutator, knowledge, scaffold, claude-plugin, lint} + relative ./*.js; rejects FS/network/eval identifier references AND their property-access bypass chains (globalThis.process, Reflect.get(globalThis, …), .constructor, Function(...)). 5-second wall-clock budget (clamped to [100ms, 10s]), 32 MB heap. Note: react/vue/svelte/solid/lit import OK but their runtime hooks throw in Node – use playground_link for UI demos. |
Composition for a "try it now" link: generate_module returns paired {moduleSource, runnerSource, suggestedFilenames} – pass both to playground_link as a files array (the runner is the entry point at src/main.ts) and the user clicks ONE URL that boots a project where tsx src/main.ts actually logs Directive facts to the StackBlitz terminal. For get_example / fix_code output (already runnable), pass the single source string instead.
Troubleshooting
The four most common first-time failures:
| Symptom | What's happening | Fix |
|---|---|---|
| Claude Desktop shows no directive server in the hammer/tools menu. | Config file wasn't read, or npx failed to install. | Fully quit Claude Desktop (Cmd-Q, not just close the window) and relaunch. Then check the log: ~/Library/Logs/Claude/mcp-server-directive.log (macOS), %APPDATA%\Claude\logs\mcp-server-directive.log (Windows). |
| review_source returns review_source failed – worker-error: ts-morph is not installed. | npm install ran with --no-optional, or your package manager skipped optionalDependencies. | npm install -g ts-morph once. ts-morph (~25 MB) is loaded only when review_source / fix_code fires. |
| --sse --host 0.0.0.0 exits with --token is required. | Public bind needs auth. | Pass --token <secret> or set DIRECTIVE_MCP_TOKEN in the environment. Loopback binds (the default 127.0.0.1) don't need a token. |
| npx -y @directive-run/mcp is slow on first launch. | npx is downloading + installing the package + ts-morph (~25 MB). | First launch is ~10-20 s on a cold npm cache. Subsequent launches use the cached tarball. To pre-warm: npm install -g @directive-run/mcp and use "command": "directive-mcp" in the config. |
If a tool errors mid-conversation, the fastest recovery is: "Ask the directive MCP server's get_server_info tool to verify connectivity."
Programmatic embedding
For tool authors who want to mount the server inside their own host process:
import {
createDirectiveServer,
startSseServer,
setMaxConcurrentLintWorkers,
} from "@directive-run/mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// stdio
const server = createDirectiveServer();
await server.connect(new StdioServerTransport());
// SSE – returns the underlying http.Server
const httpServer = await startSseServer({ port: 3000, host: "0.0.0.0" });Tuning the lint worker pool
review_source and fix_code each spawn a ts-morph worker thread to parse the input. A multi-client burst – Cursor + Claude + IDE all calling these tools in parallel – could amplify into a thread-spawn storm. setMaxConcurrentLintWorkers(n) caps the simultaneously-running lint workers. Calls beyond the cap queue FIFO; abandoned callers (signal-aborted or dropped promises) deregister cleanly. Defaults to navigator.hardwareConcurrency (falls back to 4); pass Infinity to disable.
import { setMaxConcurrentLintWorkers } from "@directive-run/mcp";
// At server boot – runs once per process.
setMaxConcurrentLintWorkers(4);See also
@directive-run/ai/mcp– adapts external MCP servers as Directive resolvers (the client side; opposite arrow from this package).@directive-run/knowledge– markdown + JSON sources this server fronts.@directive-run/lint– the ts-morph rule registry behindreview_sourceandfix_code.@directive-run/scaffold– the pure-function generators behindgenerate_module.@directive-run/claude-plugin– the Claude Code skill bundles also exposed viaget_skill.@directive-run/cli– generates static.cursorrules/CLAUDE.md/.windsurfrulesfiles for assistants that don't speak MCP.- directive.run/docs/ide-integration – the cross-editor decision tree.
