arxiv-agent-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@arxiv-agent-mcpFind papers related to my Transformer concept note"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
arXiv Research-Concept Companion
An AI/ML study-companion agent (KSE Agentic Lab assignment). It reads a concept-summary note from your Obsidian vault, finds related arXiv papers, scores each on topical relevance and age-adjusted citation impact, finds the well-established papers a surviving candidate builds on, and writes the findings back into the vault.
Existing MCP server (Part A): Obsidian Local REST API MCP.
Custom MCP server (Part B):
custom_server/— FastMCP app, 3 tools over the public arXiv and OpenAlex APIs (no auth).Agent:
agent/— a PydanticAIAgent(OpenRouter-backed) holding both MCP connections as toolsets, orchestrated by a LangGraph state machine.
Prerequisites
Python 3.12+,
uv.An OpenRouter API key.
Obsidian with the Local REST API community plugin installed and running, and an MCP server that speaks to it (any Obsidian Local REST API MCP implementation — the launch command is configurable, see below).
Related MCP server: arxiv-mcp
Install
uv sync
cp .env.example .envFill in .env:
Variable | Meaning |
| OpenRouter key — used by the agent and by |
| Model slug, e.g. |
| Local REST API plugin credentials. |
| Space-separated argv to launch your Obsidian MCP server, e.g. |
| Minimum relevance score (0–1) to survive the filter. Default |
| Minimum citations/year to pass the impact check. Default |
| Papers younger than this are exempt from the impact check. Default |
Running
Two independent processes, sharing one uv project:
# process 1 — the custom MCP server (arXiv + OpenAlex)
uv run python -m custom_server.server
# process 2 — the agent (connects to both MCP servers), driven by a free-text prompt
uv run python -m agent.graph "Find papers related to my 'Transformers Concept Note'"agent/graph.py spawns custom_server/server.py itself as a stdio
subprocess, so process 2 does not need process 1 already running — the two
commands above just demonstrate that each is independently startable.
The prompt is not a literal note title — the agent's first step
(parse_prompt) uses an LLM call to identify which Obsidian note the prompt
refers to. If it can't identify one, the run halts immediately and prints
"Not enough information: no Obsidian note or page was named in the prompt."
without touching Obsidian. If the note it finds doesn't yield enough concept
keywords (fewer than min_keywords, default 2), the run halts after reading
it and prints a similar "not enough information" message instead of
searching arXiv.
Offline / replay mode
The custom server calls three live network APIs (arXiv, OpenAlex, OpenRouter).
Setting CUSTOM_SERVER_OFFLINE=1 serves its tools from recorded fixtures in
custom_server/fixtures/ instead — no network access or OPENROUTER_API_KEY
required. Useful for a demo/defence without reliable network, or for fast
iteration.
CUSTOM_SERVER_OFFLINE=1 uv run python -m custom_server.serverWhat's covered: search_arxiv_papers (one recorded search feed, served for
any query — see limitation below), and score_paper_relevance /
find_foundational_citations for two recorded papers, GPT-3
(2005.14165) and ResNet (1512.03385).
Known limitations:
search_arxiv_papersis query-agnostic in offline mode — it always returns the same recorded feed regardless of the query text.score_paper_relevanceandfind_foundational_citationsonly recognize the two recorded papers above. An unrecorded arxiv_id raisesPaperNotFoundError(the same error a real OpenAlex miss would produce); an unrecorded paper title passed toscore_paper_relevanceraisesFixtureNotFoundError— distinguishable, not a silent wrong answer.
To regenerate or extend the fixtures: uv run python -m custom_server.fixtures.record re-fetches the recorded arXiv/OpenAlex
responses (both public, unauthenticated APIs) and overwrites the JSON/XML
files in custom_server/fixtures/. To add a new paper, add its two httpx.get
calls to record.py and a matching entry to relevance_scores.json
(hand-authored — not real OpenRouter output, since recording its raw
chat-completion response isn't worth the wire-format fragility; the
structured {relevance, novelty, rationale} fields are replayed directly
through a PydanticAI FunctionModel).
Tests
uv run pytest custom_server/tests agent/testsAll network calls (arXiv, OpenAlex, OpenRouter) are mocked; no live traffic during tests.
Tool contracts (Part C)
search_arxiv_papers (custom)
Purpose | Primary data-source tool: search arXiv for candidate papers on a topic. |
Model-facing description | "Search arXiv for papers on a topic, optionally restricted to categories and a minimum submission date. Use this to find candidate papers before evaluating them individually with score_paper_relevance. A valid query that matches nothing returns an empty list — that is a normal result, not an error." |
Input |
|
Output |
|
Error conditions |
|
Side effects | None — read-only HTTP GET to |
Example |
|
score_paper_relevance (custom)
Purpose | Evaluative tool: judge one candidate's topical fit and whether its citation record clears an age-adjusted bar. |
Model-facing description | "Score how relevant and novel a paper is to a concept summary, and check whether its citation impact clears a minimum bar (citations per year, exempting papers younger than one year). Use this on each candidate from search_arxiv_papers to decide whether it belongs in a reading list. Raises if the paper has no OpenAlex record, or if the underlying relevance-scoring model call fails." |
Input |
|
Output |
|
Error conditions |
|
Side effects | Read-only: one OpenAlex GET, one OpenRouter chat-completion call. |
Example |
|
find_foundational_citations (custom)
Purpose | Citation-graph analysis: given one paper, rank its own references by citation count to surface the well-established work it builds on. Distinct from |
Model-facing description | "Given one paper's arXiv ID, return its most-cited references — the well-established prior work it builds on. Use this after selecting a paper to read, to surface the background literature behind it. A paper with no recorded references returns an empty list — that is a normal result, not an error." |
Input |
|
Output |
|
Error conditions |
|
Side effects | Read-only: one OpenAlex paper lookup + one or more batched OpenAlex works lookups (chunked at 50 IDs per request). |
Example |
|
Obsidian Local REST API MCP (existing, Part A)
Used via the PydanticAI agent's natural-language tool calls (not a fixed wrapper function) for two operations in the flow:
Reference resolution | Before any Obsidian call, |
Read | The agent is prompted to read the note titled |
Write | The agent is prompted to create/overwrite a note titled |
Error conditions | Stopped plugin, invalid API key, or a missing note surface as a distinguishable tool-call failure from the MCP server, not a silent empty result. |
Design rationale
Why Obsidian: the assignment needs an existing MCP server the agent both reads from and writes to. A student's own concept notes are a natural "what do I already know" input, and writing survivors back closes the loop visibly in the vault.
Why arXiv + OpenAlex instead of a login-walled site: the originally considered KSE schedule/Moodle sources both require personal login, which the assignment's public-API rule rules out. arXiv and OpenAlex are public, unauthenticated, and directly support the "relevance + impact" domain.
Why relevance is LLM-judged, not embeddings: OpenRouter has no embeddings endpoint (verified against its live model catalog), so
score_paper_relevanceuses a PydanticAI structured-output call instead of vector similarity — reusing the one model credential the project already needs.Why
find_foundational_citationsisn't "search again with OpenAlex": it takes one specific paper's reference list and ranks it by citation impact, the same kind of controlled indicator-comparison the assignment's own examples use — distinct responsibility and processing from the keyword-drivensearch_arxiv_papers.Filtering is plain Python, not a 4th tool: the relevance-threshold +
impact_passfilter inagent/graph.py'sfilter_candidates_nodeis deterministic post-processing over already-scored data, not new domain logic — a tool would just be indirection around anif.Trade-offs / limitations: the custom server's offline/replay mode (see "Offline / replay mode" above) covers two recorded papers and a query-agnostic arXiv search — not a general record/replay of arbitrary queries.
agent/'s own Obsidian and OpenRouter calls are unaffected by it and still require live access. Impact/relevance thresholds are.envvalues, not runtime-tunable per request.
Deferred (flagged, not dropped)
Exposing the hardcoded thresholds as richer runtime config beyond
.env.
Demo / defence checklist
uv run python -m custom_server.serverstarts standalone; a raw MCP client'slist_toolsshows all 3 tools.uv run pytest custom_server/tests agent/tests— all green, network mocked.CUSTOM_SERVER_OFFLINE=1 uv run python -m custom_server.serverstarts and serves all 3 tool calls with no live network or API keys required (see "Offline / replay mode").Seed a demo vault note with a concept summary (e.g. "attention mechanisms"), titled e.g. "Transformers Concept Note".
uv run python -m agent.graph "Find papers related to my 'Transformers Concept Note'"— full live run: resolves the note reference, reads the note, searches arXiv, scores candidates, filters, finds foundational citations, writes"<note> — Related Papers"back to the vault.Show both MCP connections feeding the final output: the write-back note cites both arXiv/OpenAlex data (custom server) and the original concept note content (Obsidian).
Insufficient-information demo: run with a prompt that names no note (e.g.
"What's a transformer?") — show the agent halts and prints "Not enough information..." without calling Obsidian. Then run against a note with near-empty content — show it halts after reading the note, before calling arXiv.Failure demo, Obsidian: stop the Local REST API plugin (or use a bad
OBSIDIAN_API_KEY/ a nonexistent note title) — show the agent surfaces a distinguishable error, not a silent empty result.Failure demo, custom server: call
search_arxiv_paperswith an invalid category, orfind_foundational_citationswith an arXiv ID absent from OpenAlex — showValueError/PaperNotFoundErrorrespectively, distinct from a valid empty result.
Available Tools
3 toolsfind_foundational_citationsA
Given one paper's arXiv ID, return its most-cited references — the well-established prior work it builds on.
Use this after selecting a paper to read, to surface the background literature behind it. A paper with no recorded references returns an empty list — that is a normal result, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| arxiv_id | Yes | ||
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose one important behavioral fact: an empty list is normal, not an error. It also implies a read-only operation. Yet it does not explain truncation behavior related to max_results or what the output format contains, though an output schema is present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with meaningful information: what the tool returns, when to use it, and an important normalization about empty results. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description tells the agent what input is expected, when to invoke it, and how to interpret an empty result. Since an output schema exists, return-value details are covered. The main remaining gap is clarifying max_results, but the schema's default and name largely bridge that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It clarifies what arxiv_id represents (the paper's identifier), but it does not explain max_results, which limits the number of references returned. The name max_results is somewhat self-explanatory, and its default of 3 helps, but the description could have explicitly connected it to the 'most-cited' behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (return references) and resource (most-cited references for a given arXiv ID). It also conveys the purpose (surface well-established prior work), but it does not explicitly distinguish itself from sibling tools such as search_arxiv_papers or score_paper_relevance.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use the tool after selecting a paper to read, which gives a clear context. However, it does not mention when not to use it or point to alternative sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
score_paper_relevanceA
Score how relevant and novel a paper is to a concept summary, and check whether its citation impact clears a minimum bar (citations per year, exempting papers younger than one year).
Use this on each candidate from search_arxiv_papers to decide whether it belongs in a reading list. Raises if the paper has no OpenAlex record, or if the underlying relevance-scoring model call fails.
| Name | Required | Description | Default |
|---|---|---|---|
| paper | Yes | ||
| concept_summary | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the behavioral burden. It discloses two error conditions (missing OpenAlex record and underlying model failure) and explains the citation-impact filtering rule, including the one-year exemption. This goes well beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence carries necessary content: the scoring criterion, the usage context, and the failure behavior. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with an output schema and sibling context, the description covers its need: why to call it, what to pass, how it decides, and what to expect when it errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Since schema description coverage is 0%, the description has to convey parameter meaning. It explains concept_summary as the reference for scoring and clarifies that paper is a candidate from search_arxiv_papers. It does not detail paper field internals, but those are inherited from that tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: score a paper's relevance and novelty against a concept summary, and check its citation impact. This clearly distinguishes it from search_arxiv_papers (retrieval) and find_foundational_citations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states the intended use: apply this tool to each candidate from search_arxiv_papers to decide reading-list membership. It does not explicitly name alternatives or exclusions, but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_arxiv_papersA
Search arXiv for papers on a topic, optionally restricted to categories and a minimum submission date.
Use this to find candidate papers before evaluating them individually with score_paper_relevance. A valid query that matches nothing returns an empty list — that is a normal result, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| categories | No | ||
| since_date | No | ||
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the behavioral burden. It usefully discloses that an empty result is a normal outcome, not an error. However, it adds little about other behaviors such as result ordering, matching semantics, rate limits, or external API behavior, beyond what is essentially implied by a 'Search' operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each earning their place: the first states the operation and optional filters, the second gives pipeline guidance, and the third normalizes an empty result. It is front-loaded and free of filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that an output schema exists, return values are covered. The missing context is input format guidance for categories and since_date and the behavior of max_results. The description is adequate for a basic search call but not fully self-sufficient for an agent invoking an external API it has no prior knowledge about.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, so the description must compensate. It maps 'query' to topic, 'categories' to category restrictions, and 'since_date' to a minimum submission date. However, it does not explain expected formats for categories or since_date, and 'max_results' is never addressed, even though its name and default make its role partially inferable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Search arXiv for papers on a topic.' It also names the optional scope (categories, minimum submission date) and differentiates from the sibling by framing this as the discovery step before score_paper_relevance.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs when to use it: 'Use this to find candidate papers before evaluating them individually with score_paper_relevance.' This gives a clear pipeline context. It does not explicitly mention when not to use it or how it relates to the other sibling, find_foundational_citations, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
find_foundational_citations - First observed
score_paper_relevance - First observed
search_arxiv_papers
TDQS
Scored across 3 tools
The three tools have clearly distinct roles: searching arXiv, scoring a candidate paper, and tracing foundational references. There is no meaningful overlap between discovery, evaluation, and citation expansion.
All tool names follow a clean verb_noun snake_case pattern: search_arxiv_papers, score_paper_relevance, find_foundational_citations. The naming style is predictable and signals the action clearly.
Three tools is a well-scoped size for a focused arXiv triage workflow. Each tool covers a necessary step without redundant or filler tools.
The set covers the core pipeline: find candidate papers, evaluate relevance and citation impact, then discover foundational references. Minor omissions like retrieving full paper metadata or listing available arXiv categories could be useful but do not create dead ends.
Maintenance
Related MCP Connectors
Academic research MCP server for paper search, citation checks, graphs, and deep research.
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
An MCP server for deep research or task groups
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceThis MCP server enables users to search for scientific papers on arXiv and retrieve detailed metadata for specific papers. It provides tools to perform search queries and fetch in-depth information using paper IDs.3Apache 2.0
- FlicenseAqualityDmaintenanceA streamlined MCP server that connects AI assistants to arXiv's vast collection of academic papers, enabling search, retrieval, and analysis of research papers.71-
- FlicenseNot gradedqualityDmaintenanceAn advanced scholarly research MCP server that enables AI assistants to discover, fetch, process, and manage academic papers across multiple sources like arXiv, PubMed, and Semantic Scholar, with capabilities for summarization, citation analysis, and concept relationship extraction.2-
- FlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants to search arXiv papers, retrieve metadata, and access PDFs.-