Panniantong/Agent-Reach · error · McporterConfigError

mcporter 配置缺少 mcpServers 对象

Error message

mcporter 配置缺少 mcpServers 对象

What it means

Raised by the mcporter doctor when a selected config layer's parsed JSON lacks an 'mcpServers' key of dict type. Agent Reach inspects layered mcporter configs (user + project) and requires each present file to carry an mcpServers object, since it is the signal for which MCP servers mcporter can route to.

Solutions

  1. Add an mcpServers object to the offending layer: '"mcpServers": {}' at minimum, or your server definitions
  2. Identify which layer fails: doctor iterates selected layers (project file when present, plus user config) — check each existing file
  3. Align the key name exactly 'mcpServers' (camelCase) per the MCP config convention
  4. Remove the file if mcporter is not actually configured — a nonexistent layer is skipped, an existing malformed one raises

Example fix

// before
 { "defaults": { "transport": "stdio" } }
// after
 {
   "mcpServers": {},
   "defaults": { "transport": "stdio" }
 }
Defensive patterns

Strategy: validation

Validate before calling

import json, os

def layer_has_servers(path) -> bool:
    if not os.path.isfile(path):
        return True  # missing layer is skipped by the tool
    try:
        payload = json.load(open(path, encoding="utf-8"))
    except Exception:
        return False
    return isinstance(payload, dict) and isinstance(payload.get("mcpServers"), dict)

Type guard

def mcporter_layer_ok(payload) -> bool:
    return isinstance(payload, dict) and isinstance(payload.get("mcpServers"), dict)

Try / catch

from agent_reach.channels.mcporter import McporterConfigError
try:
    inspection = inspect_mcporter_config(root)
except McporterConfigError as exc:
    show_doctor_warning(str(exc))  # doctor-level degradation, not crash

Prevention

When it happens

Trigger: Calling the mcporter inspection (doctor / mcporter channel check) when mcporter.json exists (e.g. repo config/mcporter.json or ~/.config/mcporter/...) but has no 'mcpServers' key, or its value is a list/string/number. A file with 'mcpServers': {} (empty dict) is fine.

Common situations: A mcporter.json written only with 'imports' or other tool settings; renaming the key ('servers', 'mcp-servers') from older examples; JSON5-style comments stripped leaving the key out; hand-authored minimal file copied from a README that uses a different schema.

Related errors


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

Appendix: source

Thrown at agent_reach/channels/mcporter.py:56

    0.7.3 loads the first home config
    (``~/.mcporter/mcporter.json`` / ``mcporter.jsonc``) and then
    ``<cwd>/config/mcporter.json``; project entries override duplicate home
    names. Only exact ``mcpServers`` keys are returned. Editor imports are
    deliberately not opened because Doctor must not expand its
    credential-read boundary.
    """
    selected_layers = _select_config_layers(root_dir)
    if not selected_layers:
        return McporterConfigInspection(frozenset(), None)

    names = set()
    imports_unchecked = False
    sources = []
    for config_path, source in selected_layers:
        payload = _read_config_object(config_path)
        servers = payload.get("mcpServers")
        if not isinstance(servers, dict):
            raise McporterConfigError("mcporter 配置缺少 mcpServers 对象")

        for name, definition in servers.items():
            if not isinstance(name, str) or not name.strip():
                raise McporterConfigError("mcporter 配置包含无效的 server name")
            if not isinstance(definition, dict):
                raise McporterConfigError("mcporter server 定义必须是对象")
            names.add(name.casefold())

        imports = payload.get("imports", _MISSING)
        if imports is _MISSING:
            # mcporter defaults to importing supported editor configs when the
            # key is omitted. Doctor intentionally does not open those files.
            imports_unchecked = True
        elif not isinstance(imports, list) or not all(
            isinstance(item, str) for item in imports
        ):
            raise McporterConfigError("mcporter imports 必须是字符串列表")
        elif imports:

View on GitHub (pinned to 93ae1d18c3)