/ docsMCP serverllms.txt
On this page
Watch a run in the chatWhat you can askConnect your AI toolTool referenceCost & safety

MCP server — 46 tools

Connect NthCase to any AI tool that supports MCP, and your AI tool can do the whole loop from the chat: describe a test, compile it, run it on a real device, read the evidence (each step, the logs, the network traffic when the run captured it), and ask what a schedule will cost before it creates one.

Included with Pro and Team. Every call is checked against the workspace's plan, so a connection works only while the plan includes API access.

Watch a run in the chat

In an AI tool that supports MCP Apps, such as claude.ai, Claude Desktop and ChatGPT, trigger_run opens a panel in the chat that follows the run: the device live while it runs, each step as it passes, fails or waits, the credits so far and the verdict. When a device cannot be watched, the panel says why.

In a claude.ai chat, asking to run the Find the desk lamp test opens the live run panel, which follows the phone to Passed, and the chat then answers. 1:23
NthCase · Live run
Checkout survives a declined card
Acme Storefront · Pixel 8 · Android 14
Running
Credits spent2 cr
Steps
  1. 1Open the storefront and dismiss the cookie bannerPassed
  2. 2Add the first product to the basketPassed
  3. 3Go to checkout and fill the delivery formPassed
  4. 4Pay with the declined test cardRunning
  5. 5Assert the decline message names the reasonWaiting
Open in NthCase
The panel partway through a run: the device live, the credits so far, each step's word.
  • What is running. The test's name, the app and the device, and one word for where the run is: Queued, then Running, then the verdict.
  • The device, live. Its screen while the run plays on it: upright for a phone, on its side when the phone turns, and wide for a browser. When the run ends, the last screen it recorded, named by the step it came after.
  • Or why it cannot be watched. On a device in a cloud lab, or on your own device where the agent cannot stream, a note takes the screen's place and says so. The steps keep updating.
  • The verdict. When the run ends: Passed, Failed, Error, No checks, Cancelled or Unpaid, with the run's own summary.
  • The credits spent so far, counted as the run plays, by the rule that charges it.
  • Each step, with its word: Passed, Failed or Skipped once it has run, Running for the one in progress, Waiting for the rest.
  • Open in NthCase, where the chat lets an app open a link: it opens the run's own page. Where the chat offers them, the panel also moves to picture in picture or full screen.

What your AI tool needs

It has to support MCP Apps: the part of MCP that lets a server show a page of its own inside the chat, in a frame the chat keeps apart from everything else. The page loads two things from outside the chat, both from NthCase: the device's screen while the run plays, and the last screen the run recorded once it ends. Everything else it shows reaches it through the chat.

In the protocol's terms: the tool declares the extension io.modelcontextprotocol/ui with the type text/html;profile=mcp-app. trigger_run names the panel, ui://nthcase/run-<hash>, in its _meta.ui.resourceUri, and the server serves that page with the same type. The hash is the page's own, so every new version of the panel has an address of its own.

An AI tool that does not support MCP Apps loses nothing: trigger_run answers it with the run and tells the model to poll get_run until the run ends, and its tool list may show the panel's own three tools, get_run_live_state, mint_run_mirror_url and mint_run_picture_url, which only read.

Which tools it uses

trigger_run opens the panel, and the panel follows only the run that call started, until the verdict. get_run opens none: a model calls it again and again to follow a run, and a chat opens a panel for every call of a tool that names one. When your AI tool says on the call that it shows MCP Apps, the answer from trigger_run tells the model that the panel is following the run, and not to poll get_run.

The panel reads the run through three tools of its own: get_run_live_state, the run as the panel draws it, about every four seconds; mint_run_mirror_url, a short-lived address for the device's screen, bound to that run and your workspace; and mint_run_picture_url, once the run has ended, a short-lived address for the last screen it recorded, bound the same way and good for one load. All three only read. They are marked for the panel alone, so an AI tool that honours the mark leaves them out of the model's list.

What you can ask

