使用说明
DOI Citation Verifier MCP Server
A Model Context Protocol (MCP) server that prevents citation hallucination by verifying academic citations against 8 authoritative databases. Only papers with a DOI are ever verified or returned, so every citation it gives an AI assistant comes with a working https://doi.org/ link.
🚀 Quick Install
npx -y github:tfscharff/doi-mcp
Or add to your Claude Desktop config:
{
"mcpServers": {
"doi-mcp": {
"command": "npx",
"args": ["-y", "github:tfscharff/doi-mcp"]
}
}
}
To pin a release, append its tag: github:tfscharff/doi-mcp#v7.0.0. See Releases.
The Problem This Solves
Large language models sometimes "hallucinate" academic citations - citing papers that don't exist, misattributing real titles to wrong authors, or mixing up publication details. This MCP server eliminates that problem by:
- 8-database verification: Checks citations across CrossRef, OpenAlex, PubMed, zbMATH, ERIC, HAL, INSPIRE-HEP, and Semantic Scholar
- Parallel search: Queries all databases simultaneously
- Comprehensive coverage: 600+ million publications across all disciplines including STEM, humanities, social sciences, and education
- DOI-only results: A paper counts only if a database returns a DOI for it. Every verified citation, possible match, and search result includes a DOI.
Features
- 8 Database Search: CrossRef, OpenAlex, PubMed, zbMATH, ERIC, HAL, INSPIRE-HEP, Semantic Scholar
- Verify Citations: Check if a paper with specific details actually exists, one at a time or in batches
- Find Verified Papers: Search for real papers on a topic and get only DOI-backed results
- Strict matching: A candidate must match the citation's title or an author; a matching year alone never verifies anything
- Parallel Processing: All database queries run simultaneously
- Caching: Repeated successful queries return instantly (5-minute TTL, 100 entries)
- Source Selection: Search all databases or target specific sources
- Zero Configuration: No API keys required (an optional Semantic Scholar key avoids its shared rate limit)
- Failures are reported, not hidden: When a database errors or rate-limits, responses name it and say why, so a failed lookup is never mistaken for "no such paper"
- Fully Tested: 100% line coverage across scoring, caching, HTTP, all 8 database adapters, the tools, and the MCP server itself
How It Works
When an AI assistant is asked about research or for citations:
- Without this MCP: The assistant might cite "According to Smith et al. (2023) in Nature..." referencing a paper that doesn't exist
- With this MCP: The assistant uses
verifyCitationfirst, which searches across 8 databases in parallel and returns:- Verified match with a DOI → Can be cited
- No DOI-backed match found → Cannot cite; must search for real papers instead
If a DOI is supplied, it is resolved directly at doi.org first; the database search is the fallback.
Scoring
Each candidate returned by the databases is scored against the citation:
| Match | Points |
|---|---|
| Title contains the first 30 characters of the cited title (case-insensitive) | +3 |
| Exact year | +3 (±1 year: +1) |
| Each cited author whose last name appears in the candidate's authors | +2 |
A candidate is only considered if it has a DOI and matches on title or at least one author. A score of 3+ verifies the citation; 5+ is reported as high confidence.
Limitations
- Papers without a DOI can't be verified. Some real papers, such as conference proceedings that never received a DOI, will come back
verified: false. This is deliberate: the server only vouches for citations it can link to. - Speed depends on the slowest database. Most lookups take one to a few seconds; title/author searches wait for all 8 databases.
- Semantic Scholar rate-limits requests without an API key: they share one global anonymous quota that is often exhausted. Set
SEMANTIC_SCHOLAR_API_KEY(see Installation) for a dedicated quota. Without one, a 429 is retried once after a second; if that is also limited, itsRATE_LIMITEDerror is reported and the other databases are still used. - DBLP was removed in 7.0.0. dblp.org serves a bot-check page to API clients instead of JSON. Computer-science papers with DOIs are still found through CrossRef and OpenAlex.
- Each database is asked for 3×
limitresults and trimmed back tolimitafter dropping records without a DOI, so a few DOI-less top hits don't empty a source.
Tools
All tools are read-only (readOnlyHint: true, destructiveHint: false, idempotentHint: true).
verifyCitation
Primary anti-hallucination tool - Verifies a citation exists before it can be mentioned.
Input:
title(string, optional): Paper title (partial matches accepted)authors(array, optional): Author names (last names sufficient)year(number, optional): Publication yeardoi(string, optional): DOI if knownjournal(string, optional): Journal name
Returns JSON with:
verified: true/false- If verified:
confidence(high/medium),source,doi,doiUrl,title,authors,year,journal,abstractFromArticle,message - If not verified: a warning
message, pluspossibleMatches(each with a DOI) when there were near misses, anderrors(database,code,message) for any database that failed, since it may have held the match
Example successful verification:
{
"verified": true,
"confidence": "high",
"source": "CrossRef",
"doi": "10.1038/nature14539",
"doiUrl": "https://doi.org/10.1038/nature14539",
"title": "Deep learning",
"authors": ["Yann LeCun", "Yoshua Bengio", "Geoffrey Hinton"],
"year": 2015,
"journal": "Nature",
"message": "✓ Citation verified with high confidence"
}
batchVerifyCitations
Verify several citations in one call. Each citation takes the same fields as verifyCitation, plus an optional id to match results back to inputs.
Input:
citations(array):{ id?, title?, authors?, year?, doi?, journal? }objects
Returns: summary (total, verified, failed) and a results array, one entry per citation, each with id, verified, and either paper (including doiUrl) or a message. Unverified entries also carry errors for any database that failed.
findVerifiedPapers
Search for real papers on a topic and return only papers with DOIs.
Input:
query(string): Search query (topic, keywords, author names)source(string, optional): Which database to search - "all" (default), "crossref", "openalex", "pubmed", "zbmath", "eric", "hal", "inspirehep", or "semanticscholar"limit(number, optional): Number of results per source (1-20, default: 5)yearFrom(number, optional): Minimum publication yearyearTo(number, optional): Maximum publication year
Returns: Up to limit papers, deduplicated by DOI, each with source, title, authors, year, journal, doi, and doiUrl, plus errors for any database that failed.
With no papers, it returns count: 0, sourcesQueried, errors, and a message that separates "nothing with a DOI matched" from "these databases failed". If every database queried failed, the result is also flagged isError:
{
"count": 0,
"message": "Every database queried failed, so no papers could be checked: Semantic Scholar (HTTP 429: rate limited (...)).",
"sourcesQueried": ["Semantic Scholar"],
"errors": [{ "database": "Semantic Scholar", "code": "RATE_LIMITED", "message": "HTTP 429: rate limited (...)" }]
}
Example:
// Search all 8 databases
findVerifiedPapers({ query: "CRISPR gene editing", limit: 5 })
// Search only PubMed for biomedical papers
findVerifiedPapers({ query: "cancer immunotherapy", source: "pubmed", limit: 10 })
// Search zbMATH for mathematics papers
findVerifiedPapers({ query: "algebraic topology", source: "zbmath" })
// Search ERIC for education research
findVerifiedPapers({ query: "active learning pedagogy", source: "eric" })
// Search HAL for French/European humanities research
findVerifiedPapers({ query: "phenomenology Husserl", source: "hal" })
// Search INSPIRE-HEP for high-energy physics papers
findVerifiedPapers({ query: "Higgs boson", source: "inspirehep" })
Resources and prompt
citation://databases(JSON): the 8 databases with coverage and API URLscitation://guidelines(Markdown): when and how to use each toolcitation-verification-rules(prompt): rules that tell the assistant to verify before citing and to cite only with a DOI
Installation
Add to your Claude Desktop config file:
Windows: %APPDATA%\Claude\claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"doi-mcp": {
"command": "npx",
"args": ["-y", "github:tfscharff/doi-mcp"]
}
}
}
Restart Claude Desktop and the server will be available.
To give Semantic Scholar a dedicated quota, add a free API key to the server's environment:
"doi-mcp": {
"command": "npx",
"args": ["-y", "github:tfscharff/doi-mcp"],
"env": { "SEMANTIC_SCHOLAR_API_KEY": "your-key" }
}
Alternative: Global Install
npm install -g github:tfscharff/doi-mcp
Then use this config:
{
"mcpServers": {
"doi-mcp": {
"command": "doi-mcp"
}
}
}
Alternative: Clone Locally
git clone https://github.com/tfscharff/doi-mcp.git
cd doi-mcp
npm install
npm run build
Config for local install:
{
"mcpServers": {
"doi-mcp": {
"command": "node",
"args": ["/absolute/path/to/doi-mcp/dist/index.js"]
}
}
}
Troubleshooting
Server not connecting
- Check Node.js is installed:
node --version(requires v18+) - Check Claude Desktop logs:
- Windows:
%APPDATA%\Claude\logs\ - macOS:
~/Library/Logs/Claude/ - Linux:
~/.config/Claude/logs/
- Windows:
npx command fails
npm cache clean --force
Testing locally
npx @modelcontextprotocol/inspector node dist/index.js
Releases
Every change is published as a GitHub release following Semantic Versioning:
- Major (5.0.0 → 6.0.0): a change in what gets verified or returned, or in the tools' inputs and outputs
- Minor (5.0.0 → 5.1.0): new features, such as a new database or tool
- Patch (5.0.0 → 5.0.1): fixes, docs, and maintenance
See CHANGELOG.md for what changed in each version.
Development
Development requires Node.js 22.12+ (for Vitest 5). The server itself runs on Node 18+.
npm install # Install dependencies
npm run build # Compile TypeScript to dist/
npm run dev # Watch mode
npm test # Run tests
npm run test:watch # Tests in watch mode
npm run test:coverage # Tests with coverage report
Tests mock all network calls; nothing hits the live APIs.
Releasing
dist/ is committed so npx can run the server straight from GitHub. Don't commit or tag releases by hand; use:
npm run ship -- "fix(pubmed): handle missing PMIDs" --body-file notes.md
The optional notes file becomes the body of the CHANGELOG.md entry and the GitHub release notes. On Windows, npm cuts inline arguments off at the first newline, so ship refuses --body there; use --body-file.
scripts/ship.mjs checks the header is a Conventional Commit, runs the tests, rebuilds dist/, bumps the version (feat → minor; fix, docs, chore, etc. → patch; ! or BREAKING CHANGE: → major), adds a CHANGELOG.md entry, then commits, tags vX.Y.Z, pushes, and creates the GitHub release. Use --dry-run to preview, or --as X.Y.Z to force a version. It only runs on main with uncommitted changes.
Architecture
src/
├── index.ts # Entry point (stdio transport)
├── server.ts # MCP server setup, Zod input schemas
├── types.ts # Shared interfaces
├── scoring.ts # Match scoring algorithm
├── cache.ts # Result cache (5-min TTL)
├── http.ts # Fetch utilities with timeouts
├── tools/ # Tool handlers
│ ├── verifyCitation.ts
│ ├── batchVerifyCitations.ts
│ └── findVerifiedPapers.ts
└── databases/ # Database adapters
├── index.ts # Parallel query orchestrator; drops results without a DOI
├── crossref.ts
├── openalex.ts
├── pubmed.ts
└── ... (8 adapters total)
Adding a new database:
- Create
src/databases/newdb.tswithconfig,search(), andnormalize() - Import and add to
src/databases/index.ts - Add it to the database lists in the tool descriptions in
src/server.ts - Add tests in
tests/databases/newdb.test.ts
Example Usage
Before this MCP (citation hallucination):
User: "Tell me about recent AlphaFold research"
Assistant: "According to Johnson et al. (2024) in Science, AlphaFold3 achieved..."
❌ This paper doesn't exist
After this MCP (verified citations only):
User: "Tell me about recent AlphaFold research"
Assistant: [Uses findVerifiedPapers tool]
"According to Abramson et al. (2024) in Nature (https://doi.org/10.1038/s41586-024-07487-w),
AlphaFold 3 predicts..."
✓ Real paper with a DOI
Verification catches fake citations:
User: "Can you verify this citation: Smith et al. (2024), 'Quantum AI', Nature"
Assistant: [Uses verifyCitation tool - searches all 8 databases in parallel]
"⚠ I cannot verify this citation - no matching publication with a DOI
was found in any of the 8 databases. This citation may be incorrect."
Database Coverage
All databases are queried in parallel:
General Databases
- CrossRef: 150+ million scholarly publications across all disciplines
- OpenAlex: 250+ million scholarly works across all disciplines
- Semantic Scholar: 200+ million papers with AI-powered search
Specialized Databases
- PubMed: 35+ million biomedical and life sciences publications
- zbMATH: 4+ million mathematics publications
- ERIC: 1.7+ million education research publications
- HAL: 4.4+ million French/European scholarly documents (2.5M English)
- INSPIRE-HEP: 1.7+ million high-energy physics publications
Total Coverage
600+ million publications across all academic disciplines with specialized depth in STEM, computer science, biomedical sciences, mathematics, and education research. Only records that carry a DOI are used.
License
MIT
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
Related
API Documentation
- CrossRef API
- OpenAlex API
- PubMed API
- zbMATH API
- ERIC API
- HAL API
- INSPIRE-HEP API
- Semantic Scholar API