{"record":{"id":"d311c8f1b3b5db3d","repo":"Panniantong/Agent-Reach","slug":"mcporter-json","errorCode":null,"errorMessage":"mcporter 返回的 JSON 无法解析","messagePattern":"mcporter 返回的 JSON 无法解析","errorType":"exception","errorClass":"McporterConfigError","httpStatus":null,"severity":"error","filePath":"agent_reach/channels/mcporter.py","lineNumber":142,"sourceCode":"    try:\n        payload = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        raise McporterConfigError(\"mcporter 配置不是有效的 UTF-8 JSON\") from exc\n    if not isinstance(payload, dict):\n        raise McporterConfigError(\"mcporter 配置顶层必须是对象\")\n    return payload\n\n\ndef configured_server_names(output: str) -> set[str]:\n    \"\"\"Return exact configured server names from ``mcporter ... --json``.\n\n    Paths, descriptions, endpoints, and other metadata are deliberately\n    ignored: only each server object's ``name`` field is a routing signal.\n    \"\"\"\n    try:\n        payload = json.loads(output)\n    except (json.JSONDecodeError, TypeError) as exc:\n        raise McporterConfigError(\"mcporter 返回的 JSON 无法解析\") from exc\n\n    if not isinstance(payload, dict) or not isinstance(payload.get(\"servers\"), list):\n        raise McporterConfigError(\"mcporter JSON 缺少 servers 列表\")\n\n    return {\n        name.casefold()\n        for server in payload[\"servers\"]\n        if isinstance(server, dict)\n        if isinstance(name := server.get(\"name\"), str) and name.strip()\n    }\n","sourceCodeStart":124,"sourceCodeEnd":153,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/channels/mcporter.py#L124-L153","documentation":"Raised by configured_server_names(output) when json.loads on the stdout of a `mcporter ... --json` subprocess fails (JSONDecodeError) or the input is the wrong type (TypeError — e.g. None passed instead of str). This parses tool output, not a config file, so the culprit is the mcporter binary's response.","triggerScenarios":"Calling configured_server_names with the captured stdout of mcporter where mcporter printed non-JSON (log lines, an error message, version banner, partial output on crash), or programmatically passing None/bytes.","commonSituations":"mcporter version that does not support --json and prints human text; warnings/log lines mixed into stdout; locale or ANSI color codes injected; passing stderr instead of stdout by mistake.","solutions":["Run the mcporter command manually and inspect stdout — confirm it is pure JSON and the --json flag is supported","Upgrade/downgrade mcporter to a version whose --json output is clean","Ensure stderr is captured separately and never concatenated into the output passed in","If calling from code, assert isinstance(output, str) and strip nothing that would break JSON"],"exampleFix":"# before\n names = configured_server_names(proc.stdout + proc.stderr)\n# after\n names = configured_server_names(proc.stdout)","handlingStrategy":"validation","validationCode":"import json\n\ndef mcporter_output_parseable(output) -> bool:\n    if not isinstance(output, str) or not output.strip():\n        return False\n    try:\n        json.loads(output)\n        return True\n    except ValueError:\n        return False","typeGuard":"def is_json_string(s) -> bool:\n    return isinstance(s, str) and s.lstrip()[:1] in \"{[\"","tryCatchPattern":"except McporterConfigError as exc:\n    if isinstance(exc.__cause__, json.JSONDecodeError):\n        dump_raw_output_for_inspection()  # capture stdout you passed in","preventionTips":["Keep stdout pure JSON: never concatenate stderr into it","Verify `mcporter <cmd> --json` supports --json on your version","Strip ANSI codes / banners if your terminal injects them"],"tags":["mcporter","mcp","json","subprocess"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}