Each line below is something you could type into your AI tool, then the tools that do it, in order. A tool's name leads to what it does in the reference.

  • “Write a test that pays with a declined card and checks the error message, then run it on an Android phone.”

    1. list_scenarios
    2. create_scenario
    3. compile_scenario
    4. get_compile_run
    5. list_devices
    6. trigger_run

    The compile and the run are charged, and the run opens the live panel where your AI tool supports MCP Apps. A new app is added with register_target, and a person confirms in the app that it is theirs before anything runs on it.

  • “Why did last night's checkout run fail?”

    1. list_runs
    2. get_run_detail
    3. get_run_logs
    4. get_run_network

    The detail shows every step and the one that failed. The logs arrive already redacted; the network capture, when the run recorded one, is masked: credentials by their names in its addresses, headers and bodies, and the run's saved secrets.

  • “What would it cost to run the checkout tests every weekday at 9:00, Istanbul time? If it fits, set it up.”

    1. estimate_schedule
    2. preview_schedule_occurrences
    3. list_schedules
    4. create_schedule

    The estimate spends nothing, and prices the schedule per run, per cycle and per month beside your balance. A schedule takes only tests that are compiled and need no AI to find an element while they run.

  • “Explore the app and propose tests for it.”

    1. trigger_discovery
    2. get_discovery
    3. get_discovery_detail
    4. list_suggestions

    A discovery is charged the price quoted when it starts, and its answer states the budget it was given. You approve a proposed test in the app; your AI tool can write its own with create_scenario.

  • “Run the checkout test on the build before this morning's.”

    1. list_builds
    2. use_build
    3. trigger_run

    use_build makes one of the builds an app keeps the one it runs. A new build file is uploaded in the app: the hosted server cannot read your disk.

  • “Which step healed in the last run, and what did it pick instead?”

    1. list_runs
    2. get_run_detail

    Pinning that pick to the test is done on the run's page in the app: no MCP tool pins a selector.

Connect your AI tool

NthCase runs the MCP server for you, so there is nothing to install. Every AI tool that supports MCP connects to the same address, https://mcp.nthcase.com/mcp, in one of two ways.

It signs in. A tool that supports MCP's sign-in (OAuth) sends you to NthCase to sign in, choose the one workspace the connection may act in, and allow it. You copy no key. Settings → Connected apps lists the connection, with who connected it and when it was last used, and disconnects it at once.

It sends a key. Any other tool sends an API key of the workspace with every request, as the header Authorization: Bearer gp_…. You create one in Settings → API keys. The server keeps no key: it asks NthCase about yours on every request, so a key you revoke stops working on the next one.

Either way, the connection acts in one workspace and reaches exactly what an API key of that workspace reaches.

claude.ai and Claude Desktop

Claude signs in. Add NthCase as a custom connector: Add custom connector → paste the URL → sign in → Allow.

  1. Add custom connector in Customize → Connectors, from its Add menu.
  2. Paste the URL — https://mcp.nthcase.com/mcp — and add it.
  3. Sign in to NthCase when Claude sends you there, and choose the one workspace the connection may act in.
  4. Allow, and Claude is connected — there is no key to copy.
In claude.ai, a custom connector is added with NthCase's address and allowed for one workspace on NthCase's own page, then Claude lists its tools and NthCase lists Claude in Settings → Connected apps. 0:38

Removing NthCase in Claude does not end the connection: to end it, disconnect it on NthCase, in Settings → Connected apps.

Claude Code

One command adds the server, and /mcp inside Claude Code then signs you in the same way:

bash
claude mcp add --transport http nth https://mcp.nthcase.com/mcp

To send a key instead, add the header:

bash
claude mcp add --transport http nth https://mcp.nthcase.com/mcp \
  --header "Authorization: Bearer gp_…"

Cursor

Cursor connects with a key: add a server with the address and the header above.

A tool that runs only local servers

It reaches the hosted server through the mcp-remote bridge, with the key in the same header:

bash
npx mcp-remote https://mcp.nthcase.com/mcp \
  --header "Authorization: Bearer gp_…"

On your own machine

The stdio package — the server as a .NET tool on your own machine — is not published yet: it is not on NuGet or anywhere else you can install it from, and there is no download. The same server speaks MCP over stdio when it runs on your machine, but only a build of NthCase's own source runs it that way, so there is no configuration here that starts it. The hosted server above is the same server, with nothing to install.

