Skip to main content
Glama
speedtest-tracker

speedtest-tracker

by si-essence
README.md
# speedtest-tracker

MCP connector for a self-hosted [Speedtest Tracker](https://github.com/alexjustesen/speedtest-tracker) server. It was tested against Speedtest Tracker v1.15.1. It speaks the v1 JSON API over stdio and over stateless Streamable HTTP on localhost.

Speedtest Tracker is MIT software. Copyright (c) 2022 Alex Justesen. This connector does not copy the PHP application. `vendor/speedtest-openapi/openapi.json` is a copy of the v1.15.1 OpenAPI document. `vendor/speedtest-openapi/NOTICE` records that license. The connector is not affiliated with Speedtest Tracker.

`speedtest.routes.json` lists every operation in that spec, plus two public routes from `routes/api.php`. 8 operations are tools. 1 is an exclusion. `scripts/gen-operations.mjs` writes `src/operations.ts` from the spec. Do not edit `src/operations.ts` by hand.

`SPEEDTEST_TRACKER_URL` and `SPEEDTEST_TRACKER_API_TOKEN` are required. There is no default origin.

## Setup

```bash
npm install
npm run ci
npm start
npm run start:http
```

`npm start` speaks stdio. `npm run start:http` serves Streamable HTTP at `http://127.0.0.1:3000/mcp` and `GET /health`. HTTP mode has no authentication of its own. Keep it on localhost.

```json
{
  "mcpServers": {
    "speedtest-tracker": {
      "command": "node",
      "args": ["/workspace/connectors/speedtest-tracker/dist/index.js"],
      "env": {
        "SPEEDTEST_TRACKER_URL": "http://127.0.0.1:8098",
        "SPEEDTEST_TRACKER_API_TOKEN": "...",
        "SPEEDTEST_TRACKER_ALLOW_WRITES": "false",
        "SPEEDTEST_TRACKER_TOOLSETS": "results,stats,servers,meta"
      }
    }
  }
}
```

Create the token in the Speedtest Tracker UI. The read tools need the Sanctum ability `results:read`. Listing Ookla servers needs `ookla:list-servers`. Queuing a test needs `speedtests:run`.

Docker, HTTP, no authentication, keep it on localhost:

```bash
docker build -t speedtest-tracker-mcp .
docker run -p 127.0.0.1:3000:3000 \
  -e SPEEDTEST_TRACKER_URL=http://127.0.0.1:8098 \
  -e SPEEDTEST_TRACKER_API_TOKEN=... \
  speedtest-tracker-mcp
```

Do not put secrets in the image.

Regenerate the registry after a spec bump.

```bash
npm run gen:operations
```

`scripts/live-check.mjs` talks to a real server over stdio. It reads the full token from `SPEEDTEST_TRACKER_API_TOKEN` or from `SPEEDTEST_TRACKER_API_TOKEN_FILE` (default `/workspace/tools/speedtest/token.full`). It reads the read-only token from `SPEEDTEST_TRACKER_RO_TOKEN` or from `SPEEDTEST_TRACKER_RO_TOKEN_FILE` (default `/workspace/tools/speedtest/token.ro`). It unsets `DATABASE_URL`. It sets `SPEEDTEST_TRACKER_TOOLSETS=all` for the child process. It prints pass or fail lines only, and it redacts both tokens.

## Config

| Variable | Meaning |
| --- | --- |
| `SPEEDTEST_TRACKER_URL` | Required. Origin, `http` or `https`, no userinfo, query, or hash. Example `http://127.0.0.1:8098`. |
| `SPEEDTEST_TRACKER_API_TOKEN` | Required. Sent as `Authorization: Bearer` on authenticated routes. Redacted in logs, errors, and tool results. |
| `SPEEDTEST_TRACKER_ALLOW_WRITES` | Must be the literal `true` before a confirmed run is sent. |
| `SPEEDTEST_TRACKER_TOOLSETS` | Comma list, or `all`. Default is the read-only set below. |
| `SPEEDTEST_TRACKER_PER_MINUTE` | Local request budget. Default 30. Cache hits do not spend it. |
| `SPEEDTEST_TRACKER_TIMEOUT_MS` | Upstream timeout. Default 20000. |
| `SPEEDTEST_TRACKER_CACHE_TTL_SEC` | Read cache TTL. Default 60. Writes clear the cache. |
| `SPEEDTEST_TRACKER_CONTACT` | Contact token in the User-Agent. Must not contain the API token. |
| `MCP_TRANSPORT` | `stdio` or `http`. `--http` overrides. |
| `PORT` | HTTP port. Default 3000. |

Invalid values are reported by field name and issue code. The rejected value is not included.

Every request sends `Accept: application/json`. Public routes send no bearer token. Authenticated routes send the token.

## Safety

Default toolsets are reads. `run` is off until `SPEEDTEST_TRACKER_TOOLSETS` includes `run` or is `all`.

A run on an enabled toolset still needs `confirm` set to the boolean `true` and `SPEEDTEST_TRACKER_ALLOW_WRITES=true`. The string `"true"` is rejected. Otherwise the tool returns a dry-run preview of method, path, query, and body, and it sends nothing.

`queue` posts `POST /api/v1/speedtests/run`. The tracker creates a waiting result and returns. It does not wait for Ookla to finish. `server_id` is an optional query parameter.

HTTP 401 is unauthorized. HTTP 403 is forbidden. When the body is one of the tracker's missing-ability messages, the error also names the ability (`results:read`, `speedtests:run`, or `ookla:list-servers`). HTTP 404 is not found. HTTP 400, 409, and 422 are invalid input. HTTP 429 includes Retry-After when the header is present. Other failures are server, network, or timeout. Response bodies are capped at 1,000,000 bytes.

## Tools

Default `SPEEDTEST_TRACKER_TOOLSETS` publishes 4 tools and 7 read operations. `SPEEDTEST_TRACKER_TOOLSETS=all` publishes 5 tools and 8 operations. Each tool takes `action` plus optional `params`, `query`, `body`, and, on the run tool, `confirm`.

`action` `help` with optional `target` returns the fields for one action.

| Toolset | Tool | Operations | Default |
| --- | --- | --- | --- |
| results | `speedtest_tracker_results` | list, get, latest | yes |
| stats | `speedtest_tracker_stats` | aggregated | yes |
| servers | `speedtest_tracker_servers` | list | yes |
| meta | `speedtest_tracker_meta` | healthcheck, latest | yes |
| run | `speedtest_tracker_run` | queue | no |

`results` `list` accepts `sort` (for example `-created_at`), `page[size]`, `page[number]`, and `filter[ping]`, `filter[download]`, `filter[upload]`, `filter[healthy]`, `filter[status]`, `filter[scheduled]`, `filter[start_at]`, and `filter[end_at]`. The OpenAPI document names the page size `per.page`. The v1.15.1 app reads `page[size]` and `page[number]`. `latest` takes the same filters and no sort. `get` takes `params.id`.

`stats` `aggregated` takes `filter[start_at]` and `filter[end_at]`. A date with no time includes that whole day on `end_at`. The ability is `results:read`.

`servers` `list` is `GET /api/v1/ookla/list-servers`. The ability is `ookla:list-servers`.

`meta` `healthcheck` is `GET /api/healthcheck`. `meta` `latest` is the deprecated public `GET /api/speedtest/latest`. Download and upload on that route are megabits. The v1 result fields are bytes.

## What this connector leaves out

`GET /api/v1/speedtests/list-servers` is in the OpenAPI document. `routes/api/v1/routes.php` does not register it. Use `servers` `list`.

## Other speedtest MCP servers

`gh search repos "speedtest tracker mcp"` and `gh search repos "speedtest-tracker mcp"` on 2026-11-03 returned no repositories. A code search for `speedtest-tracker` together with `mcp` did not find a connector for this app. The provider file in `api-evangelist/providers` sets `mcp_server: false` for Speedtest Tracker.

Nearby GitHub projects run a speed test themselves. They do not read a Speedtest Tracker history or send a Sanctum token.

[inventer-dev/mcp-internet-speed-test](https://github.com/inventer-dev/mcp-internet-speed-test) lists `measure_download_speed`, `measure_upload_speed`, `measure_latency`, `measure_jitter`, `get_server_info`, and `run_complete_test`. It measures from the agent host. It has no confirm gate and no result history from this tracker.

[ipconfig-com/ipconfig-mcp](https://github.com/ipconfig-com/ipconfig-mcp) documents `get_my_ip`, `get_ip_location`, and `ping_test`. The repository description mentions Speedtest-MCP. The README tool list that was read does not include a speedtest tool.

[thakoreh/llm-speedtest-mcp](https://github.com/thakoreh/llm-speedtest-mcp) benchmarks model inference. It is not an internet speed test.

This connector is the one that calls Speedtest Tracker v1. Reads are the default. `queue` stays off until the `run` toolset is enabled, and a sent run still needs `confirm: true` and `SPEEDTEST_TRACKER_ALLOW_WRITES=true`.

TDQS

A3.5/5.0

Scored across 4 tools

Disambiguation4/5

The four tools are grouped by clear resource areas: meta, results, servers, and stats. The main ambiguity is that both meta and results expose a 'latest' action, and the meta description does not clarify what 'latest' means, which could cause misselection.

Naming Consistency5/5

All tool names follow a consistent snake_case pattern with the same speedtest_tracker_ prefix and a resource group suffix. This makes the set predictable and easy to scan.

Tool Count5/5

Four tools is a compact and appropriate surface for a speedtest tracker, with each tool representing a coherent resource group. Bundling multiple actions inside each tool keeps the count low without collapsing unrelated domains.

Completeness3/5

The surface covers read-oriented monitoring: health, latest results, result listing/getting, server listing, and aggregated stats. However, it lacks important lifecycle operations such as triggering a speedtest, deleting or managing results, and creating/updating servers, which may limit common tracker workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues