Skip to main content
Glama
MangelSpec

wowaudit-mcp-server

by MangelSpec
README.md
# wowaudit-mcp-server

MCP server for the documented [WoWAudit API](https://wowaudit.com/api). It exposes guild roster, raid planning, attendance, weekly activity, wishlists, loot history, and applications as structured tools for Raid Lens and other MCP clients.

The server uses stdio and `@modelcontextprotocol/server` 2.x. It serves the current MCP protocol and retains the SDK's legacy 2025-era initialize handshake for older clients. Every result includes native `structuredContent` plus the same JSON as a text block for clients that do not consume structured results.

## Requirements

- Node.js 20 or newer.
- A WoWAudit team API key. A team administrator can copy it from the team's **Settings > Team > API key** field, or open <https://wowaudit.com/api> and select the team. WoWAudit does not currently expose a scoped read-only Public API key; this server enforces read-only access locally by default.

## Setup

```bash
npm install
```

Create `.env` from `.env.example`, then set:

```dotenv
WOWAUDIT_API_KEY=your-team-api-key
```

Build the server:

```bash
npm run build
```

The API key is loaded lazily, so the MCP process can start and list tools without a configured key. API calls return a structured configuration error until the key is available.

## MCP client configuration

Use the compiled entry point from an MCP client:

```json
{
  "mcpServers": {
    "wowaudit": {
      "command": "node",
      "args": [
        "C:\\programming\\typescript\\wowaudit-mcp-server\\dist\\index.js"
      ]
    }
  }
}
```

The server resolves `.env` relative to its installed location, not the MCP client's working directory. Credentials may instead be supplied through the client's `env` configuration.

Integrators that must preserve the API key's exact UTF-8 bytes can pass it through a dedicated inherited file descriptor instead of an environment variable. Inherit a readable descriptor as FD 3 and set only `WOWAUDIT_API_KEY_FD=3`. The descriptor contents must be non-empty valid UTF-8 and are read once, cached in memory for the MCP process lifetime, and reused without trimming or newline removal. Do not also set a non-empty `WOWAUDIT_API_KEY`.

## Security model

A WoWAudit team API key can access the team's entire environment. The server applies these safeguards:

- The key is sent only as an `Authorization: Bearer` header. It is never put in a URL, result, or error.
- Only documented `/v1/` routes are available. There is no arbitrary HTTP tool.
- Write tools are not advertised or callable unless `WOWAUDIT_ENABLE_WRITES=true`. The HTTP client independently blocks mutation requests while disabled. Set `WOWAUDIT_WRITE_POLICY=raidlens-create-update-v1` to limit enabled mutations to character tracking and updates, raid creation and updates, and wishlist uploads.
- Destructive delete tools additionally require `confirm: true` on each call.
- Application tools are disabled unless `WOWAUDIT_ENABLE_APPLICATIONS=true` because applications may contain identities, questionnaire answers, and uploaded-file URLs.
- Tool annotations identify read-only, idempotent, and destructive operations to modern MCP clients.
- Responses are limited to 2 MiB by default. Adjust `WOWAUDIT_MAX_RESPONSE_BYTES` only when necessary.
- Successful GET responses use a child-local weighted LRU with 64 entries, 16 MiB total retained bytes, 4 MiB per entry, and at most 16 distinct upstream loads in flight. Values above the cache entry limit but within `WOWAUDIT_MAX_RESPONSE_BYTES` are returned uncached.
- Cache keys contain only the HTTP method, API pathname, and sorted representation query. Credentials and the fixed base URL are excluded. Returned values are cloned, and failed or malformed responses are never retained.
- Endpoint TTLs range from 15 seconds for raid detail to 10 minutes for team identity. Reads strictly refetch after expiry; stale data is not returned when revalidation fails.
- Writes invalidate affected team, period, character, historical, attendance, wishlist, raid, and loot generations before HTTP dispatch. This also prevents a read started before a write from repopulating stale data after the write begins.

Enabling application tools does not provide channel authorization. A Discord integration must enforce officer-only access before exposing those tools. Similarly, a multi-guild bot must bind its trusted Discord guild ID to the correct WoWAudit credential outside model-controlled tool arguments.

## Configuration

| Variable                              |                    Default | Purpose                                        |
| ------------------------------------- | -------------------------: | ---------------------------------------------- |
| `WOWAUDIT_API_KEY`                    | required unless FD is used | Team API key, preserved without trimming       |
| `WOWAUDIT_API_KEY_FD`                 |                      unset | Inherited API key descriptor, 1 to 1024        |
| `WOWAUDIT_BASE_URL`                   | `https://api.wowaudit.com` | API origin                                     |
| `WOWAUDIT_REQUEST_TIMEOUT_MS`         |                    `30000` | Header and body timeout, 5,000 to 120,000 ms   |
| `WOWAUDIT_MAX_RESPONSE_BYTES`         |                  `2097152` | Maximum JSON response, 64 KiB to 10 MiB        |
| `WOWAUDIT_CACHE_MAX_ENTRIES`          |                       `64` | Completed response entry limit                 |
| `WOWAUDIT_CACHE_MAX_BYTES`            |                 `16777216` | Completed response retained-byte limit         |
| `WOWAUDIT_CACHE_MAX_ENTRY_BYTES`      |                  `4194304` | Per-response retained-byte limit               |
| `WOWAUDIT_WISHLIST_MARKER_VALIDATION` |                    `false` | Enable validated wishlist retention experiment |
| `WOWAUDIT_ENABLE_WRITES`              |                    `false` | Permit POST, PUT, and DELETE tools             |
| `WOWAUDIT_WRITE_POLICY`               |                      unset | Restrict writes to `raidlens-create-update-v1` |
| `WOWAUDIT_ENABLE_APPLICATIONS`        |                    `false` | Permit sensitive application tools             |

Cache retained bytes include the UTF-8 cache key and serialized JSON value. Application reads use the unknown-GET 30-second TTL when enabled. Mutations, errors, credentials, authorization decisions, MCP results, and projected model output are not cached. `refresh: true` on RaidLens read tools removes a completed entry before lookup but joins an already active load for the same canonical resource; omitted refresh and `refresh: false` are equivalent.

`WOWAUDIT_WISHLIST_MARKER_VALIDATION` must remain false until an operator verifies `wishlist_updated_at` monotonicity across three authorized non-production wishlist edits. Disabled mode refetches the full wishlist after its normal five-minute TTL. Enabled mode retains a wishlist body for no more than 30 minutes and performs an uncached `/v1/team` marker probe every 60 seconds. Equal markers extend validation only, while larger, missing, malformed, or decreasing markers force a full refetch. Probe failures return the upstream error rather than stale wishlist data.

Successful protocol results include non-model-visible `_meta["raidlens/cache"]` telemetry with finite source/outcome labels and numeric duration and byte fields. The same data is not added to `structuredContent` or the text fallback.

The default configuration exposes 14 non-sensitive GET tools. Setting `WOWAUDIT_ENABLE_APPLICATIONS=true` adds the two read-only application tools. Setting `WOWAUDIT_ENABLE_WRITES=true` adds mutation tools; leave it unset for a strictly read-only MCP surface. For RaidLens, also set `WOWAUDIT_WRITE_POLICY=raidlens-create-update-v1`. This policy exposes the 14 non-sensitive GET tools plus only `wowaudit_track_character`, `wowaudit_update_character`, `wowaudit_create_raid`, `wowaudit_update_raid`, and `wowaudit_upload_wishlist` when writes are enabled. All application tools are suppressed regardless of `WOWAUDIT_ENABLE_APPLICATIONS`, and all other mutations remain absent and uncallable. Unknown non-empty policy values prevent startup. Omitting the policy preserves the existing general write surface for current consumers.

## Tools

Mutation tools shown below are only registered when `WOWAUDIT_ENABLE_WRITES=true` and permitted by `WOWAUDIT_WRITE_POLICY`. Application tools are only registered when `WOWAUDIT_ENABLE_APPLICATIONS=true` and no policy suppresses them.

### Team and roster

| Tool                         | API operation                |
| ---------------------------- | ---------------------------- |
| `wowaudit_get_team`          | `GET /v1/team`               |
| `wowaudit_get_period`        | `GET /v1/period`             |
| `wowaudit_list_characters`   | `GET /v1/characters`         |
| `wowaudit_track_character`   | `POST /v1/characters`        |
| `wowaudit_update_character`  | `PUT /v1/characters/{id}`    |
| `wowaudit_untrack_character` | `DELETE /v1/characters/{id}` |

### Activity and attendance

| Tool                                 | API operation                                  |
| ------------------------------------ | ---------------------------------------------- |
| `wowaudit_list_historical_data`      | `GET /v1/historical_data`                      |
| `wowaudit_get_character_history`     | `GET /v1/historical_data/{id}`                 |
| `wowaudit_get_weekly_roster_summary` | compact current-period activity and vault rows |
| `wowaudit_get_attendance`            | `GET /v1/attendance`                           |

### Raids and signups

| Tool                   | API operation           |
| ---------------------- | ----------------------- |
| `wowaudit_list_raids`  | `GET /v1/raids`         |
| `wowaudit_get_raid`    | `GET /v1/raids/{id}`    |
| `wowaudit_create_raid` | `POST /v1/raids`        |
| `wowaudit_update_raid` | `PUT /v1/raids/{id}`    |
| `wowaudit_delete_raid` | `DELETE /v1/raids/{id}` |

`wowaudit_update_raid` supports status and schedule changes, encounter enable/disable lists, signup statuses, comments, role/class overrides, selected status, and encounter-specific selections.

### Wishlists and loot

| Tool                              | API operation                                          |
| --------------------------------- | ------------------------------------------------------ |
| `wowaudit_list_wishlists`         | `GET /v1/wishlists`                                    |
| `wowaudit_get_character_wishlist` | `GET /v1/wishlists/{id}`                               |
| `wowaudit_list_wishlist_items`    | compact item rows from `GET /v1/wishlists`             |
| `wowaudit_find_wishlisted_item`   | character demand for one item from `GET /v1/wishlists` |
| `wowaudit_upload_wishlist`        | `POST /v1/wishlists`                                   |
| `wowaudit_delete_wishlist`        | `DELETE /v1/wishlists/{id}`                            |
| `wowaudit_get_loot_history`       | `GET /v1/loot_history/{seasonId}`                      |

The all-character wishlist and loot endpoints can be large. Prefer character-specific calls for one player. Use `wowaudit_list_wishlist_items` for a compact paginated guild item table, optionally filtered by slot, and `wowaudit_find_wishlisted_item` to find demand for one item by item ID or name.

### Applications

| Tool                          | API operation                  |
| ----------------------------- | ------------------------------ |
| `wowaudit_list_applications`  | `GET /v1/applications`         |
| `wowaudit_get_application`    | `GET /v1/applications/{id}`    |
| `wowaudit_update_application` | `PUT /v1/applications/{id}`    |
| `wowaudit_delete_application` | `DELETE /v1/applications/{id}` |

Applications are separately gated by `WOWAUDIT_ENABLE_APPLICATIONS=true`. Mutating them also requires `WOWAUDIT_ENABLE_WRITES=true`. The `raidlens-create-update-v1` policy suppresses every application tool regardless of these flags.

## Result envelope

Successful tools, including `wowaudit_get_team`, return the canonical `{ data, meta }` envelope consumed by RaidLens:

```json
{
  "data": {
    "teamId": "42",
    "teamDisplayName": "RaidLens Team"
  },
  "meta": {
    "endpoint": "/v1/team",
    "method": "GET"
  }
}
```

`wowaudit_get_team` validates the upstream numeric `id` and `name`, converts the ID to a string, and returns only `teamId` (1 to 128 characters) and `teamDisplayName` (1 to 200 characters). Other upstream team fields are not exposed.

Collection tools accepting `limit` additionally report `totalItems`, `returnedItems`, and `truncated`. The limit is applied after WoWAudit responds because the public API does not document server-side pagination.

Errors return `isError: true`, structured `{ "error": "..." }`, and a text fallback. Upstream errors also include `kind`, HTTP `status`, and `retryAfterSeconds` when available.

The HTTP response limit is enforced while reading decoded body chunks under the same deadline used for response headers. Non-JSON error responses retain the HTTP status and only a bounded, credential-redacted plain-text detail. `Retry-After` delta seconds and future HTTP dates are exposed as a delay capped at one hour.

## Development

```bash
npm run dev
npm test
```

Tests compile the server, verify both modern and legacy protocol negotiation, inspect all tool schemas and annotations, exercise security gates, and test the HTTP client without using a real API key.

For a small live read-only check:

```bash
npm run test:live
```

The live smoke test calls team, period, roster, and raid-list endpoints. It never invokes application or write tools.

## WoWAudit API caveats

- The public documentation defines no pagination or rate-limit contract.
- The documentation primarily supplies response examples rather than strict reusable schemas, so payload fields may evolve.
- The embedded documentation contains a development-looking server URL. This project uses the confirmed production origin `https://api.wowaudit.com` by default.
- WoWAudit accepts an API key in a query parameter, but this server deliberately uses only the authorization header to reduce credential leakage.

## License

[MIT](LICENSE), copyright WoWAudit MCP Server contributors.

TDQS

A3.9/5.0

Scored across 11 tools

Disambiguation4/5

Most tools target distinct resources: team/period/characters/raids/attendance/wishlists/loot. However, wowaudit_list_historical_data and wowaudit_get_loot_history both involve historical activity and loot, which could cause some confusion despite different scopes.

Naming Consistency5/5

All tools follow a consistent wowaudit_verb_noun pattern (e.g., list_raids, get_raid, get_attendance). The naming is predictable and easy to understand.

Tool Count5/5

With 11 tools, the server covers a focused domain (WoWAudit team management) without unnecessary clutter. Each tool serves a clear purpose and the count feels well-scoped.

Completeness4/5

The tool set covers team info, roster characters, raids, attendance, wishlists, and loot history. Missing are write operations (e.g., add character, update wishlist) but for a read-only audit tool, the coverage is solid. Minor gap: no direct tool for managing raid signups.

Maintenance

ActivityMaintained
ResponsivenessNo issues