Run that way, it reads the key from the environment, NTH_API_KEY — exactly like the CLI, and for the same reason: nothing secret in argv.

Tool reference

Every tool below carries the first sentence of its own server-side description — the inventory is read from the server's source by test, so this list cannot drift from what actually registers.

The 46 tools this page counts are the ones the hosted server offers your AI tool's model. The local server, the same server run on your own machine, also registers upload_build, listed under Builds. It reads that machine's disk, which the hosted server cannot, so it is not counted.

Three more tools register for the live run panel alone, get_run_live_state, mint_run_mirror_url and mint_run_picture_url. They are marked for the panel, so they are not counted here; Watch a run in the chat says what they do.

Scenarios & compiles

The authoring loop: an agent drafts a test in natural language, compiles it into a deterministic plan, and reads the compile's verdict.

list_scenariosList this workspace's test scenarios as a compact LOOKUP TABLE (paginated).
get_scenarioGet one scenario by id: its full definition including ordered steps and compile status.
create_scenarioCreate a NEW test scenario as a DRAFT in this workspace.
update_scenarioEdit an existing scenario's name / description / steps.
compile_scenarioCompile a scenario's steps into the deterministic PLAN its runs replay.
get_compile_runRead one compile-run by id — the authoritative outcome of a compile_scenario call.

Runs & evidence

The execution loop: trigger a run on a real device, then read the verdict with its per-step evidence, its logs and, when the run recorded one, its network capture.

trigger_runStart a run of a scenario.
cancel_runStop a run — queued or already executing. The record goes terminal at once; the device finishes the step it is already on before it stops. Not reversible; an already-finished run is a calm non-error.
list_runsList this workspace's runs (paginated, newest first), optionally filtered by scenarioId, status, or failedOnly.
get_runGet one run's summary by id: status, timing, cost, model, and outcome.
get_run_detailGet a run WITH its ordered per-step results — the step-by-step timeline.
get_run_logsFetch a run's device/server logs (already redacted server-side).
get_run_networkFetch a run's captured network entries (masked server-side: credentials by name in addresses, headers and bodies, and saved secrets) — full entries with header maps and body previews, for inspecting the HTTP traffic a run produced.

Plans & self-heal pins

When a run behaves differently than expected: inspect what the compile pipeline decided, pin which plan version replays, and take a pin off a step.

get_plan_decisionsWhat the COMPILE PIPELINE DECIDED about a scenario's compiled plan — the audit trail for "why does this step check that element?".
list_plan_versionsEvery compiled plan version of a scenario, newest first, each with: version, compiledAtUtc, actionCount, untrustedStepCount, isNewest, and isReplayed (the one unnamed runs currently replay).
set_replay_plan_versionChoose which compiled plan version a scenario's unnamed runs replay — or clear the choice.
unpin_selectorTake a pin off one scenario step: the selector a person recorded or pinned there, its drag's drop end, or the element its check reads, with the record of who put it there.

Visual baselines

When a step compares a picture with one a person approved: read every approved picture, per step and per screen, and delete one so the next run on that screen asks again. Approving a picture stays a person's, on the run's page in the app.

list_baselinesList the pictures a person APPROVED as a scenario's visual baselines — per step, one per screen.
delete_baselineDELETE one approved baseline — one step's picture on one screen, named by its `id` from list_baselines.

Discovery

Before writing tests for an unfamiliar app: crawl it, read the screen map, review the proposed scenarios — every crawl quoted before it starts.

trigger_discoveryStart an agentic DISCOVERY of a target app: the engine crawls it and produces the element map that future compiles are grounded in.
list_discoveriesList this workspace's discovery runs, newest first — optionally filtered to one target.
get_discoveryGet one discovery run's STATUS (Queued/Running/Completed/Failed/Error) without its report.
get_discovery_detailGet a discovery WITH its screen-map report — the engine's primary AI output, and the map a compile is grounded in.
get_discovery_logsGet a discovery's ENGINE TRACE — the step-by-step record of what the exploration actually did.
get_discovery_pagesGet the PAGE SOURCES a phone discovery kept — the XML the device returned when the engine read a screen, the page an engine fix or a test fixture is built from.
cancel_discoverySTOP a discovery that is still Queued or Running, and stop it SPENDING.
list_suggestionsList a target's AI-PROPOSED scenarios — the review queue every discovery pays for and which list_scenarios does NOT show.
get_target_groundingWhich discovery map a COMPILE of this app will actually be grounded in.

Targets & devices

Setting up the ground the tests run on: register the app, see what the device farm can lease, or ask it to build something specific.

list_appsList this workspace's apps (paginated): each app's id, name, platform (Web / Android / Ios), appPackageId (its package or bundle id), isAttested (whether a person has confirmed the app is theirs to test) and currentBuildId (the uploaded build it runs; null when it runs a build at an address, or none).
register_targetRegister a NEW app (target) in this workspace.
list_devicesList the REAL devices the farm can lease right now (optionally filtered by platform: Android / iOS / Web).
list_nodesList THIS workspace's own connected MACHINES and their health — why a phone somebody plugged in is not usable yet. Per-platform probe outcomes carry a reason and a remedy; an answered platform may still state a blind spot, which is a caveat to check by hand, not a failure. Machines and their state, never a device picker: the two counts (a machine's leasableDeviceCount, a platform's offerableCount) are different populations and are never added.
list_catalogList the farm's provisionable capability catalog per platform — the valid `platformVersion` (OS versions), `formFactor`, and `deviceProfile` values a run's deviceSpecJson may request.
provision_deviceAsk the farm to BUILD a new emulator/simulator matching a spec from list_catalog, when list_devices shows nothing suitable.
get_provision_statusPoll a provision started by provision_device.

Builds

A mobile app's build as a FILE rather than a link: upload it from your machine, read what an app keeps, and make one current.

upload_buildUpload an app build FROM THIS MACHINE'S DISK: an Android .apk, an iOS .ipa (a real device), or a .zip holding one simulator .app.
list_buildsList an app's uploaded builds, newest first, and which one it runs (`currentBuildId`; null when the app runs a build at an address, or none).
use_buildMake an uploaded build the one an app runs — one of its kept builds (list_builds), or one uploaded for no app yet.

Schedules

Running unattended: put scenarios on a cron cadence — and ask what that cadence will cost before creating it.

create_scheduleCreate a recurring SCHEDULE that runs scenarios unattended on a cron cadence.
update_scheduleEdit an existing schedule — a FULL REPLACE, not a patch.
pause_scheduleStop future cron firings (idempotent). A paused schedule is NOT inert: run_schedule_now still fires it, deliberately.
resume_scheduleRe-enable — the next run recomputes FROM NOW; missed cycles are never fired retroactively.
run_schedule_nowFire ONE Manual cycle through the same launcher and billing gates as cron — A SPEND (estimate_schedule prices it first); works on a PAUSED schedule; every call is a NEW billed cycle, so check get_schedule before any retry. The cycle records who fired it.
get_scheduleGet one schedule by id: name, cron, timezone, whether it is enabled, why it is paused if it is, when it next fires, and how many scenarios one firing runs. THE RIGHT CALL AFTER A create_schedule THAT TIMED OUT.
list_schedulesList this workspace's schedules (paginated).
estimate_scheduleWhat a schedule would COST before you create one: credits per run, per cycle, and — only when a cron and timezone are given — per month, beside the workspace's spendable balance.
preview_schedule_occurrencesShow the next N times a cron expression + IANA timezone actually fires, computed server-side.
estimate_schedule is the tool to reach for first. An agent can ask what a schedule would cost — per run, per cycle, per month — before spending a customer's credits. Discovery is the same shape: quoted by its chosen ceiling before the crawl starts.

Cost & safety

A machine caller is default-denied: keys reach ONLY the endpoints deliberately opted into the machine allowlist — everything else answers 403, however valid the key. Spends are visible before they happen (estimate_schedule, discovery quotes), logs arrive already redacted and network captures masked, and the key itself is workspace-scoped with no user identity. A connected app acts for the person who allowed it, in the one workspace they chose, and reaches exactly what a key reaches there — never another workspace of theirs, and never members, keys or their account.