Skip to content

Architecture

The built-in server exposes the same registered tools to an MCP host or Inspector over stdio. Server construction stays separate from transport startup, so the tool configuration can also be reused by scenario tests.

graph LR
    Host[MCP Host or Inspector] <--> Transport[stdio Transport]
    Transport <--> Server[MCP Failure Lab Server]
    Server --> Registration[Tool Registration]
    Registration --> Ping[ping]
    Registration --> Delay[delay]
    Registration --> Hang[hang]
    Registration --> Disconnect[disconnect]
    CLI[CLI serve command] --> Transport
    CLI --> Server

Figure 1. Current server and stdio transport architecture.

Failure Lab uses a real MCP client/server path. Fault behavior lives in the registered tools rather than in a proxy or a second simulation layer.

sequenceDiagram
    participant Runner as Scenario Runner
    participant Client as MCP Client
    participant Server as MCP Server

    Runner->>Client: Primary tool call
    Client->>Server: Execute primary path
    Server-->>Client: Result or protocol failure
    Client-->>Runner: Primary observation
    Runner->>Runner: Evaluate primary expectations

    opt observe is configured
        Runner->>Client: Observer tool call
        Client->>Server: Execute separate tool path
        Server-->>Client: Observer result or protocol failure
        Client-->>Runner: Observer observation
        Runner->>Runner: Evaluate observer expectations
    end

    Runner->>Runner: Produce combined scenario recording

Figure 2. Primary and optional observer calls execute sequentially.

The stdio server path separates five responsibilities:

  1. The CLI parses commands and starts serve.
  2. StdioServerTransport exchanges MCP messages over stdin and stdout.
  3. createServer constructs the server without starting I/O.
  4. ping supplies a deterministic health path.
  5. delay, hang, and disconnect reproduce controlled failures.

Server construction and execution stay separate so integration tests and future transports can reuse the same server configuration. When stdio is active, stdout is reserved for MCP traffic and diagnostics go to stderr.

The runner records the primary observation and evaluates its expectations. When observe is configured, it then performs a separate tool call on the same MCP client connection. Observer results remain separate in the recording, while their assertion failures contribute to the overall scenario status.

flowchart TD
    Primary[Execute primary call] --> PrimaryAssertions[Evaluate primary expectations]
    PrimaryAssertions --> Configured{Observer configured?}
    Configured -- No --> Final[Produce scenario recording]
    Configured -- Yes --> Observer[Execute observer call]
    Observer --> Returned{MCP result returned?}
    Returned -- No --> ObserverFailure[Observer verification fails]
    Returned -- Yes --> ObserverAssertions[Evaluate observer expectations]
    ObserverAssertions --> Match{Expectations pass?}
    Match -- Yes --> ObserverPass[Observer passes]
    Match -- No --> AssertionFailure[Record observer assertion failure]
    ObserverFailure --> Final
    ObserverPass --> Final
    AssertionFailure --> Final

Figure 3. Observer verification and failure handling.