Skip to main content

Model Context Protocol (MCP) server

Hostless ships a remote MCP server, so an AI agent can read the documentation and operate the platform as typed tools instead of scraping a dashboard. Point Claude, ChatGPT, or Cursor at one URL and it can search the docs, or deploy and manage apps, sites, workers, cron jobs, and databases using your own credentials and scopes.

There are two endpoints, and the difference is whether the agent needs an account: /mcp/docs is public and read-only, /mcp is authenticated and acts on your resources. The server is remote HTTP, hosted at https://mcp.hostless.app, so there is nothing to install.

EndpointAuthPurpose
POST /mcp/docsNoneRead Hostless documentation (docs_search, docs_get_page, docs_list)
POST /mcpAPI key, JWT, or OAuthCall platform APIs as typed tools (apps_*, projects_*, etc.)

The MCP service is separate from the REST API. Platform tool calls are proxied to the API configured on the MCP server (currently https://api.hostless.app/v1/*) using your credentials. API key scopes and project roles apply the same way as direct HTTP calls.

Use /mcp/docs when you only need documentation (onboarding agents, open-source examples, or users without a Hostless account). Use /mcp when the agent should manage apps, sites, databases, and other resources.

MCP base URL

https://mcp.hostless.app

Use the URL of your deployed MCP service if self-hosting.

RouteMethodPurpose
/healthGETLiveness check (no auth)
/.well-known/oauth-protected-resourceGETOAuth resource metadata for /mcp
/mcp/docsPOSTPublic documentation MCP (no auth)
/mcpPOSTPlatform API MCP (auth required)
/mcp, /mcp/docsGETNot supported (returns 405)

Health check

curl -sS "https://mcp.hostless.app/health"
{
"ok": true,
"service": "hostless-mcp",
"baseUrl": "https://api.hostless.app",
"docsMcpPath": "/mcp/docs"
}

Public documentation MCP (no auth)

Read-only access to Hostless guides, API reference, and framework tutorials. No API key, no JWT, no Authorization header.

Docs MCP URL

https://mcp.hostless.app/mcp/docs
ToolPurpose
searchOpenAI-compatible search; returns document ids, titles, and URLs
fetchOpenAI-compatible fetch; loads full document text and citation metadata by id
docs_searchSearch documentation by keyword; returns titles, paths, snippets, and public URLs
docs_get_pageLoad a full page by path (e.g. app/deployments, developers) — omit .md / .mdx
docs_listList every documentation page

Tips for agents

  • Prefer search then fetch for ChatGPT/OpenAI clients and deep-research-style retrieval.
  • docs_search, docs_get_page, and docs_list remain available for existing MCP clients.
  • Paths match the public docs site (https://docs.hostless.cloud/...) without the file extension.
  • For deploys, billing, or resource changes, connect to the platform API MCP instead.

Connect from Cursor (no auth)

Prefer a native HTTP MCP entry — no mcp-remote bridge and no env vars:

{
"mcpServers": {
"hostless-docs": {
"url": "https://mcp.hostless.app/mcp/docs"
}
}
}

Alternatively, use mcp-remote:

{
"mcpServers": {
"hostless-docs": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.hostless.app/mcp/docs"]
}
}
}

Restart Cursor after saving ~/.cursor/mcp.json (or your project MCP config).

Connect from Claude Desktop (no auth)

Add a streamable HTTP MCP server (Settings → Developer → MCP):

FieldValue
URLhttps://mcp.hostless.app/mcp/docs
Authorization headerOmit — not required

Local development (no auth)

Run the MCP HTTP server from the monorepo root:

npm run build:mcp
npm run start:mcp # default http://localhost:3333

For automatic rebuilds and HTTP server restarts when TypeScript files change, run npm run dev:mcp from the monorepo root instead. It uses .mcp-dev-dist separately from the API's build output. Stop an existing MCP process on port 3333 first, and keep the API running separately. Restart this command after .env changes; refresh your MCP client's tool list after changing tool registrations.

npm run start:mcp:http is an explicit alias. For stdio clients, use npm run --silent start:mcp:stdio and supply APP_TOKEN in the client process environment. These commands load hostless-api/.env. Keep the API running in a separate terminal (npm run dev:api, or npm run dev for API and frontend). Set API_BASE_URL to the API's actual address, for example http://localhost:5001 when its PORT is 5001. Rebuild MCP after source changes.

Docs are loaded automatically from hostless-docs/docs/ when the repo is checked out side by side. Set API_BASE_URL in hostless-api/.env if startup fails (required to boot the process even when you only use /mcp/docs).

Point Cursor at the local docs endpoint:

{
"mcpServers": {
"hostless-docs-local": {
"url": "http://localhost:3333/mcp/docs"
}
}
}

Verify locally:

curl -sS http://localhost:3333/health

Docs + platform API together

Use two MCP servers in the same config — docs without credentials, platform with your API key:

{
"mcpServers": {
"hostless-docs": {
"url": "https://mcp.hostless.app/mcp/docs"
},
"hostless": {
"url": "https://mcp.hostless.app/mcp",
"headers": {
"Authorization": "hlk_a1b2c3d4_your_secret_here"
}
}
}
}

For local platform API calls, use http://localhost:3333/mcp and credentials issued by the local API.

Local developer and admin tools

Set the following in hostless-api/.env. This example runs the API on port 5001; match API_BASE_URL and OAUTH_ISSUER_URL to your API's actual PORT.

PORT=5001
API_BASE_URL=http://localhost:5001
OAUTH_ISSUER_URL=http://localhost:5001
OAUTH_MCP_RESOURCE_URL=http://localhost:3333
MCP_HTTP_HOST=127.0.0.1
MCP_HTTP_PORT=3333
MCP_DEVELOPER_TOOLS_ENABLED=true
MCP_CONTEXT_TOOLS_ENABLED=true
MCP_ADMIN_TOOLS_ENABLED=true
MCP_TEST_DATA_ENABLED=true

Keep the API's configured MongoDB connection, JWT secret, and OAuth signing keys. The API and MCP process must use the same identity database and signing settings. Install dependencies from the updated lockfile before building; the MCP SDK requires the pinned Zod version (3.25.76).

Start the API with its infrastructure in one terminal:

cd hostless-api
npm run start:dev

This development script selects the hostless-dev Kubernetes context and starts the configured service port forwards. If your infrastructure is already running, start only the API with npx nest start --watch --path tsconfig.dev.json instead.

In a second terminal, build and start MCP:

cd hostless-api
npm run build
npm run start:mcp:http

Configure your local MCP client with Streamable HTTP:

{
"mcpServers": {
"hostless-local": {
"url": "http://localhost:3333/mcp",
"headers": {
"Authorization": "Bearer YOUR_LOCAL_SESSION_JWT"
}
}
}
}

Use a session JWT from signing in to the local API. Admin tools require that user to currently have the admin role. Developer tools also accept a local API key as the raw Authorization header (hlk_...) with the required scopes; API keys and OAuth grants do not unlock admin tools.

Check curl -sS http://localhost:3333/health, then reconnect the client and list tools. Restart both the API and MCP after changing feature flags. Test-data tools additionally require a disposable database and explicit membership through TEST_DATA_ENVIRONMENTS; see Disposable test-data scenarios.

For stdio, keep the API running, set APP_TOKEN in the MCP process environment to the local session JWT or API key, and have the client launch node /absolute/path/to/hostless-api/dist/mcp/mcp-main.js stdio. The stdio process loads hostless-api/.env automatically.

Platform API MCP (auth required)

Every POST /mcp request must include an Authorization header. Use the same tokens as the REST API:

Token typeHeader
API keyAuthorization: hlk_<prefix>_<secret>
API key (some clients)Authorization: Bearer hlk_<prefix>_<secret>
User JWTAuthorization: Bearer <access_token>
OAuth access tokenAuthorization: Bearer <oauth_access_token>

Create an API key in the dashboard (Account → Settings → API Keys) with the scopes you need (for example apps:read, projects:read). The MCP server does not accept a server-wide token — each client sends its own credential on every request.

OAuth for ChatGPT and Claude connectors

AI clients can connect to Hostless MCP using OAuth 2.0 authorization code + PKCE instead of pasting an API key. When a client has no token, POST /mcp returns 401 with a WWW-Authenticate header pointing at the protected-resource metadata URL.

Discovery

DocumentURL
Authorization server (API host)https://api.hostless.dev/.well-known/oauth-authorization-server
JWKS (API host)https://api.hostless.dev/.well-known/jwks.json
Protected resource (MCP host)https://mcp.hostless.app/.well-known/oauth-protected-resource

Flow (summary)

  1. Client discovers metadata from the URLs above.
  2. Client opens GET /v1/oauth/authorize on the API with PKCE (code_challenge / S256), resource=https://mcp.hostless.app, and a registered redirect_uri.
  3. Hostless redirects to the web app consent screen (/oauth/authorize). Sign in if needed, then Allow or Deny.
  4. Client exchanges the authorization code at POST /v1/oauth/token for a short-lived RS256 access token and refresh token.
  5. Client calls POST https://mcp.hostless.app/mcp with Authorization: Bearer <oauth_access_token>.

Scopes (v1): OAuth connectors receive read-only scopes (for example projects:read, apps:read, logs:read). Write and delete scopes are not granted to ChatGPT/Claude connectors in this release.

Revoke access: In the dashboard go to Account → Settings → Connected AI apps and revoke the connector. Access stops on the next MCP or API request.

Claude custom connector credentials

Claude requires a Client ID and Client secret in Advanced settings. Generate your own credentials in the dashboard (Account → Settings → Connected AI apps → Generate Claude credentials). Each credential pair is tied to your account — you do not need a shared platform secret.

  1. Generate credentials and copy the Client ID (hloc_…) and Client secret (shown once).
  2. In Claude: add a custom connector with MCP URL https://mcp.hostless.app/mcp.
  3. Open Advanced settings and paste the Client ID and Client secret.
  4. Complete OAuth consent when Claude connects.

ChatGPT

ChatGPT uses the public openai-chatgpt OAuth client. Per-connector redirect URLs (https://chatgpt.com/connector/oauth/{id}) are allowed via redirect URI prefix matching — no manual env configuration per connector.

Legacy shared Claude client

The seeded claude-custom-connector client remains for backward compatibility when OAUTH_CLAUDE_CLIENT_SECRET is set in server config. New integrations should use per-user credentials from the dashboard instead.

Connect from Cursor

Native HTTP MCP (Cursor 0.4.7+):

{
"mcpServers": {
"hostless": {
"url": "https://mcp.hostless.app/mcp",
"headers": {
"Authorization": "hlk_a1b2c3d4_your_secret_here"
}
}
}
}

Or use mcp-remote:

{
"mcpServers": {
"hostless": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://mcp.hostless.app/mcp",
"--header",
"Authorization:${HOSTLESS_TOKEN}"
],
"env": {
"HOSTLESS_TOKEN": "hlk_a1b2c3d4_your_secret_here"
}
}
}
}

