0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code向けMCP、接続成功でもログ混入

0
Posted at

Claude Code向けMCPは、接続成功だけで検収するとログ混入を見逃し、導入後の切り分けに時間を取られる。

今日、起動ログを混ぜたら、エラーが出たのに足し算は通った。意外だったんだよね。

Q. JSONのログなら混ぜてもいい?

{"msg": "boot"} もエラーになった。

手元の公式Python SDKの stdout_reader を読んだ。改行で区切った各行を JSONRPCMessage.model_validate_json に渡している。普通のJSONとして読めても、JSON-RPCの必須フィールドが足りない。

Q. どう再現した?

確認環境はPython 3.12.13、mcp 1.27.1、anyio 4.13.0、pydantic 2.13.4。probe_stdio.py に保存し、同じ環境で python3 probe_stdio.py を実行する。ローカル子プロセスで完結する。

import json
import sys

import anyio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.server.fastmcp import FastMCP

def server(mode):
    text = json.dumps({"msg": "boot"}) if mode == "json" else "boot"
    dest = sys.stderr if mode == "stderr" else sys.stdout
    print(text, file=dest, flush=True)
    app = FastMCP("stdio-check", log_level="ERROR")

    @app.tool()
    def add(a: int, b: int) -> int:
        return a + b

    app.run(transport="stdio")

async def probe(mode):
    errors = []

    async def incoming(message):
        if isinstance(message, Exception):
            errors.append(type(message).__name__)

    params = StdioServerParameters(
        command=sys.executable, args=[__file__, mode])
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write, message_handler=incoming) as s:
            await s.initialize()
            result = await s.call_tool("add", {"a": 1, "b": 2})
            assert not result.isError and result.content[0].text == "3"
    print(f"{mode}: errors={errors}, add={result.content[0].text}")

async def main():
    for mode in ("plain", "json", "stderr"):
        await probe(mode)

if __name__ == "__main__":
    if len(sys.argv) == 2:
        server(sys.argv[1])
    else:
        anyio.run(main)

実行結果。stderrには2ケースで Failed to parse JSONRPC message from server と詳細が出た。

plain: errors=['ValidationError'], add=3
json: errors=['ValidationError'], add=3
stderr: errors=[], add=3

Q. なぜエラー後も通る?

SDKはパース例外を読み取り側へ送って次の行を読む。message_handler で数えるとstdoutの2ケースで各1件。後続の応答は届き、足し算も通った。

成功だけ拾うテストだと、この差が消える。

MCPのstdio受信ではログ行の検証エラー後も正常応答を読めるため、応答結果と例外件数の両方で検収する流れ

stderrの boot は残った。起動ログはやっぱり見たい。

Q. 検収に何を足す?

合格条件に errors == [] も加える。ラッパーの 2>&1 でstderrのログがstdoutへ戻る点にも注意。

今回はPython SDKのstdio経路を測った。Claude Code本体の接続可否は未確認だ。起動ログをstderrへ寄せ、正常応答とパース例外0件をセットで検収する。今後は起動ラッパーも検収に含めたい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?