Skip to content

app: find_references and list_imports MCP tools #87

Description

@IceRhymers

Part of #82. Depends on #86.

Summary

Expose the graph to agents: find_references and list_imports MCP tools on the existing FastMCP app.

Scope

  • find_references(symbol, repo?, branch?, kind?): ranked candidate call/reference sites, each with enclosing symbol. Docstring states candidate-set semantics (grep, not LSP) explicitly — agents must know results are candidates.
  • list_imports(target, repo?, branch?, direction=imports|imported_by): 1-hop import-graph neighborhood for a file/module.
  • Both return json.dumps(dict) through the existing dispatch choke-point; recoverable states (symbol-not-found, truncation) are payload fields per the established contract.
  • Document and test the "what tests cover symbol X" composition: find_references + path filter — no new primitive.

Acceptance criteria

  • Both tools live in app/main.py, backed only by app/service.py builders.
  • Docstrings document candidate-set semantics, params, and payload shape (agents read these).
  • tests-covering composition documented + integration-tested.
  • Smoke-test coverage alongside existing MCP tool smoke checks.

Scope note (added at execution time, PR implementing this issue)

Shipped:

  • find_references(symbol, ctx, limit=200, branch=None) — thin app/main.py tool over the unchanged service.find_references_payload builder. Corpus-wide, edge_kind="call" fixed. Docstring states candidate-set (grep, not LSP) semantics explicitly.
  • list_imports(ctx, repo=None, target=None, direction="imports", branch=None, limit=DEFAULT_ROW_LIMIT) — both direction=imports and direction=imported_by ship, via one additive extension of service.list_imports_payload. imports requires repo; imported_by requires target (index-served by ix_reference_edges_target_name, no resolver SQL change). Deterministic PRE-DB structured validation (unsupported_direction / missing_repo / missing_target) lives in the service-layer builder so it stays reachable by future non-MCP callers.
  • "What tests cover symbol X" composition: find_references + client-side filename filter, documented in the tool docstring, README, and the reference-edges runbook, and proven end-to-end in the e2e test.
  • Smoke coverage: validate_references_payload shape predicate (unit-tested) + a live find_references leg in scripts/smoke.py's --enable-mcp check.

Explicitly deferred (candidate follow-up issue):

  • find_references(repo?, kind?) filters from the original scope sketch — would require an additive find_references_payload change that introduces a repo_known key, which the pinned test tests/unit/test_service.py:588 currently asserts absent. Left for a follow-up that deliberately breaks that pin as an additive contract change.
  • Per-file forward imports ("what does file F import") — needs a new resolver source-file filter; out of scope for this additive, resolver-untouched change.
  • list_imports does not add a list_imports(repo?, kind?)-style symbol-kind filter; direction already fully covers both directions from the original sketch (imports / imported_by).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions