What is wrong
create-page/update-page (and every other write that goes through wikis/mwnProvider.js's Mwn.init()/new Mwn()) can hang for up to ~255 seconds on a plain network-level failure (timeout, connection reset, DNS blip), with no config surface to shorten it and no way for the MCP caller to distinguish "still working" from "stuck."
Root cause is entirely inside mwn, which this package does not override:
mwn/build/bot.js: Mwn.requestDefaults.timeout = 60000 (60s axios timeout).
mwn/build/bot.js: defaultOptions.maxRetries = 3, defaultOptions.retryPause = 5000.
mwn/build/core.js's Response.prototype.handleRequestFailure: retries any network-level error (no error.response.status, i.e. exactly what a timeout/connection failure looks like) up to maxRetries times, sleeping retryPause between attempts.
Worst case for one network hiccup: (maxRetries + 1) * timeout + maxRetries * retryPause = 4 * 60s + 3 * 5s = 255s (4m15s).
wikis/mwnProvider.js's create() passes only apiUrl, userAgent, and credential fields to Mwn.init(options) — no timeout/maxRetries/retryPause override, and config/loadConfig.js's resolveWiki() doesn't recognize or pass through any request-timing field from config.json either. So there is currently no way to configure this shorter, short of monkeypatching mwn.
Why this matters
runtime/dispatcher.js's runDispatchInner already does the right thing once mwn finally throws — it catches the error and returns a clean, structured MCP error result. The actual problem is that nothing bounds how long mwn is allowed to sit retrying before that happens. In practice, an MCP client (e.g. Claude Desktop/Code) has its own, shorter timeout for a tool call; it gives up and reports "no result received" well before mwn's ~255s retry ladder resolves. The caller then has no idea whether the write eventually succeeded, failed, or is still in flight — and a retry from the caller just stacks another ~255s wait on top if the network issue is still present.
Repro
Reproduced live (2026-08-13) with mediawiki-mcp-server@0.13.0 / mwn@3.0.2, calling getSiteInfo() directly against a black-holed address (http://10.255.255.1, silently dropped, no RST/ICMP):
[0.0s] starting getSiteInfo() against a black-holed address
[W] Retrying in 5 seconds: encountered AxiosError: timeout of 60000ms exceeded (x3, at ~65s intervals)
[255.1s] FAILED as expected: code=ECONNABORTED message=timeout of 60000ms exceeded
Confirmed wikis/mwnProvider.js is unchanged between 0.13.0 and the current latest (0.17.0) — this affects every shipped version.
Suggested fix
Either (or both):
- Expose per-wiki request-timing config. Add optional
timeout/maxRetries/retryPause fields to the wiki config schema (config/loadConfig.js's resolveWiki()), plumbed through to Mwn.init(options) in wikis/mwnProvider.js's create() — the same passthrough pattern already used for e.g. oauth2ClientId.
- Bound the whole tool call independently of mwn's internal accounting. Wrap
tool.handle(args, ctx) in runtime/dispatcher.js's runDispatchInner in an overall timeout (Promise.race against a fixed duration, e.g. 30-45s), returning a clear timeout error to the caller regardless of what mwn is doing in the background. This guarantees a bounded, clear result for any slow upstream, not just this specific retry-ladder cause.
Option 2 is more robust long-term (doesn't depend on tuning mwn's internals correctly), but option 1 is the more direct fix for this specific mechanism and lets an operator dial in values appropriate to their wiki's network conditions.
Local mitigation (for context)
In the interim we're using a NODE_OPTIONS=--import=... preload that shrinks Mwn.requestDefaults.timeout to 25s and self-heals each Mwn instance's maxRetries/retryPause (via wrapping Mwn.prototype.request, gated on the options still being mwn's stock defaults) down to 1/3000, cutting the worst case to ~53s. Happy to share the exact patch if useful, though it's obviously not a substitute for a first-class config option.
Not verified
Whether MediaWiki-side factors (maxlag, session/token refresh) can independently extend this further — the repro above isolates purely the network-level retry path, not the maxlag/assertuserfailed branches in core.js's Response.prototype.process, which use the same retryPause but a separately-bounded retry count.
What is wrong
create-page/update-page(and every other write that goes throughwikis/mwnProvider.js'sMwn.init()/new Mwn()) can hang for up to ~255 seconds on a plain network-level failure (timeout, connection reset, DNS blip), with no config surface to shorten it and no way for the MCP caller to distinguish "still working" from "stuck."Root cause is entirely inside
mwn, which this package does not override:mwn/build/bot.js:Mwn.requestDefaults.timeout = 60000(60s axios timeout).mwn/build/bot.js:defaultOptions.maxRetries = 3,defaultOptions.retryPause = 5000.mwn/build/core.js'sResponse.prototype.handleRequestFailure: retries any network-level error (noerror.response.status, i.e. exactly what a timeout/connection failure looks like) up tomaxRetriestimes, sleepingretryPausebetween attempts.Worst case for one network hiccup:
(maxRetries + 1) * timeout + maxRetries * retryPause=4 * 60s + 3 * 5s= 255s (4m15s).wikis/mwnProvider.js'screate()passes onlyapiUrl,userAgent, and credential fields toMwn.init(options)— notimeout/maxRetries/retryPauseoverride, andconfig/loadConfig.js'sresolveWiki()doesn't recognize or pass through any request-timing field fromconfig.jsoneither. So there is currently no way to configure this shorter, short of monkeypatchingmwn.Why this matters
runtime/dispatcher.js'srunDispatchInneralready does the right thing once mwn finally throws — it catches the error and returns a clean, structured MCP error result. The actual problem is that nothing bounds how long mwn is allowed to sit retrying before that happens. In practice, an MCP client (e.g. Claude Desktop/Code) has its own, shorter timeout for a tool call; it gives up and reports "no result received" well before mwn's ~255s retry ladder resolves. The caller then has no idea whether the write eventually succeeded, failed, or is still in flight — and a retry from the caller just stacks another ~255s wait on top if the network issue is still present.Repro
Reproduced live (2026-08-13) with
mediawiki-mcp-server@0.13.0/mwn@3.0.2, callinggetSiteInfo()directly against a black-holed address (http://10.255.255.1, silently dropped, no RST/ICMP):Confirmed
wikis/mwnProvider.jsis unchanged between0.13.0and the current latest (0.17.0) — this affects every shipped version.Suggested fix
Either (or both):
timeout/maxRetries/retryPausefields to the wiki config schema (config/loadConfig.js'sresolveWiki()), plumbed through toMwn.init(options)inwikis/mwnProvider.js'screate()— the same passthrough pattern already used for e.g.oauth2ClientId.tool.handle(args, ctx)inruntime/dispatcher.js'srunDispatchInnerin an overall timeout (Promise.raceagainst a fixed duration, e.g. 30-45s), returning a clear timeout error to the caller regardless of what mwn is doing in the background. This guarantees a bounded, clear result for any slow upstream, not just this specific retry-ladder cause.Option 2 is more robust long-term (doesn't depend on tuning mwn's internals correctly), but option 1 is the more direct fix for this specific mechanism and lets an operator dial in values appropriate to their wiki's network conditions.
Local mitigation (for context)
In the interim we're using a
NODE_OPTIONS=--import=...preload that shrinksMwn.requestDefaults.timeoutto 25s and self-heals eachMwninstance'smaxRetries/retryPause(via wrappingMwn.prototype.request, gated on the options still being mwn's stock defaults) down to1/3000, cutting the worst case to ~53s. Happy to share the exact patch if useful, though it's obviously not a substitute for a first-class config option.Not verified
Whether MediaWiki-side factors (maxlag, session/token refresh) can independently extend this further — the repro above isolates purely the network-level retry path, not the
maxlag/assertuserfailedbranches incore.js'sResponse.prototype.process, which use the sameretryPausebut a separately-bounded retry count.