Replace HOSTLESS_TOKEN with your API key (hlk_...) or Bearer <jwt>. On Windows, omit spaces around the colon in --header (Authorization:${HOSTLESS_TOKEN}) if Cursor mangles spaced arguments.

Connect from Claude Desktop

Add a streamable HTTP server entry (Claude Desktop → Settings → Developer → MCP). Point the URL at https://mcp.hostless.app/mcp and set the Authorization header to your hlk_... token or Bearer JWT.

Exact UI labels vary by Claude Desktop version; the required values are the MCP URL and the same Authorization header as above.

Available tools

Tools mirror common platform operations. Names follow {resource}_{action}:

ResourceTools
Projectsprojects_list, projects_get, projects_create, projects_patch, projects_delete
Appsapps_list, apps_get, apps_create, apps_patch, apps_delete
Sitessites_list, sites_get, sites_create, sites_patch, sites_delete
Workersworkers_list, workers_get, workers_create, workers_patch, workers_delete
Cron jobscron_jobs_list, cron_jobs_get, cron_jobs_create, cron_jobs_patch, cron_jobs_delete
Databasesdatabases_list, databases_get, databases_create, databases_patch, databases_delete

Tips for agents

  • Call projects_list first, then pass projectId when listing or creating apps, sites, workers, cron jobs, or databases.
  • Apps, sites, workers, and cron jobs are identified by name, not MongoDB id.
  • Project create/update/delete requires a user JWT; API keys can only read projects (projects:read).
  • Use public documentation MCP (/mcp/docs) to look up guides without an API key.

