URL targets
mcptest accepts two target shapes for an MCP server: a stdio subprocess (command: [...]) or a running HTTP endpoint (url: ...). URL targets cover the deployed-server case, so they are first-class everywhere the docs talk about a "server."
This page collects six worked examples plus the supporting flags so you can pick a recipe and copy it into your mcptest.yml (or scaffold one with mcptest init --url <BASE>). All examples assume Streamable HTTP (the spec default); the runner negotiates SSE fallback automatically when the server advertises it.
For the broader secret resolution rules referenced below, see secrets-and-variables.md. For network diagnostics shown by mcptest doctor --url and the runner, see the "Layered failures" section at the bottom.
Scaffolding
mcptest init --url https://mcp.example.com/v1 writes a URL-keyed server: block and a smoke test that exercises the MCP initialize handshake. Pass --auth bearer --auth-env MCPTEST_API_TOKEN to add a bearer recipe, --auth oauth2 for the PKCE (Proof Key for Code Exchange) flow, or --auth custom-header --header-name X-Tenant-Id --header-env TENANT_ID for a custom header. Add --wait-for-ready 60s to scaffold a readiness poll under server.wait_for_ready.
Example 1: Local development (no auth)
A local HTTP server during development, no authentication required.
# yaml-language-server: $schema=https://mcptest.sh/schema/v1.json
servers:
local:
url: "http://localhost:8080/mcp"
tools:
- name: "lists tools without error"
server: local
tool: "tools/list"
args: {}
expect:
- target: "error"
matcher:
exact: null
message: "tools/list should not return an error"
Run it: mcptest run tests/.
Example 2: Staging preview with a bearer token
A Vercel or Render preview URL guarded by a bearer token. The token lives in an env var so the YAML stays free of secrets.
servers:
staging:
url: "https://mcp-preview-abc123.vercel.app/mcp"
auth:
bearer_token_env: MCPTEST_STAGING_TOKEN
wait_for_ready: 60s
Set the env var in .env (auto-loaded) or export it before running:
export MCPTEST_STAGING_TOKEN=...
mcptest run tests/
The wait_for_ready field polls initialize until the server is up, which is the common preview-deploy gotcha. The runner exits with code 3 if the budget elapses.
Example 3: Production with OAuth 2.1 + PKCE
OAuth 2.1 with PKCE and dynamic client registration is the specification-default auth flow for HTTP MCP servers. mcptest login runs the browser-based authorization once and caches an access token locally; the runner refreshes the token automatically when it expires .
servers:
production:
url: "https://mcp.example.com/v1"
auth:
oauth:
flow: authorization_code_pkce
mcptest login --server production
mcptest run tests/
Example 4: Cloudflare Access wrapped server
A server fronted by Cloudflare Access uses a service token (the CF-Access-Client-Id plus CF-Access-Client-Secret header pair). The client id is non-sensitive; the secret lives in an env var.
servers:
cf_protected:
url: "https://mcp.acme.example/v1"
headers:
CF-Access-Client-Id: "abc123.access"
CF-Access-Client-Secret-Env: CF_ACCESS_CLIENT_SECRET
The -Env suffix tells the runner to read the value from the environment at connect time and to redact it from logs.
Example 5: Multi-tenant SaaS routing
A multi-tenant server that dispatches by X-Tenant-Id. The tenant identifier is non-sensitive and varies per environment, so it lives in the YAML's variables: block with ${VAR} interpolation pulling from the resolved variable map.
variables:
tenant: ${TENANT_ID}
servers:
saas:
url: "https://mcp.saas.example/v1"
auth:
bearer_token_env: SAAS_API_KEY
headers:
X-Tenant-Id: "${tenant}"
TENANT_ID=acme SAAS_API_KEY=... mcptest run tests/
Example 6: Enterprise self-signed cert
A server inside an enterprise network that uses a private CA. Point the runner at the bundle file with --ca-bundle (or server.http.ca_bundle in the YAML); never disable TLS verification in production.
servers:
internal:
url: "https://mcp.internal.acme.com/v1"
auth:
bearer_token_env: ACME_INTERNAL_TOKEN
http:
ca_bundle: /etc/ssl/certs/acme-internal-ca.pem
For a one-off local probe against a self-signed dev server (no CA bundle handy), pass --insecure-skip-verify. The runner prints a loud banner so this never sneaks into a CI job by accident.
Doctor: layered diagnostics
Before running the suite, mcptest doctor --url <BASE> walks the seven network layers and prints a single line per layer:
mcptest doctor --url https://mcp.example.com/v1
[DNS] OK: resolved mcp.example.com to 2 address(es)
[TCP] OK: connected to 198.51.100.42:443
[TLS] OK: TLS handshake to mcp.example.com succeeded
[AUTH] OK: credentials accepted by the server
[MCP-INIT] OK: initialize handshake succeeded
On a failure the row turns FAIL and a hint: line points at the most likely next step. The runner uses the same shape for in-flight failures so a TLS error from doctor looks identical to a TLS error from a test step.
Common flags
| Flag | Purpose |
|---|---|
--server-url <URL> | Override every YAML server's URL for one run. Used by preview-deploy CI. |
--server-auth-bearer-env <NAME> | Swap the bearer env var name without editing YAML. |
--header <NAME=VALUE> | Send an extra literal header on every request. |
--header-env <NAME=VAR> | Send an env-backed header (the runner reads VAR at connect time). |
--http-timeout <SECONDS> | Per-request timeout, override server.http.timeout. |
--connect-timeout <SECONDS> | TCP connect timeout. |
--ca-bundle <PATH> | PEM bundle for an internal CA. |
--insecure-skip-verify | Disable TLS verification (local dev only). |
--wait-for-ready[=DUR] | Poll initialize until success or budget elapses. |
For background on the secret resolution model see secrets-and-variables.md. For the OAuth flow specifics see auth.md.
Behind a corporate proxy
Corporate networks usually tunnel outbound HTTP through a CONNECT proxy. mcptest works with that out of the box because reqwest (the HTTP client mcptest builds on) reads HTTP_PROXY, HTTPS_PROXY, and NO_PROXY from the environment at startup. The same env-var pickup applies to MCP servers (the request hitting your staging URL) and to LLM providers used by agent tests.
export HTTPS_PROXY=http://proxy.corp:8080
export NO_PROXY=localhost,.internal.example
mcptest run --config tests/mcp.yaml
When env vars are not an option, every flag below overrides the auto-pickup. They are global, so they apply to the server connection and to provider calls in the same run.
| Flag | Purpose |
|---|---|
--proxy <URL> | Catch-all proxy for both HTTP and HTTPS targets. |
--http-proxy <URL> | Plain-HTTP only. Wins over --proxy. |
--https-proxy <URL> | HTTPS only. Wins over --proxy. |
--noproxy <HOSTLIST> | Comma-separated hosts to bypass (mirrors NO_PROXY). |
--no-proxy | Disable every proxy, including env-var pickup. |
Verify what is in effect:
mcptest doctor # one-line proxy summary
mcptest run --print-config # same summary plus resolved suite
Common patterns:
# Route through the corporate proxy but go direct to localhost.
mcptest --https-proxy http://proxy.corp:8443 \
--noproxy localhost,.internal \
run
# A system-wide HTTPS_PROXY is set but this single run should go direct.
mcptest --no-proxy run
# Same proxy for both schemes, authenticated.
mcptest --proxy http://user:pass@proxy.corp:8080 run
Authentication in the proxy URL follows curl rules. Credentials in http://user:pass@host:port are sent automatically; an upstream that requires Negotiate or NTLM auth is not supported by reqwest.