# start.gg MCP Server [Health: Active]

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/tomo789/startgg-mcp-server  
**GitHub Stars:** 0  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/start-gg-mcp-server

## Description
MCP server for the start.gg GraphQL API: tournaments, events, entrants, sets, standings, streams

## Tools
Capabilities this server exposes over MCP:

- **search_videogames** — Find videogame ids by name (e.g. "Super Smash Bros. Ultimate" → 1386)
- **search_tournaments** — General tournament search: name, videogame, country/state, date range, upcoming/past, open registration
- **get_upcoming_tournaments** — Tournaments that haven't ended yet (includes in-progress), soonest first, with a days window
- **get_tournaments_by_videogame** — Tournaments for one videogame id (upcoming / past / all)
- **get_tournament** — Details, schedule, venue, events list, configured streams
- **get_tournament_events** — Events (brackets) of a tournament, optionally filtered by videogame
- **get_tournament_entrants** — Tournament-level participants (attendees); per-event seeding lives in `get_event_entrants
- **get_stream_queue** — Stream queue: streams (with derived Twitch URLs) and the sets assigned to each
- **get_event** — Event details including phases (Pools, Top 8, ...) with phase ids
- **get_event_entrants** — Entrants with seed, players, DQ flag; pagination or `fetchAll
- **get_event_standings** — Placements (use `perPage: 8` for Top 8)
- **get_event_sets** — Normalized sets with `stream`; filter by state, phase, round, entrants, players, VOD; `includeGames` for per-game details
- **get_set_games** — Per-game stage / winner / character picks for one set; see coverage note
- **get_player** — Player by id: gamer tag, prefix, linked user
- **get_player_sets** — A player's recent sets across tournaments
- **resolve_startgg_url** — start.gg URL/slug → `{ type, tournamentId, eventId, slugs, names }

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "start-gg-mcp-server": {
    "command": "npx",
    "args": ["-y","startgg-mcp-server"]
  }
}
```

## Documentation & README

# startgg-mcp-server