MCP errors

StatusMeaning
401 UnauthorizedPOST /mcp only — missing or invalid Authorization header (POST /mcp/docs never returns 401)
405 Method Not AllowedGET /mcp or GET /mcp/docs — use POST for MCP requests
Tool isError: truePlatform API error (missing scope, not found, validation, etc.) — body includes the API error
Docs tool isError: truePage not found or invalid argument (e.g. empty query or path)

Optional diagnostic tools

Diagnostic groups are disabled by default. Operators enable the matching flag on both the API and MCP processes after deploying the API support:

FlagTools
MCP_DEVELOPER_TOOLS_ENABLEDdeployments_list, deployments_get, logs_search, metrics_query, resource_health, project_overview, deployment_watch
MCP_CONTEXT_TOOLS_ENABLEDdeployment_compare, environment_audit, environment_compare, domains_diagnose, project_activity, deployment_preflight, resource_dependencies, resource_usage_insights
MCP_ADMIN_TOOLS_ENABLEDAdmin account/resource, billing, credit, usage, communications, queue and Forge webhook diagnostic tools

Developer tools use a resourceType (app, site, worker, cron_job, or database) and resourceName. Project views require projectId. Deployment operations also require a deployment ID belonging to that resource. Normal project access checks apply to session, API-key and OAuth callers.

