{"record":{"id":"129990540d0eb5b7","repo":"BerriAI/litellm","slug":"toolset-toolset-name-not-found","errorCode":null,"errorMessage":"Toolset '{toolset_name}' not found","messagePattern":"Toolset '(.+?)' not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"litellm/proxy/_experimental/mcp_server/rest_endpoints.py","lineNumber":690,"sourceCode":"        toolset_name: str | None,\n        user_api_key_dict: UserAPIKeyAuth,\n    ) -> UserAPIKeyAuth:\n        \"\"\"The one credential this tools request acts as.\n\n        A toolset name narrows the caller's own credential to that toolset; otherwise a dashboard\n        session is swapped for its admitted subject. The two are mutually exclusive by construction,\n        which is why they share an owner: the admitted subject resolves per grant source and a team\n        source deliberately carries none of the caller's ``object_permission``, so a toolset\n        narrowing layered on top would evaporate on every team-granted server.\"\"\"\n        if not toolset_name:\n            return await acting_user_auth(user_api_key_dict)\n\n        from litellm.proxy.utils import get_prisma_client_or_throw\n\n        prisma_client: Final = get_prisma_client_or_throw(\"Database not available. Connect a database to your proxy\")\n        toolset: Final = await global_mcp_server_manager.get_toolset_by_name_cached(prisma_client, toolset_name)\n        if toolset is None:\n            raise HTTPException(\n                status_code=404,\n                detail=f\"Toolset '{toolset_name}' not found\",\n            )\n        return await _apply_toolset_scope(user_api_key_dict, toolset.toolset_id)\n\n    @router.get(\"/tools/list\", dependencies=[Depends(user_api_key_auth)])\n    async def list_tool_rest_api(\n        request: Request,\n        server_id: str | None = Query(None, description=\"The server id to list tools for\"),\n        mcp_server_name: str | None = Query(None, description=\"Filter tools to a single MCP server by name or alias\"),\n        toolset_name: str | None = Query(None, description=\"Filter tools to a single toolset by name\"),\n        include_disabled_tools: bool = Query(\n            False,\n            description=(\n                \"Admin only. Return the full server tool catalog without the \"\n                \"allowed_tools filter or per-key tool permissions, so the MCP \"\n                \"settings UI can configure the allowlist. Ignored for non-admins.\"\n            ),","sourceCodeStart":672,"sourceCodeEnd":708,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/_experimental/mcp_server/rest_endpoints.py#L672-L708","documentation":"On tools/list, a non-empty toolset_name query parameter is looked up in the database (cached); an unknown name raises 404 with this message. It requires the Prisma DB to be connected - a missing DB surfaces a different error from get_prisma_client_or_throw. Toolsets narrow the visible MCP servers/tools to a named grouping.","triggerScenarios":"GET /mcp/tools/list?toolset_name=... with a typo'd, deleted, or not-yet-created toolset name; using a toolset id instead of its name; querying an environment whose DB lacks the row.","commonSituations":"Toolsets created in one environment (dev) but referenced in another (prod); renamed toolsets breaking saved dashboards/queries; copy-paste of ids from the UI where names are expected.","solutions":["List existing toolsets (dashboard or toolset DB table / API) and use the exact name.","If the toolset was renamed or deleted, update the caller to the current name or recreate the toolset.","Confirm the proxy is connected to the DB where the toolset lives."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"async def toolset_exists(client, name: str) -> bool:\n    resp = await client.get(f\"{proxy}/mcp/toolsets\", headers=headers)  # or DB/toolset API\n    return any(t.get(\"name\") == name for t in resp.json().get(\"toolsets\", []))\n\nassert await toolset_exists(client, wanted), f\"unknown toolset {wanted}\"","typeGuard":null,"tryCatchPattern":"resp = await client.get(f\"{proxy}/mcp/tools/list\", params={\"toolset_name\": name}, headers=headers)\nif resp.status_code == 404 and f\"Toolset '{name}' not found\" in resp.text:\n    raise UnknownToolset(name) from None  # permanent: fix the name, do not retry\nresp.raise_for_status()","preventionTips":["Resolve toolset names once at startup and fail fast on unknown ones.","Parameterize toolset names per environment instead of hardcoding dev names into prod calls.","Re-check saved queries/dashboards after renaming or deleting toolsets."],"tags":["mcp","http-404","toolset","database","tools-list"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}