{"record":{"id":"c940d404bbc6f8d7","repo":"PrefectHQ/fastmcp","slug":"at-least-one-of-tools-include-tags-or-exclu","errorCode":null,"errorMessage":"At least one of 'tools', 'include_tags', or 'exclude_tags' is required","messagePattern":"At least one of 'tools', 'include_tags', or 'exclude_tags' is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/mcp_config.py","lineNumber":118,"sourceCode":"    )\n\n    @model_validator(mode=\"before\")\n    @classmethod\n    def _require_at_least_one_transform_field(\n        cls, values: dict[str, Any]\n    ) -> dict[str, Any]:\n        \"\"\"Reject if none of the transforming fields are set.\n\n        This ensures that plain server configs (without tools, include_tags,\n        or exclude_tags) fall through to the base server types during union\n        validation, avoiding unnecessary proxy wrapping.\n        \"\"\"\n        if isinstance(values, dict):\n            has_tools = bool(values.get(\"tools\"))\n            has_include = values.get(\"include_tags\") is not None\n            has_exclude = values.get(\"exclude_tags\") is not None\n            if not (has_tools or has_include or has_exclude):\n                raise ValueError(\n                    \"At least one of 'tools', 'include_tags', or 'exclude_tags' is required\"\n                )\n        return values\n\n    def _to_server_and_underlying_transport(\n        self,\n        server_name: str | None = None,\n        client_name: str | None = None,\n    ) -> tuple[Any, ClientTransport]:\n        \"\"\"Turn the transforming server into a FastMCP proxy and return its transport.\"\"\"\n        try:\n            from fastmcp import Client\n            from fastmcp.server import create_proxy\n            from fastmcp.server.transforms import ToolTransform\n        except ImportError as exc:\n            raise ImportError(\n                _install_hints.full_package(\n                    \"MCP configs that use FastMCP-specific tool transforms or tag filters\"","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/mcp_config.py#L100-L136","documentation":"MCPConfig's transforming-server variant requires at least one FastMCP-specific filter to be meaningful: a 'tools' whitelist, 'include_tags', or 'exclude_tags'. Pydantic model validation raises ValueError when values is a dict with none of these set, because such a config would proxy everything unchanged.","triggerScenarios":"Constructing MCPConfig.from_dict / model_validate with a server dict that has transform-related keys present but all empty/None (e.g. tools: [], include_tags: null, exclude_tags: null), or omitting all three entirely while using the transforming config path.","commonSituations":"Copy-pasting a transforming-config example and clearing the example values; programmatically generating config where empty lists are serialized as falsy; a template leaving tags blank.","solutions":["Add the tools you want to expose: tools=[\"tool_a\",\"tool_b\"]","Set include_tags to the tags of components to include","Set exclude_tags to filter out unwanted components","If no filtering is wanted, use the plain canonical MCPConfig format instead of the transforming one"],"exampleFix":"// before\nconfig = MCPConfig.from_dict({\"mcpServers\": {\"srv\": {\"url\": \"https://x/mcp\", \"tools\": [], \"include_tags\": null, \"exclude_tags\": null}}})\n// after\nconfig = MCPConfig.from_dict({\"mcpServers\": {\"srv\": {\"url\": \"https://x/mcp\", \"tools\": [\"search\"]}}})","handlingStrategy":"validation","validationCode":"def transforming_config_ok(srv: dict) -> bool:\n    return bool(srv.get(\"tools\")) or srv.get(\"include_tags\") is not None or srv.get(\"exclude_tags\") is not None","typeGuard":null,"tryCatchPattern":"from pydantic import ValidationError\ntry:\n    cfg = MCPConfig.from_dict(data)\nexcept ValidationError as e:\n    ...  # surface which field is missing to the user","preventionTips":["Always specify at least one of tools/include_tags/exclude_tags in transforming configs","Don't serialize empty lists/nulls for these fields; omit them or fill them","Use the canonical config format when no filtering is needed"],"tags":["config","validation","pydantic","mcp"],"backgroundTag":"missing-required-field","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}