Skip to main content
Glama
research-digest

research-digest

by dneish2

Research Digest

tests ranking precision@5 License: MIT Python 3.9+

Your own arXiv library. You and your coding agent search the same papers, and every result says why it ranked where it did.

arXiv publishes thousands of papers a week. Research Digest keeps the ones in the subjects you follow, on your machine, and lets you find them again: from a search box in your browser, from the terminal, or by asking Claude Code (or any MCP client) "what have I read about evaluation harnesses?" and getting an answer from your library instead of from the open web.

  • Every result shows its arithmetic. Which words matched, what each was worth, how much recency added. No model decides the order.

  • The ranking is measured. Precision@5 is 0.761 on a frozen test set, against 0.031 for newest-first. CI fails any change that drops it below 0.75.

  • No dependencies, no account, no server. The core is the Python standard library. Your papers stay in a folder on your machine.

Quick start

About two minutes, most of it the first fetch.

pip install git+https://github.com/dneish2/research-digest-mcp
research-digest fetch      # pulls a few hundred recent papers into ~/.research-digest
research-digest search "agent evaluation"

Then connect your agent. For Claude Code:

claude mcp add research-digest -- python -m research_digest_mcp mcp

Ask it "what's in my research library about evaluation?". Other clients (Claude Desktop, VS Code, Cursor, Codex, OpenCode, Copilot CLI) are under Connect it to your agent.

On Linux, if pip says externally-managed-environment, use pipx install git+https://github.com/dneish2/research-digest-mcp or uv tool install git+https://github.com/dneish2/research-digest-mcp instead, and python3 wherever this page says python. On Windows, if research-digest is "not recognized", see Troubleshooting.

Something off? Run python -m research_digest_mcp doctor. It checks the install, the PATH, the data folder and the library, makes no network request, and ends with the exact agent config line for your machine.

You start empty. Installing gives you the tool, not a library. Your papers, bookmarks, notes and reading history live in ~/.research-digest, created on your first fetch and never shared. Set RESEARCH_DIGEST_HOME to keep it somewhere else. The only papers in this repository are a frozen test set under eval/fixtures/ that the ranking check runs against.


Related MCP server: mcp-arxiv

What it does, in one line each

These are the views in the browser interface (research-digest web). Map and Trends are browser-only; everything else is also a command and an agent tool.

Papers

everything you have fetched, best match first. Search it, or ask it a question

Digest

a small dated pick for today, the same every time you open it

Map

which subjects your library actually holds, and which ones turn up together. Click anything for the papers behind it

Trends

what arXiv as a whole is publishing more and less of, week over week

Shelf

what you saved, with your notes

Profile

what gets fetched. Edit it here

Scoring

the ranking function, with the arithmetic shown, and a scale that says what a score is worth

Two things it does that are worth knowing about up front:

It uses both of arXiv's services. arXiv runs a search API and a bulk harvest feed on separate hosts. Search rate-limits on reputation and will refuse one machine for an hour at a time, so the browser's Fetch button goes through the harvest feed and falls back to search rather than the other way around, and says which one answered. From the terminal, research-digest harvest uses the feed and research-digest fetch uses search.

It measures the field without downloading it. The Trends tab counts every cs paper arXiv published, by streaming the harvest feed and keeping only the daily totals. Three months of the whole field is a few kilobytes on disk, and your library is not touched.


Install options

pip install git+https://github.com/dneish2/research-digest-mcp

That gives you search, saved papers, trends and the web interface with no third-party packages. Similarity search ("find papers like this one") needs numpy and scikit-learn:

pip install "research-digest-mcp[embeddings] @ git+https://github.com/dneish2/research-digest-mcp"

To try it without installing anything, uv runs it straight from GitHub:

uvx --from git+https://github.com/dneish2/research-digest-mcp research-digest fetch

doctor exits 0 when everything is green, 1 when it is usable with warnings, and 2 when something is broken, so a scheduled task can gate on it.

Build your library

research-digest fetch      # pull recent papers from arXiv, against your profile
research-digest embed      # optional: build vectors for similarity search
research-digest status     # see what you have
research-digest profile    # what it fetches for you, and the query it sends

Missed a stretch of days? The browser's Fetch button finds them itself. It starts at the oldest recent day you hold nothing from, rather than at your newest paper, because anchoring to the newest paper steps over every hole behind it. For anything older than three weeks, give it a window:

research-digest harvest --since 2026-07-01 --until 2026-07-31

harvest goes through arXiv's bulk feed, which takes a date range directly and is provisioned separately from the search API, so a search rate limit does not stop it.

fetch is safe to run daily. It only adds papers you have not seen, and arXiv hands back roughly the same recent batch each time, so the library grows a few dozen papers a day, so put it on a cron job, launchd agent, or Windows scheduled task if you want it to run itself. Run it for a week and the trends view starts to mean something.

