Skip to content

3.0

Scholar MCP 3.0 corrects wrong or incomplete answers across its research tools and repairs affected cached rows on upgrade. Semantic Scholar throttling becomes background work, while converted documents arrive in pages that clients can receive. Logging variables, container log format, the Compose port binding and packaged systemd deployments change for operators, and one Python library call path changes; the upgrade steps are described below.

Upgrading

Several areas change against v2.0.0, and synced standards need one maintenance step. Three lines sum up what the upgrade means:

Clients: reconnect to pick up the changed tool surface. Code that read Semantic Scholar 429 errors polls the returned handle instead (see MCP callers).

State: the cache, downloaded PDFs and converted Markdown are kept; one-shot repairs correct affected rows at startup. Synced ISO and IEC standards are corrected by the next sync-standards run (see Synced standards).

Security posture: Compose publishes on loopback, packaged units no longer bind to every interface, and an unexpected tool failure no longer passes the exception text to the model. The dependency lock moves past published advisories, which installations without the lock must match (see Installations without the lock).

Logging variables and log format

FASTMCP_LOG_LEVEL is renamed SCHOLAR_MCP_LOG_LEVEL. The old name still works until the next major release and logs log_level_env_deprecated at startup. FASTMCP_ENABLE_RICH_LOGGING is removed; SCHOLAR_MCP_LOG_FORMAT takes rich or json. Left unset, it renders Rich lines on a terminal and one JSON object per record everywhere else, so container and journald logs change from 2.0's Rich text to JSON with ts, level, logger and event fields. Re-key log queries and alerts, or set SCHOLAR_MCP_LOG_FORMAT=rich to keep readable lines (#513, template upgrade note v9.0). Several Scholar MCP log events also changed form: s2_rate_limited now reports waiting_s= in place of waiting=…s (#510 lists each one). The Claude Desktop bundle and the Claude Code plugin map their log-level setting to the new name without any action.

Over HTTP, SCHOLAR_MCP_SHUTDOWN_GRACE_S (default 3) now gives in-flight requests that many seconds to finish on SIGTERM; 2.0 dropped them at once. The configuration reference lists both logging variables and the shutdown grace setting.

Docker Compose publishes on loopback

compose.yml now publishes the server as 127.0.0.1:8000:8000 instead of 8000:8000, so the quick start is reachable only from the Docker host. A deployment behind a reverse proxy on a shared network is unaffected. If other machines reach the container directly, confirm authentication is configured and publish on every interface from compose.override.yml:

services:
  scholar-mcp:
    ports: !override
      - "8000:8000"

