How the MCP Server Handles STDIO vs HTTP Transport and Security in code-review-graph

The code-review-graph MCP server uses FastMCP to toggle between stdio (default) and streamable-http transports via a runtime parameter, automatically setting an internal flag for stdio mode while enforcing strict Origin header validation and content-type checks for HTTP connections.

The code-review-graph repository implements a Model Context Protocol (MCP) server built on FastMCP, designed to support both local stdio and network-based HTTP transports. Understanding how the MCP server handles transport selection and security is crucial for deploying the tool safely across different environments.

Transport Architecture Overview

The server determines which transport mechanism to use based on the transport argument passed to the run() function in code_review_graph/main.py. This design allows operators to switch between local process communication and HTTP-based remote access without modifying core business logic.

STDIO Transport (Default)

When the server starts without explicit transport configuration, it defaults to stdio (standard input/output) mode. In this configuration:

  • The server uses a single-threaded, line-delimited protocol that operates over stdin/stdout streams
  • An internal module-wide flag _MCP_STDIO_ACTIVE is set to true during initialization
  • Long-running MCP tools are automatically offloaded to background threads to keep the stdio event loop responsive and prevent blocking

As implemented in code_review_graph/main.py (lines 1086-1088), the stdio transport requires no network stack and exposes no attack surface to remote clients, making it ideal for local integrations with command-line tools.

HTTP Transport (Streamable-HTTP)

When transport="streamable-http" is specified, the server initializes a lightweight ASGI HTTP server that exposes the MCP protocol over web standards:

  • The endpoint /mcp/ becomes available for JSON-RPC style communication
  • The transport utilizes Server-Sent Events (SSE) for streaming responses
  • FastMCP handles the ASGI lifecycle, converting HTTP requests into MCP tool calls

According to the source code (lines 1107-1110), this mode is activated by passing the transport string directly to FastMCP.run(), enabling browser-based clients and remote tooling to interact with the code review graph.

Security Controls for HTTP Transport

When operating in HTTP mode, the server implements multiple security layers to prevent cross-origin attacks and content-type confusion. These protections are verified in the test suite, particularly in tests/test_http_origin_guard.py.

Origin Header Validation

The server applies an origin guard middleware that inspects the Origin header of incoming HTTP requests:

  • Requests without an Origin header (typical of non-browser clients like curl or Python scripts) are accepted automatically
  • Browser-based requests must match a whitelisted origin set or be explicitly absent
  • Mismatched origins receive a 406 Not Acceptable response, mitigating Cross-Site Request Forgery (CSRF) attacks

This validation logic (lines 28-35) ensures that only intended origins can trigger MCP tool executions when the server is exposed over HTTP.

Content-Type and Accept Header Enforcement

FastMCP enforces strict header requirements for HTTP transport compliance:

  • Clients must include Accept: application/json, text/event-stream to indicate they can handle JSON responses or SSE streams
  • Requests must specify Content-Type: application/json for POST bodies
  • Missing or incorrect headers result in immediate 406 rejection (lines 28-30)

These checks prevent content-type confusion attacks and ensure clients are prepared to handle the binary or streaming responses generated by graph analysis tools.

FastMCP Version Compatibility

The security model depends on specific FastMCP features for middleware injection. The test suite verifies that the installed FastMCP version supports:

  • The run_http_async method signature
  • A middleware parameter for origin validation (lines 126-130)

If these capabilities are absent, the server cannot guarantee origin protection, and the test suite will fail fast to prevent deployment of an insecure configuration.

Practical Implementation Examples

Starting the server in stdio mode (safe for local CLI integration):

import code_review_graph.main as crg

# Uses default stdio transport, sets _MCP_STDIO_ACTIVE flag

crg.run()

Starting the server in HTTP mode (requires origin-aware client configuration):

import code_review_graph.main as crg

# Exposes /mcp/ endpoint with origin validation

crg.run(transport="streamable-http")

Python client calling the HTTP MCP endpoint with required headers:

import httpx

resp = httpx.post(
    "http://localhost:8000/mcp/",
    json={"tool": "analyze_graph", "args": {"repo": "example/repo"}},
    headers={
        "Accept": "application/json, text/event-stream",
        "Content-Type": "application/json"
    }
)
print(resp.json())

Verifying the stdio flag for thread management:


# Accessing the internal flag (defined in main.py lines 1139-1144)

from code_review_graph import main

if main._MCP_STDIO_ACTIVE:
    print("Running in stdio mode - tools will use background threads")

Summary

  • The transport mechanism is selected via the transport parameter in code_review_graph/main.py, supporting either stdio (default) or streamable-http
  • STDIO mode sets _MCP_STDIO_ACTIVE to true and offloads long-running operations to background threads to maintain stream responsiveness
  • HTTP mode exposes a /mcp/ endpoint but requires strict Accept and Content-Type headers to prevent content negotiation attacks
  • An origin validation middleware rejects cross-origin requests when Origin headers are present, mitigating CSRF risks
  • The test suite enforces FastMCP version compatibility to ensure middleware capabilities exist before allowing HTTP transport deployment

Frequently Asked Questions

What is the default transport mode for the code-review-graph MCP server?

The default transport is stdio (standard input/output). When you invoke crg.run() without arguments, the server initializes stdio streams and sets the internal _MCP_STDIO_ACTIVE flag, making it suitable for local CLI tool integration without network exposure.

How does the server protect against CSRF attacks when using HTTP transport?

The server implements an origin guard middleware that validates the Origin header on incoming HTTP requests. Requests from browser contexts with mismatched origins receive a 406 Not Acceptable response, while non-browser clients (which typically omit the Origin header) are accepted. This pattern is tested in tests/test_http_origin_guard.py (lines 69-78).

Why does the stdio transport require background thread management?

In code_review_graph/main.py (lines 1139-1144), the server detects when stdio mode is active and routes long-running MCP tool executions to background threads. This prevents the stdio event loop from blocking on graph analysis operations, ensuring the transport remains responsive for protocol handshake and heartbeat messages.

Which HTTP headers are required when calling the MCP server over HTTP?

Clients must include Accept: application/json, text/event-stream and Content-Type: application/json headers. The FastMCP framework enforces these requirements (lines 28-30 in the origin guard tests) to ensure clients can properly handle JSON responses or Server-Sent Events streams returned by graph analysis tools.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →