Skip to main content
Run metalworks mcp serve (stdio is the keyless default) to expose metalworks as MCP tools. Each tool is a thin async wrapper over a plain, unit-testable body; the bodies own the error-envelope contract. The authoritative registered set is the _TOOL_WRAPPERS tuple in metalworks.mcp.server, and each tool’s docstring in metalworks.mcp.tools begins with TIER 1 or TIER 2 — that prefix is the source of truth for its tier. 35 tools are registered.

The tier model

  • Tier 1 — zero-key. Data and deterministic tools: Reddit search/intel ([reddit] extra, no API key), the Arctic corpus readers ([arctic] extra), local-store readers, and the offline compliance check. No provider key needed.
  • Tier 2 — key-gated. Anything that calls a model: planning, the report-derived tools, the research job pattern, reply drafting, discovery, and posting. These need a chat provider key (and some need an embedding key). A missing credential surfaces a MissingKeyError envelope naming the env var and extra — it does not crash.

Tier 1 — zero-key

Tier 2 — key-gated

The report-derived tools (positioning_from_report, distribution_strategy, distribution_geo, landscape_from_report, assess_from_report, ideate_from_report, build_spec) are synchronous — run them after a stored report exists. validate_from_idea is the exception: like the pipeline it runs a demand pull (minutes), so call it sparingly or prefer the interactive validate skill.

The async job pattern

Research takes minutes, so it never runs inline. Call research_start to get a run_id immediately, then poll research_status (run state) and research_result (the finished report, or a status payload while it’s still running).

The error-envelope contract

Every tool body returns either its success payload or an error envelope. The guard decorator turns any raised exception — typed or not — into that envelope, so a host model never sees a raw traceback:
Relay the fix string verbatim. Tier-2 bodies that need a credential surface a MissingKeyError envelope naming the env var and extra.

The posting security gate

reddit_post_comment is the security boundary and is triple-gated:
  1. METALWORKS_ALLOW_POSTING=1 must be set (operator opt-in) — there is no override.
  2. The confirm_token must be the one a prior compliance_lint (or generate_reply) pass emitted over this exact text — proof the text cleared the deterministic gate unchanged. Tokens are per-process HMAC and do not survive a server restart.
  3. The compliance gate is re-run server-side and must still pass (defense in depth).
It also needs the [reddit] extra plus REDDIT_CLIENT_ID / REDDIT_CLIENT_SECRET and a connected account (metalworks reddit auth login). A model cannot post without a passing compliance check on the identical text and an explicit operator opt-in.