diff --git a/mcp_serve.py b/mcp_serve.py index d895120b18..d10306fb5c 100644 --- a/mcp_serve.py +++ b/mcp_serve.py @@ -802,7 +802,7 @@ def create_mcp_server(event_bridge: Optional[EventBridge] = None) -> "FastMCP": return json.dumps({"count": len(targets), "channels": targets}, indent=2) channels = [] - for plat, entries_list in directory.items(): + for plat, entries_list in directory.get("platforms", {}).items(): if platform and plat.lower() != platform.lower(): continue if isinstance(entries_list, list): diff --git a/tests/test_mcp_serve.py b/tests/test_mcp_serve.py index db82fa7882..86e3ae0bd3 100644 --- a/tests/test_mcp_serve.py +++ b/tests/test_mcp_serve.py @@ -828,18 +828,45 @@ class TestE2EChannelsList: assert result["channels"][0]["target"] == "slack:C1234" def test_channels_with_directory(self, mcp_server_e2e, _event_loop, monkeypatch): + """Populated channel_directory.json should be unwrapped via the 'platforms' key. + + Regression test for issue #21474: the writer wraps platforms under + {"updated_at": ..., "platforms": {...}} but the reader was iterating + directory.items() directly, so channels_list always returned 0. + """ import mcp_serve monkeypatch.setattr(mcp_serve, "_load_channel_directory", lambda: { - "telegram": [ - {"id": "123456", "name": "Alice", "type": "dm"}, - {"id": "-100999", "name": "Dev Group", "type": "group"}, - ], + "updated_at": "2026-05-07T12:00:00", + "platforms": { + "telegram": [ + {"id": "123456", "name": "Alice", "type": "dm"}, + {"id": "-100999", "name": "Dev Group", "type": "group"}, + ], + "discord": [ + {"id": "789", "name": "general", "type": "text"}, + ], + }, }) - # Need to recreate server to pick up the new mock - server, bridge = mcp_server_e2e - # The tool closure already captured the old mock, so test the function directly - directory = mcp_serve._load_channel_directory() - assert len(directory["telegram"]) == 2 + server, _ = mcp_server_e2e + result = _run_tool(server, "channels_list") + assert result["count"] == 3 + targets = {c["target"] for c in result["channels"]} + assert targets == {"telegram:123456", "telegram:-100999", "discord:789"} + + def test_channels_with_directory_platform_filter(self, mcp_server_e2e, _event_loop, monkeypatch): + """Platform filter should work against the wrapped 'platforms' payload.""" + import mcp_serve + monkeypatch.setattr(mcp_serve, "_load_channel_directory", lambda: { + "updated_at": "2026-05-07T12:00:00", + "platforms": { + "telegram": [{"id": "123456", "name": "Alice", "type": "dm"}], + "discord": [{"id": "789", "name": "general", "type": "text"}], + }, + }) + server, _ = mcp_server_e2e + result = _run_tool(server, "channels_list", {"platform": "discord"}) + assert result["count"] == 1 + assert result["channels"][0]["target"] == "discord:789" class TestE2EPermissions: