Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
作者提供的说明(英文原文)
Verified tool calls for Claude Code: verify, retry and fallback over hermetic claude calls.
这三项永远不会合并成一个分数:意见、测量和人气是不同的东西。
我们还没有为它写通俗的介绍。下面是我们从注册中心读取到的事实。
选择你使用的 AI 应用,然后复制设置。
你需要
你用的是哪个应用?
在上方选择你的应用。我们会记住它,下次按钮会显示“安装到 …”。
打开 Claude Desktop → Settings → Developer → Edit Config,把下面的内容粘贴到 claude_desktop_config.json
{
"mcpServers": {
"conductor": {
"command": "npx",
"args": [
"-y",
"@fainir/conductor"
]
}
}
}在终端中运行这条命令
claude mcp add conductor -- npx -y @fainir/conductor粘贴到项目中的 .cursor/mcp.json,或 ~/.cursor/mcp.json
{
"mcpServers": {
"conductor": {
"command": "npx",
"args": [
"-y",
"@fainir/conductor"
]
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
粘贴到项目中的 .vscode/mcp.json
{
"servers": {
"conductor": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@fainir/conductor"
]
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
这个服务器在你的电脑上运行,而 ChatGPT 只能连接互联网上的服务器。请选择其他应用。
你的选择通过 Cookie 保存在这台设备上,无需账户。
这些设置是根据作者在注册中心的条目生成的。如果 README 的写法不同,请以 README 为准。
它在你的电脑上运行;安装后,工具列表会显示在你的 AI 应用中。
我们检查的是任何人都能看到的信息;我们没有阅读代码。不适用的检查项不计入总数。 · 检查于 2026年11月7日
注册名称已通过 GitHub 账户 fainir 验证,该账户拥有此仓库
我们还没有从 GitHub 读取这个仓库
我们还没有从 GitHub 读取这个仓库
它在你的电脑上运行,没有互联网端点
在你的电脑上运行,改用本地设置
它在你的电脑上运行;我们只能读取互联网端点的工具列表
与注册中心里这个分类中所有活跃的服务器比较。只有当发布者拥有该仓库时,星标数才计入。
它在 1 项适用的基础检查中通过了 1 项。我们没有阅读代码。在添加密钥或令牌之前,请先看看这个服务器要求哪些权限,并使用只具备所需权限的密钥。
注册中心没有列出必需的密钥,不过有些服务器会在首次使用时要求你登录。
它在你的电脑上运行。你的 AI 应用会在需要时启动它,数据不会经过作者的服务器(除非它自己调用在线服务)。
GitHub 仓库最后更新于–,最新版本(0.4.1)于8天前进入注册中心。
支持 MCP 的应用,例如 Claude Desktop、Claude Code、Cursor 和 VS Code。你的电脑上还需要有 Node.js。
同一分类中有:Spec Driven Development, Remote Desktop Commander, FactLot
同一分类中其他作者的服务器,按星标数排序。
如何看卡片:★ GitHub 星标i三大支柱:评价 · 检查 · 使用情况i更新 = 最新版本发布到注册中心的时间i
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Cited CRE facts and deterministic calculators for agents: rent, CAM, debt sizing, IRR, parcel IDs.
按原文从作者的仓库复制。PopNx MCP 没有审查或背书其内容。HTML、图片和脚本已被移除。链接会离开本站。
Verified tool calls for Claude Code: an MCP server (installable as a plugin) whose 23 tools check their own output in code before you get it.
A model asked to "extract the email" or "redact the phone numbers" is usually right, and nothing tells you when it isn't. conductor puts each job behind a contract: an input schema, an output schema and a mandatory verifier. Deterministic jobs (slugs, base64, URL extraction) run as plain code and never touch a model. Judgment jobs (summaries, PII redaction) run as hermetic claude -p calls, and an answer that fails its verifier is retried with the failure as feedback, handed to a fallback, or returned as a failure; it is never silently passed through.
The skeleton (validate -> execute -> verify -> retry -> fallback -> log) is real code that cannot be skipped; the model is quarantined to the judgment-shaped holes.
You need Claude Code installed and logged in, and Node.js 20 or newer on your PATH (the plugin starts the server with node).
claude plugin marketplace add fainir/conductor
claude plugin install conductor@conductor
Restart Claude Code (or run /reload-plugins in a running session). Inside a session the same steps are /plugin marketplace add fainir/conductor and /plugin install conductor@conductor. Check that the server is up:
$ claude mcp list
plugin:conductor:conductor: node /Users/you/.claude/plugins/cache/conductor/conductor/0.4.1/dist/conductor-mcp.cjs - ✓ Connected
Then ask for the job in plain words, for example "redact the PII in this ticket with conductor". The tools show up as mcp__plugin_conductor_conductor__ .
Update with claude plugin marketplace update conductor && claude plugin update conductor@conductor, remove with claude plugin uninstall conductor@conductor.
Without the plugin system. dist/conductor-mcp.cjs is a committed, self-contained bundle, so a clone needs no install or build step:
git clone https://github.com/fainir/conductor
claude mcp add conductor -s user -- node "$PWD/conductor/dist/conductor-mcp.cjs"
Other MCP clients can run npx -y @fainir/conductor, which serves MCP over stdio. The unrelated conductor-mcp package on npm belongs to someone else.
Every tool returns the same envelope. Real output from the bundle for base64_encode with {"text": "hello"}:
{ "ok": true, "output": { "encoded": "aGVsbG8=" }, "via": "base64_encode", "attempts": 1, "verdict": { "ok": true, "score": 1 } }
via names the rung that produced the answer (the tool itself, a declared fallback, or freeform for plain Claude), and attempts counts tries on that rung. A failure sets ok: false and the tool result's isError, and the verdict says why, so the calling model can fix its call:
{ "ok": false, "via": "redact_pii", "attempts": 0,
"verdict": { "ok": false, "score": 0, "feedback": "invalid input: input: missing required property 'text'; input: unexpected property 'txt' (allowed: text)" } }
From a clone you can drive the same loop with the CLI (npm ci first). Pure tools answer instantly and cost nothing:
$ npx tsx src/cli.ts slugify '{"text":"Hello, World!"}'
{ "ok": true, "output": { "slug": "hello-world" }, "command": "slugify", "attempts": 1, "verdict": { "ok": true, "score": 1 }, "costUsd": 0 }
$ npx tsx src/cli.ts normalize_phone '{"phone":"call me"}' { "ok": false, "command": "normalize_phone", "attempts": 1, "verdict": { "ok": false, "score": 0, "feedback": "shape: normalized must match /^\\+?\\d{6,15}$/ (an optional leading '+' followed by 6-15 digits)" }, "costUsd": 0 }
The CLI exits 1 when the result fails verification. Model-backed tools work the same way (npx tsx src/cli.ts extract_contact '{"text":"Call Sam at sam@acme.io"}') and spend a claude -p call per attempt. npx tsx src/cli.ts with no arguments lists the commands, and npx tsx src/cli.ts route "make a url slug" '{"text":"Hello World"}' lets a model pick the command.
| tool | input | what it does | verifier checks |
|---|---|---|---|
slugify | text | Convert a string into a URL-safe slug. | non-empty; only [a-z0-9] runs joined by single hyphens |
word_count | text | Count the words and characters in a string. Words are whitespace-separated tokens of the trimmed text; chars is the raw length of the input. | recomputes both counts |
normalize_phone | phone | Normalize a phone string to canonical '[+]digits' form by stripping non-digit characters. | recomputes; optional + then 6-15 digits |
truncate | text, max | Truncate text to at most max characters, appending a single-character ellipsis when it must be cut. | length never exceeds max; recomputes |
dedupe_lines | text | Split text on newlines and keep the first occurrence of each line, preserving order. | no duplicates; every line comes from the input; recomputes |
extract_urls | text | Extract all http(s) URLs from a text, deduped while preserving first-seen order. | http(s) shape; each URL appears in the input |
template_fill | template, data | Fill a template by replacing every {{key}} token with String(data[key]); fails, naming the keys, if any {{key}} has no value in data. | recomputes; no {{placeholder}} left |
base64_encode | text | Encode a UTF-8 string to base64. | decodes back to the input |
base64_decode | encoded | Decode a base64 string to UTF-8 text. | re-encodes to the input (padding and line breaks ignored) |
extract_emails | text | Extract all email addresses from text. | email shape; each address appears in the input |
json_minify | json | Minify a JSON string by removing insignificant whitespace. | parses to the same value as the input |
to_snake_case | text | Convert a string to snake_case. | recomputes |
claude -p call)| tool | input | what it does | verifier checks |
|---|---|---|---|
extract_contact | text | Extract a contact's name, email, and phone from a blob of text. | schema; email and phone shape; the email must appear in the input (grounding) |
summarize | text, max_sentences? | Summarize a blob of text in at most a few sentences, using only the text itself. | at most max_sentences (default 2); not longer than the input |
extract_keywords | text, k? | Extract up to k salient keywords or short phrases that appear verbatim in the input text. | 1 to k items (default 5); each appears verbatim in the input |
classify_sentiment | text | Classify the overall sentiment of a piece of text as positive, negative, or neutral. | label is one of the three; confidence in 0..1 |
redact_pii | text | Replace every email address and phone number in the input text with [REDACTED], leaving all other text unchanged. | no email or phone pattern left; [REDACTED] present when the input had PII |
json_extract | text, fields | Extract a caller-specified list of fields from a blob of text into a JSON object. Each requested field becomes a key; the value is null when the field is absent from the text. | data is an object with every requested field as a key |
fix_json | text | Repair malformed or loosely-formatted JSON text into a valid JSON value. | json is an object or array |
extract_dates | text | Extract every date referenced in a piece of text, normalized to ISO format YYYY-MM-DD. | each is a real calendar date in YYYY-MM-DD |
categorize | text, categories | Choose the single best-fitting category for a piece of text from a provided list of categories. | exactly one of the given categories |
translate | text, target_language | Translate a piece of text into a given target language. | non-empty; at most 5x the input length + 20 |
detect_language | text | Detect the natural language of text. | non-empty name; two-letter lowercase ISO 639-1 code |
Inputs ending in ? are optional. The first three columns come from the command manifests (npm test fails if they drift); the full JSON Schemas are what the MCP server advertises.
input -> inputSchema check -> run the command -> verify -> ok? -> result
^ | no +-- retry with the verifier's feedback (model-backed, up to maxAttempts) | still no declared fallbacks -> freeform (plain Claude, same schema, same verifier)
commands/ /index.ts: a manifest (input and output JSON Schema, determinism, prompts, fallbacks) plus a verify() export. A command without a verifier cannot be registered (src/library.ts, src/registry.ts). Mechanical checks come first (schema, regex, recompute, grounding); llmJudge in src/verify.ts exists for criteria no code can express.inputSchema is rejected before anything runs, with a message that names the problem.pure commands are deterministic code: run once, cached, free, and never sent to a model. stochastic commands are run by the model and retried with feedback. effectful is reserved for commands that will need a human gate.src/cc.ts) replaces the system prompt (--system-prompt), loads no settings (--setting-sources ""), enables no tools (--tools ""), saves no session, and constrains the answer with --json-schema. This matters: a naive call once returned the operator's own email instead of the one in the input, because ambient context (global CLAUDE.md, identity, hooks) leaked in.runPipeline (src/pipeline.ts) chains commands; each step is verified before the next runs, so errors cannot silently compound.npm run scores prints per-command reliability from the CLI and eval logs, and route() (src/router.ts) shows those rates to a small model that must pick from an enum of command names.| Setting | Default | Effect |
|---|---|---|
CONDUCTOR_HOME env var | ~/.conductor | Where the MCP server appends telemetry.jsonl |
model in a manifest | sonnet | Model for that command's calls (the router and llmJudge use haiku) |
maxAttempts in a manifest | 2 | Tries with feedback before the next fallback rung (pure commands run once) |
Model-backed calls use whatever account the claude CLI is logged into.
Evals compare a single naive claude -p call with the conductor on the same inputs:
eval/run-eval.ts): baseline 100% vs conductor 100%. On easy single-shot tasks a frontier model is already reliable, so there is no gap to close.eval/contact-card.ts, extract_contact -> normalize_pho只显示了开头部分;其余内容请在仓库中阅读