A [Model Context Protocol](https://modelcontextprotocol.io) server for the
[start.gg](https://www.start.gg) GraphQL API. It lets MCP clients (Claude Code,
Claude Desktop, and others) discover tournaments, inspect events, entrants,
sets, standings, and streams for **any game on start.gg** using natural
language.

## What is this?

start.gg exposes a powerful but complex GraphQL API: entrants vs participants
vs players, integer set states, complexity-limited pagination, epoch
timestamps. This server wraps that API in a small set of MCP tools with:

- **Normalized output** — sets come back as `{ round, state: "COMPLETED", entrant1: { gamerTag, seed }, score, winnerEntrantId, ... }` instead of raw GraphQL nesting
- **URL resolution** — paste a start.gg URL, get tournament/event ids back
- **Built-in rate limiting, retries, and caching** tuned to start.gg's documented limits

The server is game-agnostic. Game-specific logic (e.g. Smash upset detection)
belongs in applications built on top — see
[`examples/smash-ultimate-watcher`](https://github.com/tomo789/startgg-mcp-server/blob/HEAD/examples/smash-ultimate-watcher/).

## Features

- 16 read-only tools covering discovery, tournaments, events, players, streams, and URL resolution
- Input validation (Zod) on every tool — bad ids, oversized page sizes, and malformed URLs never reach the API
- Sliding-window rate limiter (default 75 req/60s vs start.gg's 80), retries with exponential backoff, and `Retry-After` support
- Short-TTL in-memory cache for metadata queries
- Typed error codes: `AUTH_ERROR`, `RATE_LIMITED`, `NOT_FOUND`, `INVALID_INPUT`, `STARTGG_GRAPHQL_ERROR`, `NETWORK_ERROR`, `INTERNAL_ERROR`
- GraphQL documents kept in [`graphql/`](https://github.com/tomo789/startgg-mcp-server/blob/HEAD/graphql/) files, separate from code
- The API token never appears in output, logs, or error messages
- Compact JSON output (no pretty-printing) to keep tool results small

## Requirements

- Node.js >= 22
- A start.gg API token

## Getting a start.gg API token

1. Log in to start.gg
2. Open **[developer settings](https://start.gg/admin/profile/developer)** (Profile → Developer Settings)
3. Create a personal access token and copy it

Treat the token like a password. This server reads it only from the
`STARTGG_TOKEN` environment variable.

## Installation

### From npm (recommended)

```bash
# run without installing
npx startgg-mcp-server

# or install globally
npm install -g startgg-mcp-server
```

Requires `STARTGG_TOKEN` in the environment; MCP clients normally launch it for you (see the next section).

### From source

```bash
git clone https://github.com/tomo789/startgg-mcp-server.git
cd startgg-mcp-server
npm install
npm run build
```

## MCP client setup

### Claude Code (CLI)

```bash
claude mcp add startgg --env STARTGG_TOKEN=YOUR_TOKEN -- npx -y startgg-mcp-server
```

Running from a source checkout instead:

```bash
claude mcp add startgg --env STARTGG_TOKEN=YOUR_TOKEN -- node /path/to/startgg-mcp-server/dist/cli.js
```

### Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "startgg": {
      "command": "npx",
      "args": ["-y", "startgg-mcp-server"],
      "env": {
        "STARTGG_TOKEN": "YOUR_TOKEN"
      }
    }
  }
}
```

From a source checkout, use `"command": "node"` and `"args": ["/path/to/startgg-mcp-server/dist/cli.js"]` instead.

Any MCP client that supports stdio servers works the same way: run
`node dist/cli.js` (or the `startgg-mcp-server` bin once installed via npm)
with `STARTGG_TOKEN` set.

## Available tools

### Discovery

| Tool                           | Purpose                                                                                                 |
| ------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `search_videogames`            | Find videogame ids by name (e.g. "Super Smash Bros. Ultimate" → 1386)                                   |
| `search_tournaments`           | General tournament search: name, videogame, country/state, date range, upcoming/past, open registration |
| `get_upcoming_tournaments`     | Tournaments that haven't ended yet (includes in-progress), soonest first, with a days window            |
| `get_tournaments_by_videogame` | Tournaments for one videogame id (upcoming / past / all)                                                |

### Tournament

| Tool                      | Purpose                                                                                    |
| ------------------------- | ------------------------------------------------------------------------------------------ |
| `get_tournament`          | Details, schedule, venue, events list, configured streams                                  |
| `get_tournament_events`   | Events (brackets) of a tournament, optionally filtered by videogame                        |
| `get_tournament_entrants` | Tournament-level participants (attendees); per-event seeding lives in `get_event_entrants` |
| `get_stream_queue`        | Stream queue: streams (with derived Twitch URLs) and the sets assigned to each             |

### Event

| Tool                  | Purpose                                                                                                                   |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `get_event`           | Event details including phases (Pools, Top 8, ...) with phase ids                                                         |
| `get_event_entrants`  | Entrants with seed, players, DQ flag; pagination or `fetchAll`                                                            |
| `get_event_standings` | Placements (use `perPage: 8` for Top 8)                                                                                   |
| `get_event_sets`      | Normalized sets with `stream`; filter by state, phase, round, entrants, players, VOD; `includeGames` for per-game details |
| `get_set_games`       | Per-game stage / winner / character picks for one set; see coverage note                                                  |

### Player

| Tool              | Purpose                                      |
| ----------------- | -------------------------------------------- |
| `get_player`      | Player by id: gamer tag, prefix, linked user |
| `get_player_sets` | A player's recent sets across tournaments    |

### Utility

| Tool                  | Purpose                                                             |
| --------------------- | ------------------------------------------------------------------- |
| `resolve_startgg_url` | start.gg URL/slug → `{ type, tournamentId, eventId, slugs, names }` |

Tournament/event tools accept **either** a numeric id, a slug, or a full
start.gg URL. Scheme-less URLs (`start.gg/tournament/...`) and `<t>/event/<e>`
slugs are accepted too — you rarely need `resolve_startgg_url` explicitly, but
it is there when you want the ids.

### Normalized set shape

```json
{
  "id": 106877974,
  "round": "Grand Final",
  "roundNumber": 3,
  "state": "COMPLETED",
  "stateRaw": 3,
  "completedAt": "2026-08-24T07:19:34.000Z",
  "entrant1": {
    "entrantId": 24480092,
    "name": "LittleMacMain",
    "seed": 5,
    "players": [{ "playerId": 3655189, "gamerTag": "LittleMacMain", "prefix": "" }],
    "score": 2
  },
  "entrant2": { "...": "same shape" },
  "score": { "entrant1": 2, "entrant2": 3, "displayScore": "LittleMacMain 2 - RenSuø 3" },
  "winnerEntrantId": 24481002,
  "phase": { "id": 1994001, "name": "Bracket" },
  "vodUrl": null
}
```

Notes grounded in the live API:

- `roundNumber < 0` means losers bracket; `round` is the human-readable name
- a score of `-1` is start.gg's disqualification marker
- unstarted "preview" sets have **string** ids like `"preview_3430499_2_0"`
- `state` names are decoded from the integer `stateRaw`; both are always returned
- `entrant1`/`entrant2` use a `players` array, so doubles/teams work unchanged

### Games and characters

`get_set_games` (and `get_event_sets` with `includeGames: true`) add per-game
details when start.gg has them:

```json
{
  "orderNum": 1,
  "winnerEntrantId": 24480092,
  "stage": { "id": 484, "name": "Small Battlefield" },
  "selections": [{ "entrantId": 24481002, "character": { "id": 1846, "name": "Kazuya" } }]
}
```

`derivedCharacters` summarizes unique character names per entrant in
first-appearance order across games. This is derived, not an API field.

Character and stage data only exists when the set was reported with it. In a
2026-09 sample, late rounds (Top 8 / streamed) had it on about 90% of completed
sets; early pools about 5%. An empty `games` array means not reported, not that
no games were played. Typical flow: `get_event_sets` (e.g. `phaseIds` for Top 8)
→ pick set ids → `get_set_games`. For many sets at once, `get_event_sets` with
`includeGames: true`.

## Examples

Things to ask an MCP client once connected:

```text
Find upcoming Super Smash Bros. Ultimate tournaments this week.

Get the entrants and seeds for this start.gg tournament URL:
https://www.start.gg/tournament/.../event/...

Show me completed sets from Top 8 of that event.

Which streams are assigned to sets at this tournament?

What were the biggest seed upsets in this event?
```

A standalone example application (videogame lookup → upcoming tournaments →
sets → upset candidates by seed difference) lives in
[`examples/smash-ultimate-watcher`](https://github.com/tomo789/startgg-mcp-server/blob/HEAD/examples/smash-ultimate-watcher/).

## Environment variables

| Variable                | Required | Default | Purpose                                                         |
| ----------------------- | -------- | ------- | --------------------------------------------------------------- |
| `STARTGG_TOKEN`         | yes      | —       | start.gg API token                                              |
| `STARTGG_ENABLE_WRITES` | no       | `false` | Reserved. No write tools exist yet; the flag only logs a notice |
| `STARTGG_RATE_LIMIT`    | no       | `75`    | Requests per 60s window (hard-capped at 80)                     |
| `STARTGG_TIMEOUT_MS`    | no       | `30000` | Per-request HTTP timeout                                        |
| `STARTGG_CACHE`         | no       | `on`    | Set `off` to disable the in-memory cache                        |

The API endpoint is deliberately not configurable through the environment: the
token is only ever sent to `api.start.gg`. When using the client as a library
(tests, tooling), inject `apiUrl`/`fetchFn` via the `StartggClient` constructor.

Out-of-range or non-numeric values for `STARTGG_RATE_LIMIT` / `STARTGG_TIMEOUT_MS`
fall back to the default and log a warning on stderr.

Without `STARTGG_TOKEN` the server still starts and lists tools, but every
call returns a clear `AUTH_ERROR` explaining how to fix it.

## Security

- The token is read from the environment only, sent only to `api.start.gg`, and never included in tool output, logs, or error messages
- All tools are read-only; no mutations are implemented
- `.env` files are git-ignored; use `.env.example` as a template
- User-supplied input is schema-validated before any request is built

## Rate limits

start.gg allows **80 requests per 60 seconds** and at most **1000 objects per
request**. This server:

- keeps a sliding-window budget below the request limit (default 75/60s)
- retries `429` (honoring `Retry-After`) and transient 5xx errors with exponential backoff, at most 3 retries — GraphQL errors are never retried
- caps `perPage` per tool so responses stay under the 1000-object complexity limit (sets are expensive: ~26+ objects each, hence `perPage <= 30`)
- caps `fetchAll` at 5 pages per tool (output is meant for an LLM context, so it stays around 100 KB of compact JSON) and reports `truncated: true` when it stops early

## Development

```bash
npm run dev        # run from source (tsx)
npm run build      # compile to dist/
npm run typecheck  # tsc --noEmit
npm run lint       # eslint
npm run format     # prettier
```

GraphQL documents live in `graphql/*.graphql` (one file per domain, multiple
named operations per file; requests select an operation via `operationName`).
Schema facts verified against the live API are recorded in
[`docs/startgg-api-notes.md`](https://github.com/tomo789/startgg-mcp-server/blob/HEAD/docs/startgg-api-notes.md) — read it before
adding fields.

## Testing

```bash
npm test                    # unit tests (fixtures/mocks only, no network)
STARTGG_INTEGRATION=1 STARTGG_TOKEN=... npm test   # + 2 live API smoke tests
STARTGG_TOKEN=... node scripts/smoke.mjs           # full stdio end-to-end smoke (~10 live requests)
```

Unit tests cover the URL resolver, normalizers, input validation, pagination,
GraphQL/HTTP error handling, the rate limiter, and the cache.

## License

[MIT](https://github.com/tomo789/startgg-mcp-server/blob/HEAD/LICENSE)