Deployment metadata requires deployments:read, runtime/build logs require logs:read, and telemetry requires metrics:read. Nested REST deployment log and metric routes now use those scopes too. Resource configuration reads require the corresponding resource read scope. Project overview omits resource sections outside the token's scopes.

List pages default to 25 records (maximum 100). Logs default to 100 entries (maximum 500 and 128 KiB), with owner retention applied. Runtime logs support text, severity and time filtering. Build logs support timestamp pagination; unsupported build filters are rejected rather than silently applied to one page. Oversized individual messages are truncated to 32 KiB and identified explicitly. Timestamp cursors inherit the provider's ordering limitations. Deployment watch waits up to 12 seconds within the 15-second upstream request budget and returns nonterminal state when the wait expires.

Current diagnostics expose recorded lifecycle state, current pod readiness/restart evidence, CPU/memory samples, and app request rates/p95 latency. Provider errors are distinct from empty samples. Environment comparisons return names and equality differences, never values or fingerprints. Deployment comparisons use recorded metadata and the app/site/worker/cron-job configuration snapshots. Missing historical configuration stays unavailable. Environment audit/compare can select deploymentId and otherDeploymentId to inspect recorded snapshots without substituting current configuration. Domain inspection probes DNS and TLS for up to two attached public hostnames, pins the resolved address, and rejects private/reserved destinations. Preflight validates repository references, resource size limits, and optional hostlessFile configuration using the domain DTOs and scaling consistency rules, without building or reserving capacity. Project activity joins retained deployments through authorized resources, including older deployments without a direct project reference. Hard-deleted resource associations and unrecorded history remain unavailable. Resource dependency results include recorded links; connection strings are not parsed. Usage insights include their evidence window, observed minima/maxima/averages, and conservative headroom findings where comparable configured capacity exists. Current maximum replica capacity is not a historical allocation snapshot.

Admin access

