SineFrameM3CI gate for MCPsGitHub

Catch broken MCP behavior before it reaches main.

M3 is a pytest framework for MCP servers. It tests your server against the agents your users run, like Claude Code and Codex, instead of a bare model API. Hand the setup to your coding agent.

Install manually

Your MCP Server had the answer.
The agent didn’t ask.

Agents answer from memory when your tool doesn’t tell them not to. M3 runs Claude Code, Codex, OpenCode, or Pi against your server, records every MCP tool call, and fails the test when your server was skipped. Fix the description, rerun, ship.

tests/test_registry.pyresult = agent.run("Add Tailwind to this project.", server=registry)expect(result).to_have_tool_call(    "get_latest_version", arguments={"package": "tailwindcss"})

❯ Add Tailwind to this project.

MCP tool calls
none, answered from memory
package.json
"tailwindcss": "^3.4.1"

Expected get_latest_version(package="tailwindcss"). Observed no MCP tool calls.

Illustrative run with fixture data

Works in Claude Code. Does it work in Codex?

Run the same tests in Claude Code, Codex, OpenCode, and Pi, and compare the results side by side. Your tests don’t change.

project / terminal$ m3 test --harness claude-code=claude-sonnet-5-5 --harness codex=gpt-6.1-sol --harness opencode=anthropic/claude-sonnet-5-5 --harness pi=openai/gpt-6.1-sol -- tests
test
test_​adds_​current_​tailwindpasspassfailpass?
test_​upgrades_​reactpassfailpasspass?
test_​pins_​current_​typescriptpasspasspasspass?
Illustrative run with fixture data

Codex updated overnight. Did your server break?

Pin the version your users run today and the one they get next. M3 runs the same tests on both, so you catch a break before your users do.

project / terminal$ m3 test --runtime managed --harness [email protected]=gpt-6.1-sol --harness [email protected]=gpt-6.1-sol -- tests
testcodex 0.159.3codex 0.160.0
test_​adds_​current_​tailwindpasspass
test_​upgrades_​reactpasspass
test_​pins_​current_​typescriptpassfail
Illustrative run with fixture data

See why it failed.

The test failed when it ran with OpenCode. Open that run: the agent asked for "tailwind" instead of "tailwindcss". M3 keeps every MCP tool call, so you see what went wrong without rerunning anything.

m3 / test run feature/agent-tests
Failed2 passed1 failed 42.5 srun_01JQ8M3
Checkspytest + M3 evidence
MCP tool callfeedback.json
TESTtest_adds_current_tailwind[opencode]VERDICTfailedEXPECTEDget_latest_version(package="tailwindcss")OBSERVEDget_latest_version(package="tailwind") → error: unknown package "tailwind"
m3 test --ui -- tests
Illustrative report · fixture dataInputs and secrets excluded

Your agent writes the tests. Your repo keeps them.

  1. Copy the skill into your coding agent

    One prompt. Works in Claude Code, Codex, OpenCode, or any agent that reads skills.

  2. It writes tests for your server

    Direct tests for schemas, results, and errors, with no model needed. Agent tests like the ones above.

  3. You keep plain pytest files

    Review them like any other code. They live in your repo, not in a dashboard.

    tests/test_registry.py

Zero checks can’t pass the gate.

Run the same suite locally and on pull requests. M3 fails CI when an assertion breaks or when no tests executed at all.

project / terminal$ m3 ci test -- tests
DiscoverExecuteCountDecide
Failed gate0 tests executed

A run where every test was skipped or deselected cannot approve a change.

exit 1

Before you gate a branch.

Getting started, test scope, native execution, CI, and local reports.

How do I start using M3?

Give your coding agent the M3 skill, or install the CLI yourself and run m3 init, m3 setup, and m3 doctor in your project. Read the installation guide.

What does M3 test directly versus through an agent?

Direct tests check schemas, responses, errors, and server state without a model. Agent tests check which tools a real harness used. Both live in ordinary pytest.

Why use the harness’s own binary?

Tool choice depends on the client’s real discovery and permission flow. M3 runs the harness binary and records the resulting tool calls for your assertions.

My agent isn’t listed. Can M3 test it?

If it speaks the Agent Client Protocol (ACP), yes. Point a manifest at its command in your test’s m3 marker and it runs the same suite, keeping its own model and tools. M3 records its tool calls and checks what your server returned. An agent without ACP needs a small wrapper process. Bring your own agent.

Can the same tests run in CI?

Yes. Run the suite locally with m3 test and in CI with m3 ci test. Direct server checks and agent trials remain separate, and a run in which no tests execute fails.

Where do reports and traces go?

M3 keeps run history in .m3/executions.sqlite and writes feedback in .m3/reports. Open the optional local viewer with m3 test --ui.

Something else?

Email us at our contact address (shown when scripts load).

Start testing your MCP server with M3.

Guides for direct tests, agent tests, and running them in CI.