Skip to content

Mirror every read-only pwc command as an MCP tool - #13

Merged
NielsRogge merged 3 commits into
mainfrom
codex/mcp-cli-parity
Sep 16, 2026
Merged

NielsRogge merged 3 commits into
mainfrom
codex/mcp-cli-parity

Conversation

@NielsRogge

Copy link
Copy Markdown
Collaborator

Summary

Every read-only pwc CLI research command is now one MCP tool, and every research flag of that command is a typed tool parameter. The tools run the CLI handlers in-process through the CLI's own parser, so validation, fail-closed filter checks, and the JSON payload are the CLI's rather than a second implementation. Every result carries the complete pwc ... --json document as data beside the typed projections existing clients already read.

This closes the gaps found in the staging comparison against the reference chat: leaderboard filtering by parameter count and metric, per-paper evaluation tables, and model/artifact resources are now reachable over MCP.

Tools

Tool CLI command Status
search_papers pwc search existing, adds hybrid mode
get_paper_info pwc paper info existing, adds include_resources, include_evaluations, HF artifacts
read_paper pwc paper read unchanged (chunked with cursor)
list_papers pwc paper list existing, adds all_versions, include_resources, has_official_implementation, trending order
list_recent_papers pwc paper recent new
list_trending_papers pwc paper trending new
get_related_papers pwc paper related existing
get_paper_lineage pwc paper lineage list existing
get_task pwc task --name existing, now the CLI's richer task page
list_tasks pwc task list new
get_method pwc method --name existing
list_methods pwc method list new
get_conference / list_conferences `pwc conference [--name list]`
get_organization / list_organizations `pwc organization [--name list]`
get_framework / list_frameworks `pwc framework [--name list]`
get_benchmark pwc benchmark --name existing, adds max_parameters, require_metrics, minimum_metrics, maximum_metrics, sort_metric, pareto, matched_count
list_benchmarks pwc benchmark list existing, adds group_by_area, area, benchmarks_per_task, order_by, order_direction

mcp_server/tests/test_parity.py enumerates the CLI parser and fails when any research flag lacks a parameter, any parameter lacks a flag, or choice sets drift.

Parity rules and deliberate divergences

  • Parameter names follow the CLI flags except for the already-published MCP names: published_after/published_before, limit (for --page-size), authors, order_direction, minimum_evaluations, include_evaluations.
  • Terminal-only flags (--json, --implementation-coverage, --flat) have no parameter; MCP output is always structured.
  • limit stays capped at 25 rows (hosting contract); CLI defaults above 25 are clipped.
  • search_papers keeps keyword as default. hybrid is available and, because it runs dense retrieval upstream, counts toward the 10/minute semantic budget alongside semantic.
  • get_paper_info keeps include_resources defaulting to true so repositories/project_pages remain populated for existing clients.

Behavior changes for existing clients

  • list_papers default order_by is now trending (CLI default) instead of date_published; title was removed because the /papers/ API does not accept it.
  • list_benchmarks with task now returns trend-ranked rows like the CLI unless order_by is set.
  • get_task now returns the CLI task page (ranked benchmarks, common methods, trending papers) in data; typed fields are unchanged.
  • Default limit values follow the CLI: list_papers 20, get_benchmark 20, get_related_papers 4 (max 20).
  • CLI: pwc task list --group-by-area --page 2 and pwc benchmark list --order-by trending without --task now exit 2 (usage) instead of 4; paper references are percent-encoded in request paths.

Verification

  • uv run --project mcp_server pytest mcp_server/tests: 42 passed.
  • uv run --project standalone_cli --with pytest pytest standalone_cli/tests: 82 passed.
  • standalone_cli/scripts/check_contract.py passes; uv lock refreshed for pwc-cli 0.4.1 / pwc-mcp 0.2.0.
  • Live in-process smoke against the production catalog: all 20 tools exercised, including get_benchmark on MMLU with max_parameters: "4B" (20 matching rows) and sort_metric: "Accuracy" with minimum_metrics (176 of 240 rows matched), get_paper_info on Gemma 3 with include_evaluations (22 rows), grouped list_tasks/list_benchmarks, and a CLI usage error surfaced verbatim (unknown metric(s): latency; available metrics: Accuracy).

Follow-ups (not in this PR)

  • The chat worker in huggingface/paperswithcode should adopt the new parameters and tool names in its MCP tool registration and research prompt.
  • "Not found" hints from the CLI (for example Task not found: language-modelling; closest results: Language Modeling) are still masked by the server's generic catalog error policy; consider passing them through.

🤖 Generated with Claude Code

NielsRogge and others added 3 commits September 16, 2026 15:34
Each read-only CLI research command becomes one MCP tool and every research
flag of that command becomes a typed tool parameter, so MCP results match
`pwc ... --json` instead of a second implementation of the query logic.

- Add pwc_cli.queries: run the CLI handlers in-process through the CLI's own
  parser with a result sink (no subprocess or stdout capture). A strict parser
  raises UsageError instead of exiting; only read-only commands are reachable.
- CLI: route every --json emission through _emit_json, accept parser_class in
  build_parser, treat impossible flag combinations as usage errors, and
  percent-encode paper references in request paths like the MCP catalog.
- MCP server: 20 tools (10 new: recent/trending papers, tasks, methods,
  conferences, organizations, frameworks). Every result carries the complete
  CLI JSON as `data` beside typed projections. get_benchmark gains
  max_parameters, require_metrics, minimum/maximum_metrics, sort_metric and
  pareto; get_paper_info gains include_resources, include_evaluations and
  Hugging Face artifacts; list_tasks/list_benchmarks gain grouping by area.
- Catalog client serves the CLI handlers from the shared per-path cache and
  resolves paper URLs, legacy IDs and exact titles before the CLI runs.
- search_papers accepts hybrid mode (counted toward the semantic rate limit);
  list_papers orders by trending like the CLI and drops the unsupported
  order_by=title.
- tests/test_parity.py fails when the CLI parser and tool schemas drift.
- Skill, README and SPEC updated; pwc-cli 0.4.1, pwc-mcp 0.2.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…evidence

Unknown or ambiguous task, method, benchmark, conference, organization,
framework, area, and paper-title lookups now return the CLI's own message
(including its closest-match hint) so an agent can correct the call. Transport,
HTTP, and response-shape failures keep the generic message, and nothing is
logged. Tool descriptions now tell agents to start best/SOTA-model questions
with get_task, list_benchmarks, and get_benchmark rather than search.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
All chat traffic reaches the MCP server from one gateway address, so the
per-client limits were shared by every concurrent chat user. A direct loopback
client that carries no X-Forwarded-For may now send X-PwC-MCP-Client to name
the identity that the request, semantic, and concurrency limits apply to.
nginx always adds X-Forwarded-For to proxied traffic, so public clients cannot
use the header.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@NielsRogge

Copy link
Copy Markdown
Collaborator Author

Added in c4ffb095: a direct loopback client without X-Forwarded-For may send X-PwC-MCP-Client to name its rate-limit identity (the Papers With Code chat gateway uses one hashed identity per chat session). Proxied public traffic always carries X-Forwarded-For, which takes precedence, so the header cannot be used to evade limits. Also in c3dbdf07: lookup failures (unknown or ambiguous names) return the CLI's own message with its closest-match hint; transport failures stay generic. Verified on the staging component: 8 concurrent requests from one address → 4×429, 8 with distinct identities → 8×200.

@NielsRogge
NielsRogge merged commit 2aad810 into main Sep 16, 2026
2 checks passed
@NielsRogge
NielsRogge deleted the codex/mcp-cli-parity branch September 16, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant