unpaywall_get_by_doi
Fetch Unpaywall metadata for academic papers using a DOI to retrieve open access information and PDF links for research purposes.
Instructions
Fetch Unpaywall metadata for a DOI (accepts DOI, DOI URL, or 'doi:' prefix). Requires an email address via env UNPAYWALL_EMAIL or the optional 'email' argument.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| doi | Yes | DOI string or DOI URL, e.g. 10.1038/nphys1170 or https://doi.org/10.1038/nphys1170 | |
| No | Email to identify your requests to Unpaywall (optional override) |
Implementation Reference
- src/index.ts:200-230 (handler)Executes the 'unpaywall_get_by_doi' tool: validates DOI and email arguments, normalizes the DOI, fetches metadata from Unpaywall API, and returns the JSON response.if (tool === TOOL_GET_BY_DOI) { const args = (req.params.arguments ?? {}) as Partial<GetByDoiArgs>; const rawDoi = (args.doi ?? "").toString().trim(); if (!rawDoi) { return { content: [ { type: "text", text: "Missing required argument: 'doi'" }, ], isError: true, }; } const email = (args.email || process.env.UNPAYWALL_EMAIL || "").toString().trim(); if (!email) { return { content: [ { type: "text", text: "Unpaywall requires an email. Set UNPAYWALL_EMAIL env var for the server or pass 'email' in the tool arguments.", }, ], isError: true, }; } const doi = normalizeDoi(rawDoi); const data = await fetchUnpaywallByDoi(doi, email); return { content: [{ type: "json", json: data }], }; }
- src/index.ts:136-149 (registration)Registers the 'unpaywall_get_by_doi' tool in the listTools response, providing name, description, and input schema.{ name: TOOL_GET_BY_DOI, description: "Fetch Unpaywall metadata for a DOI (accepts DOI, DOI URL, or 'doi:' prefix). Requires an email address via env UNPAYWALL_EMAIL or the optional 'email' argument.", inputSchema: { type: "object", properties: { doi: { type: "string", description: "DOI string or DOI URL, e.g. 10.1038/nphys1170 or https://doi.org/10.1038/nphys1170" }, email: { type: "string", description: "Email to identify your requests to Unpaywall (optional override)" }, }, required: ["doi"], additionalProperties: false, }, },
- src/index.ts:140-148 (schema)Input schema (JSON Schema) defining the parameters for the 'unpaywall_get_by_doi' tool: required 'doi' string and optional 'email'.inputSchema: { type: "object", properties: { doi: { type: "string", description: "DOI string or DOI URL, e.g. 10.1038/nphys1170 or https://doi.org/10.1038/nphys1170" }, email: { type: "string", description: "Email to identify your requests to Unpaywall (optional override)" }, }, required: ["doi"], additionalProperties: false, },
- src/index.ts:47-61 (helper)Helper function that performs the actual API fetch to Unpaywall for a given DOI and email, with timeout and error handling.async function fetchUnpaywallByDoi(doi: string, email: string) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 20_000); try { const url = `https://api.unpaywall.org/v2/${encodeURIComponent(doi)}?email=${encodeURIComponent(email)}`; const resp = await fetch(url, { signal: controller.signal, headers: { "Accept": "application/json" } }); if (!resp.ok) { const text = await resp.text().catch(() => ""); throw new Error(`Unpaywall HTTP ${resp.status}: ${text.slice(0, 400)}`); } return await resp.json(); } finally { clearTimeout(timeout); } }
- src/index.ts:38-45 (helper)Utility function to normalize DOI input by removing common URL prefixes and 'doi:' prefix.function normalizeDoi(input: string): string { let doi = input.trim(); // Strip common DOI URL prefixes doi = doi.replace(/^https?:\/\/(dx\.)?doi\.org\//i, ""); // Strip leading 'doi:' prefix doi = doi.replace(/^doi:/i, ""); return doi.trim(); }