MCP mock server
An MCP mock is a fake MCP server: tools with canned responses, resources and prompts, defined in a *.mcp-mock.yaml file. Use it to:
- test an AI agent or MCP client against predictable answers, with no side effects (a mocked
delete_customerdeletes nothing); - keep testing when the real server is slow, down, rate-limited or needs credentials;
- share a server's behaviour with people who can't run it.
Record a mock from a real server
- In MCP, connect to the server and call the tools you want to capture.
- In the server's ⋯ menu (More server actions), choose Save as mock.
TestPion writes mocks/<server>.mcp-mock.yaml in the workspace, with the server's tools (names, descriptions, input schemas, annotations), resources (and their text), prompts, and each tool call you made as a response matched on its arguments. Secrets in recorded content are redacted. A server entry <server> (mock) is added, so you can connect to the mock right away.
Write one by hand
name: customer-mock
instructions: A fake customer service
tools:
- name: search_customer
description: Look up a customer by id.
inputSchema:
type: object
properties: { customer_id: { type: string } }
required: [customer_id]
responses:
- when: { customer_id: "999" } # used when the arguments contain these values
text: "No customer {{args.customer_id}}"
isError: true
- json: { id: "123", name: "Ada Lovelace", tier: gold } # the default
resources:
- uri: clinic://hours
name: Opening hours
mimeType: text/plain
text: Mon-Fri 8-18
prompts:
- name: summarize
arguments: [{ name: topic, required: true }]
messages:
- role: user
text: "Summarize {{topic}} in one line."A tool's first response whose when matches the arguments is used, otherwise the one without when. A response is text (with {{args.name}} placeholders), json (also sent as structured content), raw MCP content items, or a script (below), and isError: true makes it a tool error. Dynamic variables such as {{$guid}}, {{$randomFullName}} or {{$randomInt(1,100)}} give a fresh value on every call; a string that is only a placeholder keeps the value's type (qty: "{{$randomInt(1,5)}}" is a number).
Script answers
When the answer depends on the arguments in a way placeholders can't express, a response can be a script: JavaScript run in the same sandbox as test scripts (no network, no files, bounded time), with args in scope. Write it as (args) => result or as a body with return. A string result is sent as text; anything else as JSON (and as structured content); an object { content: [...] } is sent as it is. An exception makes a tool error with its message.
tools:
- name: refund
inputSchema: { type: object, properties: { id: { type: string }, amount: { type: number } }, required: [id, amount] }
responses:
- when: { id: "missing" }
text: "No order {{args.id}}"
isError: true
- script: |
if (args.amount > 50) throw new Error('needs approval');
return { id: args.id, refunded: args.amount, at: new Date().toISOString() };Design a toolset
A toolset is the set of tools an AI agent will see: for each, a name, a description that says when to call it, an input schema, and how it answers. An MCP mock is exactly that, and it is served as a real MCP server, so you can design and try an agent's tools before the backend that implements them exists.
In MCP, select a server whose transport is Mock (or add one and give it a file path such as mocks/orders.mcp-mock.yaml; the file is created on Save). Its Tools tab is the design surface:
- The list of tools on the left: add, duplicate, reorder and delete from each tool's menu.
- The form of a tool: name, title, description, the read-only and destructive hints, the input schema as JSON (with completion), and the responses: each one is text, JSON, a script or raw content, optionally only when the arguments match a
whenobject, and optionally a tool error. - Try calls the tool as edited (nothing saved yet) with a form generated from its schema and shows the mock's answer like any tool result, including what a script computes.
- Form / YAML switches to the raw file: the YAML is the source of truth and stays editable; Save (or Ctrl+S) writes it. Reconnect the server after saving to serve the new tools in the inspector.
- Serve shows the command lines that serve the toolset to an agent (stdio, and Streamable HTTP with its URL) and the
mcpServersconfiguration to paste, each with a copy button. - Generate with AI asks the assistant for the tools of an agent from one or two sentences about its job. The answer is AI-generated: it is loaded into the form for review (and marked as such), not saved, until you press Save.
From the command line and for agents:
testpion mock-mcp mocks/orders.mcp-mock.yaml --list # the toolset: each tool, its arguments and how it answers
testpion mock-mcp mocks/orders.mcp-mock.yaml --list --json # the same as JSON in .data (input schemas included)The MCP server has the same as mock_tools (it takes the file's path in the workspace), so an agent can read a toolset you designed, and design one by writing the YAML file.
Use it
In the app: add an MCP server with the transport Mock and the file's path in the workspace. The mock runs inside TestPion; saved MCP tests can use it like any other server.
For AI agents and other clients: serve it with the CLI.
testpion mock-mcp mocks/customer.mcp-mock.yaml # stdio: the command an agent starts
testpion mock-mcp mocks/customer.mcp-mock.yaml --http -p 3333 # Streamable HTTP on 127.0.0.1For example, in an agent's MCP configuration:
{ "mcpServers": { "customer": { "command": "testpion", "args": ["mock-mcp", "mocks/customer.mcp-mock.yaml"] } } }