Admin diagnostics require a current admin session JWT. Existing API keys and OAuth grants cannot discover or invoke them, even if their owner is an admin. Every invocation rechecks the administrator in the database and durably records an access audit before returning data. Audit failure denies the response. Admin tools are never exposed by the public documentation server.

Admin tools use explicit IDs: userId/ownerId, projectId, resourceId plus resourceType, invoiceId, or creditId. They expose recorded financial snapshots without assigning billing policies, refreshing payments, sending messages or modifying accounts. Missing ledger links and reconciliation records produce inconclusive results. Reconciliation independently checks frozen line totals, partial-payment balances, recorded conversion rates, provider finalization amounts, and compatible invoice-linked credit debits. Legacy balance semantics, absent links, missing rates and unknown opening balances produce inconclusive checks. Provider finalization is not proof of settlement. Communications history currently covers campaign events; lifecycle delivery certainty is not inferred from claimed or skipped timestamps. Queue inspection supports engine: "bullmq" (the default) and engine: "temporal". BullMQ returns backlog, waiting/active job metadata, numeric progress and retained completion metrics. Temporal requires a registered task queue; add workflowId and optionally runId for execution and pending activity/heartbeat timestamps. Connectivity, pollers and execution progress remain separate. Inputs, heartbeat payloads and job bodies are excluded. Forge delivery evidence has seven-day retention; other provider selections return unsupported. Unknown or expired Forge deliveries return unavailable with the seven-day retention boundary.

Disposable test-data scenarios

Test-data tools are an optional development capability for Hostless-owned data. They do not insert records into arbitrary customer application databases.

Set MCP_TEST_DATA_ENABLED=true in a local/dev API/MCP environment, add the user ID to MCP_TEST_DATA_USER_IDS, and configure TEST_DATA_ENVIRONMENTS on the API with explicit user membership:

{
"local": {
"database": "hostless_test_local",
"members": ["USER_OBJECT_ID"]
}
}

The database name must start with hostless_test_ and differ from the API's primary database. Use a MongoDB replica set: scenario writes and execution fences use transactions. Never point production workers or integrations at the disposable database. Only scenario-owned records are generated; no payment, email, webhook, Kubernetes, or scheduler providers run.

ToolPurposeScope
test_data_capabilitiesDiscover templates, versions, modes and limitstest-data:read
test_scenario_planPersist an immutable plan and return its digesttest-data:write
test_scenario_applyExecute a plan idempotently and return run statustest-data:write
test_scenario_getInspect status and paginated record manifesttest-data:read
test_scenario_advanceAdvance a behavioral scenario's logical timetest-data:write
test_scenario_assertCheck relationships, allocation conservation or creditstest-data:read
test_scenario_resetRemove owned records using the manifesttest-data:delete

These scopes must be granted explicitly to API keys. Session callers still require the user allowlist and environment membership. Admin status does not bypass these restrictions. Test-data scopes are not offered in public OAuth grants.

Example planning arguments:

{
"environment": "local",
"template": "usage_history",
"mode": "historical",
"seed": "usage-investigation-1",
"start": "2026-01-01T00:00:00Z",
"days": 14,
"apps": 2,
"databases": 1,
"pattern": "increasing",
"credit": 10,
"cpuRate": 0.01,
"intervalMinutes": 1440
}

Apply uses the returned scenarioId and digest, plus environment and an idempotencyKey. Poll get until the status becomes ready or failed. Advance and reset require the current revision and a new idempotency key. Expired execution leases become failed runs when inspected; reset the manifest before retrying. External references detected during cleanup block deletion. Idempotency keys retain their run association across later operations; replaying an earlier request returns its original run ID and reports when it is superseded. Completed usage samples remain unchanged as logical time advances. Older generator versions remain inspectable and resettable, but cannot be applied or advanced.

Templates include usage history, deployment history, account lifecycle, credit exhaustion, payment recovery and notification eligibility. Historical fixtures populate past records. Behavioral scenarios regenerate supported deterministic state through the target logical time using Hostless's allocation and recovery functions. CPU, memory and database storage usage are generated with explicit synthetic USD rates (cpuRate, memoryRate, storageRate), not production pricing lookups. Synthetic invoice snapshots and credits are generated from those rates. Full provider invoice processing, provider delivery and scheduler execution are not simulated. Interval size controls short-period usage generation. Seeded output is logically reproducible; scenario IDs differ across independently created runs.

