speedtest-tracker
Connects to a self-hosted Speedtest Tracker instance (v1 JSON API) to read Ookla/Speedtest history and results: list, fetch, and get the latest speed tests with filters, view aggregated download/upload/ping statistics over date ranges, list available Ookla servers, and check server health. Optionally queues a new Ookla speed test (with dry-run preview and explicit confirmation/write gating) when the run toolset is enabled.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@speedtest-trackershow my average download speed over the past week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
speedtest-tracker
MCP connector for a self-hosted 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
npm install
npm run ci
npm start
npm run start:httpnpm 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.
{
"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:
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-mcpDo not put secrets in the image.
Regenerate the registry after a spec bump.
npm run gen:operationsscripts/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.
Related MCP server: sql-explorer-mcp
Config
Variable | Meaning |
| Required. Origin, |
| Required. Sent as |
| Must be the literal |
| Comma list, or |
| Local request budget. Default 30. Cache hits do not spend it. |
| Upstream timeout. Default 20000. |
| Read cache TTL. Default 60. Writes clear the cache. |
| Contact token in the User-Agent. Must not contain the API token. |
|
|
| 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 |
| list, get, latest | yes |
stats |
| aggregated | yes |
servers |
| list | yes |
meta |
| healthcheck, latest | yes |
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 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 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 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.
Available Tools
4 toolsspeedtest_tracker_metaBRead-only
speedtest_tracker_meta covers the meta toolset (2 operations). Calls go to SPEEDTEST_TRACKER_URL. These routes are public and send no bearer token. Every request sends Accept: application/json. action help with target returns one action's parameters. Actions: healthcheck, latest.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON object or JSON array. Secrets are redacted in output. | |
| query | No | Query parameters, such as page, searchTerm, and domain. | |
| action | Yes | Speedtest Tracker operation to call, or help. | |
| params | No | Path parameters, such as shortCode, tag, and domain. | |
| target | No | With action help, the action whose parameters to describe. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, open-world, non-destructive behavior. The description adds meaningful operational context: the target URL, public/no-bearer auth, and the Accept header. It stops short of describing rate limits or what the main actions return.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the toolset and actions. It could be tightened by grouping the transport/auth details together and by placing the help/target behavior closer to the action list, but there is little wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It covers auth, endpoint, and action inventory, which is solid for a read-only meta tool. However, without an output schema, the description does not explain what healthcheck or latest return, leaving an agent to infer the main action semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the input schema already documents action, target, body, query, and params. The description's note that help with target returns an action's parameters restates the schema rather than adding new per-action parameter requirements.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the meta toolset, lists the concrete actions healthcheck and latest, and explains the help action. It lets an agent distinguish this from the results/servers/stats siblings at a high level, though 'meta toolset' could be more explicit about what each action returns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance is given: it does not say when to pick healthcheck versus latest, or when this meta tool should be chosen over results, servers, or stats. The only procedural note is how help with target behaves.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
speedtest_tracker_resultsBRead-only
speedtest_tracker_results covers the results toolset (3 operations). Calls go to SPEEDTEST_TRACKER_URL. Authenticated routes send Authorization Bearer. Required abilities: results:read. Every request sends Accept: application/json. action help with target returns one action's parameters. Actions: list, get, latest.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON object or JSON array. Secrets are redacted in output. | |
| query | No | Query parameters, such as page, searchTerm, and domain. | |
| action | Yes | Speedtest Tracker operation to call, or help. | |
| params | No | Path parameters, such as shortCode, tag, and domain. | |
| target | No | With action help, the action whose parameters to describe. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, non-destructive, openWorld, so the safety profile is covered; the description adds genuinely non-obvious operational context: the target server comes from SPEEDTEST_TRACKER_URL, requests carry a Bearer token, and the caller needs the results:read ability. It does not describe result shape, pagination, or ordering for `latest`, but the auth/environment disclosure is real value beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the scope and the action list is kept to the end. The middle sentences are telegraphic ("Authenticated routes send Authorization Bearer", "Required abilities: results:read") but each carries distinct operational information, so there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter tool with nested objects and no output schema, the definition covers transport, auth, and the action set, but leaves gaps around what each action returns, which query/params keys apply to which action, and whether list is paginated. An agent could invoke it, but would likely need to call `help` to use it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so action, target, query, params, and body are already documented in structured form. The description only restates the help+target behavior, adding no syntax, expected keys per action, or examples beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource domain ("results toolset") and enumerates the concrete operations ("list, get, latest"), which lets an agent separate it from the meta/servers/stats siblings. It never states what a "result" actually is (a recorded speedtest measurement), so the resource noun stays somewhat abstract.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage guidance is the mechanical note that "action help with target returns one action's parameters." There is no explanation of when to use list vs get vs latest, no prerequisites, and no pointer to which sibling tool to prefer for adjacent data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
speedtest_tracker_serversBRead-only
speedtest_tracker_servers covers the servers toolset (1 operations). Calls go to SPEEDTEST_TRACKER_URL. Authenticated routes send Authorization Bearer. Required abilities: ookla:list-servers. Every request sends Accept: application/json. action help with target returns one action's parameters. Actions: list.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON object or JSON array. Secrets are redacted in output. | |
| query | No | Query parameters, such as page, searchTerm, and domain. | |
| action | Yes | Speedtest Tracker operation to call, or help. | |
| params | No | Path parameters, such as shortCode, tag, and domain. | |
| target | No | With action help, the action whose parameters to describe. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which already mark it read-only, non-destructive, and open-world), the description adds concrete operational context: the SPEEDTEST_TRACKER_URL target, Bearer auth on authenticated routes, the required 'ookla:list-servers' ability, and the Accept header. It does not discuss rate limits or response shape, but the auth/ability constraints are genuinely useful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is compact and all sentences carry information, but the opening 'covers the servers toolset (1 operations)' is meta boilerplate, and the fragmented header-style sentence sequence ('Every request sends Accept: application/json.') is less front-loaded than a single clear purpose sentence would be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter gateway tool with nested objects and no output schema, the description covers auth, routing, and the help action, but it does not explain what the list action returns or which query/params fields are meaningful for listing servers. Adequate but incomplete for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents action, target, body, query, and params. The description only clarifies the help/target interaction and the enum values for action, adding little beyond the schema; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It states the tool covers the 'servers toolset' with a single action 'list' and a required ability 'ookla:list-servers', which implies listing speedtest servers. But the wording is meta/framework-oriented ('covers the servers toolset (1 operations)') rather than a clean verb+resource statement, and it does not clearly distinguish it from the sibling results/stats/meta tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage guidance is 'action help with target returns one action's parameters', which explains the help action but not when to use this tool rather than speedtest_tracker_results or speedtest_tracker_stats. No alternatives or when-not-to-use conditions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
speedtest_tracker_statsBRead-only
speedtest_tracker_stats covers the stats toolset (1 operations). Calls go to SPEEDTEST_TRACKER_URL. Authenticated routes send Authorization Bearer. Required abilities: results:read. Every request sends Accept: application/json. action help with target returns one action's parameters. Actions: aggregated.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON object or JSON array. Secrets are redacted in output. | |
| query | No | Query parameters, such as page, searchTerm, and domain. | |
| action | Yes | Speedtest Tracker operation to call, or help. | |
| params | No | Path parameters, such as shortCode, tag, and domain. | |
| target | No | With action help, the action whose parameters to describe. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only, non-destructive annotations, it discloses the `SPEEDTEST_TRACKER_URL` destination, bearer authorization on authenticated routes, the required `results:read` ability, and the JSON Accept header. It does not explain aggregation scope or response behavior, but these are concrete operational details rather than repetition of the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the toolset scope before covering connection, authentication, discovery, and available actions. Telegraphic phrasing, the grammatical error `1 operations`, and some repetition of schema-visible information keep it from being excellent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-operation tool with a fully described schema, the authentication details and help mechanism make it minimally usable. With no output schema, however, the lack of any explanation of what `aggregated` returns or accepts leaves the agent dependent on discovery calls and unable to confidently distinguish it from the results sibling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The help-and-target explanation adds a little behavioral context, but largely duplicates the schema and provides no additional semantics for `body`, `query`, or `params` when invoking `aggregated`.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the Speedtest Tracker stats toolset and its sole `aggregated` action, but never states with a clear verb what that action retrieves or calculates. The distinction between aggregated stats and the sibling `speedtest_tracker_results` tool is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides useful invocation guidance by explaining that `action` set to `help` with `target` returns an action's parameters, and it enumerates `aggregated` as the available operation. It gives no explicit when-to-use guidance or sibling alternatives for choosing between stats, results, servers, and meta.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
speedtest_tracker_meta - First observed
speedtest_tracker_results - First observed
speedtest_tracker_servers - First observed
speedtest_tracker_stats
TDQS
Scored across 4 tools
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.
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.
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.
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
Related MCP Connectors
Read-only access to live ADSBiq aircraft and network state, with community contribution metadata.
Signed internet telemetry, read-only: DNS, TLS, WHOIS, reachability. Every record Ed25519-signed.
Query your own databases and Data Sets with read-only SQL, and build hosted dashboards.
Self-hostable uptime monitoring: create checks, read incidents, manage status pages.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides read-only access to PostgreSQL databases with schema inspection, query execution in multiple formats (JSON, CSV, Markdown), and query history tracking with built-in security features.-
- AlicenseNot gradedqualityFmaintenanceRead-only MCP server for SQL databases (SQL Server, Postgres, SQLite) with multi-server support and three-layer safety using AST validation and linting.MIT
- AlicenseAqualityDmaintenanceA self-hostable PostgreSQL MCP server for exploring database schemas and running guarded read/write queries with selectable access modes (readonly, readwrite, admin), plus a dry-run confirm workflow for safety.141MIT
- AlicenseDqualityBmaintenanceA local-first MCP server that provides safe, governed read-only SQL access to SQLite and PostgreSQL, with validation, limits, task tracking, and report generation.20MIT