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_standardreturnsfull_textonly when called withfetch_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_standardorresolve_standard_identifiernever replaces a synced record. In 2.0 it could, which dropped the standard fromsearch_standardsand 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).