Plans are limited to 31 days, 10,000 records and 10,000 usage steps, with at most ten non-reset scenarios per actor per environment. Changing a registered generator version requires replanning for execution; old plans remain inspectable and resettable. No system clocks or authentication expiry timestamps are changed.

Generator adapters and simulated effects

The registry declares each template's version, models, relationships, transitions, assertions and manifest cleanup policy. Capabilities also expose the registered model field schemas without defaults or values. Add a domain adapter and its versioned contract to extend the registry; the seven MCP tool names stay stable. Unsupported overrides are rejected, and changed versions or policy snapshots invalidate execution of older plans.

For recovery templates, paymentClearsOnDay schedules a deterministic successful payment outcome; notificationFailureDay records a failed notification attempt and allows the recovery rules to retry it. These are disposable test adapters, not calls to payment or email providers. test_scenario_assert supports payment_state with expectedState, notifications_delivered, credit_exhausted, credit_nonnegative, usage_conserved, and all registered relationships. Assertions read stored scenario results. The manifest and effect records remain available after partial failures; get reports safe failure codes.

Cleanup checks registered foreign-key fields across the disposable database, including models that the scenario did not generate. Unregistered nonempty collections block cleanup because their references cannot be established safely. Do not run ordinary workers or concurrent manual writers against these databases.

Correlated investigations

admin_issue_triage composes owner controls, retained pod state, recent deployments and invoice evidence. Findings distinguish directly observed OOM/failure/pause conditions from suspected readiness or recovery inconsistencies. admin_platform_incidents groups failure classes across resources in fifteen-minute windows and reports bounded source coverage; correlation does not prove a common cause. admin_activity_timeline paginates retained events across sources on the server and discloses source retention. Current statuses are observed snapshots, not a complete historical audit ledger.

Financial outputs label major/minor units, currency basis, policy version and period. Revenue includes recorded partial payments and keeps legacy cohorts apart from frozen internal USD amounts. No inspection updates policies, reprices old invoices, refreshes payment records or sends communications.

Acceptance and rollout

Deploy the API adapters first. Enable the developer, contextual, admin and test-data flags independently on matching API/MCP processes. Test data is denied in production even when its flag is set. Disabling tool groups does not undo the scope-routing or deployment-ownership fixes. Stdio requests refresh credentials and admin discovery on every request, including after role revocation.

Run npm run test:mcp:protocol after building the API for real HTTP/stdio SDK protocol coverage with stubbed API evidence. The database acceptance suites cover tenant isolation, snapshots, invoice invariants, scenario transitions, concurrent requests, and cleanup against disposable MongoDB replica sets.

For environment checks, run npm run test:mcp:staging with credentials loaded from a local environment file. Required variables are MCP_SMOKE_URL and MCP_SMOKE_TOKEN (a non-admin credential). Optional checks use MCP_SMOKE_ADMIN_TOKEN, MCP_SMOKE_RESOURCE (a JSON resource selector), MCP_SMOKE_TEST_ENVIRONMENT (a configured disposable nonproduction environment), and MCP_SMOKE_STDIO=1 with MONGODB_URI, JWT_SECRET, and API_BASE_URL. The runner reports which checks ran and avoids logging response bodies or tokens. Never select a production test-data environment. Production health and discovery checks are read-only; deployed feature flags and valid credentials are required to exercise the new tools there.

Usage fixtures in the current local dashboard

The dashboard_usage template creates one offline billing-fixture-* app, standalone worker, or PostgreSQL database, plus usage records and reports under a project the caller owns. Set resourceKind to app (default), worker, or database, and use resourceName (or the original appName). It creates no users, deployments, credits, invoices, payments, or provider jobs. The billing dashboard prices the supplied reports using its existing presentation path; this is generated display data, not an execution of the metering or invoice pipeline. The fixture uses its own pinned shared allowance, so it does not recalculate free allowance across your other resources.

