Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
0bb59f7
1
Parent(s): cca52df
Incorporate `enabled` property
Browse files- src/fastmcp/server/server.py +3 -3
- tests/server/test_server.py +29 -29
src/fastmcp/server/server.py
CHANGED
|
@@ -555,7 +555,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 555 |
# Get tool, checking first from our tools, then from the mounted servers
|
| 556 |
if self._tool_manager.has_tool(key):
|
| 557 |
tool = self._tool_manager.get_tool(key)
|
| 558 |
-
if not
|
| 559 |
raise DisabledError(f"Tool {key!r} is disabled")
|
| 560 |
return await self._tool_manager.call_tool(key, arguments)
|
| 561 |
|
|
@@ -592,7 +592,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 592 |
"""
|
| 593 |
if self._resource_manager.has_resource(uri):
|
| 594 |
resource = await self._resource_manager.get_resource(uri)
|
| 595 |
-
if not
|
| 596 |
raise DisabledError(f"Resource {str(uri)!r} is disabled")
|
| 597 |
content = await self._resource_manager.read_resource(uri)
|
| 598 |
return [
|
|
@@ -646,7 +646,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 646 |
# Get prompt, checking first from our prompts, then from the mounted servers
|
| 647 |
if self._prompt_manager.has_prompt(name):
|
| 648 |
prompt = self._prompt_manager.get_prompt(name)
|
| 649 |
-
if not
|
| 650 |
raise DisabledError(f"Prompt {name!r} is disabled")
|
| 651 |
return await self._prompt_manager.render_prompt(name, arguments)
|
| 652 |
|
|
|
|
| 555 |
# Get tool, checking first from our tools, then from the mounted servers
|
| 556 |
if self._tool_manager.has_tool(key):
|
| 557 |
tool = self._tool_manager.get_tool(key)
|
| 558 |
+
if not self._should_enable_component(tool):
|
| 559 |
raise DisabledError(f"Tool {key!r} is disabled")
|
| 560 |
return await self._tool_manager.call_tool(key, arguments)
|
| 561 |
|
|
|
|
| 592 |
"""
|
| 593 |
if self._resource_manager.has_resource(uri):
|
| 594 |
resource = await self._resource_manager.get_resource(uri)
|
| 595 |
+
if not self._should_enable_component(resource):
|
| 596 |
raise DisabledError(f"Resource {str(uri)!r} is disabled")
|
| 597 |
content = await self._resource_manager.read_resource(uri)
|
| 598 |
return [
|
|
|
|
| 646 |
# Get prompt, checking first from our prompts, then from the mounted servers
|
| 647 |
if self._prompt_manager.has_prompt(name):
|
| 648 |
prompt = self._prompt_manager.get_prompt(name)
|
| 649 |
+
if not self._should_enable_component(prompt):
|
| 650 |
raise DisabledError(f"Prompt {name!r} is disabled")
|
| 651 |
return await self._prompt_manager.render_prompt(name, arguments)
|
| 652 |
|
tests/server/test_server.py
CHANGED
|
@@ -1242,7 +1242,7 @@ class TestShouldIncludeComponent:
|
|
| 1242 |
"""Test that when no include or exclude filters are provided, always returns True."""
|
| 1243 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1244 |
mcp = FastMCP(tools=[tool])
|
| 1245 |
-
result = mcp.
|
| 1246 |
assert result is True
|
| 1247 |
|
| 1248 |
def test_exclude_string_tag_present_returns_false(self):
|
|
@@ -1251,28 +1251,28 @@ class TestShouldIncludeComponent:
|
|
| 1251 |
name="test_tool", tags={"tag1", "tag2", "exclude_me"}, parameters={}
|
| 1252 |
)
|
| 1253 |
mcp = FastMCP(tools=[tool], exclude_tags={"exclude_me"})
|
| 1254 |
-
result = mcp.
|
| 1255 |
assert result is False
|
| 1256 |
|
| 1257 |
def test_exclude_string_tag_absent_returns_true(self):
|
| 1258 |
"""Test that when an exclude string tag is not present in tags, returns True."""
|
| 1259 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1260 |
mcp = FastMCP(tools=[tool], exclude_tags={"exclude_me"})
|
| 1261 |
-
result = mcp.
|
| 1262 |
assert result is True
|
| 1263 |
|
| 1264 |
def test_exclude_tuple_all_present_returns_false(self):
|
| 1265 |
"""Test that when all tags in exclude tuple are present, returns False."""
|
| 1266 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1267 |
mcp = FastMCP(tools=[tool], exclude_tags={("tag1", "tag2")})
|
| 1268 |
-
result = mcp.
|
| 1269 |
assert result is False
|
| 1270 |
|
| 1271 |
def test_exclude_tuple_partial_present_returns_true(self):
|
| 1272 |
"""Test that when only some tags in exclude tuple are present, returns True."""
|
| 1273 |
tool = Tool(name="test_tool", tags={"tag1", "tag3"}, parameters={})
|
| 1274 |
mcp = FastMCP(tools=[tool], exclude_tags={("tag1", "tag2")})
|
| 1275 |
-
result = mcp.
|
| 1276 |
assert result is True
|
| 1277 |
|
| 1278 |
def test_multiple_exclude_tags_any_match_returns_false(self):
|
|
@@ -1281,7 +1281,7 @@ class TestShouldIncludeComponent:
|
|
| 1281 |
mcp = FastMCP(
|
| 1282 |
tools=[tool], exclude_tags={"not_present", "tag2", "also_not_present"}
|
| 1283 |
)
|
| 1284 |
-
result = mcp.
|
| 1285 |
assert result is False
|
| 1286 |
|
| 1287 |
def test_include_string_tag_present_returns_true(self):
|
|
@@ -1290,28 +1290,28 @@ class TestShouldIncludeComponent:
|
|
| 1290 |
name="test_tool", tags={"tag1", "include_me", "tag2"}, parameters={}
|
| 1291 |
)
|
| 1292 |
mcp = FastMCP(tools=[tool], include_tags={"include_me"})
|
| 1293 |
-
result = mcp.
|
| 1294 |
assert result is True
|
| 1295 |
|
| 1296 |
def test_include_string_tag_absent_returns_false(self):
|
| 1297 |
"""Test that when an include string tag is not present in tags, returns False."""
|
| 1298 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1299 |
mcp = FastMCP(tools=[tool], include_tags={"include_me"})
|
| 1300 |
-
result = mcp.
|
| 1301 |
assert result is False
|
| 1302 |
|
| 1303 |
def test_include_tuple_all_present_returns_true(self):
|
| 1304 |
"""Test that when all tags in include tuple are present, returns True."""
|
| 1305 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1306 |
mcp = FastMCP(tools=[tool], include_tags={("tag1", "tag2")})
|
| 1307 |
-
result = mcp.
|
| 1308 |
assert result is True
|
| 1309 |
|
| 1310 |
def test_include_tuple_partial_present_returns_false(self):
|
| 1311 |
"""Test that when only some tags in include tuple are present, returns False."""
|
| 1312 |
tool = Tool(name="test_tool", tags={"tag1", "tag3"}, parameters={})
|
| 1313 |
mcp = FastMCP(tools=[tool], include_tags={("tag1", "tag2")})
|
| 1314 |
-
result = mcp.
|
| 1315 |
assert result is False
|
| 1316 |
|
| 1317 |
def test_multiple_include_tags_any_match_returns_true(self):
|
|
@@ -1320,14 +1320,14 @@ class TestShouldIncludeComponent:
|
|
| 1320 |
mcp = FastMCP(
|
| 1321 |
tools=[tool], include_tags={"not_present", "tag2", "also_not_present"}
|
| 1322 |
)
|
| 1323 |
-
result = mcp.
|
| 1324 |
assert result is True
|
| 1325 |
|
| 1326 |
def test_multiple_include_tags_none_match_returns_false(self):
|
| 1327 |
"""Test that when no include tags match, returns False."""
|
| 1328 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1329 |
mcp = FastMCP(tools=[tool], include_tags={"not_present", "also_not_present"})
|
| 1330 |
-
result = mcp.
|
| 1331 |
assert result is False
|
| 1332 |
|
| 1333 |
def test_exclude_takes_precedence_over_include(self):
|
|
@@ -1336,7 +1336,7 @@ class TestShouldIncludeComponent:
|
|
| 1336 |
name="test_tool", tags={"tag1", "tag2", "exclude_me"}, parameters={}
|
| 1337 |
)
|
| 1338 |
mcp = FastMCP(tools=[tool], include_tags={"tag1"}, exclude_tags={"exclude_me"})
|
| 1339 |
-
result = mcp.
|
| 1340 |
assert result is False
|
| 1341 |
|
| 1342 |
def test_mixed_string_and_tuple_exclude_tags(self):
|
|
@@ -1346,13 +1346,13 @@ class TestShouldIncludeComponent:
|
|
| 1346 |
name="test_tool", tags={"tag1", "tag2", "tag3", "tag4"}, parameters={}
|
| 1347 |
)
|
| 1348 |
mcp1 = FastMCP(tools=[tool1], exclude_tags={"tag1", ("tag2", "tag3")})
|
| 1349 |
-
result = mcp1.
|
| 1350 |
assert result is False
|
| 1351 |
|
| 1352 |
# Remove tag1, should still be excluded because both tag2 and tag3 are present
|
| 1353 |
tool2 = Tool(name="test_tool", tags={"tag2", "tag3", "tag4"}, parameters={})
|
| 1354 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={"tag1", ("tag2", "tag3")})
|
| 1355 |
-
result = mcp2.
|
| 1356 |
assert result is False
|
| 1357 |
|
| 1358 |
# Remove tag2, should not be excluded
|
|
@@ -1360,7 +1360,7 @@ class TestShouldIncludeComponent:
|
|
| 1360 |
name="test_tool", tags={"tag1_removed", "tag3", "tag4"}, parameters={}
|
| 1361 |
)
|
| 1362 |
mcp3 = FastMCP(tools=[tool3], exclude_tags={("tag2", "tag3")})
|
| 1363 |
-
result = mcp3.
|
| 1364 |
assert result is True
|
| 1365 |
|
| 1366 |
def test_mixed_string_and_tuple_include_tags(self):
|
|
@@ -1368,7 +1368,7 @@ class TestShouldIncludeComponent:
|
|
| 1368 |
# Should be included because both tag1 and tag2 are present (tuple match)
|
| 1369 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1370 |
mcp1 = FastMCP(tools=[tool1], include_tags={"not_present", ("tag1", "tag2")})
|
| 1371 |
-
result = mcp1.
|
| 1372 |
assert result is True
|
| 1373 |
|
| 1374 |
# Should be included because tag1 is present (string match)
|
|
@@ -1376,7 +1376,7 @@ class TestShouldIncludeComponent:
|
|
| 1376 |
mcp2 = FastMCP(
|
| 1377 |
tools=[tool2], include_tags={"tag1", ("not_present1", "not_present2")}
|
| 1378 |
)
|
| 1379 |
-
result = mcp2.
|
| 1380 |
assert result is True
|
| 1381 |
|
| 1382 |
# Should not be included because no conditions are met
|
|
@@ -1385,7 +1385,7 @@ class TestShouldIncludeComponent:
|
|
| 1385 |
tools=[tool3],
|
| 1386 |
include_tags={"not_present", ("not_present1", "not_present2")},
|
| 1387 |
)
|
| 1388 |
-
result = mcp3.
|
| 1389 |
assert result is False
|
| 1390 |
|
| 1391 |
def test_complex_scenario_with_both_filters(self):
|
|
@@ -1399,7 +1399,7 @@ class TestShouldIncludeComponent:
|
|
| 1399 |
include_tags={"api", ("read", "admin")},
|
| 1400 |
exclude_tags={"sensitive"},
|
| 1401 |
)
|
| 1402 |
-
result = mcp1.
|
| 1403 |
assert result is False
|
| 1404 |
|
| 1405 |
# Remove sensitive tag, should now be included
|
|
@@ -1409,7 +1409,7 @@ class TestShouldIncludeComponent:
|
|
| 1409 |
include_tags={"api", ("read", "admin")},
|
| 1410 |
exclude_tags={"sensitive"},
|
| 1411 |
)
|
| 1412 |
-
result = mcp2.
|
| 1413 |
assert result is True
|
| 1414 |
|
| 1415 |
def test_empty_include_exclude_sets(self):
|
|
@@ -1417,13 +1417,13 @@ class TestShouldIncludeComponent:
|
|
| 1417 |
# Empty include set means nothing matches
|
| 1418 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1419 |
mcp1 = FastMCP(tools=[tool1], include_tags=set())
|
| 1420 |
-
result = mcp1.
|
| 1421 |
assert result is False
|
| 1422 |
|
| 1423 |
# Empty exclude set means nothing excluded
|
| 1424 |
tool2 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1425 |
mcp2 = FastMCP(tools=[tool2], exclude_tags=set())
|
| 1426 |
-
result = mcp2.
|
| 1427 |
assert result is True
|
| 1428 |
|
| 1429 |
def test_empty_tags_with_filters(self):
|
|
@@ -1431,24 +1431,24 @@ class TestShouldIncludeComponent:
|
|
| 1431 |
# With include filters, empty tags should not match
|
| 1432 |
tool1 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1433 |
mcp1 = FastMCP(tools=[tool1], include_tags={"required_tag"})
|
| 1434 |
-
result = mcp1.
|
| 1435 |
assert result is False
|
| 1436 |
|
| 1437 |
# With exclude filters but no include, empty tags should pass
|
| 1438 |
tool2 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1439 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={"bad_tag"})
|
| 1440 |
-
result = mcp2.
|
| 1441 |
assert result is True
|
| 1442 |
|
| 1443 |
# Tuple filters with empty tags
|
| 1444 |
tool3 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1445 |
mcp3 = FastMCP(tools=[tool3], include_tags={("tag1", "tag2")})
|
| 1446 |
-
result = mcp3.
|
| 1447 |
assert result is False
|
| 1448 |
|
| 1449 |
tool4 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1450 |
mcp4 = FastMCP(tools=[tool4], exclude_tags={("tag1", "tag2")})
|
| 1451 |
-
result = mcp4.
|
| 1452 |
assert result is True
|
| 1453 |
|
| 1454 |
def test_single_element_tuples(self):
|
|
@@ -1456,10 +1456,10 @@ class TestShouldIncludeComponent:
|
|
| 1456 |
# Single-element tuple should behave like a string
|
| 1457 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1458 |
mcp1 = FastMCP(tools=[tool1], include_tags={("tag1",)})
|
| 1459 |
-
result = mcp1.
|
| 1460 |
assert result is True
|
| 1461 |
|
| 1462 |
tool2 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1463 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={("tag1",)})
|
| 1464 |
-
result = mcp2.
|
| 1465 |
assert result is False
|
|
|
|
| 1242 |
"""Test that when no include or exclude filters are provided, always returns True."""
|
| 1243 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1244 |
mcp = FastMCP(tools=[tool])
|
| 1245 |
+
result = mcp._should_enable_component(tool)
|
| 1246 |
assert result is True
|
| 1247 |
|
| 1248 |
def test_exclude_string_tag_present_returns_false(self):
|
|
|
|
| 1251 |
name="test_tool", tags={"tag1", "tag2", "exclude_me"}, parameters={}
|
| 1252 |
)
|
| 1253 |
mcp = FastMCP(tools=[tool], exclude_tags={"exclude_me"})
|
| 1254 |
+
result = mcp._should_enable_component(tool)
|
| 1255 |
assert result is False
|
| 1256 |
|
| 1257 |
def test_exclude_string_tag_absent_returns_true(self):
|
| 1258 |
"""Test that when an exclude string tag is not present in tags, returns True."""
|
| 1259 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1260 |
mcp = FastMCP(tools=[tool], exclude_tags={"exclude_me"})
|
| 1261 |
+
result = mcp._should_enable_component(tool)
|
| 1262 |
assert result is True
|
| 1263 |
|
| 1264 |
def test_exclude_tuple_all_present_returns_false(self):
|
| 1265 |
"""Test that when all tags in exclude tuple are present, returns False."""
|
| 1266 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1267 |
mcp = FastMCP(tools=[tool], exclude_tags={("tag1", "tag2")})
|
| 1268 |
+
result = mcp._should_enable_component(tool)
|
| 1269 |
assert result is False
|
| 1270 |
|
| 1271 |
def test_exclude_tuple_partial_present_returns_true(self):
|
| 1272 |
"""Test that when only some tags in exclude tuple are present, returns True."""
|
| 1273 |
tool = Tool(name="test_tool", tags={"tag1", "tag3"}, parameters={})
|
| 1274 |
mcp = FastMCP(tools=[tool], exclude_tags={("tag1", "tag2")})
|
| 1275 |
+
result = mcp._should_enable_component(tool)
|
| 1276 |
assert result is True
|
| 1277 |
|
| 1278 |
def test_multiple_exclude_tags_any_match_returns_false(self):
|
|
|
|
| 1281 |
mcp = FastMCP(
|
| 1282 |
tools=[tool], exclude_tags={"not_present", "tag2", "also_not_present"}
|
| 1283 |
)
|
| 1284 |
+
result = mcp._should_enable_component(tool)
|
| 1285 |
assert result is False
|
| 1286 |
|
| 1287 |
def test_include_string_tag_present_returns_true(self):
|
|
|
|
| 1290 |
name="test_tool", tags={"tag1", "include_me", "tag2"}, parameters={}
|
| 1291 |
)
|
| 1292 |
mcp = FastMCP(tools=[tool], include_tags={"include_me"})
|
| 1293 |
+
result = mcp._should_enable_component(tool)
|
| 1294 |
assert result is True
|
| 1295 |
|
| 1296 |
def test_include_string_tag_absent_returns_false(self):
|
| 1297 |
"""Test that when an include string tag is not present in tags, returns False."""
|
| 1298 |
tool = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1299 |
mcp = FastMCP(tools=[tool], include_tags={"include_me"})
|
| 1300 |
+
result = mcp._should_enable_component(tool)
|
| 1301 |
assert result is False
|
| 1302 |
|
| 1303 |
def test_include_tuple_all_present_returns_true(self):
|
| 1304 |
"""Test that when all tags in include tuple are present, returns True."""
|
| 1305 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1306 |
mcp = FastMCP(tools=[tool], include_tags={("tag1", "tag2")})
|
| 1307 |
+
result = mcp._should_enable_component(tool)
|
| 1308 |
assert result is True
|
| 1309 |
|
| 1310 |
def test_include_tuple_partial_present_returns_false(self):
|
| 1311 |
"""Test that when only some tags in include tuple are present, returns False."""
|
| 1312 |
tool = Tool(name="test_tool", tags={"tag1", "tag3"}, parameters={})
|
| 1313 |
mcp = FastMCP(tools=[tool], include_tags={("tag1", "tag2")})
|
| 1314 |
+
result = mcp._should_enable_component(tool)
|
| 1315 |
assert result is False
|
| 1316 |
|
| 1317 |
def test_multiple_include_tags_any_match_returns_true(self):
|
|
|
|
| 1320 |
mcp = FastMCP(
|
| 1321 |
tools=[tool], include_tags={"not_present", "tag2", "also_not_present"}
|
| 1322 |
)
|
| 1323 |
+
result = mcp._should_enable_component(tool)
|
| 1324 |
assert result is True
|
| 1325 |
|
| 1326 |
def test_multiple_include_tags_none_match_returns_false(self):
|
| 1327 |
"""Test that when no include tags match, returns False."""
|
| 1328 |
tool = Tool(name="test_tool", tags={"tag1", "tag2", "tag3"}, parameters={})
|
| 1329 |
mcp = FastMCP(tools=[tool], include_tags={"not_present", "also_not_present"})
|
| 1330 |
+
result = mcp._should_enable_component(tool)
|
| 1331 |
assert result is False
|
| 1332 |
|
| 1333 |
def test_exclude_takes_precedence_over_include(self):
|
|
|
|
| 1336 |
name="test_tool", tags={"tag1", "tag2", "exclude_me"}, parameters={}
|
| 1337 |
)
|
| 1338 |
mcp = FastMCP(tools=[tool], include_tags={"tag1"}, exclude_tags={"exclude_me"})
|
| 1339 |
+
result = mcp._should_enable_component(tool)
|
| 1340 |
assert result is False
|
| 1341 |
|
| 1342 |
def test_mixed_string_and_tuple_exclude_tags(self):
|
|
|
|
| 1346 |
name="test_tool", tags={"tag1", "tag2", "tag3", "tag4"}, parameters={}
|
| 1347 |
)
|
| 1348 |
mcp1 = FastMCP(tools=[tool1], exclude_tags={"tag1", ("tag2", "tag3")})
|
| 1349 |
+
result = mcp1._should_enable_component(tool1)
|
| 1350 |
assert result is False
|
| 1351 |
|
| 1352 |
# Remove tag1, should still be excluded because both tag2 and tag3 are present
|
| 1353 |
tool2 = Tool(name="test_tool", tags={"tag2", "tag3", "tag4"}, parameters={})
|
| 1354 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={"tag1", ("tag2", "tag3")})
|
| 1355 |
+
result = mcp2._should_enable_component(tool2)
|
| 1356 |
assert result is False
|
| 1357 |
|
| 1358 |
# Remove tag2, should not be excluded
|
|
|
|
| 1360 |
name="test_tool", tags={"tag1_removed", "tag3", "tag4"}, parameters={}
|
| 1361 |
)
|
| 1362 |
mcp3 = FastMCP(tools=[tool3], exclude_tags={("tag2", "tag3")})
|
| 1363 |
+
result = mcp3._should_enable_component(tool3)
|
| 1364 |
assert result is True
|
| 1365 |
|
| 1366 |
def test_mixed_string_and_tuple_include_tags(self):
|
|
|
|
| 1368 |
# Should be included because both tag1 and tag2 are present (tuple match)
|
| 1369 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1370 |
mcp1 = FastMCP(tools=[tool1], include_tags={"not_present", ("tag1", "tag2")})
|
| 1371 |
+
result = mcp1._should_enable_component(tool1)
|
| 1372 |
assert result is True
|
| 1373 |
|
| 1374 |
# Should be included because tag1 is present (string match)
|
|
|
|
| 1376 |
mcp2 = FastMCP(
|
| 1377 |
tools=[tool2], include_tags={"tag1", ("not_present1", "not_present2")}
|
| 1378 |
)
|
| 1379 |
+
result = mcp2._should_enable_component(tool2)
|
| 1380 |
assert result is True
|
| 1381 |
|
| 1382 |
# Should not be included because no conditions are met
|
|
|
|
| 1385 |
tools=[tool3],
|
| 1386 |
include_tags={"not_present", ("not_present1", "not_present2")},
|
| 1387 |
)
|
| 1388 |
+
result = mcp3._should_enable_component(tool3)
|
| 1389 |
assert result is False
|
| 1390 |
|
| 1391 |
def test_complex_scenario_with_both_filters(self):
|
|
|
|
| 1399 |
include_tags={"api", ("read", "admin")},
|
| 1400 |
exclude_tags={"sensitive"},
|
| 1401 |
)
|
| 1402 |
+
result = mcp1._should_enable_component(tool1)
|
| 1403 |
assert result is False
|
| 1404 |
|
| 1405 |
# Remove sensitive tag, should now be included
|
|
|
|
| 1409 |
include_tags={"api", ("read", "admin")},
|
| 1410 |
exclude_tags={"sensitive"},
|
| 1411 |
)
|
| 1412 |
+
result = mcp2._should_enable_component(tool2)
|
| 1413 |
assert result is True
|
| 1414 |
|
| 1415 |
def test_empty_include_exclude_sets(self):
|
|
|
|
| 1417 |
# Empty include set means nothing matches
|
| 1418 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1419 |
mcp1 = FastMCP(tools=[tool1], include_tags=set())
|
| 1420 |
+
result = mcp1._should_enable_component(tool1)
|
| 1421 |
assert result is False
|
| 1422 |
|
| 1423 |
# Empty exclude set means nothing excluded
|
| 1424 |
tool2 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1425 |
mcp2 = FastMCP(tools=[tool2], exclude_tags=set())
|
| 1426 |
+
result = mcp2._should_enable_component(tool2)
|
| 1427 |
assert result is True
|
| 1428 |
|
| 1429 |
def test_empty_tags_with_filters(self):
|
|
|
|
| 1431 |
# With include filters, empty tags should not match
|
| 1432 |
tool1 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1433 |
mcp1 = FastMCP(tools=[tool1], include_tags={"required_tag"})
|
| 1434 |
+
result = mcp1._should_enable_component(tool1)
|
| 1435 |
assert result is False
|
| 1436 |
|
| 1437 |
# With exclude filters but no include, empty tags should pass
|
| 1438 |
tool2 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1439 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={"bad_tag"})
|
| 1440 |
+
result = mcp2._should_enable_component(tool2)
|
| 1441 |
assert result is True
|
| 1442 |
|
| 1443 |
# Tuple filters with empty tags
|
| 1444 |
tool3 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1445 |
mcp3 = FastMCP(tools=[tool3], include_tags={("tag1", "tag2")})
|
| 1446 |
+
result = mcp3._should_enable_component(tool3)
|
| 1447 |
assert result is False
|
| 1448 |
|
| 1449 |
tool4 = Tool(name="test_tool", tags=set(), parameters={})
|
| 1450 |
mcp4 = FastMCP(tools=[tool4], exclude_tags={("tag1", "tag2")})
|
| 1451 |
+
result = mcp4._should_enable_component(tool4)
|
| 1452 |
assert result is True
|
| 1453 |
|
| 1454 |
def test_single_element_tuples(self):
|
|
|
|
| 1456 |
# Single-element tuple should behave like a string
|
| 1457 |
tool1 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1458 |
mcp1 = FastMCP(tools=[tool1], include_tags={("tag1",)})
|
| 1459 |
+
result = mcp1._should_enable_component(tool1)
|
| 1460 |
assert result is True
|
| 1461 |
|
| 1462 |
tool2 = Tool(name="test_tool", tags={"tag1", "tag2"}, parameters={})
|
| 1463 |
mcp2 = FastMCP(tools=[tool2], exclude_tags={("tag1",)})
|
| 1464 |
+
result = mcp2._should_enable_component(tool2)
|
| 1465 |
assert result is False
|