Skip to main content
  .-----.
  |  🔴  |
  |  🟡  |
  |  🟢  |
  '-----'
   greenlight

greenlight

PyPI Python License: MIT tests

Listed in awesome-mcp-devtools.

See what your MCP server is actually doing.

greenlight tail showing a live trace with a slow call in yellow and a failed tool call in red with its real error message, then greenlight check listing the bugs it found in a broken server

When an MCP integration misbehaves, you're usually debugging blind: the client says a tool "failed" or quietly never calls it, and you can't see what was sent or what came back. Greenlight is a transparent proxy that sits between your real client (Claude Desktop, Claude Code, Cursor, Windsurf) and your real server, relays every byte unchanged, and records every JSON-RPC message so you can watch it live, read it back later, or lint it.

  • tail: a live, color-coded trace. Green means ok, yellow means slow, red means failed, and failed calls show the tool's real error message.
  • check: catches server bugs that never show up as a failed call, like printing to stdout, tool schemas the Claude API rejects, HTTP 401s that clients report as "failed to connect", or requests that never got a response.
  • stats: a summary with a CI-friendly exit code.
  • serve: exposes the trace as an MCP server, so your coding agent can read the failures itself.

Try it in 30 seconds

uvx greenlight-mcp run -- npx -y @modelcontextprotocol/server-everything stdio

Then, in another terminal:

uvx greenlight-mcp tail -f

That's the official MCP reference server, with nothing to configure. It needs uv and Node.js. Prefer pip? pip install greenlight-mcp, then use greenlight wherever this README says uvx greenlight-mcp.

Use it with your real client

Wrap the server command in your client's MCP config:

{
  "mcpServers": {
    "my-server": {
      "command": "uvx",
      "args": ["greenlight-mcp", "run", "--name", "my-server", "--",
               "npx", "-y", "@some/mcp-server"]
    }
  }
}

Or let Greenlight write the snippet for you:

greenlight wrap

wrap finds your Claude Desktop, Claude Code, Cursor, or Windsurf config and prints each server entry rewritten to run through Greenlight. It's read-only and never edits the file, and it only shows the command and args it changes, never your env.

It also writes full paths: Python's, and your server's own command (npx becomes the path your terminal resolves it to). Clients often launch servers with a smaller PATH than your terminal has, which is where most spawn npx ENOENT / "Server disconnected" failures come from. It warns if a command isn't on your PATH either, or if an argument is a relative path the client won't be able to find. If a server still can't be started, greenlight run says why on stderr instead of dumping a traceback.

Logs go to ~/.greenlight/sessions/, whichever directory the client launched the server from. To put them somewhere else, use --log-dir or set GREENLIGHT_SESSIONS_DIR. If the log directory can't be written, Greenlight warns on stderr and keeps relaying. It never stops your server from starting.

For a remote Streamable HTTP server, proxy the URL instead:

greenlight run --http http://127.0.0.1:9000/mcp

Point your client at the local URL it prints. You get the same logs, and the same tail, check, and stats.

Commands

greenlight tail            # replay the most recent session
greenlight tail -f         # follow a live session
greenlight check           # lint the session for protocol/server bugs
greenlight stats           # counts, latency by method, pass/fail

check: bugs that don't look like failures

$ greenlight check examples/bad-session.jsonl
session: examples/bad-session.jsonl

  error    stdout-pollution        server wrote 1 non-JSON-RPC line(s) to stdout, e.g. 'server
                                   starting up...'. In the stdio transport stdout is for
                                   protocol messages only -- send logs and prints to stderr.
                                   Clients may drop these lines, fail to parse, or disconnect.
  error    tool-schema-combinator  tool 'either_or' inputSchema has top-level anyOf. It's valid
                                   JSON Schema, but the Claude API rejects it with a 400, and
                                   in Claude Code a single such tool can fail every request in
                                   the session. Make the root a plain object (nested anyOf is
                                   fine) and enforce the either/or rule in the tool handler
  error    tool-duplicate-name     tool name 'ok_tool' appears more than once in a single
                                   tools/list response
  warning  unanswered-request      'tools/call' (id 3) never got a response from the server
  ...

