Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 9 additions & 5 deletions mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,24 @@ def cortex_service_health() -> str:


@mcp.tool()
def cortex_intelligence(query: str, query_type: str = "research") -> str:
def cortex_intelligence(query: str, query_type: str = "research", project: str = "") -> str:
"""Query Cortex intelligence engine with natural language.

Args:
query: Natural language question about the codebase or projects.
query_type: One of 'spec', 'architecture', 'implementation', 'research'.
project: Target project to scope the query to (e.g. 'interac', 'manulife-genie').
Pass this whenever you know which project the question is about — the bridge
cannot reliably infer it (it falls back to its own working directory, which is
always the cortex repo). Leave empty only for genuinely project-agnostic queries.
"""
valid_types = {"spec", "architecture", "implementation", "research"}
if query_type not in valid_types:
query_type = "research"
result = _bridge_post(
"/intelligence/query",
{"request": query, "domain": DOMAIN, "query_type": query_type},
)
payload = {"request": query, "domain": DOMAIN, "query_type": query_type}
if project:
payload["project"] = project
result = _bridge_post("/intelligence/query", payload)
return json.dumps(result, indent=2)


Expand Down
43 changes: 43 additions & 0 deletions tests/test_mcp_research_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,46 @@ def test_research_digest_always_available(self):

registered = set(mcp_instance._tool_manager._tools.keys())
assert "cortex_research_digest" in registered


class TestCortexIntelligenceProjectScope:
"""cortex_intelligence forwards an explicit project to the bridge.

Regression test: the tool previously had no `project` param, so the bridge
fell back to its own working directory (always the cortex repo) and silently
mis-scoped every query to project 'cortex'. The tool must now forward an
explicit project when one is given, and omit it (preserving auto-detect) when not.
"""

@pytest.fixture(autouse=True)
def _skip_if_no_mcp(self):
pytest.importorskip("mcp")

def _capture_payload(self, monkeypatch, **kwargs):
import cortex.mcp_server as mod

captured = {}

def fake_post(path, payload, timeout=5.0):
captured["path"] = path
captured["payload"] = payload
return {"ok": True}

monkeypatch.setattr(mod, "_bridge_post", fake_post)
# @mcp.tool() wraps the function in a FunctionTool; .fn is the original callable.
fn = getattr(mod.cortex_intelligence, "fn", mod.cortex_intelligence)
fn(**kwargs)
return captured

def test_project_forwarded_when_provided(self, monkeypatch):
captured = self._capture_payload(
monkeypatch, query="What cloud is Interac on?", project="interac"
)
assert captured["path"] == "/intelligence/query"
assert captured["payload"].get("project") == "interac"

def test_project_omitted_when_empty(self, monkeypatch):
captured = self._capture_payload(monkeypatch, query="project-agnostic question")
assert "project" not in captured["payload"], (
"empty project must be omitted so the bridge default/auto-detect is preserved"
)
Loading