{"record":{"id":"d5a117f77a218b27","repo":"HKUDS/DeepTutor","slug":"mcp-configure-command-or-url","errorCode":null,"errorMessage":"mcp.configure_command_or_url","messagePattern":"mcp\\.configure_command_or_url","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/mcp_settings.py","lineNumber":45,"sourceCode":"    get_mcp_manager,\n    load_mcp_config,\n    save_mcp_config,\n    validate_mcp_url,\n)\nfrom deeptutor.services.mcp.manager import probe_server\n\nrouter = APIRouter(dependencies=[Depends(require_admin)])\n\n\nclass MCPSettingsPayload(BaseModel):\n    servers: dict[str, MCPServerConfig] = Field(default_factory=dict)\n\n\ndef _validate_servers(config: MCPConfig) -> None:\n    for name, cfg in config.servers.items():\n        transport = cfg.resolved_type()\n        if transport is None:\n            raise HTTPException(\n                status_code=400,\n                detail=t(\"mcp.configure_command_or_url\", name=name),\n            )\n        if transport in {\"sse\", \"streamableHttp\"}:\n            ok, error = validate_mcp_url(cfg.url)\n            if not ok:\n                raise HTTPException(\n                    status_code=400, detail=t(\"mcp.server_error\", name=name, error=error)\n                )\n\n\n@router.get(\"\")\nasync def get_mcp_settings() -> dict[str, Any]:\n    config = load_mcp_config()\n    manager = get_mcp_manager()\n    await manager.ensure_started()\n    return {\n        \"servers\": {name: cfg.model_dump(mode=\"json\") for name, cfg in config.servers.items()},","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/mcp_settings.py#L27-L63","documentation":"Validation error from _validate_servers (used by PUT /mcp settings and server upsert): a named MCP server entry has neither a command (stdio transport) nor a URL (sse/streamableHttp transport), so resolved_type() returns None and the server cannot be started or connected to.","triggerScenarios":"PUT /api mcp settings (update_mcp_settings) or the per-server upsert endpoint with a servers entry that has empty/missing both 'command' and 'url' fields, e.g. {\"servers\": {\"my-server\": {\"name\": \"my-server\"}}}.","commonSituations":"Partially filled server config in a settings UI where the user entered only a name; YAML/JSON config edited by hand with a typo'd or omitted command/url key; a migration or template that ships a placeholder server entry with no transport fields.","solutions":["Add either a command (for stdio servers, e.g. \"npx -y @some/mcp-server\") or a url (for SSE/streamable HTTP servers) to the offending server entry","Check the server name in the error detail to identify which entry is incomplete","Remove the half-configured server entry entirely if it is no longer needed","If using a UI, ensure the transport selector actually writes the corresponding field"],"exampleFix":"// before\n{\"servers\": {\"my-server\": {\"name\": \"my-server\"}}}\n\n// after\n{\"servers\": {\"my-server\": {\"name\": \"my-server\", \"command\": \"npx -y @modelcontextprotocol/server-filesystem\", \"args\": [\"/tmp\"]}}}","handlingStrategy":"type-guard","validationCode":"for (const [name, cfg] of Object.entries(servers)) {\n  if (!cfg.command && !cfg.url) {\n    throw new Error(`Server '${name}' needs a command (stdio) or a url (http/sse)`);\n  }\n}","typeGuard":"function hasTransport(cfg: MCPServerConfig): boolean {\n  return Boolean(cfg?.command || cfg?.url);\n}","tryCatchPattern":"try {\n  await api.put('/mcp', { servers });\n} catch (e) {\n  if (e.status === 400) console.error('MCP config rejected:', e.detail);\n  throw e;\n}","preventionTips":["Require command or url in the settings form before save","Validate the whole servers map client-side before submitting","Reject placeholder entries with only a name"],"tags":["mcp","config","validation","bad-request"],"backgroundTag":"mcp-server-misconfiguration","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}