Already have a library from an older version of this tool, or another machine? Load it in one shot instead of waiting on daily fetches to catch up:

research-digest import ~/old-library/archive.json

Safe to run more than once: papers already present are updated, not duplicated, and stale scoring output from whatever wrote the file is dropped rather than carried in, since the running code recomputes it on every read.

Use it

research-digest ask "what should I read about agent memory?"
research-digest search agentic evaluation  # keywords, over what you already hold
research-digest arxiv "speculative decoding"   # searches arXiv and ADDS what it finds
research-digest digest                     # today's top picks, written to a dated file
research-digest web                        # browser interface on localhost

search reads the shelf. arxiv puts something on it. ask reads your sentence first, and tells you what it decided before it shows you anything:

read as: Searched your library for agent; ignored memroy (in no paper you hold; did you mean memory, in 31 papers?).

That line is the point. When an answer looks wrong you need to know whether the question was misread or the library is simply thin, and those need opposite fixes.

A word appearing in zero papers is not searched for, because ranking is by how much of your query a paper covers, so a dead term lowers every real result by the same amount. That is how a typo silently costs you the answer. Instead you are offered the nearest word the library does contain, with the number of papers it will return:

Nothing in your library matched 'memroy', so this is showing results for memory.

The suggestion comes from your own papers and nowhere else, so it is never a word that returns nothing. If the odd spelling was deliberate, ask for it exactly and get the honest zero.

No model is needed for any of this. If you have a local one (Ollama, any small model) it is used for one job, turning your sentence into search terms, and it is held to two rules enforced in code, not asked for in a prompt: it may re-word your question but not re-topic it, and it never decides to go online. Nothing ranks your results except arithmetic you can read.

A full walkthrough of every command and screen is in docs/RUNNING.md.

Connect it to your agent

These start the server with python -m research_digest_mcp mcp rather than the short research-digest command. Your agent launches the server itself, often with a different PATH than your terminal, so the short command can fail there even when it works when you type it. doctor prints the same line with the full path to your Python, which is the most reliable form on Windows.

If you keep your library somewhere other than ~/.research-digest, pass RESEARCH_DIGEST_HOME in the server's environment, as the Claude examples show. Setting it in your shell does not reach a server your agent starts, and without it the agent reads the default folder, which may be a different, empty library.

Claude Code

claude mcp add research-digest -- python -m research_digest_mcp mcp
# with a library folder of your own:
claude mcp add research-digest -e RESEARCH_DIGEST_HOME=/path/to/library -- python -m research_digest_mcp mcp

Claude Desktop, in claude_desktop_config.json (Settings, Developer, Edit Config):

{
  "mcpServers": {
    "research-digest": {
      "command": "python",
      "args": ["-m", "research_digest_mcp", "mcp"],
      "env": { "RESEARCH_DIGEST_HOME": "/path/to/library" }
    }
  }
}

Leave out env if you use the default folder. Claude Desktop does not read your shell's PATH, so if it cannot start the server, replace python with the full path doctor prints.

VS Code (Copilot), in .vscode/mcp.json or your user mcp.json. The top-level key is servers, not mcpServers:

{
  "servers": {
    "research-digest": {
      "type": "stdio",
      "command": "python",
      "args": ["-m", "research_digest_mcp", "mcp"]
    }
  }
}

Cursor, in ~/.cursor/mcp.json:

{
  "mcpServers": {
    "research-digest": {
      "command": "python",
      "args": ["-m", "research_digest_mcp", "mcp"]
    }
  }
}

Codex CLI, in ~/.codex/config.toml:

[mcp_servers.research-digest]
command = "python"
args = ["-m", "research_digest_mcp", "mcp"]

codex exec (non-interactive) refuses tool calls it cannot ask you about. Add default_tools_approval_mode = "approve" under the server, or use Codex interactively.

OpenCode, in opencode.json. The command is a single array, and environment variables go under environment, not env:

{
  "mcp": {
    "research-digest": {
      "type": "local",
      "command": ["python", "-m", "research_digest_mcp", "mcp"],
      "enabled": true
    }
  }
}

GitHub Copilot CLI, in ~/.copilot/mcp-config.json:

{
  "mcpServers": {
    "research-digest": {
      "type": "local",
      "command": "python",
      "args": ["-m", "research_digest_mcp", "mcp"],
      "tools": ["*"]
    }
  }
}

Any other MCP client takes the same two things: a command, and arguments that run this package with mcp.

Then ask in normal language: "search my library for retrieval papers", "what have I saved about multi-agent systems", "find papers like 2610.22280".

Check the server responds before blaming your agent:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python -m research_digest_mcp mcp

A JSON line listing the twelve tools below means the server is fine and anything still broken is in the client config.

