mirror of
https://github.com/usestrix/strix.git
synced 2026-08-28 05:25:00 +00:00
name the run's MCP connections in the prompt again, alongside list_mcps
This commit is contained in:
parent
c220e1fd31
commit
eaf4853415
4 changed files with 51 additions and 18 deletions
|
|
@ -78,6 +78,13 @@ AUTHORIZED TARGETS:
|
|||
{% if system_prompt_context and system_prompt_context.mcp_available %}
|
||||
MCP CONNECTIONS (available this run):
|
||||
- The user connected one or more MCP (Model Context Protocol) servers — external tool providers you can reach on demand. Their individual tools do NOT appear in your tool list; three dispatch tools are the only way in.
|
||||
{% if system_prompt_context.mcp_connections %}
|
||||
- Connected this run (call describe_mcp on one to see its tools):
|
||||
{% for connection in system_prompt_context.mcp_connections %}
|
||||
- {{ connection.name }} ({{ connection.tool_count }} tools){% if connection.purpose %}: {{ connection.purpose }}{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- Reach for a connection whenever the target itself cannot give you information a connection could: its database schema and access policies, real deployment or infrastructure configuration, known issues or prior findings, or server logs. In those cases call list_mcps early to see what is available, and prefer a connection's authoritative data over inferring from the target's responses. Do not wait to be told a connection exists.
|
||||
1. Call list_mcps() to discover the available connections.
|
||||
2. Call describe_mcp(connection="<name>") to inspect one connection's tools, each with its name, description, and JSON input schema.
|
||||
3. Call call_mcp(connection="<name>", tool="<tool>", arguments={...}) to run one, passing an arguments object that matches the schema (omit arguments for a tool that takes none).
|
||||
|
|
|
|||
|
|
@ -370,13 +370,21 @@ async def run_strix_scan(
|
|||
_record_mcp_connections(connections)
|
||||
if connections:
|
||||
report(_mcp_startup_summary(connections))
|
||||
# Flag that MCP is reachable so both the root context and the
|
||||
# child factory's context (both derive from scope_context)
|
||||
# render the static three-tool guidance. Set only when a
|
||||
# connection exists, so a run with no MCP leaves the prompt
|
||||
# context unchanged. The connections themselves are discovered
|
||||
# at run time via list_mcps, not listed in the prompt.
|
||||
# Name the connected servers in the prompt so every agent
|
||||
# (root and children, both deriving from scope_context) sees
|
||||
# what is available at the start; they can still re-list or
|
||||
# inspect them at run time via list_mcps / describe_mcp. Set
|
||||
# only when a connection exists, so a run with no MCP leaves
|
||||
# the prompt context unchanged.
|
||||
scope_context["mcp_available"] = bool(mcp_registry)
|
||||
scope_context["mcp_connections"] = [
|
||||
{
|
||||
"name": summary.name,
|
||||
"purpose": summary.purpose,
|
||||
"tool_count": summary.tool_count,
|
||||
}
|
||||
for summary in mcp_registry.summaries()
|
||||
]
|
||||
except Exception:
|
||||
logger.exception("Failed to connect user MCP servers; continuing without them")
|
||||
|
||||
|
|
|
|||
|
|
@ -648,21 +648,36 @@ def test_prompt_has_no_mcp_section_without_availability() -> None:
|
|||
assert "MCP CONNECTIONS" not in render_system_prompt(system_prompt_context={})
|
||||
|
||||
|
||||
def test_prompt_no_longer_renders_a_per_connection_inventory() -> None:
|
||||
"""The old inventory loop read ``mcp_connections`` and listed each connection
|
||||
with its purpose. That data no longer drives the prompt; only the boolean
|
||||
``mcp_available`` does, so a legacy ``mcp_connections`` list renders nothing."""
|
||||
def test_prompt_renders_named_connection_inventory() -> None:
|
||||
"""With mcp_available set, the prompt names each connected server (name, tool
|
||||
count, purpose) so every agent sees what is available at the start, alongside
|
||||
the three dispatch tools for re-listing and inspecting them at run time."""
|
||||
prompt = render_system_prompt(
|
||||
system_prompt_context={
|
||||
"mcp_available": True,
|
||||
"mcp_connections": [
|
||||
{"name": "secret-conn", "purpose": "should not appear", "tool_count": 3}
|
||||
]
|
||||
{"name": "supabase", "purpose": "read the app's schema", "tool_count": 13}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
assert "MCP CONNECTIONS" in prompt
|
||||
assert "supabase" in prompt
|
||||
assert "13 tools" in prompt
|
||||
assert "read the app's schema" in prompt
|
||||
|
||||
|
||||
def test_prompt_inventory_is_gated_on_availability() -> None:
|
||||
"""The block is gated on ``mcp_available``; an ``mcp_connections`` payload
|
||||
without it renders nothing, so a stale or spoofed list cannot leak names."""
|
||||
prompt = render_system_prompt(
|
||||
system_prompt_context={
|
||||
"mcp_connections": [{"name": "secret-conn", "purpose": "x", "tool_count": 3}]
|
||||
}
|
||||
)
|
||||
|
||||
assert "MCP CONNECTIONS" not in prompt
|
||||
assert "secret-conn" not in prompt
|
||||
assert "should not appear" not in prompt
|
||||
|
||||
|
||||
# --- loader ------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -187,9 +187,10 @@ async def test_mcp_available_flag_set_when_a_connection_attaches(
|
|||
monkeypatch: pytest.MonkeyPatch,
|
||||
tmp_path: Any,
|
||||
) -> None:
|
||||
"""When at least one MCP connection attaches, the runner sets the boolean
|
||||
``mcp_available`` (not a per-connection inventory) into the scan context that
|
||||
reaches every agent."""
|
||||
"""When at least one MCP connection attaches, the runner sets ``mcp_available``
|
||||
plus a named ``mcp_connections`` inventory into the scan context that reaches
|
||||
every agent, so each agent sees which connections exist at the start while
|
||||
still being able to re-list them at run time via list_mcps."""
|
||||
scope_context: dict[str, Any] = {"scope": "built-in"}
|
||||
captured = _patch_engine_scaffold(monkeypatch, tmp_path, scope_context)
|
||||
|
||||
|
|
@ -217,8 +218,10 @@ async def test_mcp_available_flag_set_when_a_connection_attaches(
|
|||
|
||||
kwargs = captured["kwargs"]
|
||||
assert kwargs["system_prompt_context"]["mcp_available"] is True
|
||||
# The old per-connection inventory key is gone entirely.
|
||||
assert "mcp_connections" not in kwargs["system_prompt_context"]
|
||||
# The named inventory names each connected server for the prompt.
|
||||
assert kwargs["system_prompt_context"]["mcp_connections"] == [
|
||||
{"name": "fs", "purpose": "local files", "tool_count": 2}
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue