Show the setup instructions anyway
How it works
Two separate objects on the platform. A Persona is a saved assistant with its own instructions and model. An Extension is a connection to an MCP server — a small service that advertises tools over a standard protocol. You create both, then switch the extension on in a chat. The work splits cleanly in two:
| Job | Runs where |
|---|---|
| Read the paper, pull out the reference list, find the citing sentences, judge whether each citation matches the source, write the report | The eduGenAI persona — the reasoning stays on the platform |
| Look each reference up in OpenAlex; check title, authors, year, journal, DOI, volume, issue, pages; return the abstract | This MCP server — deterministic, no LLM |
Before you start
- An eduGenAI 2 account — sign in at
edugenai2.npuls.nlwith SRAM / SURFconext. - The whitelist above. Without it the extension cannot be added at all.
- A model that supports tool calling — the GPT models do. The open
willma-*models are the ones most likely to answer from memory and never call the tool.
Self-hosting this app? Every URL on this page is rewritten to the deployment you are reading it from (https://YOUR-DEPLOYMENT-HOST), so you can copy them exactly as they appear.
Step by step
-
Create the persona
Create a new Persona, give it a name, pick a GPT model, and set the conversation style to Precise.
Citation checker (OpenAlex)
Description (optional)
Checks a paper's references against OpenAlex: whether each source exists, whether the printed details match, and whether the citation matches what the source is about.
-
Paste the instructions
Into the persona's Instructions field. This is the whole workflow — what to extract, when to call the tool, and how to report. Paste it verbatim.
You check the reference list of a paper the user uploads. You have one tool, verify_references, which looks references up in OpenAlex. WHEN TO RUN. When the user uploads a document and gives any go-ahead ("check this", "start", "verify the references", or just the file with no other instruction), run the four steps below end to end without asking a clarifying question first. The document in the conversation IS the input; never ask the user to paste the bibliography. Only if no document has been provided at all, ask for one, then run. STEP 1 - EXTRACT (do this yourself, before calling the tool). Read the document. For every entry in the reference list, take: title, every author name in order, whether it ends in "et al.", year, DOI (only if printed), journal or venue, volume, issue, and pages. Also find the sentence in the body where each source is cited, with a sentence of context on either side - keep those in your notes, they are for step 3 and are never sent to the tool. Finally, list every in-text citation that has NO entry in the reference list; these ORPHAN CITATIONS cannot be looked up by any reader. If the paper has no reference list at all, every citation is an orphan: skip step 2 and report them all as missing. STEP 2 - VERIFY. Call verify_references ONCE, passing every reference that has at least a title. Never call it with an empty or placeholder list. For each reference it returns: status (found / fuzzy / not_found / lookup_failed), a badge, a severity from 0 to 100, mismatched_fields and minor_fields, a field_check comparing each printed detail with the real record, the matched work with its abstract, and - for fuzzy matches - a list of candidate works. STEP 3 - JUDGE THE USE. For every reference the tool matched, compare the abstract it returned with the citing sentences you kept in step 1. Decide whether the claim the paper attributes to the source is plausibly supported by it. If the source is clearly about something else, or is used for a narrower or broader claim than it supports, that is a MISQUOTE - raise that reference's severity to at least 80. Judge only from the abstract, and say so when the abstract is too thin to tell. STEP 4 - REPORT. Never show the user the raw JSON; it is a machine interface. Write one Markdown table, one row per reference, sorted by descending severity, with columns: # | Reference (short) | Verdict | What is wrong. Under the table, add a short "Details" section for every row that needs a look, naming the exact difference (printed vs record). If there are orphan citations, add a "Missing from the reference list" section listing them. End with one line: how many references were checked, how many are clean, how many need a look. REPORT ONLY THIS. No APA or formatting critique, no style fixes, no suggested extra literature, no praise, no summary of the paper, no advice - unless the user asks for it in a later message. These ARE citation errors and must be reported: wrong author names, wrong author order, wrong year, journal, DOI or pages, in-text citations that contradict their reference entry, and citations missing from the reference list. Punctuation, capitalisation and italics are style - stay silent on those. NEVER invent a DOI, an author, a year or a verdict the tool did not return. status "lookup_failed" means the reference could not be checked - say exactly that; it is not evidence of fabrication. status "not_found" means OpenAlex has no such work - report it as a probable fabrication, to be confirmed by hand. If the tool call fails or returns nothing, say so in one sentence and stop; do not fall back on your own memory of the literature. -
Add the extension
Go to Extensions → Add extension and fill it in:
Field Value Name Phantocite Description Checks a paper's references against OpenAlex URL of MCP server https://www.phantocite.com/mcpTransport type Streamable HTTP Authentication type No authentication Trust checkbox tick it Before registering it, you can confirm the server answers from any terminal — it should list
verify_references:curl -s -X POST https://www.phantocite.com/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The server is stateless and answers in plain JSON rather than opening a stream, which is what makes it reliable on serverless hosting. If a build of the platform offers SSE as the transport, choose Streamable HTTP anyway.Optional — OpenAlex Premium: for higher OpenAlex rate limits, set the extension's authentication to an API key sent as the header
X-OpenAlex-Key. It is used per request and never stored. Leave it off unless you have a Premium key; the tool works fine without one. -
Test it
Personas and extensions are separate objects, so the extension is switched on per chat: start a chat with the persona, enable Phantocite from the tools button in the composer, attach a paper, and ask:
Check the references in the attached paper.
The persona should extract the references itself, call
verify_referencesonce, and answer with the table. The tool call is shown in the message, so you can confirm it ran.
What the endpoint returns
Example request the agent sends to /api/verify_batch:
{
"references": [
{
"title": "Highly accurate protein structure prediction with AlphaFold",
"authors": ["Smith, J.", "Jones, B."],
"et_al": false,
"year": 2019,
"journal": "Science",
"pages": "100-110"
}
]
}Example response (abbreviated) — note the wrong authors, year, and journal are caught, and the abstract is returned for the misquote step:
{
"count": 1,
"results": [
{
"index": 1,
"status": "found",
"badge": "Verified",
"severity": 85,
"priority": "Review",
"mismatched_fields": ["authors", "year", "journal"],
"minor_fields": [],
"work": {
"title": "Highly accurate protein structure prediction with AlphaFold",
"authors": ["John Jumper", "Richard Evans", "..."],
"year": 2021,
"venue": "Nature",
"doi": "10.1038/s41586-021-03819-2",
"url": "https://doi.org/10.1038/s41586-021-03819-2",
"abstract": "Proteins are essential to life ... (returned for the misquote check)"
},
"field_mismatch_count": 3,
"field_check": [
{ "field": "title", "status": "match" },
{ "field": "authors", "status": "mismatch", "reference_value": "Smith, J., Jones, B.", "openalex_value": "John Jumper, Richard Evans, ...", "detail": "Not on the record: Smith, J., Jones, B." },
{ "field": "year", "status": "mismatch", "reference_value": 2019, "openalex_value": 2021 },
{ "field": "journal", "status": "mismatch", "reference_value": "Science", "openalex_value": "Nature" }
],
"notes": ["Metadata mismatch on: authors, year, journal. The work exists but the citation details differ."]
}
]
}POST /api/verify — same fields, but without the outer references array — if you prefer one call per reference. The batch endpoint is recommended for a whole bibliography (one round trip, kinder to OpenAlex's rate limits).From JSON to a readable table — what you'll see in chat
You never look at that JSON. It is the machine interface between the agent and the endpoint. The instructions you pasted in Step 2 tell the agent to convert it (STEP 4) into a severity-sorted table with flags, scores, and the mismatches spelled out — mirroring how this site presents results. A typical chat answer looks like:
| # | Flag | Reference (as printed) | Status | Metadata issues | Misquote | What the paper is about |
|---|---|---|---|---|---|---|
| 3 | 🔴 | Zorblatt, Q. (2021). Quantum blockchain effects on medieval cheese trading… | 🔴 Potential hallucination | — | — | — |
| 2 | 🔴 | Smith, J. & Jones, B. (2019). Highly accurate protein structure prediction… Science, 100-110. | 🟢 Verified | authors: "Smith, Jones" → "Jumper, Evans…" · year: 2019 → 2021 · journal: Science → Nature | 🔴 Mismatch — cited for labour productivity; paper is protein-structure AI | Deep-learning protein structure prediction |
| 1 | 🟢 | Vaswani, A. et al. (2017). Attention is all you need. NeurIPS. | 🟢 Verified | — | 🟢 Consistent | Attention-only sequence model (Transformer) |
…followed by a Details section for the flagged rows and a one-line summary count. The assistant does this conversion because the Detail description explicitly says the user must never see the raw JSON.
badge, severity, priority, mismatched_fields) precisely so the assistant only has to lay them out, not compute them.Troubleshooting
- The extension will not save, or the domain is refused. The domain has to be whitelisted by Npuls first — see the note at the top. Nothing on this side can work around it.
- The extension saves but no tool appears in the chat. Personas and extensions are separate: enable Phantocite from the tools button in the composer for that conversation. If the list is empty, check the transport is Streamable HTTP and confirm the server answers with the
tools/listcommand in Step 3. - The persona answers about the paper but never calls the tool. Either the model does not support tool calling — switch to a GPT model, not one of the open
willma-*ones — or the instructions were not saved. Naming the tool in the prompt forces the issue: “Use the verify_references tool to check the references in the attached paper.” - You see raw JSON in the chat. The instructions were truncated or not saved with the persona; re-paste Step 2. As a per-chat override, add: “Present the results as a severity-sorted table with the mismatches spelled out; do not show raw JSON.”
- The tool returns
count: 0. Every response carries anapi_version. Ask the persona to show the raw output and read it: if it is missing or old, the extension is pointed at a stale deployment rather than the current one. - A reference comes back
lookup_failed. That is a failed lookup, not a fabrication — usually a reference with no usable title. The instructions already tell the agent to report it that way.
To check the endpoint independently of eduGenAI, run this from any terminal — a healthy deployment answers in a couple of seconds with count: 1 and a Verified result:
curl -s -X POST https://www.phantocite.com/api/verify_batch \
-H "Content-Type: application/json" \
-d '{"references":[{"title":"Attention is all you need","year":2017}]}'If you suspect the platform is not sending the arguments
This was the failure that ended the eduGenAI 1 integration: the assistant composed the call, but the arguments never left the platform. MCP carries real JSON, and the tool accepts a stringified array too, so it should not recur — and if you ever need to prove where the fault lies, the /api/echo endpoint mirrors back exactly what arrives: method, headers, query string and raw body, with no parsing in between. If your text is not in its response, it never reached the server.
curl -s -X POST https://www.phantocite.com/api/echo \
-H "Content-Type: application/json" \
-d '{"message":"PHANTOCITE-TRANSPORT-TEST-42"}'Compare that with what comes back when the agent calls the same endpoint, and the answer is unambiguous either way.
What data passes through your server?
Because the action calls your deployment, it helps to be precise about what actually travels there — and what does not.
| Data | Where it goes |
|---|---|
| The paper's full text, the student's name, and the citing sentences | Stay inside eduGenAI. The agent keeps the citing sentences for its own misquote reasoning; they are never sent to your endpoint. |
| Reference metadata only — title, authors, year, DOI, journal, volume, issue, pages | Sent to your /api/verify_batch endpoint, and (titles/DOIs) on to OpenAlex for the lookup. |
| Any LLM key | Not involved server-side at all — the reasoning runs on eduGenAI's model. |
One caveat about the OpenAlex Premium key: it is used per-request, never stored, and scrubbed from any error message this app returns. But when your endpoint calls OpenAlex, the key travels as a query parameter on the outbound URL — so if you run behind an egress proxy that logs full outbound URLs, it could appear there. If that matters, don't set a Premium key (the tool works fine without one) or use a proxy that redacts query strings.
Notes & limits
- No LLM key is stored or used by the extension; OpenAlex is free and needs no key. The persona's own model runs on eduGenAI's side, under its terms.
- The metadata check compares against OpenAlex's canonical record. Occasionally OpenAlex's year differs from the printed year (e.g. online-first vs issue year) — treat a lone year mismatch as a prompt to double-check, not a verdict.
- The misquote judgement is based on the abstract only, so a claim supported by the full text but not the abstract may read as uncertain. These are leads for a human reviewer.
- Batch requests are capped at 200 references.