Metadata-Version: 2.4
Name: nace-mcp
Version: 0.3.0
Summary: MCP server for the Drex API: calibrated decisions and document jobs for coding agents
Keywords: drex,nace,mcp,model-context-protocol,document-intelligence
Author: Nace AI
Author-email: Nace AI <engineering@nace.ai>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Dist: nace-sdk>=0.3.0,<1
Requires-Dist: mcp>=1.28,<2
Requires-Dist: truststore>=0.10.4,<1
Requires-Python: >=3.11
Project-URL: Homepage, https://console.nace.ai
Project-URL: Documentation, https://console.nace.ai/docs/developer-tools/mcp
Description-Content-Type: text/markdown

# nace-mcp

An [MCP](https://modelcontextprotocol.io) server for the [Drex API](https://console.nace.ai/docs): coding agents get calibrated decisions, document jobs, workspace search and browser runs as tools. MIT; built on [`nace-sdk`](https://pypi.org/project/nace-sdk/).

```bash
nace-mcp login                           # or: uvx nace-mcp login; paste a key from https://console.nace.ai/dashboard/api-keys
claude mcp add nace -- uvx nace-mcp      # Claude Code
```

`nace-mcp login` checks the key against Drex and saves it to `~/.nace/config.toml` (mode 0600), the file `nace login` from [`nace-cli`](https://pypi.org/project/nace-cli/) writes too, so either signs in both. `--api-key KEY` passes the key, `--api-key -` reads it from stdin; without a terminal one of them is required. `$NACE_API_KEY`, `$NACE_BASE_URL` and `$NACE_CONFIG_PATH` in the server's environment override the file. Without a key the server still starts, and every tool answers with how to sign in until one is saved. The server reads the credentials on each call, so `nace-mcp login` while it runs, to sign in or to replace a refused key, needs no restart. `nace-mcp --version` prints the server and SDK versions.

## Connect an agent

Each example passes your API key as `NACE_API_KEY`: replace `nace_sk_...` with a key from https://console.nace.ai/dashboard/api-keys, or leave the key out if you ran `nace-mcp login`.

Claude Code: `claude mcp add nace --env NACE_API_KEY=nace_sk_... -- uvx nace-mcp`.

Codex: `codex mcp add nace --env NACE_API_KEY=nace_sk_... -- uvx nace-mcp` (or a `[mcp_servers.nace]` table with `command = "uvx"`, `args = ["nace-mcp"]` and `env = { NACE_API_KEY = "nace_sk_..." }` in `~/.codex/config.toml`).

OpenCode (`opencode.json`): `"mcp": {"nace": {"type": "local", "command": ["uvx", "nace-mcp"], "environment": {"NACE_API_KEY": "nace_sk_..."}, "enabled": true}}`.

Pi: `pi mcp add nace --env NACE_API_KEY=nace_sk_... -- uvx nace-mcp` (writes `~/.pi/agent/mcp.json`).

Hermes Agent: `hermes mcp add nace --command uvx --env NACE_API_KEY=nace_sk_... --args nace-mcp`, or in `~/.hermes/config.yaml`:

```yaml
mcp_servers:
  nace:
    command: "uvx"
    args: ["nace-mcp"]
    env:
      NACE_API_KEY: "nace_sk_..."
```

Claude Desktop (`claude_desktop_config.json`), Cursor (`~/.cursor/mcp.json`) and Pi (`~/.pi/agent/mcp.json`):

```json
{
  "mcpServers": {
    "nace": {
      "command": "uvx",
      "args": ["nace-mcp"],
      "env": { "NACE_API_KEY": "nace_sk_..." }
    }
  }
}
```

The agent starts the server, so a `NACE_API_KEY` exported in your shell doesn't reach it on its own; Hermes Agent passes a server only the variables under its `env`. To install it once instead of through `uvx`: `pipx install nace-mcp` (Python 3.11 or later), then use `nace-mcp` as the command.

## Tools

| Tool | What it does |
| --- | --- |
| `decide` | Answer typed questions (`noul`, `choice`, `score`) about text or JSON, and images with Drex Max, with calibrated probabilities. |
| `list_models` | List the models `decide` can use. |
| `upload_document` | Upload a local file into a workspace, or to the server without one. |
| `parse_document` | Convert a document to Markdown, text or layout blocks. |
| `split_document` | Cut a packet into segments, each with a class. |
| `classify_document` | Label a document, or each page, with your classes. |
| `extract_data` | Fill a JSON Schema, with a status and citation per field. |
| `ground_items` | Find where each quote appears in a document. |
| `get_job` | Read a job and a summary of its result. |
| `wait_for_job` | Wait for a job to finish. |
| `list_jobs` | List jobs, newest first. |
| `cancel_job` | Cancel a running job, or drop a finished one from the list. |
| `get_job_request` | The request a job ran under. |
| `download_job_file` | Save a file a job produced. |
| `get_job_rows` | Page through a parsed sheet's rows. |
| `list_extraction_schemas` | List saved extraction schemas. |
| `get_extraction_schema` | Read a saved schema, at its latest or a given version. |
| `list_extraction_schema_versions` | List a saved schema's versions. |
| `create_extraction_schema` | Save a new extraction schema. |
| `add_extraction_schema_version` | Add a version to a saved schema. |
| `delete_extraction_schema` | Delete a saved schema with every version. |
| `create_workspace` | Create a workspace, optionally against a published `domain_slug`. |
| `list_workspaces` | List the account's workspaces. |
| `get_workspace` | Read a workspace and its settings. |
| `workspace_stats` | Summarize what a workspace holds. |
| `delete_workspace` | Delete a workspace and everything in it. |
| `list_domains` | List the domains a workspace can classify its files against. |
| `get_domain` | Read a domain with its taxonomy. |
| `create_domain` | Create a draft domain of your own. |
| `update_domain` | Rename a draft or replace its taxonomy. |
| `publish_domain` | Freeze a draft so workspaces can use it. |
| `duplicate_domain` | Copy a domain as a draft you can edit. |
| `list_workspace_files` | List a workspace's files. |
| `get_workspace_file` | Read a file, with links to its bytes, its metadata and its versions. |
| `delete_workspace_file` | Delete a file from a workspace. |
| `ingest_workspace` | Make a workspace's files searchable. |
| `automatic_search` | Answer one question from a workspace's files, with cited evidence. |
| `qa` | Ask one turn of a conversation about a workspace's files. |
| `browser_run` | Give a cloud browser agent a task on the sites you allow, and wait for its answer. |
| `get_browser_run` | Read a browser run, optionally waiting for it to end. |
| `list_browser_runs` | List the account's browser runs, newest first. |
| `cancel_browser_run` | Cancel a queued or running browser run. |
| `get_documentation` | Usage notes for a topic, shipped with the server. |

The document tools take one source: an `https://` `url`, a local `path` (uploaded first), an uploaded file's `workspace_id` and `file_id`, or a finished parse's `parse_job_id`. They wait up to `wait_seconds` (60 at most) and return the job; one still running comes back with an instruction to call `wait_for_job`. Any other request field goes in a tool's `options`; an argument a tool doesn't have is refused rather than ignored. Results are summarised, and text or JSON longer than `max_inline_chars` is written to a file readable only by you, whose path is returned. For a document too large to return inline, `parse_document` saves the full Markdown to a file.

A workspace tool without `workspace_id` uses `$NACE_WORKSPACE_ID`, then the workspace `nace workspace-use` saved; with neither it asks for one.

Full documentation: [MCP server](https://console.nace.ai/docs/developer-tools/mcp).
