{"id":"1ea464fe-6637-4b17-a56a-cbe1d3537117","slug":"hotdocs-mcp","kind":"mcp","name":"hotdocs-mcp","summary":"MCP server for HotDocs — API coverage for document automation.","owner":"RosenAdvertising","repoUrl":"https://github.com/RosenAdvertising/hotdocs-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-10T12:14:07.000Z","addedAt":"2026-10-21T05:19:06.897Z","logoUrl":"https://avatars.githubusercontent.com/u/287193004?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["files-documents","cloud-infra","memory-knowledge"],"tags":["claude","claude-mcp","document-automation","legal-tech","python","hotdocs"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T11:31:31.786Z","sample":false,"url":"https://conduits.dev/tools/hotdocs-mcp","language":"Python","transports":["stdio"],"install":{"pypi":"hotdocs-advance-mcp"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\"><a href=\"https://rosenadvertising.com/datalink/?utm_source=github&utm_medium=readme-banner&utm_campaign=hotdocs-mcp\"><img src=\"https://image.rosenadvertising.com/datalink/readme-banner-v2.png\" alt=\"DataLink by Rosen Advertising: don't want to install and run this yourself? Get it hosted.\" width=\"100%\"></a></p>\n\n# HotDocs Advance MCP server\n\n[![CI](https://github.com/RosenAdvertising/hotdocs-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/RosenAdvertising/hotdocs-mcp/actions/workflows/ci.yml)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![MCP](https://img.shields.io/badge/MCP-2026--07--28-7C3AED.svg)](https://modelcontextprotocol.io)\n\nConnect Claude and other MCP clients to HotDocs Advance to work with work items, templates, answers and documents.\n\nHotDocs Advance MCP server is a [Model Context Protocol](https://modelcontextprotocol.io) server for HotDocs Advance, a document automation platform. It registers 13 tools: 9 that read data and 4 that create work items and versions, update answers and complete versions, each requiring `confirm=true`. It runs over stdio by default, for desktop clients such as Claude Desktop, and offers an opt-in stateless Streamable HTTP mode that implements MCP specification 2026-07-28. HotDocs Advance credentials stay on the machine that runs the server: they come from environment variables, never from the client, and are never accepted as tool inputs. The server authenticates with the documented `ResourceOwner` API-client and service-principal flow.\n\n## Features\n\n- Read work items, work groups, template packages, variable data, answers, and documents.\n- Create work items and versions, update answer sets, and complete versions. Every write tool\n  requires explicit `confirm=true`.\n- Require callers to attest that answer XML was validated against HotDocs' published Answer Set\n  XSD before writing it.\n- Return downloaded documents as structured JSON with base64-encoded content.\n- Retry rate-limited and server-error responses to read requests with `Retry-After` support and\n  exponential backoff; write requests are sent once and never retried. Failed calls return fixed error messages; HotDocs response text is never passed to the client.\n- Make one request per collection and cap returned top-level arrays locally (default 50, maximum\n  100). The public API documentation does not define pagination parameters or continuation fields,\n  so the tools do not invent them.\n\n## Tools\n\nThe server registers 13 tools.\n\n| Tool | What it does |\n| --- | --- |\n| `list_work_items` | Find work items you are allowed to see. |\n| `list_work_group_items` | List the work items held in one work group. |\n| `list_template_packages` | List the templates available for creating work items. |\n| `get_template_variable_data` | Show the questions and data fields used by a template version. |\n| `get_work_item_answers` | Retrieve the saved answers for a work item, as XML or JSON. |\n| `list_work_item_documents` | List documents from a work item's latest completed version. |\n| `list_work_item_version_documents` | List documents from one historical work item version. |\n| `get_work_item_document` | Show one document and any questions that were left unanswered. |\n| `download_work_item_document` | Download an assembled document as base64-encoded JSON. |\n| `create_work_item` | Create a new work item. Requires `confirm=true`. |\n| `create_work_item_version` | Start a new assembly version. Requires `confirm=true`. |\n| `patch_work_item_answers` | Overlay selected saved answers. Requires `confirm=true` and the XSD attestation. |\n| `complete_work_item_version` | Finish assembly and produce documents. Requires `confirm=true`; an optional callback URL must pass the [callback destination policy](#callback-destination-policy). |\n\n## Requirements\n\n- Python 3.10+\n- HotDocs Advance API client and service-principal credentials\n- An MCP client such as Claude Desktop\n\n## Installation\n\nInstall [uv](https://docs.astral.sh/uv/), then clone the repository and install its locked dependencies:\n\n```bash\ngit clone https://github.com/RosenAdvertising/hotdocs-mcp.git\ncd hotdocs-mcp\nuv sync --locked\n```\n\n## Configuration\n\nHotDocs Advance credentials come from environment variables. Set them in the environment that launches the server, such as the `env` object in your MCP client configuration.\n\n| Variable | Required | Default | Purpose |\n| --- | --- | --- | --- |\n| `HOTDOCS_TENANCY_MONIKER` | Yes | None | Your HotDocs Advance tenancy moniker: letters, numbers and hyphens only. The server connects to `https://<moniker>.hotdocsadvance.com`. |\n| `HOTDOCS_CLIENT_NAME` | Yes | None | API client name. |\n| `HOTDOCS_PRINCIPAL_NAME` | Yes | None | Service-principal name. |\n| `HOTDOCS_PRINCIPAL_PASSWORD` | Yes | None | Service-principal password. |\n| `HOTDOCS_API_VERSION` | No | `2.0` | HotDocs Advance API version. Only `2.0` is accepted. |\n| `HOTDOCS_ALLOWED_DESTINATION_HOSTS` | No | Empty | Comma-separated hosts allowed as callback destinations. While it is empty, any callback URL is refused. See [Callback destination policy](#callback-destination-policy). |\n\nSee [.env.example](.env.example) for placeholder values. The application reads environment variables directly and does not load `.env` files automatically. Keep real credentials out of source control.\n\nThe server starts and answers MCP initialization and tool listing without credentials. Tools report a configuration error until the required environment is provided. Two commands help with setup:\n\n```bash\nuv run hotdocs-mcp-setup\nuv run hotdocs-mcp-verify\n```\n\n`hotdocs-mcp-setup` prints environment-variable instructions. `hotdocs-mcp-verify` validates the local configuration and exits with code 2 if it is missing or invalid; it does not contact HotDocs Advance or prove authentication. Neither command saves or prints secret values.\n\n## Usage with Claude Desktop\n\nAdd the server to Claude Desktop's configuration file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\\Claude\\claude_desktop_config.json` on Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"hotdocs-advance\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"--locked\", \"--directory\", \"/absolute/path/to/hotdocs-mcp\", \"hotdocs-mcp\"],\n      \"env\": {\n        \"HOTDOCS_TENANCY_MONIKER\": \"your-tenancy-moniker\",\n        \"HOTDOCS_CLIENT_NAME\": \"your-api-client-name\",\n        \"HOTDOCS_PRINCIPAL_NAME\": \"your-service-principal-name\",\n        \"HOTDOCS_PRINCIPAL_PASSWORD\": \"set-in-your-local-client-config\"\n      }\n    }\n  }\n}\n```\n\nReplace `/absolute/path/to/hotdocs-mcp` with the path of your clone and the placeholder values with your credentials. Keep real credentials in your client's protected environment or secret store. Restart Claude Desktop after saving. Any other stdio MCP client uses the same command and arguments.\n\n## HTTP mode\n\nStdio is the default. Set `HOTDOCS_MCP_TRANSPORT=streamable-http` to serve the stateless Streamable HTTP transport from MCP specification 2026-07-28 at `/mcp`. Each request stands alone: no initialization handshake and no `Mcp-Session-Id`. Clients on earlier protocol versions are served on the same endpoint.\n\n> **Security: this endpoint has no authentication and no TLS.** Anyone who can reach the port can run every tool, including write tools, with this server's vendor credentials. Keep the default loopback bind (`127.0.0.1`), or put the server behind an authenticating TLS proxy on a private network. `HOTDOCS_MCP_ALLOWED_HOSTS` and `HOTDOCS_MCP_ALLOWED_ORIGINS` protect against browser DNS rebinding, not against direct callers. A proxy in front of it needs connection and idle timeouts: a legacy-style `GET /mcp` with `Accept: text/event-stream` holds a stream open until the client disconnects.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `HOTDOCS_MCP_TRANSPORT` | `stdio` | `stdio` or `streamable-http`. |\n| `HOTDOCS_MCP_HOST` | `127.0.0.1` | Bind address. `127.0.0.1`, `localhost` and `::1` use the SDK's built-in Host and Origin checks; any other value requires `HOTDOCS_MCP_ALLOWED_HOSTS`. |\n| `PORT` | `8080` | Port; must be an integer. |\n| `HOTDOCS_MCP_ALLOWED_HOSTS` | unset | Comma-separated `Host` header values accepted on a non-loopback bind, such as `mcp.example.com:8080` or `mcp.example.com:*`. |\n| `HOTDOCS_MCP_ALLOWED_ORIGINS` | unset | Comma-separated `Origin` values accepted on a non-loopback bind, such as `https://client.example.com`. Requests without an `Origin` header are accepted; any other `Origin` is refused, including when this is unset. |\n\nHotDocs Advance credentials come from the same configuration as stdio (see [Configuration](#configuration)), never from the request. Tool discovery works without vendor credentials; executing vendor tools requires them.\n\nWith the HotDocs Advance variables from Configuration exported in the process environment, run:\n\n```bash\nHOTDOCS_MCP_TRANSPORT=streamable-http PORT=8080 uv run --locked hotdocs-mcp\n```\n\nPoint the MCP client at `http://127.0.0.1:8080/mcp`. Responses use the SDK's default SSE behavior, so a client that disconnects cancels its running request.\n\n## Error handling\n\nA failed tool call returns an MCP error result (`isError`) with a fixed message. HotDocs Advance's response text is never returned to the client and is not written to the log.\n\n| Situation | The message begins |\n| --- | --- |\n| Missing or invalid configuration | `hotdocs is not configured or its configuration is invalid.` It names the four required variables and the `hotdocs-mcp-setup` command. |\n| HTTP 401 | `Authentication failed.` |\n| HTTP 403 | `Access denied.` |\n| HTTP 404 | `Resource not found.` |\n| HTTP 429 | `Rate limit reached.` |\n| HTTP 5xx | `Service unavailable.` |\n| Any other HTTP error | `Request rejected or response invalid.` |\n| Network failure or timeout | `HotDocs request failed because the connection timed out or was unavailable.` |\n| Unexpected response body | `Invalid tool input or response.` or `The operation could not be completed.` |\n\nInput problems have their own messages: a write tool called without `confirm=true` returns `Confirmation required: set confirm=true only after reviewing the ... operation.`, Answer XML without `answer_xml_is_xsd_validated=true` is refused, a callback host that is not in `HOTDOCS_ALLOWED_DESTINATION_HOSTS` is refused, and a record ID that is not a plain identifier is rejected before any request is sent.\n\nRead requests (`GET`) and the sign-in request that are answered with HTTP 429 or 5xx are retried up to 3 times. The four write tools (`create_work_item`, `create_work_item_version`, `patch_work_item_answers` and `complete_work_item_version`, which send `PUT` or `PATCH`) send their request once and never retry it, so one tool call cannot apply a change twice. The wait before a retry is the `Retry-After` value (seconds or an HTTP date) when present, and otherwise 0.25, 0.5 and 1 seconds. A 401 on an API call discards the cached token, signs in again and repeats the request once. Network failures are not retried. Requests time out after 30 seconds.\n\nAt startup the server exits with a message and status 1 on an unsupported `HOTDOCS_MCP_TRANSPORT`, a `PORT` that is not an integer, or a non-loopback `HOTDOCS_MCP_HOST` without `HOTDOCS_MCP_ALLOWED_HOSTS`. Missing credentials do not stop the server from starting; tool calls report the configuration error instead.\n\n## Callback destination policy\n\nSet `HOTDOCS_ALLOWED_DESTINATION_HOSTS` in the MCP launcher's environment, for example\n`HOTDOCS_ALLOWED_DESTINATION_HOSTS=callbacks.example.com,.trusted.example.com`.\nEntries match exact hosts; a leading dot includes that domain and its subdomains.\nComparison ignores case and trailing dots and normalizes IDNA. URL inputs must be\nASCII (use punycode for internationalized hosts), public HTTPS, and contain no\nuserinfo or fragments. Existing private/local/alternate-numeric IP checks still apply.\nAn unset/empty list refuses any supplied callback before a request; completion\nwithout a callback still works. Tools cannot change this administrator setting.\nThe same checks cover exact normalized destination keys in dictionaries/lists and\nexplicit `payload_json` fields; ordinary text is never parsed as JSON.\n\nThe allowlist prevents a model from choosing arbitrary data recipients, private-IP\nDNS aliases such as `127.0.0.1.sslip.io`, or unapproved public redirectors. Approve\nonly trusted hosts: this server does not resolve DNS or follow callbacks, and\nHotDocs/network operators must enforce safe resolution and redirect behavior for\napproved hosts as well.\n\n## Testing\n\nThe test suite runs offline and needs no HotDocs Advance account: every HotDocs Advance API call is intercepted at the HTTP layer with `respx`. It covers each tool's requests and responses, input validation, the callback destination policy, error handling, credential loading, pagination and retries, the stdio server, and the Streamable HTTP transport including the 2026-07-28 wire format, Host and Origin checks and stateless requests.\n\n```bash\nuv sync --locked\nuv run --locked pytest -q\nuv run --locked ruff check .\n```\n\nCI runs the suite on every push and pull request to `main`.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n"}