Claude Science + MCP
CiteProof MCP tool reference
This page documents all 24 tools in CiteProof MCP 0.1.0. Each entry lists the arguments, the limits the server enforces, and a realistic request and result. The tool names, fields and caps mirror the shipped schemas.
The division of labour
Claude Science searches, reads and writes. CiteProof MCP stores the protocol, PRISMA counts, screening decisions, extracted evidence, claims and risk-of-bias judgements, validates their shape, checks supplied quotes and computes the counts. The server contains no language model and does not search for papers.
How Claude Science and CiteProof MCP fit together
A research agent can draft a systematic review, but the decisions behind the draft need a record: why a paper was excluded, which studies were included, what each study reported, and whether the cited sentence appears in the source. CiteProof MCP is that record.
Claude Science: research agent
Runs searches, retrieves papers, reads full text, makes inclusion and exclusion judgements, extracts results, grades risk of bias and drafts the report. Every scientific judgement comes from the agent or its human reviewer.
CiteProof MCP: audit layer
Stores those judgements in a local review file, rejects malformed input, checks that quotes appear in the supplied text, computes deduplication and PRISMA counts, and exports the audit trail.
The MCP server is a separate open-source component. It is not part of a CiteProof web account, it does not consume DeepSearch or Research Mode runs, and it needs no model API key.
Architecture and data flow
review_status reports gaps and next steps. export_bundle returns one Markdown or JSON document.
Each review is one SQLite file at <CITEPROOF_MCP_HOME>/reviews/<review_id>.db. Writes use one immediate transaction with a 30 second busy timeout, so concurrent calls wait instead of failing with a locked database. Read tools never change the record.
Every tool returns JSON with an ok boolean. A successful result adds tool-specific fields. A handled failure returns {"ok": false, "error": "..."}.
What the server does not do
- It does not search literature, query a database or open a paper. The agent supplies every record.
- It does not contain an LLM and does not make inclusion, extraction, claim or risk-of-bias judgements.
- It does not prove that a study is valid, that a claim is scientifically true or that a review is complete.
- It does not turn a resolved DOI into evidence. A registered DOI only proves that the identifier exists; citation matching is called resolved, never verified.
- It does not write exports to disk and does not upload review data. Exports are returned as text for the client to save.
- claude.ai web custom connectors cannot start a local stdio process, so they are not supported.
Connect CiteProof MCP to Claude Science
Claude Science on Windows 11 is the tested path for this release (Claude Science 0.1.67, native sandbox). The connector runs inside a Windows sandbox that can read only its own workspace folder and Claude Science's bundled runtime. That is why the Claude Science install copies the server into the connector workspace instead of pointing at a project virtual environment.
Prerequisites
- Claude Science with Connectors available under Customize.
- This repository checked out, for the bundle build script. The script uses only the Python standard library.
- No separate Python install for the connector. The bundled
python3already providesmcp,pydanticandhttpx. - No model API key. The server makes no model calls.
Install the Claude Science connector
- Create the connector workspace. Open Customize, then Connectors, then Add connector, then Local command. Name it
citeproofand usepython3 placeholder.py. It will fail; the first start creates the workspace folder. If the folder does not appear, create it by hand in the next step. - Find the workspace folder. On Windows it is
C:/Users/<you>/.claude-science/orgs/<org-id>/workspaces/_mcp-citeproof. The commandclaude-science logsalso prints it ascwdin the sandbox policy lines. - Build the bundle into that folder. Run the command below from the repository root. The script refuses a folder that holds other files, so passing the workspace folder by mistake cannot delete your
datafolder. - Point the connector at the bundle. Remove the placeholder and add it again. Use forward slashes in the command; backslashes are stripped by the form.
- Set the data folder. Add the environment variable
CITEPROOF_MCP_HOMEso review files stay inside the sandbox workspace. - Confirm 24 tools. The connector page should list every tool from
review_createtoexport_bundle. Claude Science asks for approval before each tool run by default; set a tool to always allow only after you trust it.
python MCP/scripts/build_claude_science_bundle.py "C:/Users/<you>/.claude-science/orgs/<org-id>/workspaces/_mcp-citeproof/bundle"python3 C:/Users/<you>/.claude-science/orgs/<org-id>/workspaces/_mcp-citeproof/bundle/run.pyCITEPROOF_MCP_HOME=C:/Users/<you>/.claude-science/orgs/<org-id>/workspaces/_mcp-citeproof/dataAfter a new release, run the build script again into the same bundle folder, then remove and re-add the connector with the same settings. The running process keeps old code in memory, and the Connectors page has no restart button when the connector is healthy. Review data in the data folder survives this.
Confirm the tools are available
Ask the client to list its tools, or open the connector details. A healthy install shows 24 tools with the names on this page. If fewer appear, an older server process is still running: remove the connector and add it again.
The first useful call is review_create. If it succeeds, the server is running and can write to CITEPROOF_MCP_HOME.
Installing is not using
A successful install only makes the tools callable. It does not create a review, run a search or add records. Ask Claude Science to follow the workflow on this page, or give it the instruction “use CiteProof MCP for the review record and call review_status before moving to the next stage”.
Claude Desktop extension and npx
Two other local install paths are available. Both start the same server over stdio and use the same review format.
Claude Desktop extension
Download citeproof.mcpb from the latest release, then open it with Claude Desktop. The extension uses Claude Desktop's built-in Node and installs uv automatically if it is missing.
npx configuration
For Claude Desktop, Claude Code and other JSON-config clients, add the entry below. Node 18 or newer is required.
{
"mcpServers": {
"citeproof": {
"command": "npx",
"args": ["-y", "citeproof-mcp"]
}
}
}For Claude Code, the equivalent command is:
claude mcp add citeproof -- npx -y citeproof-mcpThe launcher installs uv automatically when it is missing, and uv fetches Python 3.12 on first run. Set CITEPROOF_NO_AUTO_INSTALL=1 to opt out and manage uv yourself. Review data goes to ~/.citeproof-mcp unless CITEPROOF_MCP_HOME is set.
Use one data folder per client
If two clients should share reviews, give them the same CITEPROOF_MCP_HOME. Do not point two servers at the same review file and expect independent writers; writes serialise on the SQLite file.
Follow the end-to-end review workflow
The order matters because later tools read earlier records. Run review_status at any point to learn the current phase and what is missing.
| Stage | What to do | Tools |
|---|---|---|
| 1. Create or recover | Create the review file, or list existing reviews and reuse a review_id. |
review_create, review_list |
| 2. Protocol | Record the question, populations, outcomes, eligibility and search plan before screening. | protocol_record |
| 3. Searches | Record one row per database, query and run date, with the hit count. | prisma_record_search |
| 4. Deduplication | Deduplicate the complete exported set and record the count. A partial batch is analysed but not recorded. | dedup_papers, prisma_record_dedup |
| 5. Screening | Screen titles and abstracts, then full text. Record each reviewer under their own name, compute agreement, then record consensus under primary. |
screening_record, screening_record_many, screening_list, screening_agreement, prisma_status |
| 6. Evidence | Record one row per paper and outcome with the quote and the source text used to check it. | evidence_record, evidence_table |
| 7. Risk of bias | Record each domain for the chosen tool, then compute the overall judgement by the published rule. | rob_record, rob_summary |
| 8. Claims | Record each key claim with a label, reason and quote, then find weak claims in the draft. | claim_record, claim_report |
| 9. Citations | Check DOIs against Crossref and doi.org, and resolve author-year citations against the paper list. | verify_dois, resolve_citations, lint_prose |
| 10. Report and export | Render the flow diagram, check the draft against the PRISMA checklist, then export the audit bundle. | prisma_flow_diagram, prisma_checklist, export_bundle, review_status |
When you resume a review in a new session, call review_status first. It reports the phase, missing protocol fields, PRISMA completeness, reviewer names, included studies, extraction and risk-of-bias coverage, claim counts, DOI checks and source-text changes.
Tool reference
Arguments marked optional may be omitted. Every result also has ok. List results are capped at 200 items unless the entry says otherwise, and a cut list sets truncated: true. Paper references use the forms described in Paper identity; use the same form for a paper in every tool.
Review setup and core checks
review_create
Creates a review file and returns its identifier. Every other tool needs that review_id.
| Argument | Type | Required | Notes |
|---|---|---|---|
title | string | Yes | Maximum 500 characters. |
question | string | Yes | Maximum 2,000 characters. |
year_min | integer | No | 1800 to 3000. Must not exceed year_max. |
year_max | integer | No | 1800 to 3000. Must not be below year_min. |
Limits. The id is generated by the server and matches ^[a-z0-9_-]{6,40}$. Creating a review never reuses an existing file.
Example request.
{"title": "Teleradiology turnaround times: a systematic review", "question": "In adults, what is the effect of teleradiology on radiology report turnaround time?", "year_min": 2010, "year_max": 2026}Example result.
{"ok": true, "review_id": "rev-9f3c2a1b", "next_step": "Record the protocol with protocol_record (PICO, eligibility criteria, databases, search strategy)."}review_list
Lists review files in the current CITEPROOF_MCP_HOME, newest first. Use it to recover an id when you resume work.
| Argument | Type | Required | Notes |
|---|---|---|---|
limit | integer | No | Default 50. Capped at 200. |
Example request.
{"limit": 10}Example result.
{"ok": true, "reviews": [{"review_id": "rev-9f3c2a1b", "title": "Teleradiology turnaround times: a systematic review", "question": "In adults, what is the effect of teleradiology on radiology report turnaround time?", "created_at": "2026-10-25T09:14:00Z", "year_min": 2010, "year_max": 2026}], "count": 1}verify_dois
Checks DOIs against Crossref and doi.org. This is the only tool that uses the network. With a review_id, the results are saved for review_status and export_bundle.
| Argument | Type | Required | Notes |
|---|---|---|---|
dois | array of strings, or one string | Yes | Up to 100 DOIs. One string may separate DOIs with spaces, commas or new lines. doi: and doi.org prefixes are normalised; duplicates are removed case-insensitively. |
review_id | string | No | Saves the result. The review must exist. |
Status. resolved means the registry returned a record. not_found means doi.org returned 404. unverified means the registry could not be reached, so there is no verdict. invalid means the value was not DOI-shaped and was never sent. retracted is true or false only for Crossref records.
Limits. Fixed HTTPS hosts, no redirect following, 15 second timeout. A redirect from doi.org is read as registered. No other host is contacted.
Example request.
{"dois": ["10.1136/bmj.n71", "https://doi.org/10.1371/journal.pmed.1003583"], "review_id": "rev-9f3c2a1b"}Example result.
{"ok": true, "results": [{"doi": "10.1136/bmj.n71", "input": "10.1136/bmj.n71", "status": "resolved", "title": "The PRISMA 2020 statement: an updated guideline for reporting systematic reviews", "year": 2021, "journal": "BMJ", "authors": "Page MJ, McKenzie JE, Bossuyt PM", "retracted": false, "registry": "crossref"}, {"doi": "10.1371/journal.pmed.1003583", "input": "https://doi.org/10.1371/journal.pmed.1003583", "status": "resolved", "title": "PRISMA 2020 explanation and elaboration", "year": 2021, "journal": "PLOS Medicine", "authors": "Page MJ, Moher D, Bossuyt PM", "retracted": false, "registry": "crossref"}], "summary": {"checked": 2, "resolved": 2, "not_found": 0, "unverified": 0, "invalid": 0, "retracted": 0}, "offline": false, "saved": true, "note": "Registry lookups only: a resolved DOI is real, which says nothing about whether it supports a claim."}resolve_citations
Matches inline citations in a draft against a supplied paper list. It rewrites common author-year forms such as Smith et al. (2020), (Smith 2020) and (Smith, 2020a) before matching. Groups that contain a DOI or URL are left alone.
| Argument | Type | Required | Notes |
|---|---|---|---|
text | string | Yes | The draft or section to check. |
papers | array of objects | Yes | Up to 2,000 papers. Each object has title, authors (list or A; B) and year; doi is optional. |
Result notes. resolved excludes ambiguous matches. Numeric citations such as [1] are counted, not resolved. orphan_papers lists papers in the supplied list that the text never cites.
Limits. A match is resolution, not verification: it shows that a citation points at a paper in the list, not that the paper supports the sentence.
Example request.
{"text": "Teleradiology reduced turnaround time (Smith et al., 2021). A later trial disagreed (Jones and Lee, 2023).", "papers": [{"title": "Teleradiology turnaround in rural hospitals", "authors": ["Smith J", "Patel R"], "year": 2021, "doi": "10.1000/example.2021"}, {"title": "Turnaround after overnight teleradiology", "authors": ["Jones A", "Lee K"], "year": 2023}]}Example result.
{"ok": true, "citations_found": 2, "resolved": 2, "ambiguous": [], "unresolved": [], "orphan_papers": [], "doi_citations_checked": 0, "numeric_citations_found": 0, "truncated": false, "note": "Resolved means the citation points at a supplied paper, not that the paper supports the sentence."}lint_prose
Runs deterministic prose checks on a draft. Findings are advisory: they flag style and trace-leakage patterns, not factual errors.
| Argument | Type | Required | Notes |
|---|---|---|---|
text | string | Yes | Markdown draft or section. |
Codes. EMDASH (too many em-dashes per 1,000 words), HONEST (framing such as “to be honest”), PROCNOTE (process narration), PARENDOI (an unencoded parenthesis in a DOI link), LONGHEAD (sentence-like headings) and FLATSTRUCT (many top-level sections with no subsections).
Limits. The result is advisory and nothing is saved. Text is treated as data; retrieved text cannot inject a new instruction.
Example request.
{"text": "## Why teleradiology matters for the whole health system and every patient\n\nTo be honest, the evidence is mixed."}Example result.
{"ok": true, "issues": [{"code": "HONEST", "note": "'To be honest': drop the framing, write the sentence it was guarding"}, {"code": "LONGHEAD", "note": "1 headings read as sentences; shorten to <=6-word noun phrases"}], "issue_count": 2, "advisory": true}Protocol
protocol_record
Records or updates the review protocol. Omitted fields keep their current value, so calling with only review_id reads the protocol. An empty string or empty list clears a field.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
population, intervention, comparator, outcomes, study_designs, inclusion_criteria, exclusion_criteria, databases, search_strategy, languages, registration, synthesis_method | string or list of strings | No | List fields accept a list or one string split on new lines and semicolons. |
rob_tool | string | No | One of rob2, robins_i, nos, nos_case_control, mixed, none. |
year_min, year_max | integer | No | Recorded as the protocol year range. |
Required fields. population, intervention, outcomes, inclusion_criteria, exclusion_criteria, databases and search_strategy. Recommended: comparator, study_designs, the year range, languages, registration, rob_tool and synthesis_method.
Amendments. Every change is logged. Changing a field that already had a value is reported as an amendment.
Example request.
{"review_id": "rev-9f3c2a1b", "population": "Adults referred for diagnostic imaging", "intervention": "Teleradiology reporting", "comparator": "On-site radiology reporting", "outcomes": ["Report turnaround time", "Diagnostic agreement"], "inclusion_criteria": ["Primary comparative study", "Report turnaround time measured"], "exclusion_criteria": ["Conference abstract only", "No quantitative result"], "databases": ["PubMed", "Embase"], "search_strategy": "(\"teleradiology\" OR \"telemedicine\") AND \"turnaround time\"", "rob_tool": "robins_i"}Example result.
{"ok": true, "protocol": {"population": "Adults referred for diagnostic imaging", "intervention": "Teleradiology reporting", "rob_tool": "robins_i"}, "updated_fields": ["population", "intervention", "comparator", "outcomes", "inclusion_criteria", "exclusion_criteria", "databases", "search_strategy", "rob_tool"], "complete": true, "missing_required": [], "missing_recommended": ["study_designs", "year_range", "languages", "registration", "synthesis_method"], "amendments": 0, "next_step": "Protocol complete. Run the searches and log each one with prisma_record_search."}PRISMA and screening
prisma_record_search
Records one database search. The same source, query and run date replaces the hit count instead of adding a row, so a retried call cannot double-count.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
source | string | Yes | Database name, matched case-insensitively. |
query | string | Yes | The query as run. |
date_run | string | Yes | A real YYYY-MM-DD date. A future date is a warning. |
hits | integer | Yes | Records returned by this search. |
Important. Adding a search or changing a hit count clears the review's deduplication record, because the old count belonged to a different set of records. The result says so in warnings. Re-sending the same search with the same hits changes nothing.
Example request.
{"review_id": "rev-9f3c2a1b", "source": "PubMed", "query": "teleradiology AND turnaround time", "date_run": "2026-10-20", "hits": 412}Example result.
{"ok": true, "search_id": 1, "updated": false, "records_identified": 412, "records_by_source": {"PubMed": 412}, "searches_recorded": 1, "warnings": []}dedup_papers
Detects duplicate records in an exported set. Same paper means the same normalised DOI, the same PMID, or the same normalised title of at least 20 characters with the same year and first-author surname. Matching is transitive.
| Argument | Type | Required | Notes |
|---|---|---|---|
papers | array of objects | Yes | Up to 10,000 exported records. Fields: id, doi, pmid, title, year, authors or first_author, abstract. |
review_id | string | No | Records the count only when the call covers every exported record. |
Recording rule. The count is saved only when review_id is given. A partial or batched call is saved too, with a warning that records_checked does not match the total hits from prisma_record_search. A count larger than the recorded hits is refused, and an earlier record is replaced.
What is kept. The record with the most complete metadata is kept. Records are not merged, so copy any field you need from a removed record before discarding it. A same-title record with a different year or author is listed in possible_duplicates instead of merged.
Example request.
{"review_id": "rev-9f3c2a1b", "papers": [{"id": "p1", "doi": "10.1000/example.2021", "title": "Teleradiology turnaround in rural hospitals", "year": 2021, "first_author": "Smith"}, {"id": "p2", "pmid": "12345678", "title": "Teleradiology turnaround in rural hospitals", "year": 2021, "first_author": "Smith"}, {"id": "p3", "doi": "10.1000/example.2023", "title": "Turnaround after overnight teleradiology", "year": 2023, "first_author": "Jones"}]}Example result.
{"ok": true, "records_checked": 3, "unique_records": 2, "duplicates_removed": 1, "removed_indices": [1], "clusters": [{"kept_index": 0, "kept_id": "p1", "member_indices": [0, 1], "matched_on": ["title_year_author"], "conflicting_dois": false}], "possible_duplicates": [], "truncated": false, "recorded": true, "method": "dedup_papers: exact DOI, then PMID, then normalised title + year + first-author surname", "warnings": ["3 records were checked but the recorded searches total 412 hits; send every exported record so the PRISMA counts add up."]}prisma_record_dedup
Records a whole-review duplicate count when deduplication was done elsewhere, for example in a reference manager. It replaces any existing dedup record.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
duplicates_removed | integer | Yes | Cannot exceed the recorded hits. |
method | string | Yes | Short description of how duplicates were found. |
Example request.
{"review_id": "rev-9f3c2a1b", "duplicates_removed": 87, "method": "Zotero duplicate merge, then manual title check"}Example result.
{"ok": true, "duplicates_removed": 87, "records_identified": 412, "records_after_dedup": 325, "method": "Zotero duplicate merge, then manual title check"}screening_record
Records one screening decision for one reviewer at one stage. Recording the same paper, stage and reviewer again updates the decision.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
paper_ref | string | Yes | DOI, pmid:<digits> or title:<title>|<year>. |
stage | string | Yes | title_abstract or full_text. |
decision | string | Yes | include or exclude; at full text also not_retrieved. |
reason | string | For exclude | Maximum 300 characters. |
reviewer | string | No | 1 to 40 characters, stored lower-case. Default primary. |
title | string | No | Optional paper title for display. |
Warnings. A full-text decision without a title/abstract include is flagged, and so is a title/abstract exclusion of a paper that already has a full-text decision.
Example request.
{"review_id": "rev-9f3c2a1b", "paper_ref": "10.1000/example.2021", "stage": "title_abstract", "decision": "include", "reviewer": "primary", "title": "Teleradiology turnaround in rural hospitals"}Example result.
{"ok": true, "updated": false, "paper_ref": "10.1000/example.2021", "stage": "title_abstract", "reviewer": "primary", "decision": "include", "stage_counts": {"include": 48, "exclude": 277, "not_retrieved": 0}, "warnings": []}screening_record_many
Records up to 500 screening decisions in one all-or-nothing call. An invalid item or a repeated paper, stage and reviewer returns an error with the item index, and nothing is written.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
decisions | array of objects | Yes | Up to 500 items with the same fields as screening_record. |
Limits. Repeated (paper_ref, stage, reviewer) triples are rejected instead of silently overwriting. Use screening_record to update one decision.
Example request.
{"review_id": "rev-9f3c2a1b", "decisions": [{"paper_ref": "10.1000/example.2023", "stage": "title_abstract", "decision": "exclude", "reason": "No turnaround time outcome", "reviewer": "secondary"}, {"paper_ref": "pmid:12345678", "stage": "title_abstract", "decision": "include", "reviewer": "secondary"}]}Example result.
{"ok": true, "count": 2, "inserted_count": 2, "updated_count": 0, "warning_count": 0, "warnings": []}screening_list
Lists screening decisions, newest first, with filters and offset paging.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
stage | string | No | title_abstract or full_text. |
reviewer | string | No | Filter by reviewer name. |
decision | string | No | include, exclude or not_retrieved. |
paper_ref | string | No | Filter by one paper. |
limit | integer | No | Default 200, capped at 200. |
offset | integer | No | Default 0. |
Example request.
{"review_id": "rev-9f3c2a1b", "stage": "full_text", "reviewer": "primary", "limit": 50}Example result.
{"ok": true, "records": [{"paper_ref": "10.1000/example.2021", "stage": "full_text", "reviewer": "primary", "decision": "include", "reason": null, "title": "Teleradiology turnaround in rural hospitals", "updated_at": "2026-10-24T16:02:00Z"}], "count": 1, "total": 48, "truncated": false, "next_offset": 1}screening_agreement
Computes Cohen's kappa between two reviewers at one stage. Only papers both reviewers decided with include or exclude enter the calculation; not_retrieved pairs are counted in not_judged.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
stage | string | Yes | title_abstract or full_text. |
reviewer_a | string | Yes | First reviewer name. |
reviewer_b | string | Yes | Second reviewer name. |
Result notes. kappa is null and the interpretation is undefined when the reviewers share no decisions or expected agreement is 1. Interpretation uses the Landis and Koch bands.
Example request.
{"review_id": "rev-9f3c2a1b", "stage": "title_abstract", "reviewer_a": "primary", "reviewer_b": "secondary"}Example result.
{"ok": true, "stage": "title_abstract", "reviewer_a": "primary", "reviewer_b": "secondary", "shared": 20, "agree": 17, "table": {"both_include": 6, "a_include_b_exclude": 1, "a_exclude_b_include": 2, "both_exclude": 11}, "po": 0.85, "pe": 0.53, "kappa": 0.681, "interpretation": "substantial", "disagreement_count": 3, "disagreements": [{"paper_ref": "10.1000/example.2023", "title": "Turnaround after overnight teleradiology", "a": "include", "b": "exclude", "reason_a": null, "reason_b": "No turnaround time outcome"}, {"paper_ref": "10.1000/example.2024", "title": "Diagnostic accuracy of remote reporting", "a": "exclude", "b": "include", "reason_a": "Wrong population", "reason_b": null}, {"paper_ref": "10.1000/example.2025", "title": "Cost of teleradiology in rural hospitals", "a": "exclude", "b": "include", "reason_a": "No turnaround time outcome", "reason_b": null}], "truncated": false, "only_a": 2, "only_b": 1, "not_judged": 4, "next_step": "Resolve the 3 disagreement(s) and record each consensus decision with reviewer='primary'."}prisma_status
Computes PRISMA 2020 counts from the search log, the dedup record and one reviewer's decisions. Run it before writing the flow section and before export.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
reviewer | string | No | Defaults to primary, else the only reviewer. Several reviewers with no primary is an error. |
Counts. Reports sought are title/abstract includes. Reports not retrieved are full-text not_retrieved. Assessed is full-text include plus exclude. A report sought with no full-text decision is full_text_pending.
Invariants. The server checks that full-text decisions exist only for title/abstract includes, so sought equals assessed plus not retrieved plus pending. complete is true when searches and dedup are recorded, every record after dedup has a title/abstract decision, no full-text decision is pending and the invariants hold.
Example request.
{"review_id": "rev-9f3c2a1b", "reviewer": "primary"}Example result.
{"ok": true, "reviewer_used": "primary", "records_identified": 412, "records_by_source": {"PubMed": 412}, "duplicates_removed": 87, "records_after_dedup": 325, "records_screened": 325, "excluded_title_abstract": 277, "full_text_requested": 48, "full_text_unavailable": 3, "full_text_assessed": 45, "excluded_full_text": 33, "studies_included": 12, "exclusion_reasons": {"Wrong population": 14, "No turnaround outcome": 11, "No comparator": 8}, "exclusion_reasons_title_abstract": {"Wrong population": 160, "No turnaround outcome": 117}, "full_text_pending": 0, "records_awaiting_screening": 0, "full_text_without_title_abstract_include": [], "searches_recorded": 1, "dedup_recorded": true, "dedup_method": "Zotero duplicate merge, then manual title check", "invariants_valid": true, "invariant_errors": [], "warnings": [], "complete": true, "next_steps": ["PRISMA counts are complete; render them with prisma_flow_diagram."]}prisma_flow_diagram
Renders the recorded PRISMA counts as a flow diagram. Output is text only and agent-supplied text is escaped for the chosen format.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
format | string | No | mermaid (default), svg or markdown. |
reviewer | string | No | Reviewer whose counts are used. |
Notes. The diagram shows the top full-text exclusion reasons and adds a pending box when decisions are incomplete. It is a rendering of recorded counts, not a new calculation.
Example request.
{"review_id": "rev-9f3c2a1b", "format": "mermaid", "reviewer": "primary"}Example result.
{"ok": true, "format": "mermaid", "diagram": "flowchart TD\n subgraph Identification\n id1[\"Records identified from databases (n = 412)<br/>PubMed: 412\"]\n id2[\"Duplicates removed (n = 87)\"]\n id3[\"Records after deduplication (n = 325)\"]\n id1 --> id2\n id2 --> id3\n end\n subgraph Screening\n sc1[\"Records screened (title/abstract) (n = 325)\"]\n sc_exc[\"Records excluded (title/abstract) (n = 277)\"]\n sc2[\"Reports sought for retrieval (n = 48)\"]\n sc_unav[\"Reports not retrieved (n = 3)\"]\n sc3[\"Reports assessed for eligibility (full-text) (n = 45)\"]\n sc_ft_exc[\"Reports excluded (full-text) (n = 33)<br/>Wrong population: 14<br/>No turnaround outcome: 11<br/>No comparator: 8\"]\n id3 --> sc1\n sc1 --> sc_exc\n sc1 --> sc2\n sc2 --> sc_unav\n sc2 --> sc3\n sc3 --> sc_ft_exc\n end\n subgraph Included\n inc[\"Studies included in review (n = 12)\"]\n sc3 --> inc\n end", "complete": true, "warnings": []}prisma_checklist
Checks a draft against the 27 PRISMA 2020 items with a keyword match, and compares sentences that state PRISMA counts with the recorded counts. Nothing is saved.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
report_text | string | Yes | The draft to check. |
reviewer | string | No | Reviewer whose counts are compared. |
What it proves. The keyword check shows whether an item is mentioned, not whether it is reported well. Item 1 checks whether the first line contains “systematic review” or “meta-analysis”. Count statements are compared within tolerance and returned with a snippet.
Example request.
{"review_id": "rev-9f3c2a1b", "report_text": "This systematic review examined teleradiology. Of 412 records identified, 12 studies were included.", "reviewer": "primary"}Example result.
{"ok": true, "found_count": 2, "total": 27, "items": [{"item": 1, "section": "Title", "topic": "Title identifies the report as a systematic review", "found": true, "matched": "systematic review"}, {"item": 2, "section": "Abstract", "topic": "Abstract", "found": false, "matched": null}, {"item": 3, "section": "Introduction", "topic": "Rationale", "found": false, "matched": null}, {"item": 4, "section": "Introduction", "topic": "Objectives", "found": false, "matched": null}, {"item": 5, "section": "Methods", "topic": "Eligibility criteria", "found": false, "matched": null}, {"item": 6, "section": "Methods", "topic": "Information sources", "found": false, "matched": null}, {"item": 7, "section": "Methods", "topic": "Search strategy", "found": false, "matched": null}, {"item": 8, "section": "Methods", "topic": "Selection process", "found": false, "matched": null}, {"item": 9, "section": "Methods", "topic": "Data collection process", "found": false, "matched": null}, {"item": 10, "section": "Methods", "topic": "Data items", "found": false, "matched": null}, {"item": 11, "section": "Methods", "topic": "Study risk of bias assessment", "found": false, "matched": null}, {"item": 12, "section": "Methods", "topic": "Effect measures", "found": false, "matched": null}, {"item": 13, "section": "Methods", "topic": "Synthesis methods", "found": false, "matched": null}, {"item": 14, "section": "Methods", "topic": "Reporting bias assessment", "found": false, "matched": null}, {"item": 15, "section": "Methods", "topic": "Certainty assessment", "found": false, "matched": null}, {"item": 16, "section": "Results", "topic": "Study selection", "found": true, "matched": "records identified"}, {"item": 17, "section": "Results", "topic": "Study characteristics", "found": false, "matched": null}, {"item": 18, "section": "Results", "topic": "Risk of bias in studies", "found": false, "matched": null}, {"item": 19, "section": "Results", "topic": "Results of individual studies", "found": false, "matched": null}, {"item": 20, "section": "Results", "topic": "Results of syntheses", "found": false, "matched": null}, {"item": 21, "section": "Results", "topic": "Reporting biases", "found": false, "matched": null}, {"item": 22, "section": "Results", "topic": "Certainty of evidence", "found": false, "matched": null}, {"item": 23, "section": "Discussion", "topic": "Discussion (interpretation, limitations, implications)", "found": false, "matched": null}, {"item": 24, "section": "Other information", "topic": "Registration and protocol", "found": false, "matched": null}, {"item": 25, "section": "Other information", "topic": "Support", "found": false, "matched": null}, {"item": 26, "section": "Other information", "topic": "Competing interests", "found": false, "matched": null}, {"item": 27, "section": "Other information", "topic": "Availability of data, code and other materials", "found": false, "matched": null}], "missing": ["Abstract", "Rationale", "Objectives", "Eligibility criteria", "Information sources", "Search strategy", "Selection process", "Data collection process", "Data items", "Study risk of bias assessment", "Effect measures", "Synthesis methods", "Reporting bias assessment", "Certainty assessment", "Study characteristics", "Risk of bias in studies", "Results of individual studies", "Results of syntheses", "Reporting biases", "Certainty of evidence", "Discussion (interpretation, limitations, implications)", "Registration and protocol", "Support", "Competing interests", "Availability of data, code and other materials"], "numbers": [{"field": "records_identified", "reported": 412, "recorded": 412, "matches": true, "snippet": "ew examined teleradiology. Of 412 records identified, 12 studies were included."}, {"field": "studies_included", "reported": 12, "recorded": 12, "matches": true, "snippet": "y. Of 412 records identified, 12 studies were included."}], "number_mismatches": 0, "numbers_note": null, "note": "Keyword check of the report text. It shows which items are mentioned, not whether they are reported well."}Evidence extraction
evidence_record
Records one evidence row per paper and outcome. The server checks that the quote appears in source_text and that every number entered is written in the quote. Only the length and SHA-256 of source_text are stored.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
paper_ref | string | Yes | Canonical paper reference. |
outcome | string | Yes | Outcome name. One row per paper and outcome. |
study_design | string | Yes | Design as reported. |
quote | string | Yes | Passage that contains the extracted numbers. |
source_text | string | Yes | Text used to check the quote. Must not be empty. |
sample_size, population, intervention, comparator, timepoint, effect_measure, effect_estimate, ci_lower, ci_upper, ci_level, notes | varies | No | effect_measure is rr, or, hr, irr, rom, rd, md, smd or other; names such as “risk ratio” are accepted. |
Refused input. An estimate without a measure, only one CI limit, lower above upper, an estimate outside its CI, a ratio measure at or below zero, a non-finite number, or an empty source_text. A quote that does not verify is stored and flagged, not rejected.
Warnings. A paper that is not among the full-text included studies is flagged. A changed source-text hash is reported as source_changed.
Example request.
{"review_id": "rev-9f3c2a1b", "paper_ref": "10.1000/example.2021", "outcome": "Report turnaround time", "study_design": "Retrospective cohort", "quote": "Median turnaround time fell by 24 minutes (95% CI 31 to 17 minutes less; n=1,204).", "source_text": "Results: Median turnaround time fell by 24 minutes (95% CI 31 to 17 minutes less; n=1,204).", "sample_size": 1204, "effect_measure": "md", "effect_estimate": -24, "ci_lower": -31, "ci_upper": -17, "ci_level": 95}Example result.
{"ok": true, "updated": false, "paper_ref": "10.1000/example.2021", "outcome": "Report turnaround time", "quote_verified": true, "quote_note": "Quote found in the supplied source text.", "numbers_not_in_quote": [], "effect": "MD -24 (95% CI -31 to -17)", "rows_for_paper": 1, "warnings": []}evidence_table
Returns the whole evidence table as Markdown, CSV or JSON. Coverage counters show included studies with no row and rows whose quote or numbers did not verify.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
format | string | No | markdown (default), csv or json. |
paper_ref | string | No | Limit the table to one paper. |
CSV safety. A text cell that starts with =, +, - or @ is prefixed with an apostrophe so a spreadsheet does not execute it.
Example request.
{"review_id": "rev-9f3c2a1b", "format": "markdown"}Example result.
{"ok": true, "format": "markdown", "row_count": 1, "table": "| Study | Design | N | Population | Intervention | Comparator | Outcome | Effect | Source quote | Checks |\n|---|---|---|---|---|---|---|---|---|---|\n| 10.1000/example.2021 | Retrospective cohort | 1204 | Adults referred for imaging | Teleradiology | On-site reporting | Report turnaround time | MD -24 (95% CI -31 to -17) | Median turnaround time fell by 24 minutes | quote verified |", "truncated": false, "included_without_rows": ["10.1000/example.2024"], "included_without_rows_count": 1, "rows_quote_not_verified": 0, "rows_numbers_not_in_quote": 0}Claims and risk of bias
claim_record
Records whether a key claim is supported by one paper. The agent supplies the label and reason; the server stores the judgement and checks the quote against the supplied source text. A claim is upserted on normalised claim text plus paper reference.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
claim_text | string | Yes | The sentence or claim being judged. |
paper_ref | string | Yes | The paper that should support it. |
label | string | Yes | supported, partial or unsupported. |
reason | string | Yes | Why the label applies. |
source_text | string | For supported and partial | Checked, then stored only as length and SHA-256. |
quote | string | For supported and partial | Must appear in source_text to verify. |
Note. quote_verified means the quote appears in the supplied text. It does not mean the passage supports the claim; that is the agent's recorded judgement.
Example request.
{"review_id": "rev-9f3c2a1b", "claim_text": "Teleradiology reduced median report turnaround time by 24 minutes.", "paper_ref": "10.1000/example.2021", "label": "supported", "reason": "The reported median difference matches the claim.", "quote": "Median turnaround time fell from 42 minutes to 18 minutes", "source_text": "Results: Median turnaround time fell from 42 minutes to 18 minutes (n=1,204)."}Example result.
{"ok": true, "claim_id": 7, "updated": false, "quote_verified": true, "quote_note": "Quote found in the supplied source text.", "warnings": []}claim_report
Summarises the claim log. With report_text, it also finds weak claims whose text appears verbatim in the draft.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
report_text | string | No | The draft in which to find weak claims. |
Fields. suspicious lists supported or partial claims whose quote did not verify. unsupported lists unsupported claims. weak_claims_in_report is null when no report text is supplied.
Example request.
{"review_id": "rev-9f3c2a1b", "report_text": "Teleradiology reduced median report turnaround time by 24 minutes."}Example result.
{"ok": true, "total": 9, "counts_by_label": {"supported": 7, "partial": 1, "unsupported": 1}, "quotes_not_verified": 1, "suspicious_count": 1, "suspicious": [{"claim_id": 8, "claim_text": "Teleradiology improved diagnostic accuracy.", "paper_ref": "10.1000/example.2024", "label": "partial", "reason": "Only sensitivity was reported; specificity was not."}], "unsupported_count": 1, "unsupported": [{"claim_id": 9, "claim_text": "Teleradiology is cost saving in every setting.", "paper_ref": "10.1000/example.2025", "label": "unsupported", "reason": "No cost outcome was reported."}], "weak_claims_in_report": [{"claim_id": 9, "claim_text": "Teleradiology is cost saving in every setting.", "paper_ref": "10.1000/example.2025", "label": "unsupported", "reason": "No cost outcome was reported."}], "truncated": false, "method": "Labels were assigned by the calling agent. The server checked only that each quote appears in the supplied source text. This is not independent verification.", "next_step": "Remove or rewrite the claims in weak_claims_in_report, or record a verified quote for them."}rob_record
Records one risk-of-bias domain judgement for one paper. The tool and domain sets are fixed, a paper cannot mix tools, and a quote is required except for a few cases.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
paper_ref | string | Yes | Included study. |
tool | string | Yes | rob2, robins_i, nos (cohort) or nos_case_control. |
domain | string | Yes | RoB 2 D1–D5, ROBINS-I D1–D7 (aliases accepted), NOS selection / comparability / outcome or exposure, or overall for RoB 2 and ROBINS-I. |
judgement | string or integer | Yes | RoB 2: low, some_concerns, high. ROBINS-I: low, moderate, serious, critical, no_information. NOS: star counts, selection 0–4, comparability 0–2, outcome or exposure 0–3. |
quote | string | Usually | Required except for overall, ROBINS-I no_information and 0 stars. |
source_text | string | Usually | Text used to check the quote. |
rationale | string | For overall | Required for an overall judgement. |
Rule. Recording the same domain again updates it. domains_missing shows what remains before rob_summary can compute an overall judgement.
Example request.
{"review_id": "rev-9f3c2a1b", "paper_ref": "10.1000/example.2021", "tool": "robins_i", "domain": "D2", "judgement": "moderate", "quote": "Consecutive cases were identified from the radiology information system.", "source_text": "Methods: Consecutive cases were identified from the radiology information system."}Example result.
{"ok": true, "updated": false, "paper_ref": "10.1000/example.2021", "tool": "robins_i", "domain": "D2", "judgement": "moderate", "quote_verified": true, "quote_note": "Quote found in the supplied source text.", "domains_recorded": 2, "domains_missing": ["D3", "D4", "D5", "D6", "D7"], "warnings": []}rob_summary
Computes the overall risk-of-bias judgement for each paper from its recorded domains and the published rule, then returns a traffic-light table and counts by overall judgement.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
Rules. RoB 2: any high gives high, else any some concerns gives some concerns, else low. ROBINS-I: any critical gives critical, else any serious gives serious, else any no information gives no information unless a recorded overall is used, else the worst of moderate and low. NOS uses the AHRQ thresholds: good, fair or poor. A paper is incomplete while a domain is missing.
Recorded overall. A reviewer's own overall is used only where the rule allows it. A recorded overall outside the rule is ignored with a note.
Example request.
{"review_id": "rev-9f3c2a1b"}Example result.
{"ok": true, "papers": [{"paper_ref": "10.1000/example.2021", "tool": "robins_i", "domains": {"D1": "low", "D2": "moderate", "D3": "low", "D4": "low", "D5": "low", "D6": "low", "D7": "low"}, "missing_domains": [], "overall": "moderate", "overall_by_rule": "moderate", "overall_recorded": null, "notes": []}], "table": [{"paper_ref": "10.1000/example.2021", "D1": "low", "D2": "moderate", "overall": "moderate"}], "counts_by_overall": {"moderate": 1}, "papers_with_unverified_quotes": [], "overall_rule": "ROBINS-I: critical > serious > no_information > moderate > low", "truncated": false}Whole-review views and export
review_status
Reports the current phase, what is complete and what is missing. It is read only and is the right first call when you resume a review.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
reviewer | string | No | Reviewer used for screening and PRISMA coverage. |
Coverage checks. Included studies without evidence rows or risk-of-bias records, evidence rows for papers not included, included DOIs not yet checked, retracted or non-resolving DOIs, single-reviewer screening and source-text changes. Paper lists show the first 20 references.
Phase. The first unfinished step of protocol, searching, deduplication, title/abstract screening, full-text screening, data extraction, risk of bias, claim checking or reporting.
Example request.
{"review_id": "rev-9f3c2a1b", "reviewer": "primary"}Example result.
{"ok": true, "review": {"review_id": "rev-9f3c2a1b", "title": "Teleradiology turnaround times: a systematic review", "question": "In adults, what is the effect of teleradiology on radiology report turnaround time?", "year_min": 2010, "year_max": 2026, "created_at": "2026-10-25T09:14:00Z"}, "phase": "reporting", "protocol": {"complete": true, "missing_required": [], "missing_recommended": []}, "prisma": {"reviewer_used": "primary", "records_identified": 412, "duplicates_removed": 87, "records_after_dedup": 325, "records_screened": 325, "records_awaiting_screening": 0, "full_text_requested": 48, "full_text_unavailable": 3, "full_text_pending": 0, "full_text_assessed": 45, "studies_included": 12, "invariants_valid": true, "complete": true}, "screening_reviewers": ["primary", "secondary"], "included_studies": 12, "extraction": {"rows": 12, "studies_with_rows": 12, "included_without_rows_count": 0, "included_without_rows": [], "rows_quote_not_verified": 0, "rows_numbers_not_in_quote": 0}, "risk_of_bias": {"papers_assessed": 12, "counts_by_overall": {"low": 3, "moderate": 7, "serious": 2}, "included_without_rob_count": 0, "included_without_rob": [], "incomplete": [], "papers_with_unverified_quotes": []}, "claims": {"total": 9, "counts_by_label": {"supported": 7, "partial": 1, "unsupported": 1}, "quotes_not_verified": 1, "suspicious_count": 1, "unsupported_count": 1}, "dois": {"checked": 12, "retracted": [], "not_found": [], "unverified": 0, "included_dois_unchecked": 0}, "source_texts": {"distinct_by_paper": 12, "changes_count": 0}, "warnings": ["Claim 9 is unsupported but appears in the draft."], "next_steps": ["Revise the draft claim flagged by claim_report.", "Export the audit bundle."]}export_bundle
Returns one document with the review record: metadata, protocol and amendments, search log, dedup, PRISMA counts and invariants with a diagram, screening decisions, agreement, evidence, risk of bias, claims, DOI checks and source-text changes.
| Argument | Type | Required | Notes |
|---|---|---|---|
review_id | string | Yes | Existing review id. |
format | string | No | markdown (default) or json. |
reviewer | string | No | Reviewer used for agreement and PRISMA coverage. |
Limits. At most 5,000 screening decisions and 5,000 claims. Source texts are never included. Nothing is written to disk; the client receives the text and may save it.
Example request.
{"review_id": "rev-9f3c2a1b", "format": "markdown", "reviewer": "primary"}Example result.
{"ok": true, "format": "markdown", "content": "# Teleradiology turnaround times: a systematic review\n\n## Protocol\n...\n\n## PRISMA 2020 flow\n...", "chars": 28410, "suggested_filename": "rev-9f3c2a1b-audit-bundle.md", "truncated": false, "phase": "reporting"}Limits and validation rules
Paper identity
Every paper_ref is stored in a canonical form. Accepted inputs are a DOI (lower-cased, with any doi: or doi.org prefix removed), pmid:<digits>, or title:<normalised title>|<year or nd>. Title matching folds accents and removes punctuation while keeping letters of every script. Anything else is refused. Use the same form for a paper in every tool, or later tools will treat it as a different paper.
Input and list caps
| Item | Cap or rule |
|---|---|
| List results | 200 items, with truncated: true when cut. |
review_id | ^[a-z0-9_-]{6,40}$, validated before it becomes a file name. |
review_create title / question | 500 / 2,000 characters. |
verify_dois | 100 DOIs per call. |
resolve_citations papers | 2,000 papers. |
dedup_papers | 10,000 records; more is refused so cross-call duplicates are not missed. |
screening_record_many | 500 decisions per call, all or nothing. |
| Screening exclusion reason | 300 characters; required for exclude. |
| Reviewer name | 1 to 40 characters, stored lower-case. |
export_bundle | 5,000 screening decisions and 5,000 claims. |
| Tool text input | 400,000 characters for a single text field. |
How quote checks work
Quote matching ignores case, whitespace, curly quotes, dash variants, zero-width characters, line-break hyphenation and hyphens inside words. It needs at least 12 normalised characters and matches on word boundaries for scripts written with spaces.
An ellipsis quote (a ... b or a [...] b) verifies only when every part is found in order and the parts are at most 1,500 characters apart. In an evidence row, every number entered must also be written in the quote; missing numbers are reported in numbers_not_in_quote.
A failed check is stored and reported. It is never silently accepted, and it is never described as verified.
Data handling and privacy
Local storage
State lives in SQLite files under CITEPROOF_MCP_HOME, which defaults to ~/.citeproof-mcp. Each review is <home>/reviews/<review_id>.db. The server opens one file per review, applies its schema on first open, and uses WAL plus a 30 second busy timeout. Concurrent calls wait rather than fail as locked.
Source text is never stored in full. The server stores its length and SHA-256, plus observations and hash changes. Exports are returned as text; nothing is written outside the home folder. Removing or moving the folder moves the review data with it.
Network calls
The only network calls are DOI checks in verify_dois, to api.crossref.org and doi.org. Hosts are fixed, redirects are not followed, the timeout is 15 seconds, and a value that is not DOI-shaped is never sent. No review data is uploaded. Metrics, accounts and telemetry are not part of the server.
What stays on your machine
Review files, screening decisions, extracted evidence, claims, risk-of-bias records and source-text hashes stay in the local SQLite database. CiteProof does not receive them. The client can read tool results and may send them to its own model provider under that provider's terms; that is outside the MCP server's control.
Handling ok:false
Every handled failure looks like this:
{"ok": false, "error": "stage must be one of: title_abstract, full_text; got 'full_pdf'"}Read error and change the argument. Common cases:
- Invalid paper reference. Use a DOI,
pmid:<digits>ortitle:<title>|<year>. Do not switch forms for the same paper. - Missing required field. An exclusion needs a reason; a supported or partial claim needs a quote and source text; an overall risk-of-bias judgement needs a rationale.
- Wrong JSON type. The MCP SDK rejects the argument before the tool runs. That is a transport-level tool error, not an
ok:falseresult. - Busy database. Retry the call. The failed attempt saved nothing.
- Internal error. The message names the tool and exception type, with no stack trace or file path. Check the arguments, retry once, then report the tool name and a redacted request.
Read-only calls are safe to repeat. Do not blindly retry a write after an error that may have partially applied; read review_status first.
Client compatibility
| Client | Install path | Status |
|---|---|---|
| Claude Science | Local command connector with the built bundle | Tested Windows 11, Claude Science 0.1.67 |
| Claude Desktop | citeproof.mcpb extension | New Extension path, not yet broadly tested |
| Claude Desktop | npx with a JSON mcpServers entry | New Not yet tested for this release |
| Claude Code | claude mcp add citeproof -- npx -y citeproof-mcp | New Not yet tested for this release |
| Cursor, VS Code, Windsurf | Any stdio launcher, or npx | Not yet tested |
| claude.ai web custom connectors | Cannot start a local stdio command | Unsupported |
The server follows the standard MCP stdio protocol and was tested against mcp 1.27 and mcp 2.x. A client that can start a stdio server should work, but “should” is not “tested”.
Troubleshooting
| Symptom | What to check |
|---|---|
| Only 18 tools appear instead of 24 | An old server process is still running. Remove the connector and add it again with the same settings. |
this kernel's Python interpreter ... is not readable inside the sandbox | The command points outside the connector workspace. Use the bundle path from the install steps. |
Set "command" to node, npx or python3 ... | You gave an absolute path to a Python that Claude Science does not provide. Use python3. |
can't open file ... Permission denied | The bundle is outside the connector workspace. Build it into .../workspaces/_mcp-citeproof/bundle. |
| Connector name rejected | Use lowercase letters, digits and hyphens only. Use citeproof. |
| The local process exits immediately | Check the command path, CITEPROOF_MCP_HOME and the connector log. The command must be readable inside the sandbox. |
| npx does not start | Check node --version. Node 18 or newer is required. If auto-install is disabled, install uv yourself; uv fetches Python 3.12 on first run. |
A DOI returns unverified | The registry was unreachable, so there is no verdict. It is not “not found”. Retry when the network is available. |
| Deduplication will not record | The call did not cover every exported record. records_checked must equal the total hits recorded by prisma_record_search, or record the whole count with prisma_record_dedup. |
| An export is empty or cut short | Check review_status for missing records and truncated in the export result. The 5,000-decision and 5,000-claim caps are the only truncation points. |
For connector-specific errors and the research-assistant failures, see Troubleshooting.
Keeping these docs accurate
This page describes CiteProof MCP 0.1.0. When the code and this page disagree, the code wins. The authoritative sources are:
- MCP/docs/SPEC.md: tool arguments, limits, result shapes, storage and security rules.
- MCP/docs/CLAUDE_SCIENCE.md: the tested Claude Science install and connector troubleshooting.
- The MCP repository: tool modules and server instructions.
To update this page, change the tool schema and the SPEC together, then revise the matching entry here. The sidebar, search index and in-page outline are generated from the heading ids, so keep each tool heading id in the form tool-<name-with-hyphens>.