Metadata-Version: 2.4
Name: hex-openapi-mcp
Version: 0.1.0
Summary: MCP server generated from Hex's official OpenAPI specification
Keywords: fastmcp,hex,mcp,openapi
Author: Mikhail Konovalov
License-Expression: MIT
Requires-Dist: fastmcp>=3.4,<4
Requires-Dist: httpx>=0.28,<1
Requires-Dist: httpx-retries>=0.6,<1
Requires-Dist: pydantic-settings>=2.10,<3
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/mskonovalov/hex-mcp
Project-URL: Issues, https://github.com/mskonovalov/hex-mcp/issues
Project-URL: Repository, https://github.com/mskonovalov/hex-mcp
Description-Content-Type: text/markdown

# hex-mcp

An MIT-licensed MCP server generated from the official Hex public API specification.

The server loads Hex's current OpenAPI document at startup and exposes its operations as deterministic, snake_case MCP tools through FastMCP.

The PyPI distribution is named `hex-openapi-mcp`; the installed command and Python import remain `hex-mcp` and `hex_mcp`.

## Capability modes

- `read-only` exposes only operations classified as non-mutating, regardless of the configured Hex token's permissions.
- `full` exposes the complete official API surface.

`read-only` is the default. It registers GET operations and the non-mutating `export_project` POST operation. Mutating tools do not exist in the MCP catalog in this mode, even when `HEX_API_TOKEN` has write permissions.

## Install

Requirements: Python 3.12 or newer and [uv](https://docs.astral.sh/uv/).

Run the server directly from PyPI:

```bash
HEX_API_TOKEN=your_hex_token uvx --from hex-openapi-mcp hex-mcp
```

Enable the complete API surface explicitly:

```bash
HEX_API_TOKEN=your_hex_token HEX_MCP_MODE=full uvx --from hex-openapi-mcp hex-mcp
```

The default transport is stdio. To run Streamable HTTP:

```bash
HEX_API_TOKEN=your_hex_token HEX_TRANSPORT=http uvx --from hex-openapi-mcp hex-mcp
```

It listens on `http://127.0.0.1:8000/mcp` by default.

## Run from source

Requirements: Python 3.12 or newer and [uv](https://docs.astral.sh/uv/).

```bash
uv sync --locked --dev
HEX_API_TOKEN=your_hex_token uv run hex-mcp
```

## MCP client configuration

From PyPI:

```json
{
  "mcpServers": {
    "hex": {
      "command": "uvx",
      "args": ["--from", "hex-openapi-mcp", "hex-mcp"],
      "env": {
        "HEX_API_TOKEN": "your_hex_token",
        "HEX_MCP_MODE": "read-only"
      }
    }
  }
}
```

For a local checkout, use `"command": "uv"` with `"args": ["--directory", "/absolute/path/to/hex-mcp", "run", "hex-mcp"]`.

For stdio, the MCP client passes `HEX_API_TOKEN` only to the child process. Do not put the token in command-line arguments.

## Configuration

| Variable | Default | Purpose |
| --- | --- | --- |
| `HEX_API_TOKEN` | Required | Hex personal or workspace bearer token |
| `HEX_MCP_MODE` | `read-only` | `read-only` or `full` tool catalog |
| `HEX_API_BASE_URL` | `https://app.hex.tech/api` | Hex API base URL |
| `HEX_OPENAPI_SPEC` | `https://static.hex.site/openapi.json` | Official spec URL or a local JSON file |
| `HEX_TRANSPORT` | `stdio` | `stdio` or `http` |
| `HEX_HTTP_HOST` | `127.0.0.1` | Streamable HTTP bind host |
| `HEX_HTTP_PORT` | `8000` | Streamable HTTP bind port |
| `HEX_HTTP_PATH` | `/mcp` | Streamable HTTP endpoint path |
| `HEX_REQUEST_TIMEOUT_SECONDS` | `30` | Spec download and Hex API timeout |

## Development

```bash
uv run ruff format --check .
uv run ruff check .
uv run mypy
uv run pytest
```

The repository does not vendor Hex's specification. Contract behavior can be tested offline by setting `HEX_OPENAPI_SPEC` to an independently supplied local copy.

## Safety and reliability

- Every tool has MCP read-only, destructive, idempotent, and open-world annotations derived from its official operation and HTTP method.
- Tool results and Hex error bodies recursively redact known credential fields and Hex bearer tokens before they reach MCP output or error logging.
- Hex HTTP errors preserve the status, reason, and trace ID in a structured MCP error without exposing internal stack traces.
- GET requests retry transient `429`, `502`, `503`, and `504` responses up to twice, respect `Retry-After`, and use bounded exponential backoff. Write requests are never retried automatically.

Hex's specification currently publishes two semantic paths with backend regex syntax as literal OpenAPI paths. Those literals return `404`, while both expanded routes exist. The loader normalizes them to the current `/v1/semantic-projects/...` naming before generating tools while retaining the original specification digest for observability.

Streamable HTTP currently uses the single server-wide `HEX_API_TOKEN` and has no inbound client authentication. Keep the default loopback bind unless access is protected by a trusted authentication proxy.

## Design documents

- [Capability matrix](docs/capability-matrix.md)
- [Implementation plan](docs/implementation-plan.md)
- [Release process](docs/releasing.md)