Nine of the tools only read. save_paper and fetch_papers add papers to the library, and get_digest writes the day's digest file. Each tool declares which it is, so a client can run the readers without asking. None deletes anything.


The tools

Tool

What it does

ask_library

A question in plain English, with the reading it used

search_papers

Keyword search, with the score breakdown for every hit

fetch_papers

Searches arXiv itself and adds what it finds to the library

get_similar

Nearest papers by embedding similarity

get_trends

Concepts rising and falling in your own feed, as shares of each week's papers

get_field_trends

What arXiv as a whole is publishing more or less of, comparing any two windows

get_saved

Your bookmarked papers and notes

suggest_reading

Unread papers on a topic, best first

suggest_profile_terms

What you save that your fetch profile never asks for

save_paper

Add a specific paper by arXiv id or URL and bookmark it

get_digest

Today's top picks against your topics, written to a dated file

library_status

Paper count, date range, last fetch time, embedding health

fetch_papers is the one that changes what an agent can do for you. Every other tool reads a shelf; without this one, "find me something on X" answers "nothing found" for a paper that exists and simply has not been fetched yet.

get_trends and get_field_trends answer different questions and are kept apart on purpose. The first is what you fetched, the second is what was published. "How many papers on RAG came out this week" answered from a personal library is a wrong answer that looks like a right one.


How ranking works

No model decides the order. Every score is arithmetic you can redo by hand, matching your topics and your query against each paper's title, abstract and extracted concept tags.

Say one of your topics is "reinforcement learning." A paper scores:

that exact phrase appears in the title or abstract

1.00

just "reinforcement" appears, on its own

0.60

just "learning" appears, on its own

0.20

three or more of your topics matched, not just this one

+0.30

exactly two matched

+0.15

published today, decaying to zero over 30 days

+0.20

"Reinforcement" is worth three times what "learning" is, because "learning" appears in nearly every paper in this field, so matching it alone is weak evidence, not none. 0.60 would let it drown out real signal; 0 would throw away the little it does carry. 0.20 is the middle ground. This only applies to words like "learning," "model" and "training" that are common in this specific literature. Plain English words such as "of" and "the" are handled differently: dropped from matching entirely, covered below.

search_papers ranks a little differently from the standing topic profile above: results are ordered by how much of your query each paper covers, weighted by how distinctive each matched word is, with a bonus for the exact phrase and for terms that recur rather than appear once. Function words like "the" and "of" are ignored for matching but still count inside a phrase match, and a query reaches inside hyphenated compounds, so "chain of thought" finds papers that wrote it "chain-of-thought".

Every result carries its own derivation, in the MCP response and in the web interface. The "How scoring works" tab lets you edit a title, an abstract and your topic list, and watch the arithmetic change.

Is it any good?

For 5 results, precision@5 is how many of them are actually relevant, out of 5. 1.00 means every result belongs; 0.20 means one out of five does.

Two separate checks, in docs/EVAL.md:

  • Exact-phrase queries: 26 queries where "relevant" can be checked by a script (the phrase is in the paper or it is not). Precision@5: 0.761, measured with the clock pinned to the corpus so the figure cannot drift as the fixture ages. Two baselines on the same queries show this is a real result and not an artifact of easy questions: sorting by recency alone gets 0.031, and random order gets 0.000.

  • Semantic queries: 8 queries where relevance is a judgment call, not a script. An LLM made that call 115 times, blind to which ranker produced which result. Precision@5: 0.80.

The 26-query number is the one to trust day to day: it runs in CI on every push, against a corpus frozen so the score cannot drift out from under a change to the ranker. The 8-query number is directional. Eight queries is not a benchmark, and there is no held-out set behind it.

Reproduce the CI number from a clone, with no library of your own:

python eval/eval-regression.py --assert-min 0.75

Read the limitations section in docs/EVAL.md before leaning on either number. Exact-phrase positives reward a keyword matcher by construction. It also walks through the one query where this ranker scores zero, and why no ranker could do better on it, which is the most useful part of the document.


Configuration

Settings live in settings.json inside your data directory:

research-digest config                          # show current settings
research-digest config --add-category cs.CV     # track another arXiv category
research-digest config --add-topic "world model"

Setting

Default

categories

cs.AI, cs.LG, cs.CL, cs.MA, cs.SE

topics

agent, evaluation, reasoning, retrieval, multi-agent, reliability, interpretability

encoder

tfidf-svd

Your interest profile

categories and topics above are the simple shape, and they keep working. If you want the tool to fetch outside your own subject, add a profile block with three tiers:

{
  "profile": {
    "work_context": "One paragraph on what you build. Not used for scoring; it is there so you can read your own profile back.",
    "core":          { "categories": ["cs.AI", "cs.LG"], "topics": ["agent benchmark", "eval harness"], "per_category": 60 },
    "complementary": { "categories": ["cs.HC", "cs.IR"], "topics": ["trust", "explainability"], "per_category": 30 },
    "stretch":       { "categories": ["stat.ME", "econ.EM"], "structural_keywords": ["confounding", "identification"], "per_category": 20 }
  }
}

