mcp-citation-checker
An MCP server that verifies whether a claim is actually supported by the source text at a given citation — independent of what the calling LLM asserts.
Why this exists
LLM agents that cite sources can still get the citation wrong: paraphrasing loosely, citing the wrong page, or asserting a source says something it doesn't. check_citation closes that gap by independently fetching the real text at the claimed citation and asking a separate LLM call to judge, strictly from that text, whether the claim holds up. The agent's own paraphrase is never trusted as evidence — only the independently-fetched source is.
Design: pluggable backends
Looking up "the real text at citation X" depends entirely on where your documents actually live — Weaviate, Postgres, a flat file, something else. Rather than hardcoding one storage system, this package defines a small interface any backend can implement:
class SourceLookup(Protocol):
def fetch(self, pdf_name: str, page_number: int) -> list[dict]:
...
weaviate is included out of the box as a working, tested implementation (bundled as an optional extra, so installing the base package doesn't force a Weaviate dependency on anyone who doesn't need it). Writing your own backend for another storage system just means implementing that one fetch method — see Writing your own backend below.
Install
pip install "mcp-citation-checker[weaviate]"
(Omit [weaviate] if you're supplying your own backend instead.)
Configuration
Set via environment variables when the server starts:
| Variable | Default | Purpose |
|---|---|---|
CITATION_BACKEND |
weaviate |
Which backend to use (currently only weaviate ships built-in). |
ANTHROPIC_API_KEY |
— | Required. Used for the verification LLM call. |
WEAVIATE_MODE |
local |
local (self-hosted) or cloud (Weaviate Cloud). |
WEAVIATE_HOST / WEAVIATE_PORT |
localhost / 8081 |
Used when WEAVIATE_MODE=local. |
WEAVIATE_CLOUD_URL / WEAVIATE_API_KEY |
— | Required when WEAVIATE_MODE=cloud. |
Usage
Run directly:
mcp-citation-checker
Or wire it into an MCP client config (e.g. Claude Desktop, or your own agent) like any other stdio MCP server:
{
"mcpServers": {
"citation-checker": {
"command": "mcp-citation-checker",
"env": {
"ANTHROPIC_API_KEY": "...",
"WEAVIATE_MODE": "cloud",
"WEAVIATE_CLOUD_URL": "...",
"WEAVIATE_API_KEY": "..."
}
}
}
}
The server exposes one tool, check_citation(claim, pdf_name, pdf_page), returning "<label>: <one-sentence reasoning>" where <label> is one of supported, contradicted, or not_mentioned.
Writing your own backend
The verification logic (mcp_citation_checker.checker.check_citation) has no storage-specific coupling at all — it only needs claim and a list of chunk dicts (pdf_name/page_number/text). Any backend just needs to implement the SourceLookup shape:
class MyBackend:
def fetch(self, pdf_name: str, page_number: int) -> list[dict]:
# return [{"pdf_name": ..., "page_number": ..., "text": ...}, ...]
...
No inheritance required — SourceLookup is a typing.Protocol, so any object with a matching fetch method satisfies it.
Two ways to actually use a custom backend:
- Bypass the bundled server entirely: call
checker.check_citation(claim, my_backend.fetch(pdf_name, page))directly from your own code/MCP server — this works today, no changes to this package needed. - Wire it into this package's own server: the current version only registers a
weaviatebackend in_get_backend()(src/mcp_citation_checker/__init__.py) — using a different backend through the bundledmcp-citation-checkercommand currently means adding a branch there yourself (a small, welcome PR).
Development
pip install -e ".[weaviate,dev]"
pytest
License
MIT — see LICENSE.
Metadata
Release files for mcp-citation-checker 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_citation_checker-0.1.0.tar.gz | 5.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_citation_checker-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.1 kB
Release files / mcp_citation_checker-0.1.0.tar.gz
| Download URL | mcp_citation_checker-0.1.0.tar.gz |
|---|---|
| Size | 5.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e5908f6d57cf20b743de3165d8e9fc36a6f7d4b4e793bed50fdbbd88d297a523
|
|
BLAKE2b-256 checksum How to use checksums |
8882373c82390149acfe760a1b97eb7b74b613f778d817269aa5c00a918e0a1a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / mcp_citation_checker-0.1.0-py3-none-any.whl
| Download URL | mcp_citation_checker-0.1.0-py3-none-any.whl |
|---|---|
| Size | 6.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f768000534dd01af7e26f32792c225c9990909587521eb8c2e54068500fddb0f
|
|
BLAKE2b-256 checksum How to use checksums |
2ea35614cfd3c9b0e32b0d76da1dd3ca00d6437afed05bca1d06439522601d32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|