Real output, abridged, from examples/bad-session.jsonl: a session recorded through the proxy against tests/bad_fixture_server.py, a server built to make these mistakes on purpose.

It also flags non-object input schemas, tool names some clients reject, responses to ids nobody sent, and very slow calls or slow startup.

Two that are worth knowing about: a top-level oneOf/anyOf/allOf in a tool's input schema is valid JSON Schema, but the Claude API rejects it with a 400, and in Claude Code a single such tool can fail every request in the session without saying which one. And for HTTP servers, a 401/403 is rejected before JSON-RPC, so a client just says "failed to connect"; Greenlight records the status and WWW-Authenticate header and check reports it.

Errors exit non-zero, and so do warnings with --strict. --json gives machine-readable output.

CI

Both check and stats exit non-zero on failure. stats fails on tool errors (result.isError) as well as JSON-RPC errors. That matters because a failed tool call arrives as a successful JSON-RPC response, and it's easy to miss if you only check for the obvious kind:

greenlight run --log-dir ./trace -- python my_server.py < scripted_session.jsonl
greenlight check --log-dir ./trace && greenlight stats --log-dir ./trace

serve: let your agent read the trace

pip install "greenlight-mcp[serve]"
greenlight serve

Add greenlight serve to your coding agent's MCP config, and it can call get_failures, get_problems, get_trace, or get_session_stats itself. It sees the real error messages, so you don't have to paste terminal output.

Server won't connect?

"Server disconnected", spawn npx ENOENT, "Connection closed (-32000)": the usual cause is that your client starts the server with a smaller PATH, and a different working directory, than your terminal has. So the command works for you and not for the client.

greenlight wrap writes full paths into the config it suggests, and warns about commands that aren't on your PATH and relative paths the client can't resolve. If the server still can't be started, greenlight run says what was missing on stderr (which clients usually capture in the server's log) instead of dumping a traceback. Once it starts but misbehaves, greenlight check and tail show what it did.

Why not MCP Inspector?

They do different jobs. Inspector is a UI you drive by hand to test a server in isolation. Greenlight sits in the path of your real client and records what actually happened in a real session. That includes the client's exact requests, which is usually where the bug turns out to be. It also leaves a durable log you can check in CI.

How it works

greenlight run spawns your server as a subprocess and relays stdin/stdout on two threads. It parses each line as JSON-RPC, correlates each response with its request by id (so every response knows its method and latency), and appends the result to a JSONL file. The one rule everything depends on: nothing but the server's own bytes ever reaches Greenlight's stdout. Status output goes to stderr, and logs go to disk.

The base install depends only on rich. Python 3.10+, tested on Linux and Windows.

More

  • CHANGELOG.md: what changed in each release.
  • notes/: a running engineering log of what broke, how it was found, and why each fix is what it is.
  • Issues and PRs welcome. If Greenlight misreads a real session, the log file is the most useful thing you can attach.

Metadata

Release files for greenlight-mcp 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for greenlight-mcp 0.6.0
File Size Uploaded Provenance
greenlight_mcp-0.6.0.tar.gz 57.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for greenlight-mcp 0.6.0
File Interpreter ABI Platform
greenlight_mcp-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 93.7 kB

Release files / greenlight_mcp-0.6.0.tar.gz

Download URL greenlight_mcp-0.6.0.tar.gz
Size 57.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7f1949a4192a587db6d4a74d8c7d9bee0445eca918dbb9411d67e849d84b434b
BLAKE2b-256 checksum
How to use checksums
b43a5e8d6bf60595c6cee2be4b0d2f3c68b20a2eff1f9717a03b8324ca7e9073
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / greenlight_mcp-0.6.0-py3-none-any.whl

Download URL greenlight_mcp-0.6.0-py3-none-any.whl
Size 35.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8c8861f95bc2f68f8abe61d7c9e50accebff47297c2eec2e947661944bdfb75f
BLAKE2b-256 checksum
How to use checksums
4ea572d032334d4a893f921a4a2b6143f1a8b5b140aa1fc7450be1e767e01567
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for greenlight-mcp 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page