mirror of
https://github.com/safishamsi/graphify.git
synced 2026-08-29 09:46:43 +00:00
fix MCP ValidationError on blank stdin lines and bump to 0.4.5
Some MCP clients send blank lines between JSON messages. The stdio transport tried to parse every line as JSONRPCMessage, crashing with a Pydantic ValidationError. _filter_blank_stdin() installs an OS-level pipe that relays stdin while silently dropping blank-only lines. Closes #201 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
0a4e6915c1
commit
2499a1c377
@@ -2,6 +2,10 @@
|
||||
|
||||
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
|
||||
|
||||
## 0.4.5 (2026-04-12)
|
||||
|
||||
- Fix: MCP server no longer crashes with `ValidationError` on blank lines sent between JSON messages by some clients (#201)
|
||||
|
||||
## 0.4.4 (2026-04-12)
|
||||
|
||||
- Fix: `watch` now preserves INFERRED/AMBIGUOUS edges (code↔doc rationale links) across rebuilds — previously all cross-type edges were dropped (#261)
|
||||
|
||||
@@ -108,6 +108,36 @@ def _find_node(G: nx.Graph, label: str) -> list[str]:
|
||||
if term in d.get("label", "").lower() or term == nid.lower()]
|
||||
|
||||
|
||||
def _filter_blank_stdin() -> None:
|
||||
"""Filter blank lines from stdin before MCP reads it.
|
||||
|
||||
Some MCP clients (Claude Desktop, etc.) send blank lines between JSON
|
||||
messages. The MCP stdio transport tries to parse every line as a
|
||||
JSONRPCMessage, so a bare newline triggers a Pydantic ValidationError.
|
||||
This installs an OS-level pipe that relays stdin while dropping blanks.
|
||||
"""
|
||||
import os
|
||||
import threading
|
||||
|
||||
r_fd, w_fd = os.pipe()
|
||||
saved_fd = os.dup(sys.stdin.fileno())
|
||||
|
||||
def _relay() -> None:
|
||||
try:
|
||||
with open(saved_fd, "rb") as src, open(w_fd, "wb") as dst:
|
||||
for line in src:
|
||||
if line.strip():
|
||||
dst.write(line)
|
||||
dst.flush()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
threading.Thread(target=_relay, daemon=True).start()
|
||||
os.dup2(r_fd, sys.stdin.fileno())
|
||||
os.close(r_fd)
|
||||
sys.stdin = open(0, "r", closefd=False)
|
||||
|
||||
|
||||
def serve(graph_path: str = "graphify-out/graph.json") -> None:
|
||||
"""Start the MCP server. Requires pip install mcp."""
|
||||
try:
|
||||
@@ -325,6 +355,7 @@ def serve(graph_path: str = "graphify-out/graph.json") -> None:
|
||||
async with stdio_server() as streams:
|
||||
await server.run(streams[0], streams[1], server.create_initialization_options())
|
||||
|
||||
_filter_blank_stdin()
|
||||
asyncio.run(main())
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "graphifyy"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
|
||||
Reference in New Issue
Block a user