Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions packages/decepticon/decepticon/mcp_server/engagements.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,24 @@ def _ensure_client(self) -> Any:
return self._client

async def list_graphs(self) -> list[GraphInfo]:
"""Return the engagement graphs (assistants) the connected server exposes."""
"""Return the engagement graphs (assistants) the connected server exposes.

Pages through ``assistants.search`` to the end. The LangGraph SDK
defaults to ``limit=10``, so a single call silently truncated installs
that expose more than ten graphs (the OSS ``standard`` bundle alone
ships 22), hiding agents such as ``recon``, ``soundwave`` and the
``decepticon`` orchestrator from callers.
Comment on lines +103 to +107

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add this user-visible fix to CHAGELOG.md

This changes the user-visible MCP graph catalog, but the commit leaves CHAGELOG.md unchanged and no Unreleased entry describes the fix, despite the commit message claiming one was added. Record the proposed fix and its PR link so release tracking does not omit it.

AGENTS.md reference: AGENTS.md:L3-L8

Useful? React with 👍 / 👎.

"""
client = self._ensure_client()
assistants = await client.assistants.search()
page_size = 100
assistants: list[Any] = []
offset = 0
while True:
page = await client.assistants.search(limit=page_size, offset=offset)
assistants.extend(page)
if len(page) < page_size:
break
offset += page_size
return [
GraphInfo(
assistant_id=str(entry.get("assistant_id", "")),
Expand Down
31 changes: 28 additions & 3 deletions packages/decepticon/tests/unit/mcp_server/test_engagements.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,17 @@ async def join_stream(


class _FakeAssistants:
async def search(self) -> list[dict[str, Any]]:
return [{"assistant_id": "a-1", "graph_id": "decepticon", "name": "decepticon"}]
def __init__(self, assistants: list[dict[str, Any]] | None = None) -> None:
self._assistants = (
assistants
if assistants is not None
else [{"assistant_id": "a-1", "graph_id": "decepticon", "name": "decepticon"}]
)
self.search_calls: list[tuple[int, int]] = []

async def search(self, *, limit: int = 10, offset: int = 0) -> list[dict[str, Any]]:
self.search_calls.append((limit, offset))
return self._assistants[offset : offset + limit]


class _FakeClient:
Expand All @@ -72,10 +81,11 @@ def __init__(
runs: list[dict[str, Any]] | None = None,
threads: list[dict[str, Any]] | None = None,
stream: list[_Part] | None = None,
assistants: list[dict[str, Any]] | None = None,
) -> None:
self.threads = _FakeThreads(threads)
self.runs = _FakeRuns(runs, stream)
self.assistants = _FakeAssistants()
self.assistants = _FakeAssistants(assistants)


def _config() -> ServerConfig:
Expand Down Expand Up @@ -213,3 +223,18 @@ async def test_list_graphs_maps_assistants() -> None:
graphs = await client.list_graphs()
assert graphs[0].graph_id == "decepticon"
assert graphs[0].assistant_id == "a-1"


async def test_list_graphs_pages_past_sdk_default_limit() -> None:
# More graphs than the LangGraph SDK's default page size — the client must
# page to the end instead of silently returning only the first page.
many = [
{"assistant_id": f"a-{n}", "graph_id": f"g{n}", "name": f"g{n}"} for n in range(150)
]
fake = _FakeClient(assistants=many)
client = EngagementClient(_config(), client=fake)
graphs = await client.list_graphs()
assert len(graphs) == 150
assert graphs[-1].graph_id == "g149"
# Explicit limit/offset paging, not a single bare search() call.
assert fake.assistants.search_calls == [(100, 0), (100, 100)]
Loading