Skip to content

Commit d15657b

Browse files
fix(skills): read MCP server registry live to avoid stale STRICT gate
CapabilityValidator cached the MCP server snapshot once, so servers that connected after the first validation stayed invisible under STRICT enforcement. Read the process-level registry live each call (cheap set-copy under lock); tool cache is unchanged. (#3307) Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
1 parent b19e4da commit d15657b

2 files changed

Lines changed: 25 additions & 7 deletions

File tree

src/praisonai-agents/praisonaiagents/skills/capability_validator.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,22 +203,21 @@ def _get_available_tools(self) -> Set[str]:
203203
return self._tool_cache
204204

205205
def _get_available_servers(self) -> Set[str]:
206-
"""Get set of available MCP server names.
206+
"""Get set of available MCP server names from the active MCP registry.
207207
208208
Derives names from the MCP client registry of servers that have been
209209
namespaced (via ``with_tool_prefix``) in this process. Without this an
210210
MCP-server-gated skill could never pass STRICT validation because the
211211
set was always empty (issue #3307).
212212
213-
Queried live (not cached) because MCP servers register lazily: a skill
214-
may be validated before its required server connects. Caching the first
215-
empty snapshot would leave STRICT validation permanently reporting the
216-
skill unavailable even after the server registers. The registry read is
217-
just a cheap ``set`` copy, so there is no hot-path cost.
213+
The MCP registry is populated dynamically as servers connect during a
214+
run, so this is read live (not cached) to avoid a stale snapshot that
215+
would keep rejecting servers registered after the first validation.
216+
The read is a cheap set copy under a lock, so there is no hot-path cost.
218217
"""
219218
try:
220219
from ..mcp.mcp import MCP
221-
return MCP.list_active_server_names()
220+
return set(MCP.list_active_server_names())
222221
except ImportError:
223222
logger.debug("MCP not available")
224223
return set()

src/praisonai-agents/tests/unit/skills/test_capability_validator.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,25 @@ def test_available_servers_read_from_mcp_registry(self):
269269
servers = validator._get_available_servers()
270270
assert "filesystem" in servers
271271

272+
def test_available_servers_read_live_not_cached(self):
273+
"""Issue #3307 Gap 3: server availability must not be cached stale.
274+
275+
The MCP registry fills in as servers connect during a run, so a server
276+
registered after the first validation must become visible without an
277+
explicit clear_cache() call.
278+
"""
279+
validator = CapabilityValidator(EnforcementLevel.STRICT)
280+
with patch(
281+
"praisonaiagents.mcp.mcp.MCP.list_active_server_names",
282+
return_value=set(),
283+
):
284+
assert validator._get_available_servers() == set()
285+
with patch(
286+
"praisonaiagents.mcp.mcp.MCP.list_active_server_names",
287+
return_value={"filesystem"},
288+
):
289+
assert "filesystem" in validator._get_available_servers()
290+
272291
def test_mcp_gated_skill_passes_strict_when_server_active(self):
273292
"""Issue #3307 Gap 3: an MCP-server-gated skill can now pass STRICT."""
274293
requirements = SkillRequirements(servers=["filesystem"])

0 commit comments

Comments
 (0)