k6-loadtest-mcp
This server lets you generate, run, and analyze k6 load tests by describing them in plain English. Key capabilities:
Generate k6 scripts from a structured test plan (base URL, request mix, load profile, thresholds).
Smoke-test scripts with 1 virtual user / 1 iteration to catch errors early.
Run full load tests against allowed hosts with control over VUs, duration, and stages.
Retrieve structured metrics including p50/p90/p95/p99 latency, error rate, RPS, per-endpoint breakdown, and threshold pass/fail.
Automate the full pipeline with a single
run_full_testcall.Safety guardrails: host allowlist (defaults to localhost), VU cap of 1000, and redirects disabled.
Works as an MCP server with Claude Desktop/Code, no separate API key required, and includes a local demo setup.
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., "@k6-loadtest-mcpRun a load test on http://localhost:4000/checkout with 40 virtual users over 1 minute"
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.
k6-loadtest-mcp
Describe an API in plain English. Get a runnable k6 load test, executed and reported.
Pipeline · Guardrail · Setup · Tools · Dashboard · Try it live
This MCP server turns a plain-English API description (or a few example requests) into a runnable k6 load test, runs it, and hands back structured, deterministic metrics — p50/p90/p95/p99 latency, error rate, RPS, per-endpoint breakdown, threshold pass/fail — for the host LLM (Claude Desktop / Claude Code) to turn into a human-readable performance report.
It's an MCP server, not a standalone CLI: the "understanding what to test" step is done by whichever Claude client you're using (no separate API key needed), and this server does the mechanical, deterministic parts — script generation, execution, and result parsing — in code, so the numbers in the report are computed, not guessed by an LLM eyeballing a log.
You: Load test my /checkout endpoint — ramp up to 50 concurrent users over 30s,
fail me if p95 goes over 250ms.
Claude: Generated script.js, smoke-tested it (1 VU, clean), ran the full load profile...
p95: 187ms error rate: 0.2% 312 req/s ✅ all thresholds passed
Latency stayed well under budget through the ramp. The one failure was a
single timeout at peak concurrency — worth a look if it recurs.Illustrative — actual output depends on the API under test and the TestPlan the host LLM builds.
Pipeline
flowchart TD
A["You describe the API<br/>(plain English or example requests)"] --> B["Host LLM builds a<br/>structured TestPlan"]
B --> C["generate_k6_script<br/>deterministic templating → reviewable script.js"]
C --> D["smoke_test_script<br/>1 VU / 1 iteration — catches errors fast"]
D --> E["run_load_test<br/>full run at the script's baked-in load profile"]
E --> F["get_test_metrics<br/>summary.json → structured RunMetrics"]
F --> G["Host LLM writes the<br/>narrative report"]
F -. optional .-> H["publish_report<br/>→ shared dashboard"]
G1["Guardrails: host allowlist,<br/>MAX_VUS cap, no redirects"]
C -. enforced before generation .-> G1
style G1 fill:#8680FF,color:#fff,stroke:#333
style H stroke-dasharray: 4 3run_full_test chains generate → smoke → run → parse in one call for convenience (and flags whether
a dashboard is configured, so Claude can ask before publishing — see Dashboard); the
granular tools let you inspect/adjust the script between
steps or re-run without regenerating.
Related MCP server: JMeter MCP Server (TypeScript Edition)
Guardrail
Load tests only run against hosts listed in ~/.k6-loadtest-mcp/config.json's allowedHosts
(localhost/127.0.0.1 by default — the file is created automatically on first run). The tools cannot
expand this list themselves — hitting a host you don't control or aren't authorized to test can look like
a denial-of-service attack. Add a host yourself, by hand, once you've confirmed you're authorized to
load-test it:
{ "allowedHosts": ["localhost", "127.0.0.1", "staging.myapp.example.com"] }This lives under your home directory (override with K6_LOADTEST_MCP_HOME), not inside the installed package —
so it's in the same predictable place whether you cloned this repo, npm installed it, or ran it via
npx github:<owner>/k6-loadtest-mcp. Run artifacts (runs/<timestamp>-<name>/script.js, summary.json, ...)
live alongside it at ~/.k6-loadtest-mcp/runs/.
Two more guardrails, both enforced in code rather than through anything a TestPlan (agent-authored, possibly
prompt-injected) can control:
VUs are capped at
MAX_VUS(1000) insrc/types.ts— a plan asking for more is rejected before a script is ever generated.Generated requests don't follow redirects (
redirects: 0). The host allowlist only vetsbaseUrl; without this, a 3xx response could silently send load at a host that was never approved. A redirect just shows up as its own status code — setexpectStatusto the 3xx code if a request is meant to test the redirect itself.
Setup
Prerequisites: Node.js 18+, and k6 installed and on your
PATH (or set K6_BIN to its full path).
npm install
npm run buildTry it locally first
A tiny demo API (demo/demo-api.mjs) is included so you can see the whole pipeline work without pointing it
at anything real:
npm run demo-api # starts http://localhost:4000 in one terminal
npm run harness # in another terminal: generates a script, smoke-tests, runs a staged
# load test against it, and prints structured metricsRegister with Claude Desktop / Claude Code
Claude Code, from a terminal (not inside a chat — there's no /mcp add slash command):
claude mcp add k6-loadtest-mcp -- node /absolute/path/to/k6-loadtest-mcp/dist/index.jsThe command after -- is what actually gets run — it must be node <path-to-dist/index.js>, not
just the path on its own (claude mcp add k6-loadtest-mcp dist/index.js without node/-- doesn't
work; claude needs a real executable as <commandOrUrl>, not a script path). If you'll also want
the dashboard later, -e sets env vars on the server at registration time — the
reliable way to do it, see the note in Pointing the MCP server at it:
claude mcp add k6-loadtest-mcp -e K6_LOADTEST_DASHBOARD_TOKEN=<token> -- node /absolute/path/to/k6-loadtest-mcp/dist/index.jsClaude Desktop, edit claude_desktop_config.json directly:
{
"mcpServers": {
"k6-loadtest-mcp": {
"command": "node",
"args": ["/absolute/path/to/k6-loadtest-mcp/dist/index.js"],
"env": { "K6_LOADTEST_DASHBOARD_TOKEN": "<token>" }
}
}
}(the env block is only needed if you're using the dashboard — omit it otherwise)
Or, once it's on a public GitHub repo, skip the local build entirely:
{
"mcpServers": {
"k6-loadtest-mcp": {
"command": "npx",
"args": ["-y", "github:<owner>/k6-loadtest-mcp"]
}
}
}Either way, fully quit and restart Claude Desktop/Claude Code after registering or changing this — it spawns the MCP server once at startup and doesn't notice config or environment changes made afterward. Retrying in the same conversation, or setting an env var in some other terminal window, won't reach the already-running server; this bites people (it bit me while building this) far more often than it should.
Then, in conversation: describe your API (or paste a few example curl commands), say what load profile you
want, and ask it to run and summarize a load test. The host LLM builds the structured TestPlan and drives
the four tools below.
Tools
Tool | Purpose |
|
|
| 1 VU / 1 iteration sanity check |
| Full run at the script's baked-in load profile |
| Parsed |
| All of the above chained, given a |
| Publishes a run's metrics to a deployed dashboard, returns a shareable URL |
TestPlan shape
{
"name": "checkout-api-smoke",
"baseUrl": "http://localhost:4000",
"requests": [
{ "name": "ListUsers", "method": "GET", "path": "/users", "weight": 5, "expectStatus": 200 },
{ "name": "GetReports", "method": "GET", "path": "/reports", "weight": 3, "maxDurationMs": 300 },
{ "name": "CreateOrder", "method": "POST", "path": "/orders", "weight": 2,
"body": { "item": "widget", "qty": 1 }, "expectStatus": 201 }
],
"loadProfile": {
"type": "ramping",
"stages": [{ "duration": "10s", "target": 10 }, { "duration": "20s", "target": 40 }, { "duration": "10s", "target": 0 }]
},
"thresholds": { "p95Ms": 250, "errorRatePct": 5 },
"thinkTimeMs": 200
}See src/types.ts for the full zod schema (also what the MCP client sees as the tool's input schema).
Dashboard
By default, a report is whatever the host LLM types into the chat — useful in the moment, gone once
the conversation scrolls. dashboard/ is an optional Spring Boot + Thymeleaf app you deploy once
(separately from the MCP server, not spawned by it) that your test runs get published to, giving you
a real, shareable URL instead. Every run also gets compared against the previous run of the same test
name, so latency/error-rate/RPS regressions show up automatically on the report page — no
separate baseline step.
It is not required — everything above works with zero dashboard configured, publish_report
just has nothing to publish to.
Screenshots from the live public demo below — that run list is real, published by an actual
run_full_test call against a real API, not staged. Deploying your own private instance (further
down) works exactly the same way, just gated behind your own login instead of open to the internet.
Try the live public demo
There's a real instance running at projects.krishanchawla.com/ai/loadtest-dashboard
— open to read without a login, and open to publish to as well, pinned to one target so it can't be
used as a general-purpose load-testing egress point (see Public demo mode for
what that means). Point your own k6-loadtest-mcp at it:
Add
playground.krishanchawla.comtoallowedHostsin your own~/.k6-loadtest-mcp/config.json(the guardrail can't add this for you — see Guardrail):{ "allowedHosts": ["localhost", "127.0.0.1", "playground.krishanchawla.com"] }Add the dashboard URL to that same file:
{ "dashboardUrl": "https://projects.krishanchawla.com/ai/loadtest-dashboard" }Then set the publish token on the MCP server's own registration, not as a plain shell env var — see Register with Claude Desktop / Claude Code for why that distinction matters. For Claude Code, either re-add the server with
-e:claude mcp add k6-loadtest-mcp -e K6_LOADTEST_DASHBOARD_TOKEN=0057371de9d3096616e06cd56a0872ae -- node /absolute/path/to/k6-loadtest-mcp/dist/index.jsor add
"env": { "K6_LOADTEST_DASHBOARD_TOKEN": "0057371de9d3096616e06cd56a0872ae" }to its entry in.mcp.json/claude_desktop_config.jsondirectly. Fully restart Claude Code/Desktop after this — same reason as above, the running server won't pick it up otherwise. (Yes, that token is intentionally in this README — public demo mode's real guard is the pinned target, not the token; see the section linked above.)Ask Claude to load test the playground's auth-token endpoint, e.g.:
Load test
POST https://playground.krishanchawla.com/api/scenarios/api-auth/tokenwith body{"username": "standard_user", "password": "Password123!"}, ramp to 20 users over 20s.Claude will notice a dashboard is configured and ask if you want this run published — say yes (or just ask directly) and you'll get back a real
projects.krishanchawla.com/ai/loadtest-dashboard/runs/{id}link, live for anyone to open.
Published runs are pruned after 3 days — it's a demo, not permanent storage. Only
playground.krishanchawla.com is accepted as a target; anything else gets a 403.
Deploying the dashboard
dashboard/ is a self-contained Spring Boot jar (its own embedded server) — not a WAR dropped into
an existing Tomcat, even if you already run one. Modern Spring Boot targets Jakarta EE (jakarta.*),
which only deploys onto Tomcat 10+; Tomcat 9-and-older (javax.*) can't load it at all, and the last
Spring Boot version that could is 2.7.x, EOL since Nov 2023 — not worth it for a publicly reachable
service. Embedding its own server sidesteps the mismatch entirely and leaves any existing Tomcat
untouched.
cd dashboard
mvn -q package # -> target/loadtest-dashboard.jarRun it (e.g. via systemd) with these env vars set:
Env var | Required | Purpose |
| yes, to accept reports | Bearer token |
| no | HTTP Basic credentials guarding every page except |
| yes, for correct links | The externally visible base URL (e.g. |
| no (default | Port the embedded server listens on. |
| no (default | Where the H2 database file lives. |
| no | Public demo mode only — pins accepted |
| no (default | Public demo mode only — auto-deletes runs older than N days, daily. |
# example systemd ExecStart -- private/team dashboard (default posture)
DASHBOARD_API_TOKEN=... DASHBOARD_BASIC_AUTH_USER=admin DASHBOARD_BASIC_AUTH_PASS=... \
DASHBOARD_PUBLIC_BASE_URL=https://loadtest.yourdomain.com \
java -jar /opt/loadtest-dashboard/loadtest-dashboard.jarPoint your existing nginx at it with one location/proxy_pass block to 127.0.0.1:8080 (or
whichever DASHBOARD_PORT) — no other nginx changes needed for this posture.
Public demo mode
The default posture above (Basic Auth required, any baseUrl accepted, nothing pruned) is right for
your own or your team's real data. It is not meant for "clone the repo, point it at my dashboard,
anyone can see it" — once DASHBOARD_API_TOKEN is published (e.g. in this README), it's not a secret
anymore, and an unrestricted ingest endpoint becomes an anonymous load-testing egress point, not just a
spam nuisance.
Public demo mode trades the login for a narrower, self-limiting deployment: reads are open, but writes are pinned to one fixed target — visitors get the real workflow (their own load test, their own report, visible without a login) without being able to point your server at arbitrary hosts.
# example systemd ExecStart -- public demo, pinned to one trusted target
DASHBOARD_API_TOKEN=... \
DASHBOARD_PUBLIC_BASE_URL=https://projects.yourdomain.com \
DASHBOARD_DEMO_TARGET_HOST=your-safe-target.yourdomain.com \
DASHBOARD_RETENTION_DAYS=3 \
java -jar /opt/loadtest-dashboard/loadtest-dashboard.jar
# DASHBOARD_BASIC_AUTH_PASS deliberately not setTwo more things this posture needs that the default doesn't:
Pick one or more targets you're certain can take anonymous concurrent traffic, and point
DASHBOARD_DEMO_TARGET_HOSTat them (comma-separated for more than one). Two ways to get a target: deploydemo/demo-api.mjs(bundled with this repo — in-memory, no real data, built for exactly this) on your own box, or reuse an existing sandbox you already control, the way the live demo above pins toplayground.krishanchawla.com,projects.krishanchawla.com— a practice API sandbox plus the same box's other self-hosted demo apps. Either way,DASHBOARD_DEMO_TARGET_HOSTchecks host (and port, if given) only, not path — pinning to a host opens everything currently (and later) served from it, not just the one endpoint you had in mind, so only add hosts you're comfortable being fully open this way.Rate-limit and cap the ingest endpoint at the nginx layer — the in-app payload check (
ApiTokenFilter) only catches requests that send aContent-Lengthheader; nginx enforces it properly regardless of encoding, and rate limiting isn't something to reinvent in application code when the reverse proxy already does it well:limit_req_zone $binary_remote_addr zone=dashboard_ingest:10m rate=5r/m; location /api/runs { limit_req zone=dashboard_ingest burst=5 nodelay; client_max_body_size 64k; proxy_pass http://127.0.0.1:8080; }
The bearer token still guards against casual/accidental hits, but in this mode DASHBOARD_DEMO_TARGET_HOST
is the real defense, not the token — treat it as public once it's in this README.
Pointing the MCP server at it
Once deployed, two settings on the machine(s) running k6-loadtest-mcp:
dashboardUrlin~/.k6-loadtest-mcp/config.json(same fileallowedHostslives in) — the dashboard'sDASHBOARD_PUBLIC_BASE_URL, e.g."dashboardUrl": "https://loadtest.yourdomain.com". Not set by default; nothing is ever sent anywhere until you add it yourself.K6_LOADTEST_DASHBOARD_TOKEN— must matchDASHBOARD_API_TOKEN. Kept out ofconfig.jsondeliberately, since it's a secret and that file isn't. Set this on the MCP server's own registration (claude mcp add ... -e K6_LOADTEST_DASHBOARD_TOKEN=..., or an"env"block in.mcp.json/claude_desktop_config.json— see Register with Claude Desktop / Claude Code), not as a plain shell/session env var. The server reads it once at startup; a variable set afterward in some other terminal, or "just retry" in the same conversation, never reaches the already-running process. This is the single most common way people (including while building this) get stuck here — ifpublish_reportkeeps saying the token isn't set after you're sure you set it, this is why.
With both set, run_full_test's response includes dashboardConfigured: true — Claude is instructed
to ask before publishing, not do it automatically, since a run's data becomes visible on whatever
that dashboard's own access posture is (see public demo mode vs. the private
default above). Call publish_report directly yourself at any point to (re-)publish a specific run,
including one driven through the granular tools instead of run_full_test.
Notes on k6's summary JSON (v2.1.0, verified by inspection)
Trend metrics (latencies):
avg/min/med/max/p(90)/p(95).p(99)is not included by default — the generated script always setssummaryTrendStatsto request it explicitly.medis the p50 — there's nop(50)key.Rate metrics (
http_req_failed, and this project's per-endpointfailed_<name>metrics):valueis already a 0–1 fraction;passesis confusingly the count where the metric was truthy — for a "failed" metric, that meanspasses= the failure count, not the success count.A metric's
thresholdsobject is keyed by the threshold expression with a boolean that means "was this breached", the opposite of "passed" — e.g. a passingp(95)<250(p95 actually 200ms) is reported asfalse, matching the CLI's own✓.src/k6/parseSummary.tsinverts this back to a plainokboolean. This was caught by cross-checking the JSON against the CLI's own✓/✗output during development — worth re-verifying if you upgrade k6.
What's not here yet
Standalone CLI mode — same pipeline, driven by a script with its own
ANTHROPIC_API_KEYinstead of an MCP host, for CI use. The core (src/k6/*,src/types.ts) is already host-agnostic; this would add a thin agent loop on top.JMeter export — k6 is the primary engine (LLM-friendly JS, clean JSON output); a JMX export path could be added via
openapi-generator's JMeter backend for orgs standardized on JMeter.OpenAPI/Postman ingestion — deriving the request mix automatically from a spec instead of the host LLM inferring it from a description.
CI-gate baseline diffing — the dashboard already diffs each run against the previous run of the same test
namefor human viewing; failing a CI job on regression would needpublish_report's response (or a new dashboard endpoint) surfaced as a pass/fail exit code.Auth token chaining —
TestPlanmodels a weighted mix of independent requests; there's no way to fetch a token in one request and reuse it in a later one, so anything needing a login step first (most real APIs) only works if you paste in a long-lived static token viaheaders. Found concretely while picking a target for the public demo above —playground.krishanchawla.com's auth-flow sandbox needs exactly this and can't be fully exercised yet.
Available Tools
5 toolsgenerate_k6_scriptGenerate a k6 load test scriptA
Turns a structured test plan (base URL, weighted request mix, load profile, thresholds) into a runnable k6 JavaScript script. Deterministic templating, not an LLM call -- reviewable before running. Returns a runDir that all later steps (smoke_test_script, run_load_test, get_test_metrics) take as input.
| Name | Required | Description | Default |
|---|---|---|---|
| plan | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It adds valuable context by stating it is deterministic templating (not an LLM call) and reviewable before running, and it discloses the return of a runDir. However, it omits side effects like file system writes, error conditions, or whether the operation is idempotent.
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?
Two sentences, front-loaded with the primary purpose, and the second sentence adds critical behavioral and integration context. No redundant words.
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?
The description conveys the tool's role and output sufficiently for a simple generator, but the absence of an output schema and annotations means more detail is needed about the returned runDir and potential side effects. The rich nested schema offsets some context gaps, but the description alone is not fully complete for a complex plan input.
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 0%, and the description only lists high-level components (base URL, weighted request mix, load profile, thresholds) without explaining the structure of the plan. It does not compensate for the low schema coverage; the user must rely on the nested schema descriptions for parameter meaning.
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 clearly states the tool's function: transforming a structured test plan into a runnable k6 JavaScript script. It identifies the specific resource (k6 script) and differentiates from siblings by positioning itself as the generation step that produces a runDir for downstream 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 description implies its use as the first step in a pipeline by naming all later steps (smoke_test_script, run_load_test, get_test_metrics) as consumers of its output. This gives clear context for when to use it, though it lacks explicit 'when not to use' or alternative scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_test_metricsGet structured metrics for a completed runA
Parses the k6 summary JSON into deterministic structured metrics: overall + per-endpoint p50/p90/p95/p99 latency, error rate, RPS, and threshold pass/fail. Use this data (not raw k6 console output) to write the human-readable performance summary -- the numbers here are computed in code, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| runDir | Yes | runDir returned by generate_k6_script, after run_load_test has completed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It states the tool parses a file (implying a read-only operation), produces deterministic metrics, and emphasizes the numbers are computed in code, not guessed. This adds useful reliability context, though it does not explicitly mention lack of side effects or failure behavior.
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?
Two sentences with no filler. The first sentence front-loads the core action and output metrics; the second sentence adds direct usage guidance. Every clause earns its place.
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?
The description covers what the tool does, what metrics it returns, and when to use it. Although no output schema exists, the list of metrics is explicit. It could add a note about behavior if the summary JSON is missing, but for a one-parameter tool, it is sufficiently complete.
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?
The schema description coverage is 100%, with the runDir parameter fully documented as the return value from generate_k6_script and intended for use after run_load_test completes. The tool description adds no further parameter detail, so the baseline score of 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 uses a specific verb 'parses' with the resource 'k6 summary JSON' and enumerates the exact metrics produced (p50/p90/p95/p99, error rate, RPS, threshold pass/fail). This clearly distinguishes it from sibling tools that generate scripts or run tests.
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?
Explicitly instructs to use this data (not raw console output) for writing the human-readable performance summary, giving a clear when-to-use directive. It also implies the prerequisite that the run must be completed through the parameter description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_full_testGenerate, smoke-test, run, and summarize a load test in one callA
Convenience tool that chains generate_k6_script -> smoke_test_script -> run_load_test -> get_test_metrics. Use the granular tools instead when you want to inspect/adjust the script between steps, or re-run the same script with different load without regenerating it.
| Name | Required | Description | Default |
|---|---|---|---|
| plan | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It transparently lists the internal pipeline with arrows, showing the sequence and that it runs the full flow. It does not mention failure behavior, duration, or real load side effects, but the chain itself is clearly disclosed.
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 two sentences: the first states the pipeline, the second gives alternative usage. It is front-loaded with the core purpose and every sentence earns its place with no filler.
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?
Given the tool's complexity as a multi-step convenience wrapper, the description adequately explains the workflow and when to use granular tools instead. It does not describe the return value or failure semantics, and there is no output schema, but the pipeline names (e.g., get_test_metrics) and alternatives make it reasonably complete for an agent.
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?
The description adds no parameter-level information. The schema has a single `plan` parameter with 0% top-level schema description coverage, and the description does not compensate by explaining what the plan should contain or how it maps to the chained tools. The nested schema is helpful, but the description itself contributes nothing to parameter semantics.
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 clearly states the tool's purpose: it chains generate_k6_script -> smoke_test_script -> run_load_test -> get_test_metrics. The title also explicitly says 'Generate, smoke-test, run, and summarize a load test in one call,' and the description distinguishes it from its granular siblings by naming them and framing this as a convenience wrapper.
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 description explicitly says to use the granular tools instead when you want to inspect/adjust the script between steps, or re-run the same script with different load without regenerating it. This gives clear when-to-use and when-not-to-use guidance, making the alternative usage obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_load_testRun the full k6 load testA
Executes the load test at the VUs/duration/stages baked into the generated script by generate_k6_script. Only runs against hosts listed in perf-agent.config.json's allowedHosts -- add a host there yourself (the tools won't do it for you) once you've confirmed you're authorized to load-test it. Can take as long as the test's own duration/stages; call smoke_test_script first.
| Name | Required | Description | Default |
|---|---|---|---|
| runDir | Yes | runDir returned by generate_k6_script |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full responsibility. It discloses the test duration, host restrictions, and authorization requirements, plus the ordering constraint with smoke_test_script. However, it does not mention what the tool returns or error behavior, which is a minor gap.
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 two sentences, front-loaded with the core action, and then adds necessary warnings and prerequisites. It is dense but not verbose, earning a high score.
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?
With one simple parameter and no output schema, the description covers prerequisites, duration, and host configuration. It lacks explicit mention of how to retrieve results, but the existence of get_test_metrics as a sibling tool partially compensates.
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?
The single parameter runDir is fully described in the schema as returned by generate_k6_script. The description reinforces that context but adds no additional semantics beyond what the schema already provides, so the baseline of 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?
The description clearly states the tool executes a load test using pre-generated parameters, with a specific verb ('executes') and resource ('load test at the VUs/duration/stages baked into the generated script'). It distinguishes itself from siblings by referencing the script from generate_k6_script and implying smoke_test_script is a lighter alternative.
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?
Provides explicit when-to-use guidance: call smoke_test_script first, and prerequisites like adding the host to allowedHosts after confirming authorization. It also tells the user what the tool will not do ('the tools won't do it for you'), which clarifies responsibility.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
smoke_test_scriptSmoke-test a generated k6 scriptA
Runs the script for 1 VU / 1 iteration to catch syntax or runtime errors fast, before committing to a full load test. Always call this before run_load_test.
| Name | Required | Description | Default |
|---|---|---|---|
| runDir | Yes | runDir returned by generate_k6_script |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden. It discloses the minimal execution scope (1 VU/1 iteration), the purpose (fast error detection), and the workflow position. It does not detail side effects or output, but for a smoke-test tool this is acceptable and non-contradictory.
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?
Two sentences, tightly packed with purpose, scope, and usage order. No wasted words or redundancy.
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 simple one-parameter tool with no output schema and no annotations, the description provides essential context: what it runs, at what scale, and when to invoke it. It does not explain return values or error behavior, but these are not critical for the primary workflow.
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%, with the only parameter (runDir) already described as being returned by generate_k6_script. The description adds no extra parameter-level detail beyond what the schema provides, but schema fully covers it.
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?
Description states a specific action ('Runs the script for 1 VU / 1 iteration') with clear scope and intent ('catch syntax or runtime errors fast'). It distinguishes itself from siblings like run_load_test by explicitly contrasting with a full load test.
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?
Provides explicit when-to-use guidance: 'Always call this before run_load_test.' This also implies when not to use it (i.e., not for full load testing) and names the key alternative.
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.
5 tool updates
v1.0.0- First observed
generate_k6_script - First observed
get_test_metrics - First observed
run_full_test - First observed
run_load_test - First observed
smoke_test_script
TDQS
Scored across 5 tools
Each tool has a clearly distinct role in the k6 testing pipeline: generate script, smoke test, full load test, parse metrics, and a convenience orchestrator. No two tools overlap in purpose, and the descriptions emphasize their unique inputs and outputs.
All tool names follow a consistent snake_case verb_noun pattern: generate_k6_script, smoke_test_script, run_load_test, get_test_metrics, run_full_test. The verbs clearly indicate actions, and nouns identify the target, making the set predictable.
Five tools is a well-scoped size for a load-testing server. Each tool maps to a necessary step in the workflow, and the convenience wrapper avoids redundancy without bloating the surface.
The core load-testing lifecycle is covered: script generation, smoke testing, full execution, metrics retrieval, and an all-in-one runner. Minor gaps exist around script editing or cleanup, but the provided workflow is complete enough for typical use.
Maintenance
Related MCP Connectors
AI-callable tools for API mocking, testing, monitoring, security, and automation.
Load & browser performance testing — drive MaxoPerf from your AI agent with your API key.
Drive OctoPerf load testing from any AI agent: import, edit, validate, run scenarios, read metrics.
End-to-end API testing — generate and run tests from OpenAPI, curl, Postman, or real user traffic.
Related MCP Servers
- AlicenseCqualityDmaintenanceA Model Context Protocol (MCP) server implementation that allows AI assistants to run k6 load tests through natural language commands, supporting custom test durations and virtual users.226MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to programmatically create, execute, and analyze Apache JMeter performance tests. It supports automated bottleneck detection, report generation, and distributed testing management through natural language.MIT
- FlicenseNot gradedqualityCmaintenanceIntegrates Apache JMeter with AI assistants to run and manage load tests through natural language. It enables users to execute test plans, parse results, inspect test structures, and compare performance metrics across different runs.-
- FlicenseNot gradedqualityDmaintenanceEnables running k6 load tests with customizable duration and virtual users via natural language, with real-time output and LLM-powered analysis.1-