A reading list of twenty sources through a citation endpoint. Ten came back as complete records with RIS and BibTeX, in eight seconds. The interesting half is the other ten — because only one of them was stopped by a bot defence. Five answered every request in full and simply had no citation data to declare.
A bibliography is the part of a piece of work where a machine looks most useful and is hardest to check. Hand an assistant twenty addresses, ask for a reference list, and something plausible comes back for all twenty. The question worth measuring is not how many entries appear. It is how many are records — read from what the page declares about itself — and whether the rest are named as gaps or quietly filled in.
Each source was sent once to extract_citation on this site's
MCP endpoint, which reads the
citation metadata a page publishes about itself and returns a structured
record. Nothing was retried, nothing was chosen for whether it works. Every
address was checked in a browser before the run, so that a typo of ours could
not be counted as a failure of theirs.
Not between disciplines, and not between paid and free. It runs between pages built to be cited and pages built to be read.
| Kind of source | Complete records |
|---|---|
| reference | 2 of 2 |
| bare doi | 1 of 1 |
| publisher | 4 of 5 |
| open access | 2 of 3 |
| repository | 1 of 3 |
| preprint | 0 of 1 |
| official | 0 of 3 |
| grey lit | 0 of 1 |
| news | 0 of 1 |
Journal publishers are the easiest case, whether the article is paywalled or
open: 4/5 and 2/3. A journal page
carries citation_author, citation_title and a DOI in
its head, because it wants to be indexed. An encyclopaedia entry and a bare
DOI resolve just as cleanly.
Official statistics, chambers of commerce and newspapers are the hard case: none of the four produced a record. Not because they defend themselves — they answered every request in full — but because a statistics portal page is a topic overview, not a work, and declares no author, no date and no title of the kind a reference list needs.
The distinction matters because each cause needs a different response from whoever is writing. Lumping them together as “blocked” is what makes a citation tool feel unreliable when it is being accurate.
| Host | Kind | What happened |
|---|---|---|
www.mdpi.com | open access | answers a browser, refuses the reader |
This is the only case in twenty where a browser sees something a server-side reader is not allowed to see. It is also the only case where opening the page yourself changes the outcome — see what to do with the ten.
| Host | Kind | What happened |
|---|---|---|
www.sciencedirect.com | publisher | refuses both — HTTP 403 from a data centre address |
papers.ssrn.com | preprint | refuses both — HTTP 403 from a data centre address |
eur-lex.europa.eu | official | refuses both — HTTP 202 from a data centre address |
www.oecd.org | official | refuses both — HTTP 403 from a data centre address |
These answered 403 to a browser user agent as readily as to a reader. The common factor is not the client but the network: requests from a data centre are refused whatever they claim to be. From a home connection the same pages open normally. That is worth stating plainly, because it is the one result here that would look different measured from a different place.
| Host | Kind | What happened |
|---|---|---|
www.ssoar.info | repository | answers in full, declares no citation data |
zenodo.org | repository | answers in full, declares no citation data |
www.statistik.at | official | answers in full, declares no citation data |
www.wko.at | grey lit | answers in full, declares no citation data |
www.derstandard.at | news | answers in full, declares no citation data |
Fifty to ninety kilobytes of perfectly readable HTML, no defence of any kind,
and no citation_* metadata, no author, no publication date. A
reference for these has to be written by a person who decides what the work
is — a page of a statistics portal, an article in a newspaper, a
software release on a repository. No amount of retrying changes that, and any
tool that returns a tidy entry here has invented the missing half.
Two of the five silent cases are the trap this measurement was worth doing
for. The Zenodo record returns
"kjswedberg/kjswedberg.github.io: First Release" with an author
attached; the statistics portal returns
"Forschung, Innovation, Digitalisierung" with
STATISTIK AUSTRIA as author. Both look like results. Both come
back with complete: false.
Anything reading the title field and skipping the flag will file both as sources. The lesson is not about this endpoint — it applies to every citation service: read the completeness flag, not the title. On this endpoint that check is one field:
if not record["complete"]:
hand_back(url, record.get("warning") or "no citation data on the page")
A gap we should close on our side: in these five cases the
warning field is empty. complete: false is correct
and sufficient to act on, but a reason would be more useful than a silence,
and it is noted
as such.
One URL per line in, one importable .ris out, with the refusals
named on stderr instead of half-imported. The
recipes page has the same thing for Claude Code,
Claude Desktop, Python and the browser.
while read -r u; do
curl -sX POST https://provinglab.dev/mcp \
-H 'content-type: application/json' \
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",
\"params\":{\"name\":\"extract_citation\",\"arguments\":{\"url\":\"$u\"}}}" \
| python3 -c 'import json,sys
d = json.loads(json.load(sys.stdin)["result"]["content"][0]["text"])
sys.stdout.write(d["ris"]) if d.get("complete") else \
sys.stderr.write("hand back: " + d["url"] + "\n")'
done < reading-list.txt > literature.ris
Then Zotero → File → Import, or Citavi → Import → RIS. No
key, no account. One caveat worth knowing: this site sits behind a filter that
refuses the user agent Python's urllib sends by default. Set any
user agent of your own and it answers normally.