This mode requires NODE_ENV=local, MCP_TEST_DATA_ENABLED=true, TEST_DATA_DASHBOARD_ENABLED=true, and a server-configured environment such as:

TEST_DATA_ENVIRONMENTS={"dashboard":{"database":"YOUR_LOCAL_DB","members":["USER_OBJECT_ID"],"dashboardFixtures":true}}

The database must equal the local API's current database. Never configure this against production data. Ordinary isolated scenarios continue to require a separate hostless_test_* database. API keys still require the test-data scopes.

Use test_scenario_plan with environment: "dashboard", template: "dashboard_usage", mode: "historical", projectId, appName: "billing-fixture-week-one", seed, an ISO start, and days (1–7). Workers and databases accept intervalMinutes: 60 or 1440 for hourly or daily records. Databases also accept storageGiB (default 10, maximum 1000); storage reports preserve size and duration for GiB-day billing. Optional cpuCores and memoryMiB set the constant resource usage; defaults are 0.5 vCPU and 1024 MiB. The entire period must be in the past. Then use the returned digest with test_scenario_apply and inspect progress with test_scenario_get. Select the matching project and date range in the local dashboard. test_scenario_reset uses the ownership manifest and fails closed when external references or unregistered collections prevent safe cleanup.

Private test-data access

Test-data tools and permission grants require all of:

  • NODE_ENV is exactly local, dev, or development.
  • MCP_TEST_DATA_ENABLED=true.
  • The user's ID appears in the comma-separated MCP_TEST_DATA_USER_IDS allowlist.
  • The user belongs to the selected TEST_DATA_ENVIRONMENTS target.
  • API keys have the required test-data:read, test-data:write, or test-data:delete scope.

Production and unknown environments deny test-data access even when flags are on. Administrator status does not bypass these gates. Current-dashboard fixtures remain local-only and additionally require TEST_DATA_DASHBOARD_ENABLED=true.

Eligible users can open Account → API keys → Edit to select the Test data permissions. Saving preserves the existing token and expiry. Scope choices come from the authenticated API; the API validates both key creation and edits. These permissions are not offered through public OAuth grants. Restart API and MCP after changing server environment flags or the user allowlist, and reconnect MCP after editing key scopes to refresh discovery.

Local test invoices from dashboard usage

After a dashboard_usage run is ready, call test_scenario_plan with template: "dashboard_invoice", environment: "dashboard", mode: "historical", sourceScenarioId, a seed, and the source run's exact start and days. Apply its returned digest with test_scenario_apply, then inspect with test_scenario_get. This creates one invoice without duplicating the app or usage. The existing local-only environment, user allowlist, membership and test-data scopes apply.

The invoice appears as Local test in billing history and adds its period to Cost Breakdown. It freezes recorded fixture usage, free/billable quantities, USD rates effective at the period start, and cent-rounded totals. It covers only the selected fixture resources; allowance allocation is not recalculated across existing resources. No payments, credits, reminders, or recovery are initiated. Payment entry points reject test invoices. Pricing/provider overrides are unsupported; missing usage or an existing invoice for that project/period start blocks planning.

Reset the invoice scenario before its source usage scenario. Each reset remains limited to manifest-owned records, and external references can block cleanup.

To include several fixtures in one invoice, pass up to five additionalSourceScenarioIds alongside sourceScenarioId. Every source must be ready and belong to the same caller, project, and exact period. App, standalone worker and database summaries populate the corresponding Cost Breakdown tabs. Allowances remain independent per source scenario; these fixtures do not recalculate the account-wide shared pool.

To extend an existing test invoice, also pass replacesInvoiceScenarioId. Apply atomically replaces that scenario-owned test invoice at the same invoice ID, transfers its manifest entry, and marks the old scenario superseded, retaining its frozen plan. Real invoices and stale replacement scenarios are rejected. Reset the current combined invoice before resetting any of its source scenarios.