See the Docker deployment guide (#513, template upgrade note v9.3).

HTTP sessions and combined authentication

Over HTTP, an MCP session now expires after 30 idle minutes, where it never expired before. With both bearer and OIDC authentication configured, existing sessions and tasks start new ownership scopes after the upgrade, so let pending tasks finish first. Both changes come with FastMCP 4.1 (FastMCP v4.1.0 release notes, #524).

Packaged systemd deployments

The .deb and .rpm unit no longer supplies SCHOLAR_MCP_HOST=0.0.0.0, and its generated /etc/scholar-mcp/env.example is fully commented. Before or after upgrading, set SCHOLAR_MCP_CACHE_DIR=/var/lib/scholar-mcp in /etc/scholar-mcp/env. If the service must accept off-host connections, also set SCHOLAR_MCP_HOST=0.0.0.0. An installation that relied on the old unit default otherwise binds to 127.0.0.1 after the package restarts it (#423). See the systemd deployment guide for the complete unit and file layout. The journal receives JSON records under the logging change above.

Python library callers

scholar_mcp.server.build_event_store now uses the shared core signature build_event_store(env_prefix, config). Replace calls with no arguments, or with only a URL, by passing "SCHOLAR_MCP" and a ServerConfig (#422).

Installations without the lock

The container image installs from the dependency lock. If you install with pip or resolve dependencies yourself, confirm at least pypdf 6.21.4, authlib 1.9.1 and PyJWT 2.14.0; the package's own version ranges still allow older, affected releases (see Server errors, logs and security).

MCP callers

Semantic Scholar 429 responses no longer return the immediate error shapes from v2.0.0; callers receive a job or native task handle while the lookup waits. Code that interpreted the old error must poll the returned handle instead (#463).

Converted-document defaults are compatible rather than removed. Follow next_offset to collect the document in pages, or pass max_chars=null when a client can receive the complete remaining text (#465).

Synced standards

Run scholar-mcp sync-standards once after upgrading. ISO and IEC records synced by 2.0 keep their shortened titles until the next sync rewrites them; the upgrade makes that run rewrite every ISO, IEC and IEEE record even when upstream has not changed (#498). See the standards guide.

Correct answers, including cached records

The stabilization package set out to make Scholar MCP "answer correctly where 2.0 answered wrongly or not at all," including for rows cached before an upgrade (epic #429). The fixes include a one-shot cache repair system. On startup, each repair removes or corrects only the rows made invalid by its corresponding fix and records that it ran. Operators do not need to clear the cache or discard downloaded PDFs and converted Markdown (#440, #441). Synced ISO and IEC standards are the one exception: they are corrected by the next sync-standards run, described under Upgrading.

Paper and book workflows now return the requested data instead of leaking quirks from their upstream sources. get_author pages the publications of a direct-ID lookup with limit and offset and adds next_offset when more follow. In 2.0 both parameters were ignored, because Semantic Scholar's author endpoint honours neither; every page is now served from one cached record (#367, #431, #490, #504). search_papers, get_citations, get_references and recommend_papers cap limit at each endpoint's documented maximum (100, 1,000, 1,000 and 500) rather than passing a larger value on and returning an opaque upstream_error (#476, #489). When batch_resolve falls back to OpenAlex for a DOI, the paper it returns uses Semantic Scholar field names and honours the requested fields preset instead of carrying the raw OpenAlex work (#478, #502). Citation generation uses Semantic Scholar's conference publication type for BibTeX @inproceedings, CSL-JSON paper-conference, and RIS CONF output (#404, #432). ISBN lookups can fill an empty author list from an already-cached Open Library work record (#403, #449).

fetch_paper_pdf and fetch_and_convert now use the same 30-day paper cache as get_paper. They resolve identifier aliases before reading the cache, write a fresh record and alias on a miss, and make no Semantic Scholar request when the metadata and converted files are already present (#373, #435, #467). The PDF download tools also check that what they downloaded is a PDF. A response whose body does not begin with %PDF- returns {"error": "not_pdf"} before it is cached or converted, where 2.0 stored an HTML page as a .pdf and reported only that conversion produced no Markdown. A cached file without the header is downloaded again (#484, #492, contributed by @mikemikimike).

Patent records now include the abstract and the country associated with each EPO legal event. Patent numbers also normalize spacing, punctuation, and letter case before cache lookup, so equivalent spellings reuse one metadata row and one PDF (#399, #405, #402, #444). Non-patent literature citations resolve when the DOI is written as a doi.org link or as DOI 10.… without a colon, not only after doi:; on the patent in the report, none of 22 citations resolved before (#482, #503).

Standards lookups match NIST identifiers exactly rather than by substring. ETSI failures are no longer reported as missing standards: direct lookup returns a rate-limit or upstream-error payload, identifier resolution preserves the canonical value with a warning, and multi-body search marks partial results without caching them (#400, #401, #452, #455). The warning names each source that gave no usable answer, with its HTTP status and the reason, for example ETSI (HTTP 200: answered with a non-JSON body, content-type: text/html) (#477, #495).

Standards records themselves are corrected in three ways:

  • ISO and IEC records carry the full composed title. In 2.0 they carried only its first part, so ISO/IEC 27001:2022 and 27002:2022 shared one title (#480, #498).
  • get_standard returns full_text only when called with fetch_full_text=true. In 2.0, once any caller had fetched a standard's text, every later lookup returned the whole text as well; converted text is now stored apart from the record and still not converted twice (#479, #497).
  • A lookup through get_standard or resolve_standard_identifier never replaces a synced record. In 2.0 it could, which dropped the standard from search_standards and put it under the 90-day cache expiry; Common Criteria records were affected on every resolution (#496, #501).

The cache repairs move previously stored text out of standards records and restore Common Criteria records to the synced set. The tool reference documents the final response shapes and identifier rules, and the standards guide describes sync behaviour.

Semantic Scholar throttling becomes a job

All Semantic Scholar traffic from one server process now passes through one gate with at least 1.1 seconds between requests. A 429 extends a shared cooldown, so a refusal slows concurrent Graph and Recommendations calls instead of starting an independent retry ladder in each call (#408, #462). Separate server processes are not coordinated.

For MCP callers, throttled work continues through the existing jobs system. A plain call promptly returns a handle with the reason Semantic Scholar is throttling requests; work continues. Poll get_job_result; the running body resumes from where it paused rather than restarting. With the default one-hour result TTL, retries may continue for 50 minutes before the job settles as {"error":"rate_limited","retryable":true} (#409, #463). Native MCP task clients keep their native task handle.

No new setting is required. The existing defaults remain 25 seconds for SCHOLAR_MCP_JOBS_SOFT_DEADLINE_S, 3,600 seconds for SCHOLAR_MCP_JOBS_RESULT_TTL_S, and 256 retained jobs per subject. See rate limiting and background jobs for the operator contract.

The server still depends on the live Semantic Scholar service. Research found that papers plus abstracts alone require about 82 GB of compressed source data, before authors, so the project chose shared pacing and deferred jobs rather than an offline store (#406, #466).

Converted documents arrive in pages

Five document tools used to return the entire conversion in one MCP response. The reported examples reached 242,042 characters and exceeded the caller's response limit, so the model could not receive the result (#372).

convert_pdf_to_markdown, fetch_and_convert, fetch_pdf_by_url, fetch_patent_pdf, and get_standard now return at most 20,000 Markdown or full-text characters by default. Responses include character counts and next_offset when another page remains. Call the same tool with text_offset=next_offset; the complete conversion stays cached and is not run again. Clients that can accept the remaining text in one response can set max_chars=null for the previous behavior (#465). The PDF conversion guide has the paging recipe.

Server errors, logs and security

This release moves to fastmcp-server-template v11.0.2 and fastmcp-pvl-core 10.2, from template v8.1.0 and pvl-core 7.1 in 2.0 (#513, #524). The effects that reach users of this server follow; the logging and session changes are under Upgrading.

When a tool fails with an unexpected exception, the model receives a fixed message, "The call failed because of a server-side error; the request itself was fine. Retry later, and tell the user if it keeps failing." In 2.0 it received FastMCP's Error calling tool text with the exception's own message. The server logs the failure once as tool_failed at ERROR with its traceback. Results the tools return on purpose, such as {"error": "not_found"}, are unchanged (template upgrade note v10.0).

The project now publishes a SECURITY.md policy and accepts private vulnerability reports through GitHub. The new security model page lists the upstream services each tool family calls and the credentials the server holds for them, and names the cache directory as the only place tools write. It also states that fetch_pdf_by_url, hidden in the default read-only mode, downloads any URL a caller passes, including addresses on the server's own network (#514 tracks this).

The dependency lock pins PyJWT 2.15.1. v2.0.0 locked PyJWT 2.13.0, which ten advisories published on 2026-09-29 affect (one critical, five high, four medium; all fixed in 2.14.0) (#516, #517). PyJWT reaches Scholar MCP only through client code in the MCP SDK; neither this server nor FastMCP's server-side authentication imports it. The container image installs from the lock.

The lock also moves past the other advisories published against the release candidate's dependencies: 38 in 8 runtime packages, among them pypdf, authlib, urllib3, fastmcp and joserfc (#523, #524). The pypdf advisories almost all concern slow or memory-hungry parsing of malformed PDFs, and Scholar MCP parses the PDF pages EPO returns with pypdf. The authlib advisories include a critical one, empty JWS signatures accepted (GHSA-6v38-4h7w-rj9h), and authlib reaches the server through FastMCP's authentication. Whether calls from Scholar MCP reach the affected functions has not been assessed. The lock pins pypdf 6.21.4 and authlib 1.9.1; v2.0.0 locked 6.18.0 and 1.7.2. Installations without the lock need the upgrade step under Upgrading.

get_server_info reports the negotiated protocol version and the client's name and version, and each request's log line ends with the same fields when they are known (fastmcp-pvl-core v10.2.0, #524).