@millwork/solver-mcp
Official# @millwork/solver-mcp
`@millwork/solver-mcp` is the Millwork Solver execution MCP server. It gives an
approved assistant 28 tenant-authenticated `solver_*` tools over stdio. Some
tools read state. Others connect model sources, submit work, cancel a run, or
decide a proposal, so the server is write-capable.
## Install
Requires Node 20 or Node 22.
```bash
npm install @millwork/solver-mcp
solver-mcp --help
```
`npm install @millwork/solver-mcp` resolves the `latest` dist-tag. Pin an exact
version for reproducible application builds.
Or run it directly:
```bash
npx --yes @millwork/solver-mcp --help
```
## Connect an output check
Discover `solver_list_verifiers` first. An empty page without `next_cursor`
returns a typed `scaffold_output_check` next action. Install
`@millwork/solver@0.1.17` or later to scaffold and test an output check locally,
then deploy its HTTPS endpoint.
The [build-and-connect guide](https://docs.getmillwork.dev/cookbook/output-checks/build-the-dock)
starts with Recipe 0 and shows the local test, deployment, and recovery path.
Register a credential-less endpoint with `solver_connect_verifier` and retest with
`solver_test_verifier`:
```text
solver_connect_verifier({ access: "public", endpoint: "<https-url>",
name: "<name>", version: "<version>", idempotency_key: "<caller-owned-id>" })
```
For a protected endpoint, connect with `access: "managed"`, then use
`solver_start_verifier_connection` to obtain the private browser handoff.
Give its `continue_url` only to the intended person, and use
`solver_inspect_verifier_connection` and
`solver_continue_verifier_connection` to resume the same operation after
private key entry. Never put the endpoint key in chat or a tool argument.
Disconnecting requires separate host confirmation and
`confirm_disconnect: true`; it stops Millwork's use of the key but does not
revoke the key at the endpoint. Pass the returned `verifier_id` into
`solver_submit` only after choosing the check. Connecting a check is not
approval to run a task.
## Configure stdio
Point the MCP client at the `solver-mcp` binary with no arguments. Supply
these environment variables through the client's secret-aware environment
configuration. Do not paste their values into a prompt, log, screenshot, or
support report.
| Variable | Required | Meaning |
|---|---:|---|
| `SOLVERAPI_API_KEY` | yes | Tenant API key held by the server process and sent as bearer authentication. |
| `SOLVERAPI_BASE_URL` | yes | API base including `/v1`; the production value is `https://api.getmillwork.dev/v1`. |
| `SOLVERAPI_MAX_RETRIES` | no | Network/5xx retry limit. Default: `2`. It never widens the safe retry boundary. |
| `SOLVERAPI_REFUSE_BASELINE_SUBMIT` | no | When `1` or `true`, a live `solver_submit` without `verifier_id` is refused. Echo is not refused. Default: off. |
| `SOLVERAPI_RETRY_BACKOFF_MS` | no | Exponential-backoff base in milliseconds. Default: `500`. |
The transport contract is exact:
```text
command: solver-mcp
arguments: none
transport: stdio
stdout: MCP JSON-RPC only
stderr: diagnostics
```
## Use it with an assistant
Any MCP-capable assistant can use the same tool surface. Start with a
read-only request:
```text
Use solver_list_sources and solver_list_source_connections to show what this
organization can see. Do not call a tool that requires human confirmation.
Return tool names and safe counts only. Do not print credentials or customer
content.
```
For a write-capable request, make the stop explicit:
```text
Prepare a solver_submit call but do not run it yet. Show the exact budget,
verifier, data classes, and caller-owned idempotency key. Wait for my explicit
confirmation before one call. If the outcome is uncertain, inspect status with
a read tool; do not submit again under a new key unless I confirm that new
intent.
```
Human confirmation is a client-side stop. The tenant API key still carries the
server-side permissions assigned to it. Confirmation does not turn a
tenant-wide machine key into a narrower credential.
A live `solver_submit` also requires the supported host-isolation profile. The
host, not the prompt or launch environment, owns the fixed attestation,
read-only admission ledger, and exact one-run approval channel. The first call
can return `host_approval_required`; after the host writes the returned approval
document to the named host-owned file, retry the exact same tool arguments and
idempotency key. Echo submissions remain free and do not require this approval.
## Tool surface
The server registers exactly 28 `solver_*` tools; `tools/list` over stdio is
the authoritative surface, and every tool description states what the tool
maps to and whether it writes. No tool ever accepts or returns raw credential
material. Provider and protected-verifier setup use private browser handoffs;
the tools return short-lived continuation URLs and opaque operation references,
never raw keys.
## Retry and recovery boundary
The 28 tools divide into:
- 13 safe reads that may retry network and 5xx failures;
- 7 same-key mutations, including `solver_submit` and
`solver_disconnect_verifier_connection`, which may retry
only with the same caller-owned, non-empty idempotency key and the same
request bytes; and
- 8 write-capable tools that make one attempt because they expose no
caller-owned idempotency key.
For those eight tools, a network or 5xx failure is a failure, not an automatic
retry. The write might have applied before the response was lost. Inspect
state with a safe read or your existing dashboard recovery path, then ask for
explicit human intent before another write-capable tool call. Raising
`SOLVERAPI_MAX_RETRIES` does not make those writes replay-safe.
Backend failures use RFC 7807. The MCP error result keeps the parsed Problem
in `structuredContent.problem`; transport failures use `network_error`.
## Support
Report problems on this repository's
[issue tracker](https://github.com/millworkdev/solver-mcp/issues). Useful
evidence includes the tool name, retry boundary, attempt count, package and
Node versions, and the Problem `type`, `title`, `status`, `instance`, and
`retry_after_s` fields. Never include credentials or customer content: omit
your tenant API key, your provider key/account details, authorization
headers, task content, and tenant or resource identifiers.
## Scope
This package is tenant-authenticated and write-capable. It is not a
documentation-retrieval service and receives no tenant key from any other
package. The Millwork documentation assistant is a separate, retrieval-only
service with no execution authority.
TDQS
Scored across 18 tools
Most tools map cleanly to distinct lifecycle stages: source handoff, connection testing, deployment sync, arm registration, execution submission, and proposal review. The main ambiguity is between solver_enable_model_arm and solver_register_arm, which both create arms, and between solver_list_source_connections and solver_list_sources because their names are very close.
All tool names share the solver_ prefix and consistently use snake_case with clear action/resource stems. Minor inconsistency comes from noun-style names like solver_proposals, solver_status, solver_result, and solver_receipt, which deviate from the verb_noun pattern used elsewhere.
18 tools is slightly above the typical 3-15 range, but the count is reasonable for a governed execution platform spanning source connections, credential handoffs, arms, executions, and proposals. There are no obvious redundant or filler tools.
The core workflow is well covered: connect a source, sync deployments, register arms, submit executions, poll status, fetch results/receipts, and review proposals. However, there are notable lifecycle gaps: no way to list executions, disconnect or delete a source connection, or disable/delete an arm.