Panniantong/Agent-Reach · error · McporterConfigError

mcporter 返回的 JSON 无法解析

Error message

mcporter 返回的 JSON 无法解析

What it means

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.

Source

Thrown at agent_reach/channels/mcporter.py:142

    try:
        payload = json.loads(raw)
    except json.JSONDecodeError as exc:
        raise McporterConfigError("mcporter 配置不是有效的 UTF-8 JSON") from exc
    if not isinstance(payload, dict):
        raise McporterConfigError("mcporter 配置顶层必须是对象")
    return payload


def configured_server_names(output: str) -> set[str]:
    """Return exact configured server names from ``mcporter ... --json``.

    Paths, descriptions, endpoints, and other metadata are deliberately
    ignored: only each server object's ``name`` field is a routing signal.
    """
    try:
        payload = json.loads(output)
    except (json.JSONDecodeError, TypeError) as exc:
        raise McporterConfigError("mcporter 返回的 JSON 无法解析") from exc

    if not isinstance(payload, dict) or not isinstance(payload.get("servers"), list):
        raise McporterConfigError("mcporter JSON 缺少 servers 列表")

    return {
        name.casefold()
        for server in payload["servers"]
        if isinstance(server, dict)
        if isinstance(name := server.get("name"), str) and name.strip()
    }

View on GitHub (pinned to 93ae1d18c3)

Solutions

  1. Run the mcporter command manually and inspect stdout — confirm it is pure JSON and the --json flag is supported
  2. Upgrade/downgrade mcporter to a version whose --json output is clean
  3. Ensure stderr is captured separately and never concatenated into the output passed in
  4. If calling from code, assert isinstance(output, str) and strip nothing that would break JSON

Example fix

# before
 names = configured_server_names(proc.stdout + proc.stderr)
# after
 names = configured_server_names(proc.stdout)
Defensive patterns

Strategy: validation

Validate before calling

import json

def mcporter_output_parseable(output) -> bool:
    if not isinstance(output, str) or not output.strip():
        return False
    try:
        json.loads(output)
        return True
    except ValueError:
        return False

Type guard

def is_json_string(s) -> bool:
    return isinstance(s, str) and s.lstrip()[:1] in "{["

Try / catch

except McporterConfigError as exc:
    if isinstance(exc.__cause__, json.JSONDecodeError):
        dump_raw_output_for_inspection()  # capture stdout you passed in

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14). Data as JSON: /api/errors/d311c8f1b3b5db3d. Report an issue: GitHub.