core is the subject you work in, fetched deepest. complementary is the adjacent lanes, fetched shallower so they season the feed rather than flood it. stretch is for fields you do not work in, matched on structural_keywords, which are about method rather than subject: a stat.ME paper on identification strategy is worth reading for how it argues, not for what it is about.

per_category is how many papers that tier asks arXiv for, per category, per run. This is the number that decides whether your library grows. Set it too low and each run sees only the last hour of submissions.

Run research-digest profile to see what the tool believes about you, how many papers you actually hold in each category, and the exact arXiv query it sends. A category listed there holding zero papers is configured and not delivering.

Topic lists longer than six are covered across runs rather than truncated: each fetch asks about the next six and the window advances, so a forty-topic profile is fully covered in about a week of daily runs.

Data lives in ~/.research-digest by default. Point RESEARCH_DIGEST_HOME somewhere else if you prefer:

export RESEARCH_DIGEST_HOME=~/notes/papers          # macOS, Linux
$env:RESEARCH_DIGEST_HOME = "$env:APPDATA\research-digest"   # Windows

The directory holds archive.json, saved.json, settings.json and, if you built them, embeddings.db.


A note on the embeddings

The default encoder is TF-IDF followed by SVD. It is fitted to your corpus, which means the 384 columns it produces are derived from the particular set of papers it saw. Vectors from two different fits are not comparable, even when both are 384 wide.

So research-digest embed always rebuilds the whole store in one pass, and the store records which fit produced every row. If it ever finds more than one, it refuses to compare them and tells you to re-embed rather than returning confident nonsense.

If you would rather have a fixed basis that survives incremental updates, install sentence-transformers and run research-digest embed --engine minilm. That downloads about 90 MB the first time.


Development

The names: the product is Research Digest, the command you type is research-digest, the Python package is research_digest_mcp, and the repo is research-digest-mcp.

uv venv && uv pip install -e ".[dev]"
python -m unittest discover -s tests -v

Any Python installer works here. pip install -e ".[dev]" is the same install without uv.

The MCP server is plain JSON-RPC over stdin and stdout, about 350 lines, with no SDK. One JSON object per line each way, which makes it easy to drive from a shell script when something looks wrong.

Troubleshooting

research-digest is "not recognized" or "command not found"

The install worked. Your shell just cannot see it.

pip puts the research-digest launcher in a per-user scripts folder that is often missing from PATH, especially on Windows and with the Microsoft Store build of Python. pip prints a warning about this, but it scrolls past in the middle of the install output:

WARNING: The script research-digest.exe is installed in
'...\local-packages\Python313\Scripts' which is not on PATH.

Every command in this README also works in this form, which does not depend on PATH at all:

python -m research_digest_mcp web       # instead of: research-digest web
python -m research_digest_mcp fetch
python -m research_digest_mcp status

Note the underscores: research_digest_mcp is the Python package, while research-digest is the shortcut command. If python is not the right name on your system, use python3.

Prefer the short command? Add the folder pip named in its warning to PATH:

# Windows, PowerShell. Paste the path from YOUR pip warning.
$dir = "$env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\Scripts"
[Environment]::SetEnvironmentVariable(
    "PATH", [Environment]::GetEnvironmentVariable("PATH", "User") + ";$dir", "User")
# macOS and Linux, then reopen the shell
echo 'export PATH="$(python3 -m site --user-base)/bin:$PATH"' >> ~/.zshrc

Open a new terminal afterwards. The old one keeps the old PATH.

The agent sees an empty library

The server reads ~/.research-digest unless RESEARCH_DIGEST_HOME is set in its own environment. Add it to the client config as shown above, or ask the agent to call library_status, which names the folder it is reading.

arXiv answers 429 or 406

arXiv rate-limits its search service per machine, sometimes for an hour. Its bulk harvest feed is separate and usually still answers:

research-digest harvest --since 2026-10-15   # a date a few days back

Security

The web interface listens on 127.0.0.1 only and refuses requests from other sites. Paper titles and abstracts come from arXiv and are untrusted text, and none of the tools an agent can call deletes anything. To report a problem, see SECURITY.md.

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server that provides AI assistants with a seamless, programmatic interface to search and read academic papers from the open-access arXiv repository.
    2
    MIT
  • F
    license
    A
    quality
    C
    maintenance
    Enables semantic search across personal PDF paper collections with page-level citations, allowing users to query their library from any MCP-capable client.
    9
    -
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that enables searching arXiv, importing papers, enriching with citation data, generating summaries and research ideas, and querying a local library using local LLMs and embeddings.
    9
    1
    MIT