Architecture

Mcph is a Python async CLI built on six modular components:

Component Overview

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   .mcph file │ →  │    Parser    │ →  │     AST      │
└──────────────┘    └──────────────┘    └──────────────┘
                                               │
                                               ▼
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   Reporter   │ ←  │   Runtime    │ ←  │   Session    │
│ JUnit, JSON  │    │  (runner)    │    │  (executor)  │
└──────────────┘    └──────────────┘    └──────────────┘
                          │
              ┌───────────┼───────────┐
              ▼           ▼           ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ Protocol │ │ Assertion│ │ Capture  │
        │  Engine  │ │  Engine  │ │ Registry │
        └──────────┘ └──────────┘ └──────────┘
              │
              ▼
        ┌──────────┐
        │Transport │
        │ stdio/HTTP│
        └──────────┘

Modules

Parser (src/mcph/parser.py)

Hand-written recursive descent parser. Line-oriented, Hurl-inspired syntax. Produces an AST of 15 node types from .mcph source text.

Transport (src/mcph/transport/)

  • StdioTransport — spawns MCP server as async subprocess, newline-delimited JSON-RPC framing, stderr isolation
  • HttpTransport — httpx-based, Mcp-Session-Id header tracking, POST to single MCP endpoint

Protocol Engine (src/mcph/protocol.py)

Transport-agnostic JSON-RPC 2.0 layer. Sequential request IDs, response validation, initialize → initialized handshake, method mapping.

Assertion Engine (src/mcph/assertion.py)

Evaluates assertions against protocol responses. JSONPath via jsonpath-ng, regex matching, fuzzy type matchers (#string, #number, ##object), structural dict subset equality.

Capture Registry (src/mcph/capture.py)

JSONPath + regex extraction from responses. Recursive {{var}} template resolution through dicts and lists. Nested variable path support.

Runtime (src/mcph/session.py, src/mcph/runner.py)

Orchestrates the full execution pipeline: parse → connect → initialize → execute steps → report. REQUIRE_CAPABILITY gating, soft/hard failure modes, transport cleanup.

Design Decisions

DecisionRationale
Python + uvStrong JSON Schema ecosystem, async I/O, single-binary via PyInstaller
Custom runnerStdio lifecycle + JSON-RPC multiplexing fundamentally different from HTTP
Hand-written parserClear error messages, no parser generator dependency
Hurl-inspired syntaxProven readability, familiar to developers
Transport-agnosticSame code tests local and remote servers
AST-firstEnables future validation passes and compilation