{"record":{"id":"b61c861e6b1e1017","repo":"langchain-ai/deepagents","slug":"server-server-name-cannot-set-both-allowedtoo","errorCode":null,"errorMessage":"Server '{server_name}' cannot set both 'allowedTools' and 'disabledTools' — pick one.","messagePattern":"Server '(.+?)' cannot set both 'allowedTools' and 'disabledTools' — pick one\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/mcp_tools.py","lineNumber":988,"sourceCode":"    (`disabledTools`) — both are almost certainly user errors; omit the field\n    instead.\n\n    Args:\n        server_name: Name of the server (for error messages).\n        server_config: Server configuration dictionary.\n\n    Raises:\n        TypeError: If a field is not a list of strings.\n        ValueError: If both fields are set, or either field is empty.\n    \"\"\"\n    has_allowed = \"allowedTools\" in server_config\n    has_disabled = \"disabledTools\" in server_config\n    if has_allowed and has_disabled:\n        error_msg = (\n            f\"Server '{server_name}' cannot set both 'allowedTools' and\"\n            \" 'disabledTools' — pick one.\"\n        )\n        raise ValueError(error_msg)\n\n    for field_name in (\"allowedTools\", \"disabledTools\"):\n        if field_name not in server_config:\n            continue\n        value = server_config[field_name]\n        if not isinstance(value, list) or not all(\n            isinstance(item, str) for item in value\n        ):\n            error_msg = (\n                f\"Server '{server_name}' '{field_name}' must be a list of strings\"\n            )\n            raise TypeError(error_msg)\n        if not value:\n            error_msg = (\n                f\"Server '{server_name}' '{field_name}' must be non-empty;\"\n                \" omit the field to disable filtering.\"\n            )\n            raise ValueError(error_msg)","sourceCodeStart":970,"sourceCodeEnd":1006,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/mcp_tools.py#L970-L1006","documentation":"deepagents_code MCP server configs let you filter which tools are exposed either with an allow-list (`allowedTools`) or a block-list (`disabledTools`), but not both at once. `_validate_tool_filter_fields` raises this ValueError during `_validate_server_config` when a single server entry defines both keys, because the combined semantics would be ambiguous. Fix the config so exactly one of the two fields is present per server.","triggerScenarios":"Loading an MCP config (via _load_mcp_config_top_level -> _validate_server_config) where one server dict under 'mcpServers' contains both 'allowedTools' and 'disabledTools' keys, e.g. {\"mcpServers\": {\"fs\": {\"command\": \"mcp-server-fs\", \"allowedTools\": [\"read_file\"], \"disabledTools\": [\"write_file\"]}}}.","commonSituations":"Merging configs from two sources (project .mcp.json plus user config) where one set allowedTools and the other disabledTools; copy-pasting a server entry from docs that used allowedTools and appending a disabledTools exclusion; team members with different filtering conventions editing the same config file.","solutions":["Choose one filtering style for the server: keep 'allowedTools' (allow-list) and delete the 'disabledTools' key, or vice versa.","If you need allow-list semantics with exclusions, move the excluded tools out of 'allowedTools' instead of listing them in 'disabledTools'.","If the conflict comes from merged configs, ensure the merge is per-key (last-writer-wins) rather than concatenating keys into the same server dict."],"exampleFix":"// before\n{\"mcpServers\": {\"fs\": {\"command\": \"mcp-server-fs\", \"allowedTools\": [\"read_file\"], \"disabledTools\": [\"write_file\"]}}}\n// after\n{\"mcpServers\": {\"fs\": {\"command\": \"mcp-server-fs\", \"allowedTools\": [\"read_file\"]}}}","handlingStrategy":"validation","validationCode":"def check_tool_filter(server):\n    has_allowed = \"allowedTools\" in server\n    has_disabled = \"disabledTools\" in server\n    if has_allowed and has_disabled:\n        raise ValueError(\"set only one of allowedTools/disabledTools\")","typeGuard":"def has_conflicting_filters(server: dict) -> bool:\n    return \"allowedTools\" in server and \"disabledTools\" in server","tryCatchPattern":"try:\n    load_mcp_config(path)\nexcept ValueError as e:\n    if \"cannot set both\" in str(e):\n        fix_config_file(path)  # drop one of the two keys\n    else:\n        raise","preventionTips":["Pick one filtering convention per project and document it in the config README.","When merging configs, merge per-server dicts wholesale instead of key-by-key.","Add a CI check that validates the MCP config schema before deployment."],"tags":["config","mcp","validation","tool-filtering"],"backgroundTag":"conflicting-config-fields","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}