Metadata-Version: 2.4
Name: traackr-api-mcp
Version: 0.1.0a1
Summary: MCP server for the Traackr API v1, generated from its OpenAPI spec.
Project-URL: Homepage, https://www.traackr.ai
Project-URL: Documentation, https://api.traackr.ai/api/openapi/v1
Author: Traackr
License-Expression: MIT
License-File: LICENSE
Keywords: fastmcp,influencer-marketing,mcp,model-context-protocol,openapi,traackr
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: fastmcp>=3.4.2
Requires-Dist: httpx>=0.28.1
Requires-Dist: python-dotenv>=1.2.2
Description-Content-Type: text/markdown

# Traackr API MCP Server

An [MCP](https://modelcontextprotocol.io) server for the **Traackr API v1**, built
with [FastMCP](https://gofastmcp.com) directly from the API's OpenAPI spec. Point
any MCP client (Claude Code, Claude Desktop, Codex, …) at it and it runs on your
machine with your own API key.

It is published to [PyPI](https://pypi.org/project/traackr-api-mcp/) as
`traackr-api-mcp`, so installing is a single `uvx` command — no clone, no build,
no repository access.

## Tools

Tool names, summaries, and descriptions are derived entirely from the OpenAPI spec
(each operation's `operationId` / `summary` / `description`) — nothing is hardcoded,
so new endpoints appear automatically as the spec evolves.

| Tool | Method / Path | Description |
| --- | --- | --- |
| `getCreator` | `GET /v1/creators/{creatorId}` | Get a creator's details by id |
| `listCampaigns` | `GET /v1/campaigns` | List campaigns visible to the account |
| `getCampaign` | `GET /v1/campaigns/{campaignId}` | Get full detail for one campaign |
| `listCampaignCreators` | `GET /v1/campaigns/{campaignId}/creators` | List creators on a campaign |

## Prerequisites

- [`uv`](https://docs.astral.sh/uv/) (provides `uvx`). Install with:
  ```bash
  curl -LsSf https://astral.sh/uv/install.sh | sh
  ```
- A Traackr API key (provisioned by Traackr; sent as the `X-Api-Key` header).

`uvx` fetches and runs the published package in one step — there is nothing else
to install.

## Quick start

Pick your client. In every case, replace `your-api-key-here` with your key.

### Claude Code

```bash
claude mcp add traackr \
  --env TRAACKR_API_KEY=your-api-key-here \
  -- uvx traackr-api-mcp
```

### Claude Desktop

Edit the config file (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`,
Windows: `%APPDATA%\Claude\claude_desktop_config.json`) and add:

```json
{
  "mcpServers": {
    "traackr": {
      "command": "uvx",
      "args": ["traackr-api-mcp"],
      "env": { "TRAACKR_API_KEY": "your-api-key-here" }
    }
  }
}
```

Restart Claude Desktop afterward.

### Codex

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.traackr]
command = "uvx"
args = ["traackr-api-mcp"]
env = { TRAACKR_API_KEY = "your-api-key-here" }
```

### Any other MCP client

Use the same command and args:

```
command: uvx
args:    traackr-api-mcp
env:     TRAACKR_API_KEY=your-api-key-here
```

## Versioning

`uvx traackr-api-mcp` runs the latest published release. To pin a specific
version, append `@<version>`:

```bash
claude mcp add traackr \
  --env TRAACKR_API_KEY=your-api-key-here \
  -- uvx traackr-api-mcp@1.2.0
```

`uvx` caches builds, so if a new version has been published and you want it
immediately, force a refresh:

```bash
uvx --refresh traackr-api-mcp
```

A full client restart after refreshing ensures the MCP server process is
relaunched against the new build.

## Configuration

All configuration is via environment variables (set them in your client's `env` block):

| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `TRAACKR_API_KEY` | yes | — | API key, sent as the `X-Api-Key` header |
| `TRAACKR_API_BASE_URL` | no | first `servers` entry in the spec | Override the API base URL (e.g. a pilot host) |
| `TRAACKR_OPENAPI_URL` | no | `https://api.traackr.ai/api/openapi/v1` | Load the OpenAPI spec from this URL (e.g. a staging spec) |

### Staying in sync with the API

By default the server fetches the **live** OpenAPI spec from
`https://api.traackr.ai/api/openapi/v1` at startup and builds its tools from it — so
new endpoints, fields, and description changes show up automatically with no package
update. The package also ships a bundled copy (`src/traackr_mcp/traackrapi.json`) that
is used only as an offline fallback if the live URL can't be reached.

To point at a different spec (e.g. staging), set `TRAACKR_OPENAPI_URL`:

```
TRAACKR_OPENAPI_URL=https://staging.traackr.ai/api/openapi/v1
```

## Authentication

The Traackr API authenticates with an `X-Api-Key` header. OAuth is planned for a
future release; when it lands, the static header on the httpx client in
[`src/traackr_mcp/server.py`](src/traackr_mcp/server.py) can be swapped for an auth
flow without changing the tool surface.

## Troubleshooting

- **`403 {"message":"Forbidden"}`** (AWS `ForbiddenException`) — the request is fine,
  but the gateway is rejecting the key. Check the key is activated for the target
  environment. Reproduce outside MCP with:
  ```bash
  curl -i -H "X-Api-Key: $TRAACKR_API_KEY" "https://api.traackr.ai/api/v1/campaigns?limit=3"
  ```
- **`Output validation error`** — handled: the server runs with output-schema
  validation disabled, since the API returns `null` for optional fields the
  OpenAPI 3.0.1 spec marks non-nullable.

---

## For Traackr engineers

The source lives in the [`application-platform`](https://github.com/traackr-internal-engineering/application-platform)
monorepo under `services/api/mcp/traackr-api`. Releases are cut by release-please
and published to PyPI automatically on the resulting tag (see
`.github/workflows/release-mcp-traackr-api.yml`).

**Release flow.** A merged `feat:`/`fix:` commit touching this package puts it in
release-please's rolling release PR; merging that PR tags
`traackr-api-mcp-<version>`, which runs the publish workflow. Publishing uses
PyPI Trusted Publishing (OIDC) — the workflow header documents the one-time PyPI
and GitHub Environment setup it depends on. No API token is stored in the repo.

### Local development

From a checkout of the monorepo:

```bash
cd services/api/mcp/traackr-api
uv sync

cp env.local.example .env     # then set TRAACKR_API_KEY in .env

uv run python test_server.py  # lists tools + makes a live listCampaigns call
uv run traackr-api-mcp        # run the stdio server directly

# Run the test suite (also runs in CI via the mcp-traackr-api leg)
mise run agentic:test-mcp-traackr-api
```

### Testing the publish flow locally

CI publishes with Trusted Publishing (OIDC), which only works from the workflow —
a local publish needs an API token instead. **Test against
[TestPyPI](https://test.pypi.org) first**: real PyPI versions are immutable and
cannot be re-uploaded or deleted, so a mistake there burns that version number
permanently.

```bash
cd services/api/mcp/traackr-api
uv build                       # writes dist/*.whl + dist/*.tar.gz

# Upload to TestPyPI (create a TestPyPI token first; scope it to this project)
uv publish --publish-url https://test.pypi.org/legacy/ --token <testpypi-token>

# Verify the published artifact actually runs. TestPyPI has no copies of our
# deps, so pull the package from TestPyPI and its deps from real PyPI:
uvx --index https://test.pypi.org/simple/ \
    --index-strategy unsafe-best-match \
    --refresh traackr-api-mcp
```

Inspect what you're about to ship without uploading anything:

```bash
uv build && unzip -l dist/*.whl   # confirm traackrapi.json + assets/icon.svg are bundled
```

Publishing to **real** PyPI from a laptop should be a one-off at most — the first
upload, if you want a token-created project rather than a PyPI *pending
publisher*. After that, let the tag-triggered workflow own every release:

```bash
uv publish --token <pypi-token>   # prefer letting CI do this
```

### Testing an unreleased branch

Before a change is published, other engineers can run it straight from a branch
with `uvx --from git+ssh://…` (requires SSH access to the private monorepo). Insert
a git ref with `@<ref>` before the `#subdirectory` fragment; keep the URL quoted so
the shell doesn't treat `#` as a comment:

```bash
claude mcp add traackr-branch \
  --env TRAACKR_API_KEY=your-api-key-here \
  -- uvx --from "git+ssh://git@github.com/traackr-internal-engineering/application-platform@my-feature-branch#subdirectory=services/api/mcp/traackr-api" traackr-api-mcp
```

Registering it under a distinct name (e.g. `traackr-branch`) keeps the branch build
alongside a released one. `uvx` caches by source URL, so after pushing new commits
either pin the new commit SHA (`@<sha>`) or add `--refresh`.

### Icon

The server icon is bundled at `src/traackr_mcp/assets/icon.svg` and embedded as a
data URI at startup. It is currently a **placeholder** — replace that file with the
official Traackr brand mark (keep the filename so no code change is needed).
