Skip to main content
Glama
ElliotPadfield

Unpaywall MCP Server

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
NameRequiredDescriptionDefault
doiYesDOI string or DOI URL, e.g. 10.1038/nphys1170 or https://doi.org/10.1038/nphys1170
emailNoEmail to identify your requests to Unpaywall (optional override)

Implementation Reference

  • 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,
      },
    },
  • 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,
    },
  • 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);
      }
    }
  • 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();
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ElliotPadfield/unpaywall-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server