HKUDS/DeepTutor · error · HTTPException

{exc}

Error message

{exc}

What it means

Raised by PUT '' (update_mcp_settings) when constructing MCPConfig(servers=payload.servers) raises a Pydantic ValidationError or ValueError — i.e. the submitted server configuration fails model-level validation (wrong field types, unknown/invalid enum values, malformed structure) before semantic checks run. Returns 400 with the exception's message.

Source

Thrown at deeptutor/api/routers/mcp_settings.py:73


@router.get("")
async def get_mcp_settings() -> dict[str, Any]:
    config = load_mcp_config()
    manager = get_mcp_manager()
    await manager.ensure_started()
    return {
        "servers": {name: cfg.model_dump(mode="json") for name, cfg in config.servers.items()},
        "status": manager.status(),
    }


@router.put("")
async def update_mcp_settings(payload: MCPSettingsPayload) -> dict[str, Any]:
    try:
        config = MCPConfig(servers=payload.servers)
    except (ValidationError, ValueError) as exc:
        raise HTTPException(status_code=400, detail=str(exc))
    _validate_servers(config)
    save_mcp_config(config)
    manager = get_mcp_manager()
    await manager.reload()
    return {"status": manager.status()}


@router.put("/servers/{name}")
async def upsert_mcp_server(name: str, cfg: MCPServerConfig) -> dict[str, Any]:
    """Upsert one server, leaving every other entry byte-identical.

    The whole-map ``PUT`` above cannot express "change this one": a client has to
    send back everything it read, so it silently drops any field it does not
    model (a hand-written ``disabled_tools`` blocklist) and overwrites whatever
    a second administrator saved in between.
    """
    config = load_mcp_config()
    servers = dict(config.servers)

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Read the detail message — Pydantic errors name the exact field and expected type
  2. Fix the offending field type per the MCPServerConfig schema (args: list[str], env: dict, etc.)
  3. Validate the payload against the documented schema (or fetch GET the current settings and mirror its shape) before PUTting
  4. After upgrading deeptutor, re-check the settings schema for renamed/retyped fields

Example fix

// before
{"servers": {"fs": {"command": "npx", "args": "-y server-fs /tmp"}}}

// after
{"servers": {"fs": {"command": "npx", "args": ["-y", "server-fs", "/tmp"]}}}
Defensive patterns

Strategy: validation

Validate before calling

const res = await api.get('/mcp');
const validShape = res.servers; // mirror this structure
// validate types before PUT
for (const cfg of Object.values(newServers)) {
  if (cfg.args && !Array.isArray(cfg.args)) throw new Error('args must be an array');
  if (cfg.env && typeof cfg.env !== 'object') throw new Error('env must be an object');
}

Type guard

function isMCPServerConfig(v: unknown): v is MCPServerConfig {
  const c = v as Record<string, unknown>;
  return typeof c === 'object' && c !== null &&
    (c.command === undefined || typeof c.command === 'string') &&
    (c.args === undefined || Array.isArray(c.args)) &&
    (c.env === undefined || typeof c.env === 'object');
}

Try / catch

try {
  await api.put('/mcp', { servers });
} catch (e) {
  if (e.status === 400) {
    // e.detail contains the Pydantic message naming the bad field — fix and retry
  }
}

Prevention

When it happens

Trigger: PUT the MCP settings endpoint with a payload whose servers values violate MCPServerConfig field types, e.g. args as a string instead of a list, env as a list instead of a dict, or numeric values where strings are required.

Common situations: Hand-writing the settings JSON from memory instead of copying the schema; a frontend form serializing types incorrectly; API docs out of date with the current Pydantic model after an upgrade changed field types.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/af2d045c4c5268aa. Report an issue: GitHub.