Skip to main content
Glama

mcpstub

A fake MCP server generated from the real contract.

mcpstub turns an mcpdoctor report or a small JSON fixture into a deterministic stdio server. Test MCP clients, gateways, and agent harnesses without live credentials, flaky APIs, or hand-written JSON-RPC plumbing.

mcpstub turns a contract into a deterministic modern or legacy test server

$ mcpstub from mcpdoctor.json --out fixtures/docs.json
mcpstub: wrote fixtures/docs.json (14 tools)

$ mcpstub check fixtures/docs.json
✓ valid mcpstub fixture: fixtures/docs.json

$ mcpstub serve fixtures/docs.json
# speaks MCP on stdin/stdout until the client disconnects

The useful loop

Inspect a real server once, review the contract, then test against the local stub:

# 1. Inventory the server. mcpdoctor never calls its tools.
npx --yes github:jovial-liu/mcpdoctor#v1 inspect \
  --format json --out mcpdoctor.json -- \
  npx -y @modelcontextprotocol/server-filesystem /tmp

# 2. Generate a safe starting fixture from the advertised contract.
npx --yes github:jovial-liu/mcpstub#v1 from mcpdoctor.json --out fixtures/files.json

# 3. Point an MCP client at the deterministic fixture server.
npx --yes github:jovial-liu/mcpstub#v1 serve fixtures/files.json

The generated fixture preserves tool names, descriptions, schemas, annotations, resources, templates, prompts, and server identity. It generates placeholder results—never captured production tool output.

Hand-authored scenarios

Fixtures are ordinary reviewable JSON. Add argument-specific cases directly to a tool:

{
  "schema": "mcpstub/v1",
  "server": { "name": "weather-fixture", "version": "1.0.0" },
  "tools": [
    {
      "name": "get_weather",
      "description": "Get a fixture forecast",
      "inputSchema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      },
      "cases": [
        {
          "when": { "city": "Paris" },
          "result": { "content": [{ "type": "text", "text": "Paris: 21°C, clear" }] }
        },
        {
          "when": { "city": "Atlantis" },
          "error": { "code": -32004, "message": "Fixture city not found" }
        }
      ],
      "result": { "content": [{ "type": "text", "text": "Fixture forecast unavailable" }] }
    }
  ]
}

when performs recursive subset matching on argument objects. Object cases can ignore unrelated arguments; arrays match by length and position. The first matching case wins, then result is the fallback. Without either, mcpstub returns a deterministic generated result containing the tool name and arguments.

Try the maintained example:

npx --yes github:jovial-liu/mcpstub#v1 check examples/weather.json
npx --yes github:jovial-liu/mcpstub#v1 serve examples/weather.json

What it implements

  • modern 2026-07-28 server/discover, result discriminators, and cache metadata;

  • legacy initialize negotiation, defaulting to 2025-11-25;

  • tools/list and deterministic tools/call results or JSON-RPC errors;

  • resource and resource-template listing plus resources/read;

  • prompt listing plus prompts/get;

  • ping, unknown-method errors, and parse errors;

  • optional JSONL recording of calls made to the stub.

Both protocol eras are available from the same fixture process. A modern client starts with server/discover; a legacy client starts with initialize.

Optional call assertions

Record what the system under test asked the stub to do:

mcpstub serve fixture.json --log calls.jsonl

The log contains timestamps, tool names, and arguments. It is opt-in because arguments may contain secrets or private data. Keep call logs out of source control unless reviewed and sanitized.

CLI

mcpstub from <mcpdoctor.json> [--out mcpstub.json]
mcpstub check <fixture.json> [--json]
mcpstub serve <fixture.json> [--log calls.jsonl]
mcpstub --version

The fixture format is versioned by schema/fixture.schema.json. check also rejects duplicate names and malformed cases with stable finding codes.

Safety and limits

mcpstub does not start a real MCP server, call a real tool, invoke a shell, load environment credentials, or make network requests. It reads only the fixture you name and writes only an explicit output or log path.

It is a protocol fixture, not a security sandbox or complete server emulator:

  • stdio is supported; Streamable HTTP and authorization are not;

  • multi-round-trip requests, subscriptions, sampling, elicitation, and extensions are not simulated;

  • advertised JSON Schemas are not used to validate call arguments;

  • generated fixtures contain contracts and placeholder responses, not behavioral recordings;

  • a malicious fixture can still return malicious text to the client under test, so review third-party fixtures as code-like test data.

For recorded live sessions, use a cassette-style recorder. mcpstub is intentionally contract-driven: small fixtures, explicit cases, deterministic results.

Development

git clone https://github.com/jovial-liu/mcpstub.git
cd mcpstub
npm run check

Node.js 20+ and zero runtime dependencies. See CONTRIBUTING.md and SECURITY.md.

License

MIT

-
license - not tested
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.

  • Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.

  • Hosted AgentLux MCP server for marketplace, identity, creator, services, and social flows.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jovial-liu/mcpstub'

If you have feedback or need assistance with the MCP directory API, please join our Discord server