Skip to content
contract-ops CLI suite

Agent integrations

Built for Claude, Cursor, Codex, OpenClaw — and any agent that speaks MCP or runs a shell.

The suite ships three MCP servers. contract-ops-mcp is the one to start with — a single stdio server that exposes all nine CLIs as tools (extract, draft, lint, compare, convert, review, the vaults), so an agent connects once and drives the whole pipeline. sign-cli ships its own 19-tool server for the entire signing surface with the per-signer-token guardrail intact, and compare-cli-mcp exposes three focused drift-gate tools. Wire any of them into an MCP-aware client — or, for a shell-running agent like OpenClaw, skip MCP entirely and run the CLIs directly (see below).

If you're on… Do this
Claude Desktop / Cursor / Codex / any Smithery client One-click via Smithery, or drop an MCP config snippet (below)
A shell-running agent (e.g. OpenClaw) Skip MCP — run the CLIs directly; discover each via --catalog json
langchain / AutoGen / OpenAI SDK (no MCP) Use the /v1/* HTTP API
Any other MCP-aware client Wire contract-ops-mcp (whole suite) + sign-cli (signing) into mcpServers
contract-ops-mcp — the whole suite, one server
{
  "mcpServers": {
    "contract-ops": { "command": "npx", "args": ["-y", "contract-ops-mcp"] }
  }
}
One install, every client — npm i -g @drbaher/sign-cli — then drop the wire-up snippet below into your client's MCP config. Every command is also a stable MCP tool with input/output schemas; agents discover the live catalog via sign mcp tools.

Smithery — one-click install (no setup)

The fastest path for Claude Desktop, Cursor, Codex, and any other Smithery-aware client: head to the hosted listing and follow the per-client install flow.

smithery.ai/servers/drbaher/sign-cli ↗

The Smithery listing exposes the same 19 tools / 4 prompts / 12 resources as the local stdio path. It runs against an ephemeral demo database (read-only mode, wiped every 4 hours) so it's safe to explore but not suitable for real signing — for that, use the local install with the wire-up snippets below.

Adding compare-cli-mcp (the pre-signature drift gate)

compare-cli-mcp is a separate npm package that wraps compare-cli as an MCP server. Three narrow tools, stdio transport, JSON-first responses byte-identical to compare --json. Substantive drift is a successful tool call (the agent asked what's different and the server answered) — only I/O failures, malformed input, and "no agreed round found" surface as MCP errors.

install
npm i -g compare-cli compare-cli-mcp
compare-mcp           # spawns the server on stdio (for testing)

Wire-up looks the same shape as sign-cli's. Add another entry under mcpServers in whichever client config you're using (Claude Code, Claude Desktop, Cursor, Codex — the snippets below show sign-cli; each gets a sibling entry):

adding compare-cli-mcp
{
  "mcpServers": {
    "sign-cli": {
      "command": "npx",
      "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"]
    },
    "compare-cli": {
      "command": "compare-mcp",
      "env": {
        "COMPARE_MCP_BASE_DIR": "/path/to/contract/documents"
      }
    }
  }
}

COMPARE_MCP_BASE_DIR locks down the server's filesystem reach to one directory (symlinks collapsed, descendants only). Without it, the server reads any file the process can read — fine for an interactive Claude Desktop session, not fine for an unattended agent loop. Documented in detail at docs/mcp.md §3.2.

Claude Code

Add to ~/.config/claude-code/settings.json (or the project-level .claude/settings.json):

.claude/settings.json
{
  "mcpServers": {
    "sign-cli": {
      "command": "npx",
      "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"]
    }
  }
}

After Claude Code restarts, every sign-cli MCP tool shows up. Ask the agent to "send contract.pdf to alice@acme.com and bob@beta.com via SignWell" and it will call the right tools with the right arguments. The agent never sees per-signer tokens — those go to the human signers directly.

Claude Desktop

Same as Claude Code, but the file is ~/Library/Application Support/Claude/claude_desktop_config.json on macOS:

claude_desktop_config.json
{
  "mcpServers": {
    "sign-cli": {
      "command": "npx",
      "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"],
      "env": {
        "SIGN_DB_PATH": "/Users/you/.sign-cli/data.db",
        "SIGN_LOCAL_AUTOCOMPLETE": "false"
      }
    }
  }
}

The env block is optional. Setting SIGN_DB_PATH pins the persistent storage location so multiple Claude Desktop sessions share state. SIGN_LOCAL_AUTOCOMPLETE=false tells the local provider to hold at "sent" until a signer explicitly runs sign sign — required for the agent-as-signer flow.

Cursor

Cursor's MCP config lives at ~/.cursor/mcp.json:

~/.cursor/mcp.json
{
  "mcpServers": {
    "sign-cli": {
      "command": "npx",
      "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"],
      "env": {}
    }
  }
}

Cursor's agent will see the tool catalog on next restart. Ask it to verify a signed PDF or detect a signature field in any document open in the workspace — the tool calls work the same way.

Codex / GitHub Copilot Workspace

Codex and similar OpenAI-based agents support MCP via the same mcpServers config shape. The exact location varies; recent versions read ~/.config/openai-codex/mcp.json. Same JSON as Cursor:

codex MCP config
{
  "mcpServers": {
    "sign-cli": {
      "command": "npx",
      "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"]
    }
  }
}

OpenAI Agents SDK

The OpenAI Agents SDK can attach MCP servers as tool sources. For Python:

Python
from agents import Agent
from agents.mcp import MCPServerStdio

sign_server = MCPServerStdio(
    name="sign-cli",
    params={"command": "npx", "args": ["-y", "@drbaher/sign-cli", "mcp", "serve"]},
)

agent = Agent(
    name="Contract Ops",
    instructions="Help the user send, track, and verify PDFs for signature.",
    mcp_servers=[sign_server],
)

langchain (Python or JS)

langchain doesn't speak MCP natively, but you can either use the langchain-mcp-adapters package or wrap the CLI directly. The langchain wrapper starter is shipped in integrations/ in the sign-cli repo.

OpenClaw (a shell-running agent — no MCP needed)

OpenClaw — "the AI that actually does things" — is a local agent framework with full shell access. It drives tools by running them as commands, not over MCP, which is a clean fit for this suite: every CLI is a plain command with a machine-readable contract, so OpenClaw drives all nine directly with no server to wire up. This is how the suite has been exercised end to end.

The pattern any shell-running agent should follow:

# 1. Discover — never hardcode flags or subcommands. Every CLI answers --catalog json:
extract --catalog json          template-vault --catalog json   draft --catalog json
nda-review-cli --catalog json   compare --catalog json          docx2pdf --catalog json
sign --catalog json             contract-vault --catalog json

# 2. Run with --json and branch on the exit code (see the matrix below)
draft template.md --params deal.json --json
compare negotiated.md ready-to-sign.pdf --json   # 0 safe · 2 substantive · 3 cosmetic · 4 moved

# 3. Pipe the pre-execution chain end to end (every tool reads '-' from stdin)
template-vault get nda/house-mutual | draft - --params deal.json \
  | nda-review-cli review --file - --playbook config/org-policy.json

Install OpenClaw with npm i -g openclaw (then openclaw onboard) and the suite from the install page; from there OpenClaw runs the CLIs like any other shell tool. MCP-aware clients can additionally use sign-cli's and compare-cli's MCP servers (above) — OpenClaw doesn't need them.

HTTP / non-MCP clients

If your agent framework doesn't speak MCP, sign-cli also exposes the same 19-tool surface as 20 HTTP routes at /v1/* via sign serve:

sign serve --port 4000 --auth-token <bearer> --read-only true --rate-limit 5
curl http://localhost:4000/v1/openapi.json    # full OpenAPI 3.1 spec

Every MCP tool has a 1:1 HTTP equivalent. Same input shape, same path-traversal guards, same read-only gating. Useful for langchain, Llama Index, AutoGen, CrewAI, or any framework that can speak REST.

Sandboxed mode

For agents that should inspect and track without mutating state, run with --read-only true and an explicit tool allow-list:

sign mcp serve --read-only true \
  --tool request_show --tool audit_verify --tool pdf_detect_signature_field \
  --tool pdf_inspect_signatures \
  --emit-events ./mcp-events.ndjson \
  --emit-events-redact true

Mutating tools return FORBIDDEN_READ_ONLY with exit 3. --emit-events writes one NDJSON line per tool call to disk for replay or audit. --emit-events-redact true masks token-shaped fields in the log.

The asymmetry: what the agent can and can't do

Agent does Human approves
Send a PDF to one or many signers The actual signing gesture (per-signer token)
Track status, retry, rotate providers Provider configuration changes (`sign init`, secret writes)
Verify signed PDFs + audit chains offline Audit-chain anomalies surfaced for investigation
Anchor with RFC 3161 timestamps Anything outside declared per-signer / TTL guardrails
Detect signature fields, stamp previews, draft NDAs Sign-off before finalize on negotiations

The mechanism is the per-signer approval token: TTL-bounded, scoped to one email, single-use. The requester (which can be the agent) holds the token at create-time and DMs it to the human signer; the signer pastes it into sign sign --token .... The agent never sees signer tokens. Pre-sign safety checks (--require-hash / --require-title / --require-signer-email) throw structured errors before any state mutation, so an agent computing a hash earlier can refuse to sign if the document was swapped in flight.

The other CLIs — agent-friendly over stdio

sign-cli ships the suite's flagship MCP server because it's the one with persistent, multi-step state (a signing request is an object that benefits from typed tools). compare-cli ships a smaller MCP server too — compare-cli-mcp, three tools over stdio. The rest — extract-cli, template-vault-cli, draft-cli, nda-review-cli, docx2pdf-cli, and contract-vault-cli — are pure functions: they take input, return output. For those, agents drive them directly over stdio with a stable JSON contract.

extract-cli — the open-loop front door

Single-file Python (stdlib only). Turn any contract — a counterparty's foreign paper in .md / .txt / .html / .docx / .pdf — into structured JSON with a confidence and source on every field. The clause map is normalized onto the suite's canonical vocabulary, so a foreign document lines up with what the rest of the suite speaks.

agent loop: ingest a counterparty contract
extract --catalog json                                 # discover commands + flags
extract counterparty.docx --output extract.json        # structured JSON; exit 1 = low-signal
extract counterparty.docx | jq -e '.clauses | all(.confidence > 0.7)'   # gate on confidence

nda-review-cli — drafting + reviewing + negotiating

Single-file Python (stdlib only at runtime). Every command emits structured output behind --json; deterministic-by-default, opt-in LLM adjudication via Anthropic / OpenAI / Ollama. The two-party negotiation flow uses a hash-chained JSON state file that bounces between counterparties — each round is signed by exactly one party and tampering is detected on load.

agent loop: review a counterparty NDA
nda-review-cli --catalog json                          # discover commands + flags
nda-review-cli review --file counterparty.docx \
  --playbook policy.json --json --why                  # structured verdict on stdout; --why adds evidence
# negotiate keeps hash-chained state across 12 subcommands; e.g. a two-party sim:
nda-review-cli negotiate simulate \
  --party-a-base ours.txt --party-b-base theirs.txt \
  --stance-a conservative --out rounds.json            # round-by-round result

Hash-chained state, deterministic stance + clause priority engine, fatigue-concession rule that force-resolves clauses that have bounced too many times. The agent drives every step; humans only sign each finalized round (via sign-cli, optionally).

docx2pdf-cli — the conversion step

Node.js. Six hybrid backends auto-selected by availability (LibreOffice, Gotenberg, ConvertAPI, Pages, Word, textutil-cups). --capabilities returns a stable JSON contract; --doctor probes host readiness and emits per-host install commands so the agent can self-check before invoking.

agent preflight + batch convert
docx2pdf --capabilities                # which flags exist, on this version
docx2pdf --doctor json                 # which backends are usable on this host
docx2pdf --catalog json                # full CLI command + flag inventory
docx2pdf in.docx out.pdf --json        # one-shot, structured success/error
docx2pdf --out-dir ./pdfs \
         --concurrency 4 --json drafts/*.docx   # batch (--out-dir enables it); --json → NDJSON

Success rows include outputBytes and durationMs; failures include exitCode. --strict-fidelity refuses the text-only fallback when the agent needs a guarantee that the visual layout was preserved. --why prints the backend-selection decision tree for debugging.

Discovery — never hardcode

Three commands every agent should call at startup rather than parsing prose:

sign --catalog json    # full CLI command + flag inventory
sign mcp tools         # live MCP tool catalog (inputSchema + outputSchema per tool)
sign --version

The same pattern works across the suite — template-vault info <ref> --json, draft --list-placeholders --json, nda-review-cli --catalog json, compare … --json (branch on the exit code), and docx2pdf --capabilities are the corresponding discovery commands for the other CLIs.

Exit codes across the suite

Most of the suite shares 0 success / 2 invalid input / 3 policy-or-verification / 4 not-found — but the meanings are not uniform. Three CLIs need special-casing: compare-cli reuses 04 as drift severities, template-vault-cli uses a 0/1/2 scheme, and draft-cli has its own 04 (1 = I/O, 4 = LLM). Don't assume a shared meaning — branch per CLI, discover the codes from --catalog json, and confirm against each tool's AGENTS.md.

CLI Exit codes Note
template-vault-cli 0 ok · 1 failure (verify / doctor / drift) · 2 bad usage differs — 0/1/2
draft-cli 0 ok · 1 i/o error · 2 validation · 3 template-vault failure · 4 llm failure own 04 (uses 1 = I/O)
nda-review-cli 0 ok · 2 invalid input · 3 policy / chain / consent · 4 not found common 0/2/3/4
compare-cli 0 clean · 1 I/O error · 2 substantive drift · 3 cosmetic / typographic · 4 clauses moved 2/3/4 are drift severities, not errors
docx2pdf-cli 0 ok · 2 bad flag / input · 3 NO_BACKEND · 4 conversion failed common 0/2/3/4
sign-cli 0 ok · 2 invalid input · 3 policy / chain (forbidden, tampered) · 4 not found common 0/2/3/4

See also

Edit this page on GitHub