{"record":{"id":"b34b50495bff1ee4","repo":"PrefectHQ/fastmcp","slug":"no-server-url-found-in-openapi-spec-either-add-a","errorCode":null,"errorMessage":"No server URL found in OpenAPI spec. Either add a 'servers' entry to the spec or provide an httpx2.AsyncClient explicitly.","messagePattern":"No server URL found in OpenAPI spec\\. Either add a 'servers' entry to the spec or provide an httpx2\\.AsyncClient explicitly\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/providers/openapi/provider.py","lineNumber":193,"sourceCode":"            route_tags = set(route.tags) | route_map.mcp_tags | (tags or set())\n\n            if route_type == MCPType.TOOL:\n                self._create_openapi_tool(route, component_name, tags=route_tags)\n            elif route_type == MCPType.RESOURCE:\n                self._create_openapi_resource(route, component_name, tags=route_tags)\n            elif route_type == MCPType.RESOURCE_TEMPLATE:\n                self._create_openapi_template(route, component_name, tags=route_tags)\n            elif route_type == MCPType.EXCLUDE:\n                logger.debug(f\"Excluding route: {route.method} {route.path}\")\n\n        logger.debug(f\"Created OpenAPIProvider with {len(http_routes)} routes\")\n\n    @classmethod\n    def _create_default_client(cls, openapi_spec: dict[str, Any]) -> httpx2.AsyncClient:\n        \"\"\"Create a default httpx client from the OpenAPI spec's server URL.\"\"\"\n        servers = openapi_spec.get(\"servers\", [])\n        if not servers or not servers[0].get(\"url\"):\n            raise ValueError(\n                \"No server URL found in OpenAPI spec. Either add a 'servers' \"\n                \"entry to the spec or provide an httpx2.AsyncClient explicitly.\"\n            )\n        base_url = servers[0][\"url\"]\n        variables = servers[0].get(\"variables\", {})\n        for name, var in variables.items():\n            base_url = base_url.replace(f\"{{{name}}}\", var.get(\"default\", \"\"))\n        return httpx2.AsyncClient(base_url=base_url, timeout=DEFAULT_TIMEOUT)\n\n    @asynccontextmanager\n    async def lifespan(self) -> AsyncIterator[None]:\n        \"\"\"Manage the lifecycle of the auto-created httpx client.\"\"\"\n        if self._owns_client:\n            async with self._client:\n                yield\n        else:\n            yield\n","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/providers/openapi/provider.py#L175-L211","documentation":"When no explicit httpx.AsyncClient is supplied, the provider tries to derive a base URL from the spec's first servers entry; if servers is missing/empty or the first entry has no url, it raises this ValueError telling you to add a servers entry or pass a client explicitly.","triggerScenarios":"Constructing OpenAPIProvider/FastMCPProvider from a spec dict without a 'servers' key (or with servers: [{}]) and without providing a client.","commonSituations":"Specs written for Swagger 2.0 use 'host'/'basePath' instead of 'servers'; specs trimmed down for testing with servers removed; relative server URLs used with an assumed host.","solutions":["Add a servers entry to the spec: spec['servers'] = [{'url': 'https://api.example.com'}]","Pass an explicit client: FastMCPProvider(spec, client=httpx.AsyncClient(base_url='https://api.example.com'))","Convert Swagger 2.0 host/basePath to an OpenAPI 3 servers entry"],"exampleFix":"// before\nspec = {'openapi': '3.1.0', 'paths': {...}}\nprovider = FastMCPProvider(spec)\n// after\nspec = {'openapi': '3.1.0', 'servers': [{'url': 'https://api.example.com'}], 'paths': {...}}\nprovider = FastMCPProvider(spec)","handlingStrategy":"validation","validationCode":"def ensure_server_url(spec: dict) -> dict:\n    servers = spec.get('servers')\n    if not servers or not servers[0].get('url'):\n        raise ValueError('spec needs a servers[0].url before creating a provider')\n    return spec","typeGuard":"def has_server_url(spec: object) -> bool:\n    return (\n        isinstance(spec, dict)\n        and bool(spec.get('servers'))\n        and bool(spec['servers'][0].get('url'))\n    )","tryCatchPattern":"try:\n    provider = FastMCPProvider(spec)\nexcept ValueError as e:\n    if 'No server URL found' in str(e):\n        provider = FastMCPProvider(spec, client=httpx.AsyncClient(base_url=DEFAULT_BASE_URL))\n    else:\n        raise","preventionTips":["Always include a servers entry in specs used with FastMCP","Pass an explicit AsyncClient when the spec lacks servers","Migrate Swagger 2.0 host/basePath to OpenAPI 3 servers"],"tags":["openapi","configuration","http"],"backgroundTag":"missing-server-url","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}