From 292f4683667eb0bdf529db8f82bf26b526a47da5 Mon Sep 17 00:00:00 2001 From: teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 7 May 2026 13:05:49 -0700 Subject: [PATCH] fix(mcp): unwrap platforms key in channels_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit channels_list was iterating directory.items() directly, yielding ("updated_at", str) and ("platforms", dict) pairs — neither passed the isinstance(entries_list, list) check, so the inner loop never ran and every call returned count=0 even when channel_directory.json was populated. The writer (gateway/channel_directory.py) wraps the payload as {"updated_at": ..., "platforms": {...}}; every other reader in the codebase unwraps via directory.get("platforms", {}). This aligns channels_list with that convention. Also tightens the existing test_channels_with_directory test, which bypassed the bug by asserting against _load_channel_directory() directly instead of calling channels_list. It now calls the tool end-to-end and a new test_channels_with_directory_platform_filter covers the filter path. Both tests fail against the pre-fix code. Closes #21474 Co-authored-by: chrisworksai <262485129+chrisworksai@users.noreply.github.com> --- mcp_serve.py | 2 +- tests/test_mcp_serve.py | 45 ++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 10 deletions(-) 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: