@xiedada/nodemw-mcp-server 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -3
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
27
27
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
28
28
|
*/
|
|
29
|
-
import{StdioServerTransport as
|
|
29
|
+
import{StdioServerTransport as Ke}from"@modelcontextprotocol/sdk/server/stdio.js";import{parseArgs as Ze}from"util";import{McpServer as _t}from"@modelcontextprotocol/sdk/server/mcp.js";var F="nodemw-mcp-server/1.0";function O(t,e=!1){let o,r=e?" Write operations are available.":" Running in guest mode \u2014 only read operations are available.";return t?o=`Connected to ${t.sitename} (${t.base}). Running ${t.generator}.${r} When connecting for the first time, call the get-site-info tool for full site details.`:o=`When connecting to this server for the first time, call the get-site-info tool to understand the target MediaWiki site (version, namespaces, extensions, etc.) before using other tools.${r}`,new _t({name:"nodemw-mcp-server",version:"1.0.0",description:o},{capabilities:{tools:{}}})}import{z as v}from"zod";import Qt from"nodemw";var T=null,Vt=null,U=!1;function z(t){Vt=t}function W(t){let{server:e,path:o,protocol:r,port:a,proxy:c,userAgent:m,concurrency:p,debug:u,username:g,password:y,domain:R,dryRun:x}=t;return new Qt({server:e,protocol:r||"https",port:a,path:o,proxy:c,userAgent:m||F,concurrency:p,debug:u,username:g||void 0,password:y||void 0,domain:R,dryRun:x})}async function Yt(t){try{return await i(t,"getSiteInfo",["general"]),!0}catch{return!1}}async function $(t){let e=["/w",""];for(let o of e){let r={...t,path:o},a=W(r);if(await Yt(a))return o}throw new Error('Could not auto-detect MediaWiki API path. Tried /w/api.php and /api.php. Please specify --path explicitly (e.g., --path /w or --path "" for root).')}async function N(t){T=W(t);let{username:e,password:o}=t;return e&&o&&await new Promise((r,a)=>{T.logIn(c=>{c?a(new Error(`Login failed for user '${e}': ${c.message}`)):(U=!0,r())})}),T}function n(){if(!T)throw new Error("Bot not initialized. Server must be started first.");return T}function L(){return U}function i(t,e,...o){return new Promise((r,a)=>{let c=(m,p)=>{m?a(m):r(p)};t[e](...o,c)})}function D(t){return t.tool("get-article","Retrieve the content of a wiki article",{title:v.string().describe("Article title"),followRedirect:v.boolean().optional().default(!0).describe("Follow redirects"),redirectInfo:v.boolean().optional().default(!1).describe("Include information about redirects")},{title:"Get article",readOnlyHint:!0,destructiveHint:!1},async({title:e,followRedirect:o,redirectInfo:r})=>Jt(e,o,r))}async function Jt(t,e,o){try{let r=await n();if(o){let a=await new Promise((u,g)=>{let y=(R,x,qt)=>{R?g(R):u([x,qt])};r.getArticle(t,e,y)}),[c,m]=a;return c==null?{content:[{type:"text",text:`Page "${t}" not found or has no content.`}],isError:!0}:{content:[{type:"text",text:m?`Content:
|
|
30
30
|
|
|
31
31
|
${c}
|
|
32
32
|
|
|
33
33
|
Redirect Information:
|
|
34
34
|
|
|
35
|
-
${JSON.stringify(m,null,2)}`:c}]}}else return{content:[{type:"text",text:await n(s,"getArticle",t,e)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s.message}`}],isError:!0}}}import{z as $}from"zod";function l(t){return{content:[{type:"text",text:JSON.stringify(t,null,2)}]}}function i(t,e){return{content:[{type:"text",text:JSON.stringify({error:t,details:e?.message},null,2)}],isError:!0}}function D(t){return t.tool("search","Search for wiki pages by keyword",{keyword:$.string().describe("Search keyword"),limit:$.number().optional().default(10).describe("Maximum number of results")},{title:"Search",readOnlyHint:!0,destructiveHint:!1},async({keyword:e,limit:o})=>Vt(e,o))}async function Vt(t,e){try{let o=await r(),s=await n(o,"search",t),a=s.slice(0,e);return l({total:s.length,limit:e,keyword:t,results:a})}catch(o){return i("Failed to search",o)}}import{z as Yt}from"zod";function q(t){return t.tool("get-pages-in-category","Get all pages in a category",{category:Yt.string().describe("Category name (with or without Category: prefix)")},{title:"Get pages in category",readOnlyHint:!0,destructiveHint:!1},async({category:e})=>Jt(e))}async function Jt(t){try{let e=await r(),o=t.replace(/^Category:/i,""),s=await n(e,"getPagesInCategory",o);return l({category:o,pages:s,count:s.length})}catch(e){return i("Failed to get pages in category",e)}}import{z as Xt}from"zod";function _(t){return t.tool("get-categories","Get all categories matching a prefix",{prefix:Xt.string().optional().default("").describe("Prefix to filter categories")},{title:"Get categories",readOnlyHint:!0,destructiveHint:!1},async({prefix:e})=>Kt(e))}async function Kt(t){try{let e=await r(),o=await n(e,"getCategories",t);return l({prefix:t,categories:o,count:o.length})}catch(e){return i("Failed to get categories",e)}}import{z as Q}from"zod";function V(t){return t.tool("get-users","Get all users matching a prefix",{prefix:Q.string().optional().default("").describe("Prefix to filter usernames"),onlyWithEdits:Q.boolean().optional().default(!1).describe("Only include users with at least one edit")},{title:"Get users",readOnlyHint:!0,destructiveHint:!1},async({prefix:e,onlyWithEdits:o})=>Zt(e,o))}async function Zt(t,e){try{let o=await r(),s=await n(o,"getUsers",{prefix:t,witheditsonly:e});return l({prefix:t,onlyWithEdits:e,users:s,count:s.length})}catch(o){return i("Failed to get users",o)}}import{z as te}from"zod";function Y(t){return t.tool("get-all-pages","Get all non-redirect pages from the wiki",{limit:te.number().optional().default(500).describe("Maximum number of pages to return")},{title:"Get all pages",readOnlyHint:!0,destructiveHint:!1},async({limit:e})=>ee(e))}async function ee(t){try{let e=await r(),o=await n(e,"getAllPages"),s=o.slice(0,t);return l({total:o.length,displayed:s.length,pages:s,limit:t})}catch(e){return i("Failed to get all pages",e)}}import{z as oe}from"zod";function J(t){return t.tool("get-pages-in-namespace","Get all non-redirect pages in a specific namespace",{namespace:oe.number().describe("Namespace number to filter pages")},{title:"Get pages in namespace",readOnlyHint:!0,destructiveHint:!1},async({namespace:e})=>re(e))}async function re(t){try{let e=await r(),o=await n(e,"getPagesInNamespace",t);return l({namespace:t,pages:o,count:o.length})}catch(e){return i("Failed to get pages in namespace",e)}}import{z as ne}from"zod";function X(t){return t.tool("get-pages-by-prefix","Get pages starting with a specific prefix",{prefix:ne.string().describe("Prefix to match page titles")},{title:"Get pages by prefix",readOnlyHint:!0,destructiveHint:!1},async({prefix:e})=>se(e))}async function se(t){try{let e=await r(),o=await n(e,"getPagesByPrefix",t);return l({prefix:t,pages:o,count:o.length})}catch(e){return i("Failed to get pages by prefix",e)}}import{z as ie}from"zod";function K(t){return t.tool("get-pages-transcluding","Get all pages that transclude (include) a specific template",{template:ie.string().describe("Template title to find transclusions")},{title:"Get pages transcluding template",readOnlyHint:!0,destructiveHint:!1},async({template:e})=>le(e))}async function le(t){try{let e=await r(),s=(await n(e,"getPagesTranscluding",t))[1],a=Array.isArray(s)?s.filter(c=>c!=null&&typeof c=="object"&&"title"in c):[];return l({template:t,pages:a,count:a.length})}catch(e){return i("Failed to get pages transcluding template",e)}}import{z as w}from"zod";function Z(t){return t.tool("get-article-revisions","Get all revisions of a wiki article",{title:w.union([w.string(),w.number()]).describe("Article title or page ID")},{title:"Get article revisions",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>ae(e))}async function ae(t){try{let e=await r(),s=(await n(e,"getArticleRevisions",t)).flat();return l({title:t,revisions:s,count:s.length})}catch(e){return i("Failed to get article revisions",e)}}import{z as k}from"zod";function tt(t){return t.tool("get-article-categories","Get all categories that an article belongs to",{title:k.union([k.string(),k.number()]).describe("Article title or page ID")},{title:"Get article categories",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>ce(e))}async function ce(t){try{let e=await r(),o=await n(e,"getArticleCategories",t);return l({title:t,categories:o,count:o.length})}catch(e){return i("Failed to get article categories",e)}}import{z as me}from"zod";function et(t){return t.tool("get-article-properties","Get page properties for a wiki article",{title:me.string().describe("Article title")},{title:"Get article properties",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>pe(e))}async function pe(t){try{let e=await r(),o=await n(e,"getArticleProperties",t);return l({title:t,properties:o})}catch(e){return i("Failed to get article properties",e)}}import{z as d}from"zod";function ot(t){return t.tool("get-article-info","Get detailed information about one or more articles",{title:d.union([d.string(),d.number(),d.array(d.union([d.string(),d.number()]))]).describe("Article title, page ID, or array of titles/IDs"),properties:d.array(d.string()).optional().describe("Specific properties to retrieve")},{title:"Get article info",readOnlyHint:!0,destructiveHint:!1},async({title:e,properties:o})=>ue(e,o))}async function ue(t,e){try{let o=await r(),a=await n(o,"getArticleInfo",t,e?{inprop:e}:{}),c=Array.isArray(a)?a:[a];return l({title:t,results:c,count:c.length})}catch(o){return i("Failed to get article info",o)}}import{z as M}from"zod";function rt(t){return t.tool("get-user-contribs","Get contributions made by a specific user",{username:M.string().describe("Username to get contributions for"),namespace:M.number().optional().describe("Filter contributions by namespace"),limit:M.number().optional().default(50).describe("Maximum number of contributions to return")},{title:"Get user contributions",readOnlyHint:!0,destructiveHint:!1},async({username:e,namespace:o,limit:s})=>ge(e,o,s))}async function ge(t,e,o=50){try{let s=await r(),a={user:t,...e!==void 0&&{namespace:e}},c=await n(s,"getUserContribs",a),m=Array.isArray(c[1])?c[1]:[],p=m.slice(0,o);return l({username:t,namespace:e,limit:o,total:m.length,displayed:p.length,contributions:p})}catch(s){return i("Failed to get user contributions",s)}}function nt(t){return t.tool("whoami","Get information about the currently logged in user",{},{title:"Who am I",readOnlyHint:!0,destructiveHint:!1},async()=>de())}async function de(){try{let t=await r(),e=await n(t,"whoami");return l(e)}catch(t){return i("Failed to get current user info",t)}}import{z as fe}from"zod";function st(t){return t.tool("whois","Get information about a specific user",{username:fe.string().describe("Username to look up")},{title:"Whois",readOnlyHint:!0,destructiveHint:!1},async({username:e})=>ye(e))}async function ye(t){try{let e=await r(),o=await n(e,"whois",t);return o.missing?i(`User "${t}" not found.`):l(o)}catch(e){return i("Failed to get user info",e)}}import{z as it}from"zod";function lt(t){return t.tool("whoare","Get information about multiple wiki users",{usernames:it.array(it.string()).describe("Array of usernames to query")},{title:"Who are",readOnlyHint:!0,destructiveHint:!1},async e=>Te(e))}async function Te(t){try{let e=await r(),o=await n(e,"whoare",t.usernames);return l(o)}catch(e){return i("Failed to get user information",e)}}import{z as at}from"zod";function ct(t){return t.tool("get-images","Get list of images starting from a specific name",{startFrom:at.string().optional().default("").describe("Start from this image name"),limit:at.number().optional().default(50).describe("Maximum number of images to return")},{title:"Get images",readOnlyHint:!0,destructiveHint:!1},async({startFrom:e,limit:o})=>Re(e,o))}async function Re(t,e){try{let o=await r(),s=await new Promise((c,m)=>{o.getImages(t,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=s.slice(0,e);return l({total:s.length,limit:e,startFrom:t,images:a})}catch(o){return i("Failed to get images",o)}}import{z as A}from"zod";function mt(t){return t.tool("get-images-from-article","Get all images embedded in a specific article",{title:A.union([A.string(),A.number()]).describe("Article title or page ID")},{title:"Get images from article",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>he(e))}async function he(t){try{let e=await r(),o=await n(e,"getImagesFromArticle",t);return l({title:t,images:o,count:o.length})}catch(e){return i("Failed to get images from article",e)}}import{z as be}from"zod";function pt(t){return t.tool("get-image-usage","Get all pages that use a specific image",{filename:be.string().describe("Image filename with File: prefix")},{title:"Get image usage",readOnlyHint:!0,destructiveHint:!1},async({filename:e})=>xe(e))}async function xe(t){try{let e=await r(),o=await n(e,"getImageUsage",t);return l({filename:t,pages:o,count:o.length})}catch(e){return i("Failed to get image usage",e)}}import{z as ve}from"zod";function ut(t){return t.tool("get-image-info","Get detailed information about an image file",{filename:ve.string().describe("Image filename with File: prefix")},{title:"Get image info",readOnlyHint:!0,destructiveHint:!1},async({filename:e})=>we(e))}async function we(t){try{let e=await r(),o=await n(e,"getImageInfo",t);return o?l({filename:t,info:o}):i(`Image "${t}" not found.`)}catch(e){return i("Failed to get image info",e)}}import{z as S}from"zod";function gt(t){return t.tool("get-log","Get log entries of a specific type",{type:S.string().describe("Log type (e.g. delete, block, move)"),start:S.string().optional().default("").describe("Start timestamp (YYYYMMDDHHMMSS format)"),limit:S.number().optional().default(50).describe("Maximum number of entries to return")},{title:"Get log entries",readOnlyHint:!0,destructiveHint:!1},async({type:e,start:o,limit:s})=>ke(e,o,s))}async function ke(t,e,o){try{let s=await r(),a=await new Promise((m,p)=>{s.getLog(t,e,(u,...g)=>{if(u)p(u);else{let y=g[0];m(Array.isArray(y)?y:[])}})}),c=a.slice(0,o);return l({type:t,start:e,limit:o,total:a.length,displayed:c.length,entries:c})}catch(s){return i("Failed to get log entries",s)}}import{z as dt}from"zod";function ft(t){return t.tool("expand-templates","Expand templates in wikitext",{text:dt.string().describe("Wikitext with templates to expand"),title:dt.string().optional().describe("Context page title")},{title:"Expand templates",readOnlyHint:!0,destructiveHint:!1},async({text:e,title:o})=>Me(e,o))}async function Me(t,e){try{let o=await r();return{content:[{type:"text",text:await n(o,"expandTemplates",t,e||"")}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as yt}from"zod";function Tt(t){return t.tool("parse","Parse wikitext to HTML",{text:yt.string().describe("Wikitext to parse"),title:yt.string().optional().describe("Context page title")},{title:"Parse wikitext",readOnlyHint:!0,destructiveHint:!1},async({text:e,title:o})=>Ae(e,o))}async function Ae(t,e){try{let o=await r(),s=await n(o,"parse",t,e||""),a=s[1]||"",c=Array.isArray(s[2])?s[2]:[];return{content:[{type:"text",text:["Parsed XML structure:","",a,"",`Images found: ${c.length>0?c.join(", "):"none"}`].join(`
|
|
36
|
-
`)}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as Rt}from"zod";function ht(t){return t.tool("get-recent-changes","Get recent changes on the wiki",{start:Rt.string().optional().describe("Start timestamp"),limit:Rt.number().optional().default(50).describe("Maximum number of changes to return")},{title:"Get recent changes",readOnlyHint:!0,destructiveHint:!1},async({start:e,limit:o})=>Se(e,o))}async function Se(t,e=50){try{let o=await r(),s=await new Promise((c,m)=>{o.getRecentChanges(t,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=s.slice(0,e);return l({total:s.length,limit:e,start:t,changes:a})}catch(o){return i("Failed to get recent changes",o)}}import{z as bt}from"zod";function xt(t){return t.tool("get-site-info","Get site information from MediaWiki",{properties:bt.array(bt.string()).describe("List of site information properties to retrieve")},{title:"Get site info",readOnlyHint:!0,destructiveHint:!1},async({properties:e})=>Ce(e))}async function Ce(t){try{let e=await r(),o=await n(e,"getSiteInfo",t);return l(o||{})}catch(e){return i("Failed to get site info",e)}}function vt(t){return t.tool("get-site-stats","Get site statistics",{},{title:"Get site stats",readOnlyHint:!0,destructiveHint:!1},async()=>Pe())}async function Pe(){try{let t=await r(),e=await n(t,"getSiteStats");return l(e)}catch(t){return i("Failed to get site stats",t)}}function wt(t){return t.tool("get-mediawiki-version","Get MediaWiki version running on the server",{},{title:"Get MediaWiki version",readOnlyHint:!0,destructiveHint:!1},async()=>je())}async function je(){try{let t=await r(),e=await n(t,"getMediaWikiVersion");return l({version:e})}catch(t){return i("Failed to get MediaWiki version",t)}}import{z as Be}from"zod";function kt(t){return t.tool("get-query-page","Get results from a query page (special page)",{name:Be.string().describe("Name of the query page")},{title:"Get query page results",readOnlyHint:!0,destructiveHint:!1},async({name:e})=>Ee(e))}async function Ee(t){try{let e=await r(),o=await n(e,"getQueryPage",t);return l({name:t,results:o,count:o.length})}catch(e){return i("Failed to get query page results",e)}}import{z as C}from"zod";function Mt(t){return t.tool("get-external-links","Get all external links from an article",{title:C.union([C.string(),C.number()]).describe("Article title or page ID")},{title:"Get external links",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>He(e))}async function He(t){try{let e=await r(),o=await n(e,"getExternalLinks",t);return l({title:t,links:o.map(s=>s["*"]),count:o.length})}catch(e){return i("Failed to get external links",e)}}import{z as Ie}from"zod";function At(t){return t.tool("get-backlinks","Get all backlinks to a specific page",{title:Ie.string().describe("Target page title to find backlinks for")},{title:"Get backlinks",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>Ge(e))}async function Ge(t){try{let e=await r(),o=await n(e,"getBacklinks",t);return l({target:t,backlinks:o,count:o.length})}catch(e){return i("Failed to get backlinks",e)}}import{z as h}from"zod";function St(t){return t.tool("edit","Edit a wiki page (requires authentication)",{title:h.string().describe("Page title to edit"),content:h.string().describe("New content for the page"),summary:h.string().describe("Edit summary"),minor:h.boolean().optional().default(!1).describe("Mark as minor edit")},{title:"Edit page",readOnlyHint:!1,destructiveHint:!0},async e=>Fe(e))}async function Fe(t){try{let e=await r(),o=`[nodemw-mcp] ${t.summary}`,s=await n(e,"edit",t.title,t.content,o,t.minor||!1);return l(s)}catch(e){return i("Failed to edit page",e)}}import{z as P}from"zod";function Ct(t){return t.tool("append","Append content to a wiki page (requires authentication)",{title:P.string().describe("Page title"),content:P.string().describe("Content to append"),summary:P.string().describe("Edit summary")},{title:"Append to page",readOnlyHint:!1,destructiveHint:!0},async e=>Oe(e))}async function Oe(t){try{let e=await r(),o=`[nodemw-mcp] ${t.summary}`;return await n(e,"append",t.title,t.content,o),l({success:!0,title:t.title})}catch(e){return i("Failed to append to page",e)}}import{z as j}from"zod";function Pt(t){return t.tool("prepend","Prepend content to a wiki page (requires authentication)",{title:j.string().describe("Page title to prepend to"),content:j.string().describe("Content to prepend"),summary:j.string().describe("Edit summary")},{title:"Prepend to page",readOnlyHint:!1,destructiveHint:!0},async e=>Ue(e))}async function Ue(t){try{let e=await r(),o=`[nodemw-mcp] ${t.summary}`,s=await n(e,"prepend",t.title,t.content,o);return l(s)}catch(e){return i("Failed to prepend to page",e)}}import{z as B}from"zod";function jt(t){return t.tool("move","Move (rename) a wiki page (requires authentication)",{from:B.string().describe("Current page title"),to:B.string().describe("New page title"),summary:B.string().describe("Move summary")},{title:"Move page",readOnlyHint:!1,destructiveHint:!0},async e=>ze(e))}async function ze(t){try{let e=await r(),o=`[nodemw-mcp] ${t.summary}`,s=await n(e,"move",t.from,t.to,o);return l(s)}catch(e){return i("Failed to move page",e)}}import{z as Bt}from"zod";function Et(t){return t.tool("delete","Delete a wiki page (requires authentication)",{title:Bt.string().describe("Page title to delete"),reason:Bt.string().describe("Reason for deletion")},{title:"Delete page",readOnlyHint:!1,destructiveHint:!0},async e=>We(e))}async function We(t){try{let e=await r(),o=`[nodemw-mcp] ${t.reason}`,s=await n(e,"delete",t.title,o);return l(s)}catch(e){return i("Failed to delete page",e)}}import{z as f}from"zod";function Ht(t){return t.tool("protect","Protect a wiki page (requires authentication)",{title:f.string().describe("Page title to protect"),protections:f.array(f.object({type:f.string().describe("Action type (e.g., edit, move)"),level:f.string().optional().default("all").describe("Protection level (e.g., sysop, autoconfirmed)"),expiry:f.string().optional().describe("Expiry time (e.g., 1 week, never)")})).describe("Protection settings"),reason:f.string().optional().describe("Reason for protection"),cascade:f.boolean().optional().default(!1).describe("Apply cascade protection")},{title:"Protect page",readOnlyHint:!1,destructiveHint:!0},async e=>Ne(e))}async function Ne(t){try{let e=await r(),o={};t.reason&&(o.reason=`[nodemw-mcp] ${t.reason}`),t.cascade&&(o.cascade=t.cascade);let s=await n(e,"protect",t.title,t.protections,o);return l(s)}catch(e){return i("Failed to protect page",e)}}import{z as b}from"zod";function It(t){return t.tool("purge","Purge cache for wiki pages",{titles:b.union([b.string(),b.array(b.string())]).describe("Page title(s) or category to purge")},{title:"Purge pages",readOnlyHint:!1,destructiveHint:!1},async e=>Le(e))}async function Le(t){try{let e=await r(),o=await n(e,"purge",t.titles);return l(o)}catch(e){return i("Failed to purge pages",e)}}import{z as E}from"zod";function Gt(t){return t.tool("send-email","Send email to a wiki user (requires authentication)",{username:E.string().describe("Username to email"),subject:E.string().describe("Email subject"),text:E.string().describe("Email content")},{title:"Send email",readOnlyHint:!1,destructiveHint:!1},async e=>$e(e))}async function $e(t){try{let e=await r(),o=await n(e,"sendEmail",t.username,t.subject,t.text);return l(o)}catch(e){return i("Failed to send email",e)}}import{z as H}from"zod";function Ft(t){return t.tool("upload","Upload a file to wiki (requires authentication)",{filename:H.string().describe("Destination filename on wiki"),content:H.string().describe("File content as base64 string"),comment:H.string().optional().describe("Upload comment")},{title:"Upload file",readOnlyHint:!1,destructiveHint:!1},async e=>De(e))}async function De(t){try{let e=await r(),o=Buffer.from(t.content,"base64"),s=t.comment?`[nodemw-mcp] ${t.comment}`:"[nodemw-mcp] File upload",a=await n(e,"upload",t.filename,o,s);return l(a)}catch(e){return i("Failed to upload file",e)}}import{z as I}from"zod";function Ot(t){return t.tool("upload-by-url","Upload a file to wiki from URL (requires authentication)",{filename:I.string().describe("Destination filename on wiki"),url:I.string().url().describe("Source URL to download file from"),summary:I.string().optional().describe("Upload summary")},{title:"Upload file by URL",readOnlyHint:!1,destructiveHint:!1},async e=>qe(e))}async function qe(t){try{let e=await r(),o=t.summary?`[nodemw-mcp] ${t.summary}`:"[nodemw-mcp] File upload from URL",s=await n(e,"uploadByUrl",t.filename,t.url,o);return l(s)}catch(e){return i("Failed to upload file by URL",e)}}import{z as G}from"zod";function Ut(t){return t.tool("add-flow-topic","Add a new Flow topic to a wiki page (requires authentication)",{title:G.string().describe("Page title to add topic to"),subject:G.string().describe("Topic subject"),content:G.string().describe("Topic content in wikitext")},{title:"Add Flow topic",readOnlyHint:!1,destructiveHint:!1},async e=>_e(e))}async function _e(t){try{let e=await r(),o=await n(e,"addFlowTopic",t.title,t.subject,t.content);return l(o)}catch(e){return i("Failed to add Flow topic",e)}}import{z as zt}from"zod";function Wt(t){return t.tool("create-account","Create a new MediaWiki user account (requires authentication)",{username:zt.string().describe("New account username"),password:zt.string().describe("New account password")},{title:"Create user account",readOnlyHint:!1,destructiveHint:!1},async e=>Qe(e))}async function Qe(t){try{let e=await r(),o=await n(e,"createAccount",t.username,t.password);return l(o)}catch(e){return i("Failed to create account",e)}}var Ve=[L,D,q,_,V,Y,J,X,K,Z,tt,et,ot,rt,nt,st,lt,ct,mt,pt,ut,gt,ft,Tt,ht,xt,vt,wt,kt,Mt,At,St,Ct,Pt,jt,Et,Ht,It,Gt,Ft,Ot,Ut,Wt];function Nt(t){let e=[];for(let o of Ve)try{e.push(o(t))}catch(s){console.error(`Error registering tool: ${s.message}`)}return e}function Xe(){let{values:t,positionals:e}=Je({options:{server:{type:"string",short:"s"},path:{type:"string"},endpoint:{type:"string"},user:{type:"string",short:"u"},pass:{type:"string",short:"p"},token:{type:"string"},"dry-run":{type:"boolean"}},strict:!1,allowPositionals:!0}),o=t.server??e[0]??process.env.NODEMW_MCP_SERVER;o||(console.error("Error: target server is required (-s, positional arg, or NODEMW_MCP_SERVER env)"),process.exit(1));let s,a,c;try{if(o.startsWith("http://")||o.startsWith("https://")){let u=new URL(o);s=u.hostname,a=u.protocol.replace(":",""),u.port&&(c=parseInt(u.port,10))}else s=o}catch{s=o}let m=process.env.NODEMW_MCP_ENDPOINT_PATH,p=!!(t.path??t.endpoint??m);return{config:{server:s,protocol:a,port:c,path:t.path??t.endpoint??m??"/w",username:t.user??process.env.NODEMW_MCP_MW_USER,password:t.pass??process.env.NODEMW_MCP_MW_PASS,token:t.token,dryRun:t["dry-run"]},pathExplicit:p}}async function Ke(){let{config:t,pathExplicit:e}=Xe();if(!e)try{t.path=await W(t),console.error(`Auto-detected API path: ${t.path}`)}catch(m){console.error("Error:",m.message),process.exit(1)}U(t);try{await N(t)}catch(m){console.error("Error:",m.message),process.exit(1)}let o=r(),s;try{let p=(await n(o,"getSiteInfo",["general"]))?.general;p&&(s={sitename:p.sitename||"Unknown",base:p.base||"",generator:p.generator||"MediaWiki"})}catch{console.error("Warning: Could not fetch site info for server description.")}let a=O(s);Nt(a);let c=new Ye;await a.connect(c)}Ke().catch(console.error);
|
|
35
|
+
${JSON.stringify(m,null,2)}`:c}]}}else{let a=await i(r,"getArticle",t,e);return a==null?{content:[{type:"text",text:`Page "${t}" not found or has no content.`}],isError:!0}:{content:[{type:"text",text:a}]}}}catch(r){return{content:[{type:"text",text:`Error: ${r.message}`}],isError:!0}}}import{z as q}from"zod";function l(t){return{content:[{type:"text",text:JSON.stringify(t,null,2)}]}}function s(t,e){return{content:[{type:"text",text:JSON.stringify({error:t,details:e?.message},null,2)}],isError:!0}}function _(t){return t.tool("search","Search for wiki pages by keyword",{keyword:q.string().describe("Search keyword"),limit:q.number().optional().default(10).describe("Maximum number of results")},{title:"Search",readOnlyHint:!0,destructiveHint:!1},async({keyword:e,limit:o})=>Xt(e,o))}async function Xt(t,e){try{let o=await n(),r=await i(o,"search",t),a=r.slice(0,e);return l({total:r.length,limit:e,keyword:t,results:a})}catch(o){return s("Failed to search",o)}}import{z as Kt}from"zod";function Q(t){return t.tool("get-pages-in-category","Get all pages in a category",{category:Kt.string().describe("Category name (with or without Category: prefix)")},{title:"Get pages in category",readOnlyHint:!0,destructiveHint:!1},async({category:e})=>Zt(e))}async function Zt(t){try{let e=await n(),o=t.replace(/^Category:/i,""),r=await i(e,"getPagesInCategory",o);return l({category:o,pages:r,count:r.length})}catch(e){return s("Failed to get pages in category",e)}}import{z as te}from"zod";function V(t){return t.tool("get-categories","Get all categories matching a prefix",{prefix:te.string().optional().default("").describe("Prefix to filter categories")},{title:"Get categories",readOnlyHint:!0,destructiveHint:!1},async({prefix:e})=>ee(e))}async function ee(t){try{let e=await n(),o=await i(e,"getCategories",t);return l({prefix:t,categories:o,count:o.length})}catch(e){return s("Failed to get categories",e)}}import{z as Y}from"zod";function J(t){return t.tool("get-users","Get all users matching a prefix",{prefix:Y.string().optional().default("").describe("Prefix to filter usernames"),onlyWithEdits:Y.boolean().optional().default(!1).describe("Only include users with at least one edit")},{title:"Get users",readOnlyHint:!0,destructiveHint:!1},async({prefix:e,onlyWithEdits:o})=>oe(e,o))}async function oe(t,e){try{let o=await n(),r=await i(o,"getUsers",{prefix:t,witheditsonly:e});return l({prefix:t,onlyWithEdits:e,users:r,count:r.length})}catch(o){return s("Failed to get users",o)}}import{z as re}from"zod";function X(t){return t.tool("get-all-pages","Get all non-redirect pages from the wiki",{limit:re.number().optional().default(500).describe("Maximum number of pages to return")},{title:"Get all pages",readOnlyHint:!0,destructiveHint:!1},async({limit:e})=>ne(e))}async function ne(t){try{let e=await n(),o=await i(e,"getAllPages"),r=o.slice(0,t);return l({total:o.length,displayed:r.length,pages:r,limit:t})}catch(e){return s("Failed to get all pages",e)}}import{z as ie}from"zod";function K(t){return t.tool("get-pages-in-namespace","Get all non-redirect pages in a specific namespace",{namespace:ie.number().describe("Namespace number to filter pages")},{title:"Get pages in namespace",readOnlyHint:!0,destructiveHint:!1},async({namespace:e})=>se(e))}async function se(t){try{let e=await n(),o=await i(e,"getPagesInNamespace",t);return l({namespace:t,pages:o,count:o.length})}catch(e){return s("Failed to get pages in namespace",e)}}import{z as le}from"zod";function Z(t){return t.tool("get-pages-by-prefix","Get pages starting with a specific prefix",{prefix:le.string().describe("Prefix to match page titles")},{title:"Get pages by prefix",readOnlyHint:!0,destructiveHint:!1},async({prefix:e})=>ae(e))}async function ae(t){try{let e=await n(),o=await i(e,"getPagesByPrefix",t);return l({prefix:t,pages:o,count:o.length})}catch(e){return s("Failed to get pages by prefix",e)}}import{z as ce}from"zod";function tt(t){return t.tool("get-pages-transcluding","Get all pages that transclude (include) a specific template",{template:ce.string().describe("Template title to find transclusions")},{title:"Get pages transcluding template",readOnlyHint:!0,destructiveHint:!1},async({template:e})=>me(e))}async function me(t){try{let e=await n(),r=(await i(e,"getPagesTranscluding",t))[1],a=Array.isArray(r)?r.filter(c=>c!=null&&typeof c=="object"&&"title"in c):[];return l({template:t,pages:a,count:a.length})}catch(e){return s("Failed to get pages transcluding template",e)}}import{z as w}from"zod";function et(t){return t.tool("get-article-revisions","Get all revisions of a wiki article",{title:w.union([w.string(),w.number()]).describe("Article title or page ID")},{title:"Get article revisions",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>pe(e))}async function pe(t){try{let e=await n(),r=(await i(e,"getArticleRevisions",t)).flat();return l({title:t,revisions:r,count:r.length})}catch(e){return s("Failed to get article revisions",e)}}import{z as k}from"zod";function ot(t){return t.tool("get-article-categories","Get all categories that an article belongs to",{title:k.union([k.string(),k.number()]).describe("Article title or page ID")},{title:"Get article categories",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>ue(e))}async function ue(t){try{let e=await n(),o=await i(e,"getArticleCategories",t);return l({title:t,categories:o,count:o.length})}catch(e){return s("Failed to get article categories",e)}}import{z as ge}from"zod";function rt(t){return t.tool("get-article-properties","Get page properties for a wiki article",{title:ge.string().describe("Article title")},{title:"Get article properties",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>de(e))}async function de(t){try{let e=await n(),o=await i(e,"getArticleProperties",t);return l({title:t,properties:o})}catch(e){return s("Failed to get article properties",e)}}import{z as d}from"zod";function nt(t){return t.tool("get-article-info","Get detailed information about one or more articles",{title:d.union([d.string(),d.number(),d.array(d.union([d.string(),d.number()]))]).describe("Article title, page ID, or array of titles/IDs"),properties:d.array(d.string()).optional().describe("Specific properties to retrieve")},{title:"Get article info",readOnlyHint:!0,destructiveHint:!1},async({title:e,properties:o})=>fe(e,o))}async function fe(t,e){try{let o=await n(),a=await i(o,"getArticleInfo",t,e?{inprop:e}:{}),c=Array.isArray(a)?a:[a];return l({title:t,results:c,count:c.length})}catch(o){return s("Failed to get article info",o)}}import{z as A}from"zod";function it(t){return t.tool("get-user-contribs","Get contributions made by a specific user",{username:A.string().describe("Username to get contributions for"),namespace:A.number().optional().describe("Filter contributions by namespace"),limit:A.number().optional().default(50).describe("Maximum number of contributions to return")},{title:"Get user contributions",readOnlyHint:!0,destructiveHint:!1},async({username:e,namespace:o,limit:r})=>ye(e,o,r))}async function ye(t,e,o=50){try{let r=await n(),a={user:t,...e!==void 0&&{namespace:e}},c=await i(r,"getUserContribs",a),m=Array.isArray(c[1])?c[1]:[],p=m.slice(0,o);return l({username:t,namespace:e,limit:o,total:m.length,displayed:p.length,contributions:p})}catch(r){return s("Failed to get user contributions",r)}}function st(t){return t.tool("whoami","Get information about the currently logged in user",{},{title:"Who am I",readOnlyHint:!0,destructiveHint:!1},async()=>Te())}async function Te(){try{let t=await n(),e=await i(t,"whoami");return l(e)}catch(t){return s("Failed to get current user info",t)}}import{z as Re}from"zod";function lt(t){return t.tool("whois","Get information about a specific user",{username:Re.string().describe("Username to look up")},{title:"Whois",readOnlyHint:!0,destructiveHint:!1},async({username:e})=>he(e))}async function he(t){try{let e=await n(),o=await i(e,"whois",t);return o.missing?s(`User "${t}" not found.`):l(o)}catch(e){return s("Failed to get user info",e)}}import{z as at}from"zod";function ct(t){return t.tool("whoare","Get information about multiple wiki users",{usernames:at.array(at.string()).describe("Array of usernames to query")},{title:"Who are",readOnlyHint:!0,destructiveHint:!1},async e=>be(e))}async function be(t){try{let e=await n(),o=await i(e,"whoare",t.usernames);return l(o)}catch(e){return s("Failed to get user information",e)}}import{z as mt}from"zod";function pt(t){return t.tool("get-images","Get list of images starting from a specific name",{startFrom:mt.string().optional().default("").describe("Start from this image name"),limit:mt.number().optional().default(50).describe("Maximum number of images to return")},{title:"Get images",readOnlyHint:!0,destructiveHint:!1},async({startFrom:e,limit:o})=>xe(e,o))}async function xe(t,e){try{let o=await n(),r=await new Promise((c,m)=>{o.getImages(t,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,e);return l({total:r.length,limit:e,startFrom:t,images:a})}catch(o){return s("Failed to get images",o)}}import{z as M}from"zod";function ut(t){return t.tool("get-images-from-article","Get all images embedded in a specific article",{title:M.union([M.string(),M.number()]).describe("Article title or page ID")},{title:"Get images from article",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>ve(e))}async function ve(t){try{let e=await n(),o=await i(e,"getImagesFromArticle",t);return l({title:t,images:o,count:o.length})}catch(e){return s("Failed to get images from article",e)}}import{z as we}from"zod";function gt(t){return t.tool("get-image-usage","Get all pages that use a specific image",{filename:we.string().describe("Image filename with File: prefix")},{title:"Get image usage",readOnlyHint:!0,destructiveHint:!1},async({filename:e})=>ke(e))}async function ke(t){try{let e=await n(),o=await i(e,"getImageUsage",t);return l({filename:t,pages:o,count:o.length})}catch(e){return s("Failed to get image usage",e)}}import{z as Ae}from"zod";function dt(t){return t.tool("get-image-info","Get detailed information about an image file",{filename:Ae.string().describe("Image filename with File: prefix")},{title:"Get image info",readOnlyHint:!0,destructiveHint:!1},async({filename:e})=>Me(e))}async function Me(t){try{let e=await n(),o=await i(e,"getImageInfo",t);return o?l({filename:t,info:o}):s(`Image "${t}" not found.`)}catch(e){return s("Failed to get image info",e)}}import{z as S}from"zod";function ft(t){return t.tool("get-log","Get log entries of a specific type",{type:S.string().describe("Log type (e.g. delete, block, move)"),start:S.string().optional().default("").describe("Start timestamp (YYYYMMDDHHMMSS format)"),limit:S.number().optional().default(50).describe("Maximum number of entries to return")},{title:"Get log entries",readOnlyHint:!0,destructiveHint:!1},async({type:e,start:o,limit:r})=>Se(e,o,r))}async function Se(t,e,o){try{let r=await n(),a=await new Promise((m,p)=>{r.getLog(t,e,(u,...g)=>{if(u)p(u);else{let y=g[0];m(Array.isArray(y)?y:[])}})}),c=a.slice(0,o);return l({type:t,start:e,limit:o,total:a.length,displayed:c.length,entries:c})}catch(r){return s("Failed to get log entries",r)}}import{z as yt}from"zod";function Tt(t){return t.tool("expand-templates","Expand templates in wikitext",{text:yt.string().describe("Wikitext with templates to expand"),title:yt.string().optional().describe("Context page title")},{title:"Expand templates",readOnlyHint:!0,destructiveHint:!1},async({text:e,title:o})=>Ce(e,o))}async function Ce(t,e){try{let o=await n(),r=await i(o,"expandTemplates",t,e||"");return r==null?{content:[{type:"text",text:`Failed to expand templates for "${t}".`}],isError:!0}:{content:[{type:"text",text:r}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as Rt}from"zod";function ht(t){return t.tool("parse","Parse wikitext to HTML",{text:Rt.string().describe("Wikitext to parse"),title:Rt.string().optional().describe("Context page title")},{title:"Parse wikitext",readOnlyHint:!0,destructiveHint:!1},async({text:e,title:o})=>Pe(e,o))}async function Pe(t,e){try{let o=await n(),r=await i(o,"parse",t,e||""),a=r[1]||"",c=Array.isArray(r[2])?r[2]:[];return{content:[{type:"text",text:["Parsed XML structure:","",a,"",`Images found: ${c.length>0?c.join(", "):"none"}`].join(`
|
|
36
|
+
`)}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as bt}from"zod";function xt(t){return t.tool("get-recent-changes","Get recent changes on the wiki",{start:bt.string().optional().describe("Start timestamp"),limit:bt.number().optional().default(50).describe("Maximum number of changes to return")},{title:"Get recent changes",readOnlyHint:!0,destructiveHint:!1},async({start:e,limit:o})=>je(e,o))}async function je(t,e=50){try{let o=await n(),r=await new Promise((c,m)=>{o.getRecentChanges(t,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,e);return l({total:r.length,limit:e,start:t,changes:a})}catch(o){return s("Failed to get recent changes",o)}}import{z as vt}from"zod";function wt(t){return t.tool("get-site-info","Get site information from MediaWiki",{properties:vt.array(vt.string()).describe("List of site information properties to retrieve")},{title:"Get site info",readOnlyHint:!0,destructiveHint:!1},async({properties:e})=>Be(e))}async function Be(t){try{let e=await n(),o=await i(e,"getSiteInfo",t);return l(o||{})}catch(e){return s("Failed to get site info",e)}}function kt(t){return t.tool("get-site-stats","Get site statistics",{},{title:"Get site stats",readOnlyHint:!0,destructiveHint:!1},async()=>Ee())}async function Ee(){try{let t=await n(),e=await i(t,"getSiteStats");return l(e)}catch(t){return s("Failed to get site stats",t)}}function At(t){return t.tool("get-mediawiki-version","Get MediaWiki version running on the server",{},{title:"Get MediaWiki version",readOnlyHint:!0,destructiveHint:!1},async()=>He())}async function He(){try{let t=await n(),e=await i(t,"getMediaWikiVersion");return l({version:e})}catch(t){return s("Failed to get MediaWiki version",t)}}import{z as Ie}from"zod";function Mt(t){return t.tool("get-query-page","Get results from a query page (special page)",{name:Ie.string().describe("Name of the query page")},{title:"Get query page results",readOnlyHint:!0,destructiveHint:!1},async({name:e})=>Ge(e))}async function Ge(t){try{let e=await n(),o=await i(e,"getQueryPage",t);return l({name:t,results:o,count:o.length})}catch(e){return s("Failed to get query page results",e)}}import{z as C}from"zod";function St(t){return t.tool("get-external-links","Get all external links from an article",{title:C.union([C.string(),C.number()]).describe("Article title or page ID")},{title:"Get external links",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>Fe(e))}async function Fe(t){try{let e=await n(),o=await i(e,"getExternalLinks",t);return l({title:t,links:o.map(r=>r["*"]),count:o.length})}catch(e){return s("Failed to get external links",e)}}import{z as Oe}from"zod";function Ct(t){return t.tool("get-backlinks","Get all backlinks to a specific page",{title:Oe.string().describe("Target page title to find backlinks for")},{title:"Get backlinks",readOnlyHint:!0,destructiveHint:!1},async({title:e})=>Ue(e))}async function Ue(t){try{let e=await n(),o=await i(e,"getBacklinks",t);return l({target:t,backlinks:o,count:o.length})}catch(e){return s("Failed to get backlinks",e)}}import{z as h}from"zod";function Pt(t){return t.tool("edit","Edit a wiki page (requires authentication)",{title:h.string().describe("Page title to edit"),content:h.string().describe("New content for the page"),summary:h.string().describe("Edit summary"),minor:h.boolean().optional().default(!1).describe("Mark as minor edit")},{title:"Edit page",readOnlyHint:!1,destructiveHint:!0},async e=>ze(e))}async function ze(t){try{let e=await n(),o=`[nodemw-mcp] ${t.summary}`,r=await i(e,"edit",t.title,t.content,o,t.minor||!1);return l(r)}catch(e){return s("Failed to edit page",e)}}import{z as P}from"zod";function jt(t){return t.tool("append","Append content to a wiki page (requires authentication)",{title:P.string().describe("Page title"),content:P.string().describe("Content to append"),summary:P.string().describe("Edit summary")},{title:"Append to page",readOnlyHint:!1,destructiveHint:!0},async e=>We(e))}async function We(t){try{let e=await n(),o=`[nodemw-mcp] ${t.summary}`;return await i(e,"append",t.title,t.content,o),l({success:!0,title:t.title})}catch(e){return s("Failed to append to page",e)}}import{z as j}from"zod";function Bt(t){return t.tool("prepend","Prepend content to a wiki page (requires authentication)",{title:j.string().describe("Page title to prepend to"),content:j.string().describe("Content to prepend"),summary:j.string().describe("Edit summary")},{title:"Prepend to page",readOnlyHint:!1,destructiveHint:!0},async e=>$e(e))}async function $e(t){try{let e=await n(),o=`[nodemw-mcp] ${t.summary}`,r=await i(e,"prepend",t.title,t.content,o);return l(r)}catch(e){return s("Failed to prepend to page",e)}}import{z as B}from"zod";function Et(t){return t.tool("move","Move (rename) a wiki page (requires authentication)",{from:B.string().describe("Current page title"),to:B.string().describe("New page title"),summary:B.string().describe("Move summary")},{title:"Move page",readOnlyHint:!1,destructiveHint:!0},async e=>Ne(e))}async function Ne(t){try{let e=await n(),o=`[nodemw-mcp] ${t.summary}`,r=await i(e,"move",t.from,t.to,o);return l(r)}catch(e){return s("Failed to move page",e)}}import{z as Ht}from"zod";function It(t){return t.tool("delete","Delete a wiki page (requires authentication)",{title:Ht.string().describe("Page title to delete"),reason:Ht.string().describe("Reason for deletion")},{title:"Delete page",readOnlyHint:!1,destructiveHint:!0},async e=>Le(e))}async function Le(t){try{let e=await n(),o=`[nodemw-mcp] ${t.reason}`,r=await i(e,"delete",t.title,o);return l(r)}catch(e){return s("Failed to delete page",e)}}import{z as f}from"zod";function Gt(t){return t.tool("protect","Protect a wiki page (requires authentication)",{title:f.string().describe("Page title to protect"),protections:f.array(f.object({type:f.string().describe("Action type (e.g., edit, move)"),level:f.string().optional().default("all").describe("Protection level (e.g., sysop, autoconfirmed)"),expiry:f.string().optional().describe("Expiry time (e.g., 1 week, never)")})).describe("Protection settings"),reason:f.string().optional().describe("Reason for protection"),cascade:f.boolean().optional().default(!1).describe("Apply cascade protection")},{title:"Protect page",readOnlyHint:!1,destructiveHint:!0},async e=>De(e))}async function De(t){try{let e=await n(),o={};t.reason&&(o.reason=`[nodemw-mcp] ${t.reason}`),t.cascade&&(o.cascade=t.cascade);let r=await i(e,"protect",t.title,t.protections,o);return l(r)}catch(e){return s("Failed to protect page",e)}}import{z as b}from"zod";function Ft(t){return t.tool("purge","Purge cache for wiki pages",{titles:b.union([b.string(),b.array(b.string())]).describe("Page title(s) or category to purge")},{title:"Purge pages",readOnlyHint:!1,destructiveHint:!1},async e=>qe(e))}async function qe(t){try{let e=await n(),o=await i(e,"purge",t.titles);return l(o)}catch(e){return s("Failed to purge pages",e)}}import{z as E}from"zod";function Ot(t){return t.tool("send-email","Send email to a wiki user (requires authentication)",{username:E.string().describe("Username to email"),subject:E.string().describe("Email subject"),text:E.string().describe("Email content")},{title:"Send email",readOnlyHint:!1,destructiveHint:!1},async e=>_e(e))}async function _e(t){try{let e=await n(),o=await i(e,"sendEmail",t.username,t.subject,t.text);return l(o)}catch(e){return s("Failed to send email",e)}}import{z as H}from"zod";function Ut(t){return t.tool("upload","Upload a file to wiki (requires authentication)",{filename:H.string().describe("Destination filename on wiki"),content:H.string().describe("File content as base64 string"),comment:H.string().optional().describe("Upload comment")},{title:"Upload file",readOnlyHint:!1,destructiveHint:!1},async e=>Qe(e))}async function Qe(t){try{let e=await n(),o=Buffer.from(t.content,"base64"),r=t.comment?`[nodemw-mcp] ${t.comment}`:"[nodemw-mcp] File upload",a=await i(e,"upload",t.filename,o,r);return l(a)}catch(e){return s("Failed to upload file",e)}}import{z as I}from"zod";function zt(t){return t.tool("upload-by-url","Upload a file to wiki from URL (requires authentication)",{filename:I.string().describe("Destination filename on wiki"),url:I.string().url().describe("Source URL to download file from"),summary:I.string().optional().describe("Upload summary")},{title:"Upload file by URL",readOnlyHint:!1,destructiveHint:!1},async e=>Ve(e))}async function Ve(t){try{let e=await n(),o=t.summary?`[nodemw-mcp] ${t.summary}`:"[nodemw-mcp] File upload from URL",r=await i(e,"uploadByUrl",t.filename,t.url,o);return l(r)}catch(e){return s("Failed to upload file by URL",e)}}import{z as G}from"zod";function Wt(t){return t.tool("add-flow-topic","Add a new Flow topic to a wiki page (requires authentication)",{title:G.string().describe("Page title to add topic to"),subject:G.string().describe("Topic subject"),content:G.string().describe("Topic content in wikitext")},{title:"Add Flow topic",readOnlyHint:!1,destructiveHint:!1},async e=>Ye(e))}async function Ye(t){try{let e=await n(),o=await i(e,"addFlowTopic",t.title,t.subject,t.content);return l(o)}catch(e){return s("Failed to add Flow topic",e)}}import{z as $t}from"zod";function Nt(t){return t.tool("create-account","Create a new MediaWiki user account (requires authentication)",{username:$t.string().describe("New account username"),password:$t.string().describe("New account password")},{title:"Create user account",readOnlyHint:!1,destructiveHint:!1},async e=>Je(e))}async function Je(t){try{let e=await n(),o=await i(e,"createAccount",t.username,t.password);return l(o)}catch(e){return s("Failed to create account",e)}}var Lt=[D,_,Q,V,J,X,K,Z,tt,et,ot,rt,nt,it,st,lt,ct,pt,ut,gt,dt,ft,Tt,ht,xt,wt,kt,At,Mt,St,Ct],Xe=[Pt,jt,Bt,Et,It,Gt,Ft,Ot,Ut,zt,Wt,Nt];function Dt(t,e=!0){let o=e?[...Lt,...Xe]:Lt,r=[];for(let a of o)try{r.push(a(t))}catch(c){console.error(`Error registering tool: ${c.message}`)}return r}function to(){let{values:t,positionals:e}=Ze({options:{server:{type:"string",short:"s"},path:{type:"string"},endpoint:{type:"string"},user:{type:"string",short:"u"},pass:{type:"string",short:"p"},token:{type:"string"},"dry-run":{type:"boolean"}},strict:!1,allowPositionals:!0}),o=t.server??e[0]??process.env.NODEMW_MCP_SERVER;o||(console.error("Error: target server is required (-s, positional arg, or NODEMW_MCP_SERVER env)"),process.exit(1));let r,a,c;try{if(o.startsWith("http://")||o.startsWith("https://")){let u=new URL(o);r=u.hostname,a=u.protocol.replace(":",""),u.port&&(c=parseInt(u.port,10))}else r=o}catch{r=o}let m=process.env.NODEMW_MCP_ENDPOINT_PATH,p=!!(t.path??t.endpoint??m);return{config:{server:r,protocol:a,port:c,path:t.path??t.endpoint??m??"/w",username:t.user??process.env.NODEMW_MCP_MW_USER,password:t.pass??process.env.NODEMW_MCP_MW_PASS,token:t.token,dryRun:t["dry-run"]},pathExplicit:p}}async function eo(){let{config:t,pathExplicit:e}=to();if(!e)try{t.path=await $(t),console.error(`Auto-detected API path: ${t.path}`)}catch(p){console.error("Error:",p.message),process.exit(1)}z(t);try{await N(t)}catch(p){console.error("Error:",p.message),process.exit(1)}let o=n(),r;try{let u=(await i(o,"getSiteInfo",["general"]))?.general;u&&(r={sitename:u.sitename||"Unknown",base:u.base||"",generator:u.generator||"MediaWiki"})}catch{console.error("Warning: Could not fetch site info for server description.")}let a=L(),c=O(r,a);Dt(c,a);let m=new Ke;await c.connect(m)}eo().catch(console.error);
|
|
37
37
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/server.ts", "../src/tools/ro/get-article.ts", "../src/common/nodemwBot.ts", "../src/tools/ro/search.ts", "../src/common/utils.ts", "../src/tools/ro/get-pages-in-category.ts", "../src/tools/ro/get-categories.ts", "../src/tools/ro/get-users.ts", "../src/tools/ro/get-all-pages.ts", "../src/tools/ro/get-pages-in-namespace.ts", "../src/tools/ro/get-pages-by-prefix.ts", "../src/tools/ro/get-pages-transcluding.ts", "../src/tools/ro/get-article-revisions.ts", "../src/tools/ro/get-article-categories.ts", "../src/tools/ro/get-article-properties.ts", "../src/tools/ro/get-article-info.ts", "../src/tools/ro/get-user-contribs.ts", "../src/tools/ro/whoami.ts", "../src/tools/ro/whois.ts", "../src/tools/ro/whoare.ts", "../src/tools/ro/get-images.ts", "../src/tools/ro/get-images-from-article.ts", "../src/tools/ro/get-image-usage.ts", "../src/tools/ro/get-image-info.ts", "../src/tools/ro/get-log.ts", "../src/tools/ro/expand-templates.ts", "../src/tools/ro/parse.ts", "../src/tools/ro/get-recent-changes.ts", "../src/tools/ro/get-site-info.ts", "../src/tools/ro/get-site-stats.ts", "../src/tools/ro/get-mediawiki-version.ts", "../src/tools/ro/get-query-page.ts", "../src/tools/ro/get-external-links.ts", "../src/tools/ro/get-backlinks.ts", "../src/tools/editing/edit.ts", "../src/tools/editing/append.ts", "../src/tools/editing/prepend.ts", "../src/tools/editing/move.ts", "../src/tools/editing/delete.ts", "../src/tools/editing/protect.ts", "../src/tools/editing/purge.ts", "../src/tools/editing/send-email.ts", "../src/tools/editing/upload.ts", "../src/tools/editing/upload-by-url.ts", "../src/tools/editing/add-flow-topic.ts", "../src/tools/editing/create-account.ts", "../src/tools/index.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { parseArgs } from 'util';\nimport { createServer } from './server.js';\nimport { registerAllTools } from './tools/index.js';\nimport {\n\tinitServerConfig,\n\tgetBot,\n\tinitBot,\n\tautoDetectPath,\n\tpromisifyBotMethod,\n\ttype ServerConfig\n} from './common/nodemwBot.js';\n\nfunction parseCliArgs(): { config: ServerConfig; pathExplicit: boolean } {\n\tconst { values, positionals } = parseArgs({\n\t\toptions: {\n\t\t\tserver: { type: 'string', short: 's' },\n\t\t\tpath: { type: 'string' },\n\t\t\tendpoint: { type: 'string' },\n\t\t\tuser: { type: 'string', short: 'u' },\n\t\t\tpass: { type: 'string', short: 'p' },\n\t\t\ttoken: { type: 'string' },\n\t\t\t'dry-run': { type: 'boolean' },\n\t\t},\n\t\tstrict: false,\n\t\tallowPositionals: true,\n\t});\n\n\t// Server can be specified via --server/-s or as the first positional argument\n\tconst serverUrl = (values.server as string) ?? positionals[0] ?? process.env.NODEMW_MCP_SERVER;\n\tif (!serverUrl) {\n\t\tconsole.error('Error: target server is required (-s, positional arg, or NODEMW_MCP_SERVER env)');\n\t\tprocess.exit(1);\n\t}\n\tlet server: string;\n\tlet protocol: string | undefined;\n\tlet port: number | undefined;\n\n\ttry {\n\t\tif (serverUrl.startsWith('http://') || serverUrl.startsWith('https://')) {\n\t\t\tconst url = new URL(serverUrl);\n\t\t\tserver = url.hostname;\n\t\t\tprotocol = url.protocol.replace(':', '');\n\t\t\tif (url.port) {\n\t\t\t\tport = parseInt(url.port, 10);\n\t\t\t}\n\t\t} else {\n\t\t\tserver = serverUrl;\n\t\t}\n\t} catch {\n\t\tserver = serverUrl;\n\t}\n\n\tconst pathFromEnv = process.env.NODEMW_MCP_ENDPOINT_PATH;\n\tconst pathExplicit = !!(values.path ?? values.endpoint ?? pathFromEnv);\n\n\treturn {\n\t\tconfig: {\n\t\t\tserver,\n\t\t\tprotocol,\n\t\t\tport,\n\t\t\tpath: (values.path as string) ?? (values.endpoint as string) ?? pathFromEnv ?? '/w',\n\t\t\tusername: (values.user as string) ?? process.env.NODEMW_MCP_MW_USER,\n\t\t\tpassword: (values.pass as string) ?? process.env.NODEMW_MCP_MW_PASS,\n\t\t\ttoken: values.token as string | undefined,\n\t\t\tdryRun: values['dry-run'] as boolean | undefined,\n\t\t},\n\t\tpathExplicit,\n\t};\n}\n\nasync function main(): Promise<void> {\n\tconst { config, pathExplicit } = parseCliArgs();\n\n\t// Step 1: Auto-detect API path if not explicitly specified\n\tif (!pathExplicit) {\n\t\ttry {\n\t\t\tconfig.path = await autoDetectPath(config);\n\t\t\tconsole.error(`Auto-detected API path: ${config.path}`);\n\t\t} catch (err) {\n\t\t\tconsole.error('Error:', (err as Error).message);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tinitServerConfig(config);\n\n\t// Step 2: Initialize bot \u2014 creates connection and logs in if credentials provided\n\ttry {\n\t\tawait initBot(config);\n\t} catch (err) {\n\t\tconsole.error('Error:', (err as Error).message);\n\t\tprocess.exit(1);\n\t}\n\n\t// Step 3: Fetch site info to enrich the server description\n\tconst bot = getBot();\n\tlet siteInfo: { sitename: string; base: string; generator: string } | undefined;\n\ttry {\n\t\tconst info = await promisifyBotMethod<{ general?: { sitename?: string; base?: string; generator?: string } }>(bot, 'getSiteInfo', ['general']);\n\t\tconst general = info?.general;\n\t\tif (general) {\n\t\t\tsiteInfo = {\n\t\t\t\tsitename: general.sitename || 'Unknown',\n\t\t\t\tbase: general.base || '',\n\t\t\t\tgenerator: general.generator || 'MediaWiki',\n\t\t\t};\n\t\t}\n\t} catch {\n\t\tconsole.error('Warning: Could not fetch site info for server description.');\n\t}\n\n\t// Step 4: Create server with site-aware description\n\tconst server = createServer(siteInfo);\n\tregisterAllTools(server);\n\n\t// Step 5: Connect stdio transport\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(console.error);\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nexport const USER_AGENT = 'nodemw-mcp-server/1.0';\n\nexport interface SiteInfoSummary {\n\tsitename: string;\n\tbase: string;\n\tgenerator: string;\n}\n\nexport function createServer(siteInfo?: SiteInfoSummary): McpServer {\n\tlet description: string;\n\tif (siteInfo) {\n\t\tdescription = `Connected to ${siteInfo.sitename} (${siteInfo.base}). Running ${siteInfo.generator}. When connecting for the first time, call the get-site-info tool for full site details.`;\n\t} else {\n\t\tdescription = 'When connecting to this server for the first time, call the get-site-info tool to understand the target MediaWiki site (version, namespaces, extensions, etc.) before using other tools.';\n\t}\n\n\treturn new McpServer(\n\t\t{\n\t\t\tname: 'nodemw-mcp-server',\n\t\t\tversion: '1.0.0',\n\t\t\tdescription\n\t\t},\n\t\t{ capabilities: { tools: {} } }\n\t);\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function getArticleTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-article',\r\n\t\t'Retrieve the content of a wiki article',\r\n\t\t{\r\n\t\t\ttitle: z.string().describe( 'Article title' ),\r\n\t\t\tfollowRedirect: z.boolean().optional().default( true ).describe( 'Follow redirects' ),\r\n\t\t\tredirectInfo: z.boolean().optional().default( false ).describe( 'Include information about redirects' )\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get article',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title, followRedirect, redirectInfo } ) => handleGetArticleTool( title, followRedirect, redirectInfo )\r\n\t);\r\n}\r\n\r\nasync function handleGetArticleTool(\r\n\ttitle: string,\r\n\tfollowRedirect: boolean,\r\n\tredirectInfo: boolean\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tif (redirectInfo) {\r\n\t\t\t// When redirectInfo is requested, get both content and redirect info\r\n\t\t\tconst result = await new Promise<[string, unknown]>((resolve, reject) => {\r\n\t\t\t\tconst callback = (err: Error | null, content: string, redirectInfo: unknown) => {\r\n\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\treject(err);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tresolve([content, redirectInfo]);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\t// @ts-expect-error: any method call\r\n\t\t\t\tbot.getArticle(title, followRedirect, callback);\r\n\t\t\t});\r\n\t\t\tconst [content, redirect] = result;\r\n\t\t\tconst responseText = redirect \r\n\t\t\t\t? `Content:\\n\\n${content}\\n\\nRedirect Information:\\n\\n${JSON.stringify(redirect, null, 2)}`\r\n\t\t\t\t: content;\r\n\t\t\t\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [ { type: 'text', text: responseText } ]\r\n\t\t\t};\r\n\t\t} else {\r\n\t\t\t// Original behavior: just return content\r\n\t\t\tconst result = await promisifyBotMethod<string>(\r\n\t\t\t\tbot,\r\n\t\t\t\t'getArticle',\r\n\t\t\t\ttitle,\r\n\t\t\t\tfollowRedirect\r\n\t\t\t);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [ { type: 'text', text: result } ]\r\n\t\t\t};\r\n\t\t}\r\n\t} catch ( error ) {\r\n\t\treturn {\r\n\t\t\tcontent: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n\t\t\tisError: true\r\n\t\t};\r\n\t}\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport Bot from 'nodemw';\nimport { USER_AGENT } from '../server.js';\n\nexport interface ServerConfig {\n\tserver: string;\n\tpath: string;\n\tprotocol?: string;\n\tport?: number;\n\tproxy?: string;\n\tuserAgent?: string;\n\tconcurrency?: number;\n\tdebug?: boolean;\n\tusername?: string;\n\tpassword?: string;\n\ttoken?: string;\n\tdomain?: string;\n\tdryRun?: boolean;\n}\n\nlet botInstance: Bot | null = null;\nlet serverConfig: ServerConfig | null = null;\n\nexport function initServerConfig(config: ServerConfig): void {\n\tserverConfig = config;\n}\n\nfunction createBotFromConfig(config: ServerConfig): Bot {\n\tconst {\n\t\tserver,\n\t\tpath,\n\t\tprotocol,\n\t\tport,\n\t\tproxy,\n\t\tuserAgent,\n\t\tconcurrency,\n\t\tdebug,\n\t\tusername,\n\t\tpassword,\n\t\tdomain,\n\t\tdryRun\n\t} = config;\n\n\treturn new Bot({\n\t\tserver,\n\t\tprotocol: protocol || 'https',\n\t\tport,\n\t\tpath,\n\t\tproxy,\n\t\tuserAgent: userAgent || USER_AGENT,\n\t\tconcurrency,\n\t\tdebug,\n\t\tusername: username || undefined,\n\t\tpassword: password || undefined,\n\t\tdomain,\n\t\t// @ts-expect-error: dryRun is supported by nodemw at runtime but missing from BotOptions types\n\t\tdryRun\n\t});\n}\n\nasync function testApiConnection(bot: Bot): Promise<boolean> {\n\ttry {\n\t\tawait promisifyBotMethod(bot, 'getSiteInfo', ['general']);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function autoDetectPath(baseConfig: ServerConfig): Promise<string> {\n\t// nodemw constructs URL as ${server}${path}/api.php \u2014 so /w means /w/api.php, '' means /api.php\n\tconst pathsToTry = ['/w', ''];\n\tfor (const path of pathsToTry) {\n\t\tconst testConfig = { ...baseConfig, path };\n\t\tconst bot = createBotFromConfig(testConfig);\n\t\tif (await testApiConnection(bot)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'Could not auto-detect MediaWiki API path. ' +\n\t\t'Tried /w/api.php and /api.php. ' +\n\t\t'Please specify --path explicitly (e.g., --path /w or --path \"\" for root).'\n\t);\n}\n\nexport async function initBot(config: ServerConfig): Promise<Bot> {\n\tbotInstance = createBotFromConfig(config);\n\n\tconst { username, password } = config;\n\tif (username && password) {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tbotInstance!.logIn((err: Error | null) => {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(new Error(`Login failed for user '${username}': ${err.message}`));\n\t\t\t\t} else {\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\treturn botInstance;\n}\n\nexport function getBot(): Bot {\n\tif (!botInstance) {\n\t\tthrow new Error('Bot not initialized. Server must be started first.');\n\t}\n\treturn botInstance;\n}\n\nexport function clearBotCache(): void {\n\tbotInstance = null;\n}\n\nexport function promisifyBotMethod<T>(\n\tbot: Bot,\n\tmethod: string,\n\t...args: unknown[]\n): Promise<T> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst callback = (err: Error | null, result: T) => {\n\t\t\tif (err) {\n\t\t\t\treject(err);\n\t\t\t} else {\n\t\t\t\tresolve(result);\n\t\t\t}\n\t\t};\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t(bot as any)[method](...args, callback);\n\t});\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface SearchResult extends Record<string, any> {\r\n\ttitle: string;\r\n\tsnippet?: string;\r\n\turl?: string;\r\n\tpageId?: number;\r\n}\r\n\r\nexport function searchTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'search',\r\n\t\t'Search for wiki pages by keyword',\r\n\t\t{\r\n\t\t\tkeyword: z.string().describe( 'Search keyword' ),\r\n\t\t\tlimit: z.number().optional().default( 10 ).describe( 'Maximum number of results' )\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Search',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { keyword, limit } ) => handleSearchTool( keyword, limit )\r\n\t);\r\n}\r\n\r\nasync function handleSearchTool(\r\n\tkeyword: string,\r\n\tlimit: number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\r\n\t\t// nodemw search returns array of results directly\r\n\t\tconst results = await promisifyBotMethod<SearchResult[]>(\r\n\t\t\tbot,\r\n\t\t\t'search',\r\n\t\t\tkeyword\r\n\t\t);\r\n\r\n\t\t// Limit results\r\n\t\tconst limitedResults = results.slice( 0, limit );\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttotal: results.length,\r\n\t\t\tlimit,\r\n\t\t\tkeyword,\r\n\t\t\tresults: limitedResults\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to search', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type Bot from 'nodemw';\r\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\r\n\r\nexport function promisifyBotMethod<T>(\r\n\tbot: Bot,\r\n\tmethod: string,\r\n\t...args: unknown[]\r\n): Promise<T> {\r\n\treturn new Promise( ( resolve, reject ) => {\r\n\t\tconst callback = ( err: Error | null, result: T ) => {\r\n\t\t\tif ( err ) {\r\n\t\t\t\treject( err );\r\n\t\t\t} else {\r\n\t\t\t\tresolve( result );\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t( bot as any )[ method ]( ...args, callback );\r\n\t} );\r\n}\r\n\r\nexport function isNonNullish<T>(\r\n\tvalue: T | null | undefined\r\n): value is T {\r\n\treturn value !== null && value !== undefined;\r\n}\r\n\r\nexport function jsonResult(data: unknown): CallToolResult {\r\n\treturn {\r\n\t\tcontent: [{\r\n\t\t\ttype: 'text',\r\n\t\t\ttext: JSON.stringify(data, null, 2)\r\n\t\t}]\r\n\t};\r\n}\r\n\r\nexport function errorResult(message: string, error?: Error): CallToolResult {\r\n\treturn {\r\n\t\tcontent: [{\r\n\t\t\ttype: 'text',\r\n\t\t\ttext: JSON.stringify({\r\n\t\t\t\terror: message,\r\n\t\t\t\tdetails: error?.message\r\n\t\t\t}, null, 2)\r\n\t\t}],\r\n\t\tisError: true\r\n\t};\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageInCategory extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid?: number;\r\n\tns?: number;\r\n}\r\n\r\nexport function getPagesInCategoryTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-pages-in-category',\r\n\t\t'Get all pages in a category',\r\n\t\t{\r\n\t\t\tcategory: z.string().describe( 'Category name (with or without Category: prefix)' )\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get pages in category',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { category } ) => handleGetPagesInCategoryTool( category )\r\n\t);\r\n}\r\n\r\nasync function handleGetPagesInCategoryTool(\r\n\tcategory: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\r\n\t\t// Remove \"Category:\" prefix if present\r\n\t\tconst cleanCategory = category.replace( /^Category:/i, '' );\r\n\r\n\t\tconst results = await promisifyBotMethod<PageInCategory[]>(\r\n\t\t\tbot,\r\n\t\t\t'getPagesInCategory',\r\n\t\t\tcleanCategory\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tcategory: cleanCategory,\r\n\t\t\tpages: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get pages in category', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getCategoriesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-categories',\r\n\t\t'Get all categories matching a prefix',\r\n\t\t{\r\n\t\t\tprefix: z.string().optional().default('').describe('Prefix to filter categories')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get categories',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { prefix } ) => handleGetCategoriesTool( prefix )\r\n\t);\r\n}\r\n\r\nasync function handleGetCategoriesTool(\r\n\tprefix: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst results = await promisifyBotMethod<string[]>(\r\n\t\t\tbot,\r\n\t\t\t'getCategories',\r\n\t\t\tprefix\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tprefix,\r\n\t\t\tcategories: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get categories', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserInfo extends Record<string, any> {\r\n\tname: string;\r\n\tuserid: number;\r\n}\r\n\r\nexport function getUsersTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-users',\r\n\t\t'Get all users matching a prefix',\r\n\t\t{\r\n\t\t\tprefix: z.string().optional().default('').describe('Prefix to filter usernames'),\r\n\t\t\tonlyWithEdits: z.boolean().optional().default(false).describe('Only include users with at least one edit')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get users',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { prefix, onlyWithEdits } ) => handleGetUsersTool( prefix, onlyWithEdits )\r\n\t);\r\n}\r\n\r\nasync function handleGetUsersTool(\r\n\tprefix: string,\r\n\tonlyWithEdits: boolean\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst results = await promisifyBotMethod<UserInfo[]>(\r\n\t\t\tbot,\r\n\t\t\t'getUsers',\r\n\t\t\t{ prefix, witheditsonly: onlyWithEdits }\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tprefix,\r\n\t\t\tonlyWithEdits,\r\n\t\t\tusers: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get users', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface AllPage extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getAllPagesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-all-pages',\r\n\t\t'Get all non-redirect pages from the wiki',\r\n\t\t{\r\n\t\t\tlimit: z.number().optional().default(500).describe('Maximum number of pages to return')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get all pages',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { limit } ) => handleGetAllPagesTool( limit )\r\n\t);\r\n}\r\n\r\nasync function handleGetAllPagesTool(\r\n\tlimit: number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst allResults = await promisifyBotMethod<AllPage[]>(\r\n\t\t\tbot,\r\n\t\t\t'getAllPages'\r\n\t\t);\r\n\r\n\t\t// Limit results\r\n\t\tconst results = allResults.slice(0, limit);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttotal: allResults.length,\r\n\t\t\tdisplayed: results.length,\r\n\t\t\tpages: results,\r\n\t\t\tlimit\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get all pages', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageInNamespace extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getPagesInNamespaceTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-pages-in-namespace',\r\n\t\t'Get all non-redirect pages in a specific namespace',\r\n\t\t{\r\n\t\t\tnamespace: z.number().describe('Namespace number to filter pages')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get pages in namespace',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { namespace } ) => handleGetPagesInNamespaceTool( namespace )\r\n\t);\r\n}\r\n\r\nasync function handleGetPagesInNamespaceTool(\r\n\tnamespace: number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst results = await promisifyBotMethod<PageInNamespace[]>(\r\n\t\t\tbot,\r\n\t\t\t'getPagesInNamespace',\r\n\t\t\tnamespace\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tnamespace,\r\n\t\t\tpages: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get pages in namespace', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageByPrefix extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getPagesByPrefixTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-pages-by-prefix',\r\n\t\t'Get pages starting with a specific prefix',\r\n\t\t{\r\n\t\t\tprefix: z.string().describe('Prefix to match page titles')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get pages by prefix',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { prefix } ) => handleGetPagesByPrefixTool( prefix )\r\n\t);\r\n}\r\n\r\nasync function handleGetPagesByPrefixTool(\r\n\tprefix: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst results = await promisifyBotMethod<PageByPrefix[]>(\r\n\t\t\tbot,\r\n\t\t\t'getPagesByPrefix',\r\n\t\t\tprefix\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tprefix,\r\n\t\t\tpages: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get pages by prefix', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface TranscludingPage extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getPagesTranscludingTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-pages-transcluding',\r\n\t\t'Get all pages that transclude (include) a specific template',\r\n\t\t{\r\n\t\t\ttemplate: z.string().describe('Template title to find transclusions')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get pages transcluding template',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { template } ) => handleGetPagesTranscludingTool( template )\r\n\t);\r\n}\r\n\r\nasync function handleGetPagesTranscludingTool(\r\n\ttemplate: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst callbackArgs = await promisifyBotMethod<[Error | null, TranscludingPage[] | [undefined]]>(\r\n\t\t\tbot,\r\n\t\t\t'getPagesTranscluding',\r\n\t\t\ttemplate\r\n\t\t);\r\n\r\n\t\t// Extract results from callback args (ignore first arg if it's error, which promisifyBotMethod already handles)\r\n\t\tconst rawResults = callbackArgs[1];\r\n\t\tconst results = Array.isArray(rawResults) \r\n\t\t\t? rawResults.filter((page): page is TranscludingPage => page != null && typeof page === 'object' && 'title' in page)\r\n\t\t\t: [];\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttemplate,\r\n\t\t\tpages: results,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get pages transcluding template', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Revision extends Record<string, any> {\r\n\trevid: number;\r\n\ttimestamp: string;\r\n\tuser: string;\r\n\tcomment: string;\r\n\tsize: number;\r\n}\r\n\r\nexport function getArticleRevisionsTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-article-revisions',\r\n\t\t'Get all revisions of a wiki article',\r\n\t\t{\r\n\t\t\ttitle: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get article revisions',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetArticleRevisionsTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetArticleRevisionsTool(\r\n\ttitle: string | number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst allRevisions = await promisifyBotMethod<Revision[][]>(\r\n\t\t\tbot,\r\n\t\t\t'getArticleRevisions',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\t// Flatten the results\r\n\t\tconst revisions = allRevisions.flat();\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\trevisions,\r\n\t\t\tcount: revisions.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get article revisions', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getArticleCategoriesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-article-categories',\r\n\t\t'Get all categories that an article belongs to',\r\n\t\t{\r\n\t\t\ttitle: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get article categories',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetArticleCategoriesTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetArticleCategoriesTool(\r\n\ttitle: string | number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst categories = await promisifyBotMethod<string[]>(\r\n\t\t\tbot,\r\n\t\t\t'getArticleCategories',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\tcategories,\r\n\t\t\tcount: categories.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get article categories', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageProperties extends Record<string, any> {\r\n\t[key: string]: string | undefined;\r\n}\r\n\r\nexport function getArticlePropertiesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-article-properties',\r\n\t\t'Get page properties for a wiki article',\r\n\t\t{\r\n\t\t\ttitle: z.string().describe('Article title')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get article properties',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetArticlePropertiesTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetArticlePropertiesTool(\r\n\ttitle: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst properties = await promisifyBotMethod<PageProperties>(\r\n\t\t\tbot,\r\n\t\t\t'getArticleProperties',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\tproperties\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get article properties', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ArticleInfo extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getArticleInfoTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-article-info',\r\n\t\t'Get detailed information about one or more articles',\r\n\t\t{\r\n\t\t\ttitle: z.union([\r\n\t\t\t\tz.string(),\r\n\t\t\t\tz.number(),\r\n\t\t\t\tz.array(z.union([z.string(), z.number()]))\r\n\t\t\t]).describe('Article title, page ID, or array of titles/IDs'),\r\n\t\t\tproperties: z.array(z.string()).optional().describe('Specific properties to retrieve')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get article info',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title, properties } ) => handleGetArticleInfoTool( title, properties )\r\n\t);\r\n}\r\n\r\nasync function handleGetArticleInfoTool(\r\n\ttitle: string | number | (string | number)[],\r\n\tproperties?: string[]\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst options = properties ? { inprop: properties } : {};\r\n\t\tconst info = await promisifyBotMethod<ArticleInfo>(\r\n\t\t\tbot,\r\n\t\t\t'getArticleInfo',\r\n\t\t\ttitle,\r\n\t\t\toptions\r\n\t\t);\r\n\r\n\t\t// Handle array of results vs single result\r\n\t\tconst results = Array.isArray(info) ? info : [info];\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\tresults,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get article info', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserContrib extends Record<string, any> {\r\n\ttitle: string;\r\n\trevid: number;\r\n\ttimestamp: string;\r\n\tcomment: string;\r\n}\r\n\r\nexport function getUserContribsTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-user-contribs',\r\n\t\t'Get contributions made by a specific user',\r\n\t\t{\r\n\t\t\tusername: z.string().describe('Username to get contributions for'),\r\n\t\t\tnamespace: z.number().optional().describe('Filter contributions by namespace'),\r\n\t\t\tlimit: z.number().optional().default(50).describe('Maximum number of contributions to return')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get user contributions',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { username, namespace, limit } ) => handleGetUserContribsTool( username, namespace, limit )\r\n\t);\r\n}\r\n\r\nasync function handleGetUserContribsTool(\r\n\tusername: string,\r\n\tnamespace?: number,\r\n\tlimit: number = 50\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst options = {\r\n\t\t\tuser: username,\r\n\t\t\t...(namespace !== undefined && { namespace })\r\n\t\t};\r\n\r\n\t\tconst callbackArgs = await promisifyBotMethod<[Error | null, UserContrib[], string | boolean]>(\r\n\t\t\tbot,\r\n\t\t\t'getUserContribs',\r\n\t\t\toptions\r\n\t\t);\r\n\r\n\t\tconst contribs = Array.isArray(callbackArgs[1]) ? callbackArgs[1] : [];\r\n\r\n\t\t// Limit results\r\n\t\tconst limitedContribs = contribs.slice(0, limit);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tusername,\r\n\t\t\tnamespace,\r\n\t\t\tlimit,\r\n\t\t\ttotal: contribs.length,\r\n\t\t\tdisplayed: limitedContribs.length,\r\n\t\t\tcontributions: limitedContribs\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get user contributions', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserInfo extends Record<string, any> {\r\n\tname: string;\r\n\tid: number;\r\n\tgroups: string[];\r\n\trights: string[];\r\n}\r\n\r\nexport function whoamiTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'whoami',\r\n\t\t'Get information about the currently logged in user',\r\n\t\t{},\r\n\t\t{\r\n\t\t\ttitle: 'Who am I',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync () => handleWhoamiTool()\r\n\t);\r\n}\r\n\r\nasync function handleWhoamiTool(): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst userInfo = await promisifyBotMethod<UserInfo>(\r\n\t\t\tbot,\r\n\t\t\t'whoami'\r\n\t\t);\r\n\r\n\t\treturn jsonResult(userInfo);\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get current user info', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface WhoisUserInfo extends Record<string, any> {\r\n\tname: string;\r\n\tuserid: number;\r\n\tgroups: string[];\r\n\trights: string[];\r\n}\r\n\r\nexport function whoisTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'whois',\r\n\t\t'Get information about a specific user',\r\n\t\t{\r\n\t\t\tusername: z.string().describe('Username to look up')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Whois',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { username } ) => handleWhoisTool( username )\r\n\t);\r\n}\r\n\r\nasync function handleWhoisTool(\r\n\tusername: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst userInfo = await promisifyBotMethod<WhoisUserInfo & { missing?: string }>(\r\n\t\t\tbot,\r\n\t\t\t'whois',\r\n\t\t\tusername\r\n\t\t);\r\n\r\n\t\tif (userInfo.missing) {\r\n\t\t\treturn errorResult(`User \"${username}\" not found.`);\r\n\t\t}\r\n\r\n\t\treturn jsonResult(userInfo);\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get user info', error as Error);\r\n\t}\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function whoareTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'whoare',\n\t\t'Get information about multiple wiki users',\n\t\t{\n\t\t\tusernames: z.array( z.string() ).describe( 'Array of usernames to query' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Who are',\n\t\t\treadOnlyHint: true,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleWhoareTool( params )\n\t);\n}\n\nasync function handleWhoareTool(\n\tparams: {\n\t\tusernames: string[];\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\n\t\tconst users = await promisifyBotMethod<any[]>(\n\t\t\tbot,\n\t\t\t'whoare',\n\t\t\tparams.usernames\n\t\t);\n\n\t\treturn jsonResult(users);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to get user information', error as Error);\n\t}\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Image extends Record<string, any> {\r\n\tname: string;\r\n\timg_timestamp: string;\r\n\tuser: string;\r\n}\r\n\r\nexport function getImagesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-images',\r\n\t\t'Get list of images starting from a specific name',\r\n\t\t{\r\n\t\t\tstartFrom: z.string().optional().default('').describe('Start from this image name'),\r\n\t\t\tlimit: z.number().optional().default(50).describe('Maximum number of images to return')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get images',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { startFrom, limit } ) => handleGetImagesTool( startFrom, limit )\r\n\t);\r\n}\r\n\r\nasync function handleGetImagesTool(\r\n\tstartFrom: string,\r\n\tlimit: number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\t// getImages has a different callback signature - let's handle it manually\r\n\t\tconst images = await new Promise<Image[]>((resolve, reject) => {\r\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t\t(bot as any).getImages(startFrom, (err: Error | null, ...args: any[]) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\treject(err);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst imgs = args[0];\r\n\t\t\t\t\tresolve(Array.isArray(imgs) ? imgs : []);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// Limit results\r\n\t\tconst limitedImages = images.slice(0, limit);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttotal: images.length,\r\n\t\t\tlimit,\r\n\t\t\tstartFrom,\r\n\t\t\timages: limitedImages\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get images', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ArticleImage extends Record<string, any> {\r\n\ttitle: string;\r\n\tns: number;\r\n}\r\n\r\nexport function getImagesFromArticleTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-images-from-article',\r\n\t\t'Get all images embedded in a specific article',\r\n\t\t{\r\n\t\t\ttitle: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get images from article',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetImagesFromArticleTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetImagesFromArticleTool(\r\n\ttitle: string | number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst images = await promisifyBotMethod<ArticleImage[]>(\r\n\t\t\tbot,\r\n\t\t\t'getImagesFromArticle',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\timages,\r\n\t\t\tcount: images.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get images from article', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type {CallToolResult, ToolAnnotations} from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ImageUsage extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n\tns: number;\r\n}\r\n\r\nexport function getImageUsageTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-image-usage',\r\n\t\t'Get all pages that use a specific image',\r\n\t\t{\r\n\t\t\tfilename: z.string().describe('Image filename with File: prefix')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get image usage',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { filename } ) => handleGetImageUsageTool( filename )\r\n\t);\r\n}\r\n\r\nasync function handleGetImageUsageTool(\r\n\tfilename: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst pages = await promisifyBotMethod<ImageUsage[]>(\r\n\t\t\tbot,\r\n\t\t\t'getImageUsage',\r\n\t\t\tfilename\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tfilename,\r\n\t\t\tpages,\r\n\t\t\tcount: pages.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get image usage', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ImageInfo extends Record<string, any> {\r\n\ttimestamp: string;\r\n\tuser: string;\r\n\twidth: number;\r\n\theight: number;\r\n\tsize: number;\r\n\turl: string;\r\n\tdescriptionurl: string;\r\n\texif?: Record<string, string>;\r\n}\r\n\r\nexport function getImageInfoTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-image-info',\r\n\t\t'Get detailed information about an image file',\r\n\t\t{\r\n\t\t\tfilename: z.string().describe('Image filename with File: prefix')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get image info',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { filename } ) => handleGetImageInfoTool( filename )\r\n\t);\r\n}\r\n\r\nasync function handleGetImageInfoTool(\r\n\tfilename: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst info = await promisifyBotMethod<ImageInfo | undefined>(\r\n\t\t\tbot,\r\n\t\t\t'getImageInfo',\r\n\t\t\tfilename\r\n\t\t);\r\n\r\n\t\tif (!info) {\r\n\t\t\treturn errorResult(`Image \"${filename}\" not found.`);\r\n\t\t}\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tfilename,\r\n\t\t\tinfo\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get image info', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface LogEntry extends Record<string, any> {\r\n\ttitle: string;\r\n\ttimestamp: string;\r\n\tuser: string;\r\n\taction: string;\r\n\tcomment: string;\r\n}\r\n\r\nexport function getLogTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-log',\r\n\t\t'Get log entries of a specific type',\r\n\t\t{\r\n\t\t\ttype: z.string().describe('Log type (e.g. delete, block, move)'),\r\n\t\t\tstart: z.string().optional().default('').describe('Start timestamp (YYYYMMDDHHMMSS format)'),\r\n\t\t\tlimit: z.number().optional().default(50).describe('Maximum number of entries to return')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get log entries',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { type, start, limit } ) => handleGetLogTool( type, start, limit )\r\n\t);\r\n}\r\n\r\nasync function handleGetLogTool(\r\n\ttype: string,\r\n\tstart: string,\r\n\tlimit: number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\t// Handle getLog's callback signature manually\r\n\t\tconst entries = await new Promise<LogEntry[]>((resolve, reject) => {\r\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t\t(bot as any).getLog(type, start, (err: Error | null, ...args: any[]) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\treject(err);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst ents = args[0];\r\n\t\t\t\t\tresolve(Array.isArray(ents) ? ents : []);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// Limit results\r\n\t\tconst limitedEntries = entries.slice(0, limit);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttype,\r\n\t\t\tstart,\r\n\t\t\tlimit,\r\n\t\t\ttotal: entries.length,\r\n\t\t\tdisplayed: limitedEntries.length,\r\n\t\t\tentries: limitedEntries\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get log entries', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function expandTemplatesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'expand-templates',\r\n\t\t'Expand templates in wikitext',\r\n\t\t{\r\n\t\t\ttext: z.string().describe('Wikitext with templates to expand'),\r\n\t\t\ttitle: z.string().optional().describe('Context page title'),\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Expand templates',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { text, title } ) => handleExpandTemplatesTool( text, title )\r\n\t);\r\n}\r\n\r\nasync function handleExpandTemplatesTool(\r\n\ttext: string,\r\n\ttitle?: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst expandedXml = await promisifyBotMethod<string>(\r\n\t\t\tbot,\r\n\t\t\t'expandTemplates',\r\n\t\t\ttext,\r\n\t\t\ttitle || ''\r\n\t\t);\r\n\r\n\t\treturn {\r\n\t\t\tcontent: [ { type: 'text', text: expandedXml } ]\r\n\t\t};\r\n\t} catch ( error ) {\r\n\t\treturn {\r\n\t\t\tcontent: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n\t\t\tisError: true\r\n\t\t};\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function parseTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'parse',\r\n\t\t'Parse wikitext to HTML',\r\n\t\t{\r\n\t\t\ttext: z.string().describe('Wikitext to parse'),\r\n\t\t\ttitle: z.string().optional().describe('Context page title')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Parse wikitext',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { text, title } ) => handleParseTool( text, title )\r\n\t);\r\n}\r\n\r\nasync function handleParseTool(\r\n\ttext: string,\r\n\ttitle?: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst callbackArgs = await promisifyBotMethod<[Error | null, string, string[]]>(\r\n\t\t\tbot,\r\n\t\t\t'parse',\r\n\t\t\ttext,\r\n\t\t\ttitle || ''\r\n\t\t);\r\n\r\n\t\tconst xml = callbackArgs[1] || '';\r\n\t\tconst images = Array.isArray(callbackArgs[2]) ? callbackArgs[2] : [];\r\n\r\n\t\tconst output = [\r\n\t\t\t'Parsed XML structure:',\r\n\t\t\t'',\r\n\t\t\txml,\r\n\t\t\t'',\r\n\t\t\t`Images found: ${images.length > 0 ? images.join(', ') : 'none'}`\r\n\t\t].join( '\\n' );\r\n\r\n\t\treturn {\r\n\t\t\tcontent: [ { type: 'text', text: output } ]\r\n\t\t};\r\n\t} catch ( error ) {\r\n\t\treturn {\r\n\t\t\tcontent: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n\t\t\tisError: true\r\n\t\t};\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface RecentChange extends Record<string, any> {\r\n\ttitle: string;\r\n\ttimestamp: string;\r\n\tuser: string;\r\n\tcomment: string;\r\n}\r\n\r\nexport function getRecentChangesTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-recent-changes',\r\n\t\t'Get recent changes on the wiki',\r\n\t\t{\r\n\t\t\tstart: z.string().optional().describe('Start timestamp'),\r\n\t\t\tlimit: z.number().optional().default(50).describe('Maximum number of changes to return')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get recent changes',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { start, limit } ) => handleGetRecentChangesTool( start, limit )\r\n\t);\r\n}\r\n\r\nasync function handleGetRecentChangesTool(\r\n\tstart?: string,\r\n\tlimit: number = 50\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\t// Handle getRecentChanges's callback signature manually\r\n\t\tconst changes = await new Promise<RecentChange[]>((resolve, reject) => {\r\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t\t(bot as any).getRecentChanges(start, (err: Error | null, ...args: any[]) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\treject(err);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst chgs = args[0];\r\n\t\t\t\t\tresolve(Array.isArray(chgs) ? chgs : []);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// Limit results\r\n\t\tconst limitedChanges = changes.slice(0, limit);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttotal: changes.length,\r\n\t\t\tlimit,\r\n\t\t\tstart,\r\n\t\t\tchanges: limitedChanges\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get recent changes', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getSiteInfoTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-site-info',\r\n\t\t'Get site information from MediaWiki',\r\n\t\t{\r\n\t\t\tproperties: z.array(z.string()).describe('List of site information properties to retrieve')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get site info',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { properties } ) => handleGetSiteInfoTool( properties )\r\n\t);\r\n}\r\n\r\nasync function handleGetSiteInfoTool(\r\n\tproperties: string[]\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst info = await promisifyBotMethod<Record<string, unknown>>(\r\n\t\t\tbot,\r\n\t\t\t'getSiteInfo',\r\n\t\t\tproperties\r\n\t\t);\r\n\r\n\t\treturn jsonResult(info || {});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get site info', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface SiteStats extends Record<string, any> {\r\n\tpages: number;\r\n\tarticles: number;\r\n\tedits: number;\r\n\timages: number;\r\n\tusers: number;\r\n\tactiveusers: number;\r\n\tadmins: number;\r\n\tjobs: number;\r\n}\r\n\r\nexport function getSiteStatsTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-site-stats',\r\n\t\t'Get site statistics',\r\n\t\t{},\r\n\t\t{\r\n\t\t\ttitle: 'Get site stats',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync () => handleGetSiteStatsTool()\r\n\t);\r\n}\r\n\r\nasync function handleGetSiteStatsTool(): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst stats = await promisifyBotMethod<SiteStats>(\r\n\t\t\tbot,\r\n\t\t\t'getSiteStats'\r\n\t\t);\r\n\r\n\t\treturn jsonResult(stats);\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get site stats', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getMediaWikiVersionTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-mediawiki-version',\r\n\t\t'Get MediaWiki version running on the server',\r\n\t\t{},\r\n\t\t{\r\n\t\t\ttitle: 'Get MediaWiki version',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync () => handleGetMediaWikiVersionTool()\r\n\t);\r\n}\r\n\r\nasync function handleGetMediaWikiVersionTool(): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst version = await promisifyBotMethod<string>(\r\n\t\t\tbot,\r\n\t\t\t'getMediaWikiVersion'\r\n\t\t);\r\n\r\n\t\treturn jsonResult({ version });\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get MediaWiki version', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface QueryPageResult extends Record<string, any> {\r\n\ttitle: string;\r\n\tvalue: number;\r\n}\r\n\r\nexport function getQueryPageTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-query-page',\r\n\t\t'Get results from a query page (special page)',\r\n\t\t{\r\n\t\t\tname: z.string().describe('Name of the query page')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get query page results',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { name } ) => handleGetQueryPageTool( name )\r\n\t);\r\n}\r\n\r\nasync function handleGetQueryPageTool(\r\n\tname: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst results = await promisifyBotMethod<QueryPageResult[]>(\r\n\t\t\tbot,\r\n\t\t\t'getQueryPage',\r\n\t\t\tname\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\tname,\r\n\t\t\tresults,\r\n\t\t\tcount: results.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get query page results', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ExternalLink extends Record<string, any> {\r\n\t'*': string;\r\n}\r\n\r\nexport function getExternalLinksTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-external-links',\r\n\t\t'Get all external links from an article',\r\n\t\t{\r\n\t\t\ttitle: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get external links',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetExternalLinksTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetExternalLinksTool(\r\n\ttitle: string | number\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst links = await promisifyBotMethod<ExternalLink[]>(\r\n\t\t\tbot,\r\n\t\t\t'getExternalLinks',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttitle,\r\n\t\t\tlinks: links.map(link => link['*']),\r\n\t\t\tcount: links.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get external links', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Backlink extends Record<string, any> {\r\n\ttitle: string;\r\n\tpageid: number;\r\n}\r\n\r\nexport function getBacklinksTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'get-backlinks',\r\n\t\t'Get all backlinks to a specific page',\r\n\t\t{\r\n\t\t\ttitle: z.string().describe('Target page title to find backlinks for')\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Get backlinks',\r\n\t\t\treadOnlyHint: true,\r\n\t\t\tdestructiveHint: false\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( { title } ) => handleGetBacklinksTool( title )\r\n\t);\r\n}\r\n\r\nasync function handleGetBacklinksTool(\r\n\ttitle: string\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst backlinks = await promisifyBotMethod<Backlink[]>(\r\n\t\t\tbot,\r\n\t\t\t'getBacklinks',\r\n\t\t\ttitle\r\n\t\t);\r\n\r\n\t\treturn jsonResult({\r\n\t\t\ttarget: title,\r\n\t\t\tbacklinks,\r\n\t\t\tcount: backlinks.length\r\n\t\t});\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to get backlinks', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function editTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'edit',\r\n\t\t'Edit a wiki page (requires authentication)',\r\n\t\t{\r\n\t\t\ttitle: z.string().describe( 'Page title to edit' ),\r\n\t\t\tcontent: z.string().describe( 'New content for the page' ),\r\n\t\t\tsummary: z.string().describe( 'Edit summary' ),\r\n\t\t\tminor: z.boolean().optional().default( false ).describe( 'Mark as minor edit' )\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Edit page',\r\n\t\t\treadOnlyHint: false,\r\n\t\t\tdestructiveHint: true\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( params ) => handleEditTool( params )\r\n\t);\r\n}\r\n\r\nasync function handleEditTool(\r\n\tparams: {\r\n\t\ttitle: string;\r\n\t\tcontent: string;\r\n\t\tsummary: string;\r\n\t\tminor?: boolean;\r\n\t}\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst prefixedSummary = `[nodemw-mcp] ${params.summary}`;\r\n\r\n\t\tconst result = await promisifyBotMethod<{\r\n\t\t\ttitle: string;\r\n\t\t\tpageid?: number;\r\n\t\t\toldrevid?: number;\r\n\t\t\tnewrevid?: number;\r\n\t\t}>(\r\n\t\t\tbot,\r\n\t\t\t'edit',\r\n\t\t\tparams.title,\r\n\t\t\tparams.content,\r\n\t\t\tprefixedSummary,\r\n\t\t\tparams.minor || false\r\n\t\t);\r\n\r\n\t\treturn jsonResult(result);\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to edit page', error as Error);\r\n\t}\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function appendTool( server: McpServer ): RegisteredTool {\r\n\treturn server.tool(\r\n\t\t'append',\r\n\t\t'Append content to a wiki page (requires authentication)',\r\n\t\t{\r\n\t\t\ttitle: z.string().describe( 'Page title' ),\r\n\t\t\tcontent: z.string().describe( 'Content to append' ),\r\n\t\t\tsummary: z.string().describe( 'Edit summary' )\r\n\t\t},\r\n\t\t{\r\n\t\t\ttitle: 'Append to page',\r\n\t\t\treadOnlyHint: false,\r\n\t\t\tdestructiveHint: true\r\n\t\t} as ToolAnnotations,\r\n\t\tasync ( params ) => handleAppendTool( params )\r\n\t);\r\n}\r\n\r\nasync function handleAppendTool(\r\n\tparams: {\r\n\t\ttitle: string;\r\n\t\tcontent: string;\r\n\t\tsummary: string;\r\n\t}\r\n): Promise<CallToolResult> {\r\n\ttry {\r\n\t\tconst bot = await getBot();\r\n\t\tconst prefixedSummary = `[nodemw-mcp] ${params.summary}`;\r\n\r\n\t\tawait promisifyBotMethod<void>(\r\n\t\t\tbot,\r\n\t\t\t'append',\r\n\t\t\tparams.title,\r\n\t\t\tparams.content,\r\n\t\t\tprefixedSummary\r\n\t\t);\r\n\r\n\t\treturn jsonResult({ success: true, title: params.title });\r\n\t} catch ( error ) {\r\n\t\treturn errorResult('Failed to append to page', error as Error);\r\n\t}\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function prependTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'prepend',\n\t\t'Prepend content to a wiki page (requires authentication)',\n\t\t{\n\t\t\ttitle: z.string().describe( 'Page title to prepend to' ),\n\t\t\tcontent: z.string().describe( 'Content to prepend' ),\n\t\t\tsummary: z.string().describe( 'Edit summary' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Prepend to page',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: true\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handlePrependTool( params )\n\t);\n}\n\nasync function handlePrependTool(\n\tparams: {\n\t\ttitle: string;\n\t\tcontent: string;\n\t\tsummary: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst prefixedSummary = `[nodemw-mcp] ${params.summary}`;\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\ttitle: string;\n\t\t\tpageid?: number;\n\t\t\toldrevid?: number;\n\t\t\tnewrevid?: number;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'prepend',\n\t\t\tparams.title,\n\t\t\tparams.content,\n\t\t\tprefixedSummary\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to prepend to page', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function moveTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'move',\n\t\t'Move (rename) a wiki page (requires authentication)',\n\t\t{\n\t\t\tfrom: z.string().describe( 'Current page title' ),\n\t\t\tto: z.string().describe( 'New page title' ),\n\t\t\tsummary: z.string().describe( 'Move summary' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Move page',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: true\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleMoveTool( params )\n\t);\n}\n\nasync function handleMoveTool(\n\tparams: {\n\t\tfrom: string;\n\t\tto: string;\n\t\tsummary: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst prefixedSummary = `[nodemw-mcp] ${params.summary}`;\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\tfrom: string;\n\t\t\tto: string;\n\t\t\treason: string;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'move',\n\t\t\tparams.from,\n\t\t\tparams.to,\n\t\t\tprefixedSummary\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to move page', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function deleteTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'delete',\n\t\t'Delete a wiki page (requires authentication)',\n\t\t{\n\t\t\ttitle: z.string().describe( 'Page title to delete' ),\n\t\t\treason: z.string().describe( 'Reason for deletion' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Delete page',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: true\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleDeleteTool( params )\n\t);\n}\n\nasync function handleDeleteTool(\n\tparams: {\n\t\ttitle: string;\n\t\treason: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst prefixedReason = `[nodemw-mcp] ${params.reason}`;\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\ttitle: string;\n\t\t\treason: string;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'delete',\n\t\t\tparams.title,\n\t\t\tprefixedReason\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to delete page', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function protectTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'protect',\n\t\t'Protect a wiki page (requires authentication)',\n\t\t{\n\t\t\ttitle: z.string().describe( 'Page title to protect' ),\n\t\t\tprotections: z.array(\n\t\t\t\tz.object({\n\t\t\t\t\ttype: z.string().describe( 'Action type (e.g., edit, move)' ),\n\t\t\t\t\tlevel: z.string().optional().default('all').describe( 'Protection level (e.g., sysop, autoconfirmed)' ),\n\t\t\t\t\texpiry: z.string().optional().describe( 'Expiry time (e.g., 1 week, never)' )\n\t\t\t\t})\n\t\t\t).describe( 'Protection settings' ),\n\t\t\treason: z.string().optional().describe( 'Reason for protection' ),\n\t\t\tcascade: z.boolean().optional().default(false).describe( 'Apply cascade protection' )\n\t\t},\n\t\t{\n\t\t\ttitle: 'Protect page',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: true\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleProtectTool( params )\n\t);\n}\n\nasync function handleProtectTool(\n\tparams: {\n\t\ttitle: string;\n\t\tprotections: Array<{ type: string; level?: string; expiry?: string }>;\n\t\treason?: string;\n\t\tcascade?: boolean;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst options: any = {};\n\t\tif (params.reason) {\n\t\t\toptions.reason = `[nodemw-mcp] ${params.reason}`;\n\t\t}\n\t\tif (params.cascade) {\n\t\t\toptions.cascade = params.cascade;\n\t\t}\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\ttitle: string;\n\t\t\tprotections: any[];\n\t\t}>(\n\t\t\tbot,\n\t\t\t'protect',\n\t\t\tparams.title,\n\t\t\tparams.protections,\n\t\t\toptions\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to protect page', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function purgeTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'purge',\n\t\t'Purge cache for wiki pages',\n\t\t{\n\t\t\ttitles: z.union([z.string(), z.array(z.string())]).describe( 'Page title(s) or category to purge' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Purge pages',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handlePurgeTool( params )\n\t);\n}\n\nasync function handlePurgeTool(\n\tparams: {\n\t\ttitles: string | string[];\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\n\t\tconst result = await promisifyBotMethod<any[]>(\n\t\t\tbot,\n\t\t\t'purge',\n\t\t\tparams.titles\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to purge pages', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function sendEmailTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'send-email',\n\t\t'Send email to a wiki user (requires authentication)',\n\t\t{\n\t\t\tusername: z.string().describe( 'Username to email' ),\n\t\t\tsubject: z.string().describe( 'Email subject' ),\n\t\t\ttext: z.string().describe( 'Email content' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Send email',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleSendEmailTool( params )\n\t);\n}\n\nasync function handleSendEmailTool(\n\tparams: {\n\t\tusername: string;\n\t\tsubject: string;\n\t\ttext: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\tresult: string;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'sendEmail',\n\t\t\tparams.username,\n\t\t\tparams.subject,\n\t\t\tparams.text\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to send email', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function uploadTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'upload',\n\t\t'Upload a file to wiki (requires authentication)',\n\t\t{\n\t\t\tfilename: z.string().describe( 'Destination filename on wiki' ),\n\t\t\tcontent: z.string().describe( 'File content as base64 string' ),\n\t\t\tcomment: z.string().optional().describe( 'Upload comment' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Upload file',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleUploadTool( params )\n\t);\n}\n\nasync function handleUploadTool(\n\tparams: {\n\t\tfilename: string;\n\t\tcontent: string;\n\t\tcomment?: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst fileContent = Buffer.from(params.content, 'base64');\n\t\tconst comment = params.comment ? `[nodemw-mcp] ${params.comment}` : '[nodemw-mcp] File upload';\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\tresult: string;\n\t\t\tfilename: string;\n\t\t\timageinfo?: any;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'upload',\n\t\t\tparams.filename,\n\t\t\tfileContent,\n\t\t\tcomment\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to upload file', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function uploadByUrlTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'upload-by-url',\n\t\t'Upload a file to wiki from URL (requires authentication)',\n\t\t{\n\t\t\tfilename: z.string().describe( 'Destination filename on wiki' ),\n\t\t\turl: z.string().url().describe( 'Source URL to download file from' ),\n\t\t\tsummary: z.string().optional().describe( 'Upload summary' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Upload file by URL',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleUploadByUrlTool( params )\n\t);\n}\n\nasync function handleUploadByUrlTool(\n\tparams: {\n\t\tfilename: string;\n\t\turl: string;\n\t\tsummary?: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\t\tconst prefixedSummary = params.summary ? `[nodemw-mcp] ${params.summary}` : '[nodemw-mcp] File upload from URL';\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\tresult: string;\n\t\t\tfilename: string;\n\t\t\timageinfo?: any;\n\t\t}>(\n\t\t\tbot,\n\t\t\t'uploadByUrl',\n\t\t\tparams.filename,\n\t\t\tparams.url,\n\t\t\tprefixedSummary\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to upload file by URL', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function addFlowTopicTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'add-flow-topic',\n\t\t'Add a new Flow topic to a wiki page (requires authentication)',\n\t\t{\n\t\t\ttitle: z.string().describe( 'Page title to add topic to' ),\n\t\t\tsubject: z.string().describe( 'Topic subject' ),\n\t\t\tcontent: z.string().describe( 'Topic content in wikitext' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Add Flow topic',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleAddFlowTopicTool( params )\n\t);\n}\n\nasync function handleAddFlowTopicTool(\n\tparams: {\n\t\ttitle: string;\n\t\tsubject: string;\n\t\tcontent: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\n\t\tconst result = await promisifyBotMethod<{\n\t\t\t'new-topic': {\n\t\t\t\tstatus: string;\n\t\t\t\tworkflow: string;\n\t\t\t};\n\t\t}>(\n\t\t\tbot,\n\t\t\t'addFlowTopic',\n\t\t\tparams.title,\n\t\t\tparams.subject,\n\t\t\tparams.content\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to add Flow topic', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function createAccountTool( server: McpServer ): RegisteredTool {\n\treturn server.tool(\n\t\t'create-account',\n\t\t'Create a new MediaWiki user account (requires authentication)',\n\t\t{\n\t\t\tusername: z.string().describe( 'New account username' ),\n\t\t\tpassword: z.string().describe( 'New account password' ),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Create user account',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: false\n\t\t} as ToolAnnotations,\n\t\tasync ( params ) => handleCreateAccountTool( params )\n\t);\n}\n\nasync function handleCreateAccountTool(\n\tparams: {\n\t\tusername: string;\n\t\tpassword: string;\n\t}\n): Promise<CallToolResult> {\n\ttry {\n\t\tconst bot = await getBot();\n\n\t\tconst result = await promisifyBotMethod<any>(\n\t\t\tbot,\n\t\t\t'createAccount',\n\t\t\tparams.username,\n\t\t\tparams.password\n\t\t);\n\n\t\treturn jsonResult(result);\n\t} catch ( error ) {\n\t\treturn errorResult('Failed to create account', error as Error);\n\t}\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\n\n// Read tools\nimport { getArticleTool } from './ro/get-article.js';\nimport { searchTool } from './ro/search.js';\nimport { getPagesInCategoryTool } from './ro/get-pages-in-category.js';\nimport { getCategoriesTool } from './ro/get-categories.js';\nimport { getUsersTool } from './ro/get-users.js';\nimport { getAllPagesTool } from './ro/get-all-pages.js';\nimport { getPagesInNamespaceTool } from './ro/get-pages-in-namespace.js';\nimport { getPagesByPrefixTool } from './ro/get-pages-by-prefix.js';\nimport { getPagesTranscludingTool } from './ro/get-pages-transcluding.js';\nimport { getArticleRevisionsTool } from './ro/get-article-revisions.js';\nimport { getArticleCategoriesTool } from './ro/get-article-categories.js';\nimport { getArticlePropertiesTool } from './ro/get-article-properties.js';\nimport { getArticleInfoTool } from './ro/get-article-info.js';\nimport { getUserContribsTool } from './ro/get-user-contribs.js';\nimport { whoamiTool } from './ro/whoami.js';\nimport { whoisTool } from './ro/whois.js';\nimport { whoareTool } from './ro/whoare.js';\nimport { getImagesTool } from './ro/get-images.js';\nimport { getImagesFromArticleTool } from './ro/get-images-from-article.js';\nimport { getImageUsageTool } from './ro/get-image-usage.js';\nimport { getImageInfoTool } from './ro/get-image-info.js';\nimport { getLogTool } from './ro/get-log.js';\nimport { expandTemplatesTool } from './ro/expand-templates.js';\nimport { parseTool } from './ro/parse.js';\nimport { getRecentChangesTool } from './ro/get-recent-changes.js';\nimport { getSiteInfoTool } from './ro/get-site-info.js';\nimport { getSiteStatsTool } from './ro/get-site-stats.js';\nimport { getMediaWikiVersionTool } from './ro/get-mediawiki-version.js';\nimport { getQueryPageTool } from './ro/get-query-page.js';\nimport { getExternalLinksTool } from './ro/get-external-links.js';\nimport { getBacklinksTool } from './ro/get-backlinks.js';\n\n// Write tools\nimport { editTool } from './editing/edit.js';\nimport { appendTool } from './editing/append.js';\nimport { prependTool } from './editing/prepend.js';\nimport { moveTool } from './editing/move.js';\nimport { deleteTool } from './editing/delete.js';\nimport { protectTool } from './editing/protect.js';\nimport { purgeTool } from './editing/purge.js';\nimport { sendEmailTool } from './editing/send-email.js';\nimport { uploadTool } from './editing/upload.js';\nimport { uploadByUrlTool } from './editing/upload-by-url.js';\nimport { addFlowTopicTool } from './editing/add-flow-topic.js';\nimport { createAccountTool } from './editing/create-account.js';\n\nconst toolRegistrars = [\n\t// Read tools\n\tgetArticleTool,\n\tsearchTool,\n\tgetPagesInCategoryTool,\n\tgetCategoriesTool,\n\tgetUsersTool,\n\tgetAllPagesTool,\n\tgetPagesInNamespaceTool,\n\tgetPagesByPrefixTool,\n\tgetPagesTranscludingTool,\n\tgetArticleRevisionsTool,\n\tgetArticleCategoriesTool,\n\tgetArticlePropertiesTool,\n\tgetArticleInfoTool,\n\tgetUserContribsTool,\n\twhoamiTool,\n\twhoisTool,\n\twhoareTool,\n\tgetImagesTool,\n\tgetImagesFromArticleTool,\n\tgetImageUsageTool,\n\tgetImageInfoTool,\n\tgetLogTool,\n\texpandTemplatesTool,\n\tparseTool,\n\tgetRecentChangesTool,\n\tgetSiteInfoTool,\n\tgetSiteStatsTool,\n\tgetMediaWikiVersionTool,\n\tgetQueryPageTool,\n\tgetExternalLinksTool,\n\tgetBacklinksTool,\n\n\t// Write tools\n\teditTool,\n\tappendTool,\n\tprependTool,\n\tmoveTool,\n\tdeleteTool,\n\tprotectTool,\n\tpurgeTool,\n\tsendEmailTool,\n\tuploadTool,\n\tuploadByUrlTool,\n\taddFlowTopicTool,\n\tcreateAccountTool\n];\n\nexport function registerAllTools(server: McpServer): RegisteredTool[] {\n\tconst registeredTools: RegisteredTool[] = [];\n\tfor (const registrar of toolRegistrars) {\n\t\ttry {\n\t\t\tregisteredTools.push(registrar(server));\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error registering tool: ${(error as Error).message}`);\n\t\t}\n\t}\n\treturn registeredTools;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["StdioServerTransport", "parseArgs", "McpServer", "USER_AGENT", "createServer", "siteInfo", "description", "z", "Bot", "botInstance", "serverConfig", "initServerConfig", "config", "createBotFromConfig", "server", "path", "protocol", "port", "proxy", "userAgent", "concurrency", "debug", "username", "password", "domain", "dryRun", "Bot", "USER_AGENT", "testApiConnection", "bot", "promisifyBotMethod", "autoDetectPath", "baseConfig", "pathsToTry", "testConfig", "initBot", "resolve", "reject", "err", "getBot", "promisifyBotMethod", "bot", "method", "args", "resolve", "reject", "callback", "err", "result", "getArticleTool", "server", "z", "title", "followRedirect", "redirectInfo", "handleGetArticleTool", "bot", "getBot", "result", "resolve", "reject", "callback", "err", "content", "redirect", "promisifyBotMethod", "error", "z", "jsonResult", "data", "errorResult", "message", "error", "searchTool", "server", "z", "keyword", "limit", "handleSearchTool", "bot", "getBot", "results", "promisifyBotMethod", "limitedResults", "jsonResult", "error", "errorResult", "z", "getPagesInCategoryTool", "server", "z", "category", "handleGetPagesInCategoryTool", "bot", "getBot", "cleanCategory", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getCategoriesTool", "server", "z", "prefix", "handleGetCategoriesTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getUsersTool", "server", "z", "prefix", "onlyWithEdits", "handleGetUsersTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getAllPagesTool", "server", "z", "limit", "handleGetAllPagesTool", "bot", "getBot", "allResults", "promisifyBotMethod", "results", "jsonResult", "error", "errorResult", "z", "getPagesInNamespaceTool", "server", "z", "namespace", "handleGetPagesInNamespaceTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getPagesByPrefixTool", "server", "z", "prefix", "handleGetPagesByPrefixTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getPagesTranscludingTool", "server", "z", "template", "handleGetPagesTranscludingTool", "bot", "getBot", "rawResults", "promisifyBotMethod", "results", "page", "jsonResult", "error", "errorResult", "z", "getArticleRevisionsTool", "server", "z", "title", "handleGetArticleRevisionsTool", "bot", "getBot", "revisions", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticleCategoriesTool", "server", "z", "title", "handleGetArticleCategoriesTool", "bot", "getBot", "categories", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticlePropertiesTool", "server", "z", "title", "handleGetArticlePropertiesTool", "bot", "getBot", "properties", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticleInfoTool", "server", "z", "title", "properties", "handleGetArticleInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "results", "jsonResult", "error", "errorResult", "z", "getUserContribsTool", "server", "z", "username", "namespace", "limit", "handleGetUserContribsTool", "bot", "getBot", "options", "callbackArgs", "promisifyBotMethod", "contribs", "limitedContribs", "jsonResult", "error", "errorResult", "whoamiTool", "server", "handleWhoamiTool", "bot", "getBot", "userInfo", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "whoisTool", "server", "z", "username", "handleWhoisTool", "bot", "getBot", "userInfo", "promisifyBotMethod", "errorResult", "jsonResult", "error", "z", "whoareTool", "server", "z", "params", "handleWhoareTool", "bot", "getBot", "users", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImagesTool", "server", "z", "startFrom", "limit", "handleGetImagesTool", "bot", "getBot", "images", "resolve", "reject", "err", "args", "imgs", "limitedImages", "jsonResult", "error", "errorResult", "z", "getImagesFromArticleTool", "server", "z", "title", "handleGetImagesFromArticleTool", "bot", "getBot", "images", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImageUsageTool", "server", "z", "filename", "handleGetImageUsageTool", "bot", "getBot", "pages", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImageInfoTool", "server", "z", "filename", "handleGetImageInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "jsonResult", "errorResult", "error", "z", "getLogTool", "server", "z", "type", "start", "limit", "handleGetLogTool", "bot", "getBot", "entries", "resolve", "reject", "err", "args", "ents", "limitedEntries", "jsonResult", "error", "errorResult", "z", "expandTemplatesTool", "server", "z", "text", "title", "handleExpandTemplatesTool", "bot", "getBot", "promisifyBotMethod", "error", "z", "parseTool", "server", "z", "text", "title", "handleParseTool", "bot", "getBot", "callbackArgs", "promisifyBotMethod", "xml", "images", "error", "z", "getRecentChangesTool", "server", "z", "start", "limit", "handleGetRecentChangesTool", "bot", "getBot", "changes", "resolve", "reject", "err", "args", "chgs", "limitedChanges", "jsonResult", "error", "errorResult", "z", "getSiteInfoTool", "server", "z", "properties", "handleGetSiteInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "jsonResult", "error", "errorResult", "getSiteStatsTool", "server", "handleGetSiteStatsTool", "bot", "getBot", "stats", "promisifyBotMethod", "jsonResult", "error", "errorResult", "getMediaWikiVersionTool", "server", "handleGetMediaWikiVersionTool", "bot", "getBot", "version", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getQueryPageTool", "server", "z", "name", "handleGetQueryPageTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getExternalLinksTool", "server", "z", "title", "handleGetExternalLinksTool", "bot", "getBot", "links", "promisifyBotMethod", "jsonResult", "link", "error", "errorResult", "z", "getBacklinksTool", "server", "z", "title", "handleGetBacklinksTool", "bot", "getBot", "backlinks", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "editTool", "server", "z", "params", "handleEditTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "appendTool", "server", "z", "params", "handleAppendTool", "bot", "getBot", "prefixedSummary", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "prependTool", "server", "z", "params", "handlePrependTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "moveTool", "server", "z", "params", "handleMoveTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "deleteTool", "server", "z", "params", "handleDeleteTool", "bot", "getBot", "prefixedReason", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "protectTool", "server", "z", "params", "handleProtectTool", "bot", "getBot", "options", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "purgeTool", "server", "z", "params", "handlePurgeTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "sendEmailTool", "server", "z", "params", "handleSendEmailTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "uploadTool", "server", "z", "params", "handleUploadTool", "bot", "getBot", "fileContent", "comment", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "uploadByUrlTool", "server", "z", "params", "handleUploadByUrlTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "addFlowTopicTool", "server", "z", "params", "handleAddFlowTopicTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "createAccountTool", "server", "z", "params", "handleCreateAccountTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "
|
|
4
|
+
"sourcesContent": ["/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { parseArgs } from 'util';\nimport { createServer } from './server.js';\nimport { registerAllTools } from './tools/index.js';\nimport {\n initServerConfig,\n getBot,\n initBot,\n autoDetectPath,\n promisifyBotMethod,\n isAuthenticated,\n type ServerConfig\n} from './common/nodemwBot.js';\n\nfunction parseCliArgs(): { config: ServerConfig; pathExplicit: boolean } {\n const { values, positionals } = parseArgs({\n options: {\n server: { type: 'string', short: 's' },\n path: { type: 'string' },\n endpoint: { type: 'string' },\n user: { type: 'string', short: 'u' },\n pass: { type: 'string', short: 'p' },\n token: { type: 'string' },\n 'dry-run': { type: 'boolean' },\n },\n strict: false,\n allowPositionals: true,\n });\n\n // Server can be specified via --server/-s or as the first positional argument\n const serverUrl = (values.server as string) ?? positionals[0] ?? process.env.NODEMW_MCP_SERVER;\n if (!serverUrl) {\n console.error('Error: target server is required (-s, positional arg, or NODEMW_MCP_SERVER env)');\n process.exit(1);\n }\n let server: string;\n let protocol: string | undefined;\n let port: number | undefined;\n\n try {\n if (serverUrl.startsWith('http://') || serverUrl.startsWith('https://')) {\n const url = new URL(serverUrl);\n server = url.hostname;\n protocol = url.protocol.replace(':', '');\n if (url.port) {\n port = parseInt(url.port, 10);\n }\n } else {\n server = serverUrl;\n }\n } catch {\n server = serverUrl;\n }\n\n const pathFromEnv = process.env.NODEMW_MCP_ENDPOINT_PATH;\n const pathExplicit = !!(values.path ?? values.endpoint ?? pathFromEnv);\n\n return {\n config: {\n server,\n protocol,\n port,\n path: (values.path as string) ?? (values.endpoint as string) ?? pathFromEnv ?? '/w',\n username: (values.user as string) ?? process.env.NODEMW_MCP_MW_USER,\n password: (values.pass as string) ?? process.env.NODEMW_MCP_MW_PASS,\n token: values.token as string | undefined,\n dryRun: values['dry-run'] as boolean | undefined,\n },\n pathExplicit,\n };\n}\n\nasync function main(): Promise<void> {\n const { config, pathExplicit } = parseCliArgs();\n\n // Step 1: Auto-detect API path if not explicitly specified\n if (!pathExplicit) {\n try {\n config.path = await autoDetectPath(config);\n console.error(`Auto-detected API path: ${config.path}`);\n } catch (err) {\n console.error('Error:', (err as Error).message);\n process.exit(1);\n }\n }\n\n initServerConfig(config);\n\n // Step 2: Initialize bot \u2014 creates connection and logs in if credentials provided\n try {\n await initBot(config);\n } catch (err) {\n console.error('Error:', (err as Error).message);\n process.exit(1);\n }\n\n // Step 3: Fetch site info to enrich the server description\n const bot = getBot();\n let siteInfo: { sitename: string; base: string; generator: string } | undefined;\n try {\n const info = await promisifyBotMethod<{ general?: { sitename?: string; base?: string; generator?: string } }>(bot, 'getSiteInfo', ['general']);\n const general = info?.general;\n if (general) {\n siteInfo = {\n sitename: general.sitename || 'Unknown',\n base: general.base || '',\n generator: general.generator || 'MediaWiki',\n };\n }\n } catch {\n console.error('Warning: Could not fetch site info for server description.');\n }\n\n // Step 4: Create server with site-aware description\n const auth = isAuthenticated();\n const server = createServer(siteInfo, auth);\n registerAllTools(server, auth);\n\n // Step 5: Connect stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch(console.error);\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nexport const USER_AGENT = 'nodemw-mcp-server/1.0';\n\nexport interface SiteInfoSummary {\n sitename: string;\n base: string;\n generator: string;\n}\n\nexport function createServer(siteInfo?: SiteInfoSummary, authenticated = false): McpServer {\n let description: string;\n const authSuffix = authenticated\n ? ' Write operations are available.'\n : ' Running in guest mode \u2014 only read operations are available.';\n if (siteInfo) {\n description = `Connected to ${siteInfo.sitename} (${siteInfo.base}). Running ${siteInfo.generator}.${authSuffix} When connecting for the first time, call the get-site-info tool for full site details.`;\n } else {\n description = `When connecting to this server for the first time, call the get-site-info tool to understand the target MediaWiki site (version, namespaces, extensions, etc.) before using other tools.${authSuffix}`;\n }\n\n return new McpServer(\n {\n name: 'nodemw-mcp-server',\n version: '1.0.0',\n description\n },\n { capabilities: { tools: {} } }\n );\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function getArticleTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-article',\r\n 'Retrieve the content of a wiki article',\r\n {\r\n title: z.string().describe( 'Article title' ),\r\n followRedirect: z.boolean().optional().default( true ).describe( 'Follow redirects' ),\r\n redirectInfo: z.boolean().optional().default( false ).describe( 'Include information about redirects' )\r\n },\r\n {\r\n title: 'Get article',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title, followRedirect, redirectInfo } ) => handleGetArticleTool( title, followRedirect, redirectInfo )\r\n );\r\n}\r\n\r\nasync function handleGetArticleTool(\r\n title: string,\r\n followRedirect: boolean,\r\n redirectInfo: boolean\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n if (redirectInfo) {\r\n // When redirectInfo is requested, get both content and redirect info\r\n const result = await new Promise<[string, unknown]>((resolve, reject) => {\r\n const callback = (err: Error | null, content: string, redirectInfo: unknown) => {\r\n if (err) {\r\n reject(err);\r\n } else {\r\n resolve([content, redirectInfo]);\r\n }\r\n };\r\n\r\n // @ts-expect-error: any method call\r\n bot.getArticle(title, followRedirect, callback);\r\n });\r\n const [content, redirect] = result;\r\n if (content == null) {\r\n return {\r\n content: [{ type: 'text', text: `Page \"${title}\" not found or has no content.` }],\r\n isError: true\r\n };\r\n }\r\n const responseText = redirect\r\n ? `Content:\\n\\n${content}\\n\\nRedirect Information:\\n\\n${JSON.stringify(redirect, null, 2)}`\r\n : content;\r\n\r\n return {\r\n content: [ { type: 'text', text: responseText } ]\r\n };\r\n } else {\r\n // Original behavior: just return content\r\n const result = await promisifyBotMethod<string>(\r\n bot,\r\n 'getArticle',\r\n title,\r\n followRedirect\r\n );\r\n if (result == null) {\r\n return {\r\n content: [{ type: 'text', text: `Page \"${title}\" not found or has no content.` }],\r\n isError: true\r\n };\r\n }\r\n return {\r\n content: [ { type: 'text', text: result } ]\r\n };\r\n }\r\n } catch ( error ) {\r\n return {\r\n content: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n isError: true\r\n };\r\n }\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport Bot from 'nodemw';\nimport { USER_AGENT } from '../server.js';\n\nexport interface ServerConfig {\n server: string;\n path: string;\n protocol?: string;\n port?: number;\n proxy?: string;\n userAgent?: string;\n concurrency?: number;\n debug?: boolean;\n username?: string;\n password?: string;\n token?: string;\n domain?: string;\n dryRun?: boolean;\n}\n\nlet botInstance: Bot | null = null;\nlet serverConfig: ServerConfig | null = null;\nlet authenticated = false;\n\nexport function initServerConfig(config: ServerConfig): void {\n serverConfig = config;\n}\n\nfunction createBotFromConfig(config: ServerConfig): Bot {\n const {\n server,\n path,\n protocol,\n port,\n proxy,\n userAgent,\n concurrency,\n debug,\n username,\n password,\n domain,\n dryRun\n } = config;\n\n return new Bot({\n server,\n protocol: protocol || 'https',\n port,\n path,\n proxy,\n userAgent: userAgent || USER_AGENT,\n concurrency,\n debug,\n username: username || undefined,\n password: password || undefined,\n domain,\n // @ts-expect-error: dryRun is supported by nodemw at runtime but missing from BotOptions types\n dryRun\n });\n}\n\nasync function testApiConnection(bot: Bot): Promise<boolean> {\n try {\n await promisifyBotMethod(bot, 'getSiteInfo', ['general']);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function autoDetectPath(baseConfig: ServerConfig): Promise<string> {\n // nodemw constructs URL as ${server}${path}/api.php \u2014 so /w means /w/api.php, '' means /api.php\n const pathsToTry = ['/w', ''];\n for (const path of pathsToTry) {\n const testConfig = { ...baseConfig, path };\n const bot = createBotFromConfig(testConfig);\n if (await testApiConnection(bot)) {\n return path;\n }\n }\n throw new Error(\n 'Could not auto-detect MediaWiki API path. ' +\n 'Tried /w/api.php and /api.php. ' +\n 'Please specify --path explicitly (e.g., --path /w or --path \"\" for root).'\n );\n}\n\nexport async function initBot(config: ServerConfig): Promise<Bot> {\n botInstance = createBotFromConfig(config);\n\n const { username, password } = config;\n if (username && password) {\n await new Promise<void>((resolve, reject) => {\n botInstance!.logIn((err: Error | null) => {\n if (err) {\n reject(new Error(`Login failed for user '${username}': ${err.message}`));\n } else {\n authenticated = true;\n resolve();\n }\n });\n });\n }\n\n return botInstance;\n}\n\nexport function getBot(): Bot {\n if (!botInstance) {\n throw new Error('Bot not initialized. Server must be started first.');\n }\n return botInstance;\n}\n\nexport function clearBotCache(): void {\n botInstance = null;\n authenticated = false;\n}\n\nexport function isAuthenticated(): boolean {\n return authenticated;\n}\n\nexport function promisifyBotMethod<T>(\n bot: Bot,\n method: string,\n ...args: unknown[]\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const callback = (err: Error | null, result: T) => {\n if (err) {\n reject(err);\n } else {\n resolve(result);\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (bot as any)[method](...args, callback);\n });\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface SearchResult extends Record<string, any> {\r\n title: string;\r\n snippet?: string;\r\n url?: string;\r\n pageId?: number;\r\n}\r\n\r\nexport function searchTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'search',\r\n 'Search for wiki pages by keyword',\r\n {\r\n keyword: z.string().describe( 'Search keyword' ),\r\n limit: z.number().optional().default( 10 ).describe( 'Maximum number of results' )\r\n },\r\n {\r\n title: 'Search',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { keyword, limit } ) => handleSearchTool( keyword, limit )\r\n );\r\n}\r\n\r\nasync function handleSearchTool(\r\n keyword: string,\r\n limit: number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n\r\n // nodemw search returns array of results directly\r\n const results = await promisifyBotMethod<SearchResult[]>(\r\n bot,\r\n 'search',\r\n keyword\r\n );\r\n\r\n // Limit results\r\n const limitedResults = results.slice( 0, limit );\r\n\r\n return jsonResult({\r\n total: results.length,\r\n limit,\r\n keyword,\r\n results: limitedResults\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to search', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type Bot from 'nodemw';\r\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\r\n\r\nexport function promisifyBotMethod<T>(\r\n bot: Bot,\r\n method: string,\r\n ...args: unknown[]\r\n): Promise<T> {\r\n return new Promise( ( resolve, reject ) => {\r\n const callback = ( err: Error | null, result: T ) => {\r\n if ( err ) {\r\n reject( err );\r\n } else {\r\n resolve( result );\r\n }\r\n };\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n ( bot as any )[ method ]( ...args, callback );\r\n } );\r\n}\r\n\r\nexport function isNonNullish<T>(\r\n value: T | null | undefined\r\n): value is T {\r\n return value !== null && value !== undefined;\r\n}\r\n\r\nexport function jsonResult(data: unknown): CallToolResult {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: JSON.stringify(data, null, 2)\r\n }]\r\n };\r\n}\r\n\r\nexport function errorResult(message: string, error?: Error): CallToolResult {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: JSON.stringify({\r\n error: message,\r\n details: error?.message\r\n }, null, 2)\r\n }],\r\n isError: true\r\n };\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageInCategory extends Record<string, any> {\r\n title: string;\r\n pageid?: number;\r\n ns?: number;\r\n}\r\n\r\nexport function getPagesInCategoryTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-pages-in-category',\r\n 'Get all pages in a category',\r\n {\r\n category: z.string().describe( 'Category name (with or without Category: prefix)' )\r\n },\r\n {\r\n title: 'Get pages in category',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { category } ) => handleGetPagesInCategoryTool( category )\r\n );\r\n}\r\n\r\nasync function handleGetPagesInCategoryTool(\r\n category: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n\r\n // Remove \"Category:\" prefix if present\r\n const cleanCategory = category.replace( /^Category:/i, '' );\r\n\r\n const results = await promisifyBotMethod<PageInCategory[]>(\r\n bot,\r\n 'getPagesInCategory',\r\n cleanCategory\r\n );\r\n\r\n return jsonResult({\r\n category: cleanCategory,\r\n pages: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get pages in category', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getCategoriesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-categories',\r\n 'Get all categories matching a prefix',\r\n {\r\n prefix: z.string().optional().default('').describe('Prefix to filter categories')\r\n },\r\n {\r\n title: 'Get categories',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { prefix } ) => handleGetCategoriesTool( prefix )\r\n );\r\n}\r\n\r\nasync function handleGetCategoriesTool(\r\n prefix: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const results = await promisifyBotMethod<string[]>(\r\n bot,\r\n 'getCategories',\r\n prefix\r\n );\r\n\r\n return jsonResult({\r\n prefix,\r\n categories: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get categories', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserInfo extends Record<string, any> {\r\n name: string;\r\n userid: number;\r\n}\r\n\r\nexport function getUsersTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-users',\r\n 'Get all users matching a prefix',\r\n {\r\n prefix: z.string().optional().default('').describe('Prefix to filter usernames'),\r\n onlyWithEdits: z.boolean().optional().default(false).describe('Only include users with at least one edit')\r\n },\r\n {\r\n title: 'Get users',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { prefix, onlyWithEdits } ) => handleGetUsersTool( prefix, onlyWithEdits )\r\n );\r\n}\r\n\r\nasync function handleGetUsersTool(\r\n prefix: string,\r\n onlyWithEdits: boolean\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const results = await promisifyBotMethod<UserInfo[]>(\r\n bot,\r\n 'getUsers',\r\n { prefix, witheditsonly: onlyWithEdits }\r\n );\r\n\r\n return jsonResult({\r\n prefix,\r\n onlyWithEdits,\r\n users: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get users', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface AllPage extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getAllPagesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-all-pages',\r\n 'Get all non-redirect pages from the wiki',\r\n {\r\n limit: z.number().optional().default(500).describe('Maximum number of pages to return')\r\n },\r\n {\r\n title: 'Get all pages',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { limit } ) => handleGetAllPagesTool( limit )\r\n );\r\n}\r\n\r\nasync function handleGetAllPagesTool(\r\n limit: number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const allResults = await promisifyBotMethod<AllPage[]>(\r\n bot,\r\n 'getAllPages'\r\n );\r\n\r\n // Limit results\r\n const results = allResults.slice(0, limit);\r\n\r\n return jsonResult({\r\n total: allResults.length,\r\n displayed: results.length,\r\n pages: results,\r\n limit\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get all pages', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageInNamespace extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getPagesInNamespaceTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-pages-in-namespace',\r\n 'Get all non-redirect pages in a specific namespace',\r\n {\r\n namespace: z.number().describe('Namespace number to filter pages')\r\n },\r\n {\r\n title: 'Get pages in namespace',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { namespace } ) => handleGetPagesInNamespaceTool( namespace )\r\n );\r\n}\r\n\r\nasync function handleGetPagesInNamespaceTool(\r\n namespace: number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const results = await promisifyBotMethod<PageInNamespace[]>(\r\n bot,\r\n 'getPagesInNamespace',\r\n namespace\r\n );\r\n\r\n return jsonResult({\r\n namespace,\r\n pages: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get pages in namespace', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageByPrefix extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getPagesByPrefixTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-pages-by-prefix',\r\n 'Get pages starting with a specific prefix',\r\n {\r\n prefix: z.string().describe('Prefix to match page titles')\r\n },\r\n {\r\n title: 'Get pages by prefix',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { prefix } ) => handleGetPagesByPrefixTool( prefix )\r\n );\r\n}\r\n\r\nasync function handleGetPagesByPrefixTool(\r\n prefix: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const results = await promisifyBotMethod<PageByPrefix[]>(\r\n bot,\r\n 'getPagesByPrefix',\r\n prefix\r\n );\r\n\r\n return jsonResult({\r\n prefix,\r\n pages: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get pages by prefix', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface TranscludingPage extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getPagesTranscludingTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-pages-transcluding',\r\n 'Get all pages that transclude (include) a specific template',\r\n {\r\n template: z.string().describe('Template title to find transclusions')\r\n },\r\n {\r\n title: 'Get pages transcluding template',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { template } ) => handleGetPagesTranscludingTool( template )\r\n );\r\n}\r\n\r\nasync function handleGetPagesTranscludingTool(\r\n template: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const callbackArgs = await promisifyBotMethod<[Error | null, TranscludingPage[] | [undefined]]>(\r\n bot,\r\n 'getPagesTranscluding',\r\n template\r\n );\r\n\r\n // Extract results from callback args (ignore first arg if it's error, which promisifyBotMethod already handles)\r\n const rawResults = callbackArgs[1];\r\n const results = Array.isArray(rawResults) \r\n ? rawResults.filter((page): page is TranscludingPage => page != null && typeof page === 'object' && 'title' in page)\r\n : [];\r\n\r\n return jsonResult({\r\n template,\r\n pages: results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get pages transcluding template', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Revision extends Record<string, any> {\r\n revid: number;\r\n timestamp: string;\r\n user: string;\r\n comment: string;\r\n size: number;\r\n}\r\n\r\nexport function getArticleRevisionsTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-article-revisions',\r\n 'Get all revisions of a wiki article',\r\n {\r\n title: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n },\r\n {\r\n title: 'Get article revisions',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetArticleRevisionsTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetArticleRevisionsTool(\r\n title: string | number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const allRevisions = await promisifyBotMethod<Revision[][]>(\r\n bot,\r\n 'getArticleRevisions',\r\n title\r\n );\r\n\r\n // Flatten the results\r\n const revisions = allRevisions.flat();\r\n\r\n return jsonResult({\r\n title,\r\n revisions,\r\n count: revisions.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get article revisions', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getArticleCategoriesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-article-categories',\r\n 'Get all categories that an article belongs to',\r\n {\r\n title: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n },\r\n {\r\n title: 'Get article categories',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetArticleCategoriesTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetArticleCategoriesTool(\r\n title: string | number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const categories = await promisifyBotMethod<string[]>(\r\n bot,\r\n 'getArticleCategories',\r\n title\r\n );\r\n\r\n return jsonResult({\r\n title,\r\n categories,\r\n count: categories.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get article categories', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface PageProperties extends Record<string, any> {\r\n [key: string]: string | undefined;\r\n}\r\n\r\nexport function getArticlePropertiesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-article-properties',\r\n 'Get page properties for a wiki article',\r\n {\r\n title: z.string().describe('Article title')\r\n },\r\n {\r\n title: 'Get article properties',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetArticlePropertiesTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetArticlePropertiesTool(\r\n title: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const properties = await promisifyBotMethod<PageProperties>(\r\n bot,\r\n 'getArticleProperties',\r\n title\r\n );\r\n\r\n return jsonResult({\r\n title,\r\n properties\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get article properties', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ArticleInfo extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getArticleInfoTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-article-info',\r\n 'Get detailed information about one or more articles',\r\n {\r\n title: z.union([\r\n z.string(),\r\n z.number(),\r\n z.array(z.union([z.string(), z.number()]))\r\n ]).describe('Article title, page ID, or array of titles/IDs'),\r\n properties: z.array(z.string()).optional().describe('Specific properties to retrieve')\r\n },\r\n {\r\n title: 'Get article info',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title, properties } ) => handleGetArticleInfoTool( title, properties )\r\n );\r\n}\r\n\r\nasync function handleGetArticleInfoTool(\r\n title: string | number | (string | number)[],\r\n properties?: string[]\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const options = properties ? { inprop: properties } : {};\r\n const info = await promisifyBotMethod<ArticleInfo>(\r\n bot,\r\n 'getArticleInfo',\r\n title,\r\n options\r\n );\r\n\r\n // Handle array of results vs single result\r\n const results = Array.isArray(info) ? info : [info];\r\n\r\n return jsonResult({\r\n title,\r\n results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get article info', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserContrib extends Record<string, any> {\r\n title: string;\r\n revid: number;\r\n timestamp: string;\r\n comment: string;\r\n}\r\n\r\nexport function getUserContribsTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-user-contribs',\r\n 'Get contributions made by a specific user',\r\n {\r\n username: z.string().describe('Username to get contributions for'),\r\n namespace: z.number().optional().describe('Filter contributions by namespace'),\r\n limit: z.number().optional().default(50).describe('Maximum number of contributions to return')\r\n },\r\n {\r\n title: 'Get user contributions',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { username, namespace, limit } ) => handleGetUserContribsTool( username, namespace, limit )\r\n );\r\n}\r\n\r\nasync function handleGetUserContribsTool(\r\n username: string,\r\n namespace?: number,\r\n limit: number = 50\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const options = {\r\n user: username,\r\n ...(namespace !== undefined && { namespace })\r\n };\r\n\r\n const callbackArgs = await promisifyBotMethod<[Error | null, UserContrib[], string | boolean]>(\r\n bot,\r\n 'getUserContribs',\r\n options\r\n );\r\n\r\n const contribs = Array.isArray(callbackArgs[1]) ? callbackArgs[1] : [];\r\n\r\n // Limit results\r\n const limitedContribs = contribs.slice(0, limit);\r\n\r\n return jsonResult({\r\n username,\r\n namespace,\r\n limit,\r\n total: contribs.length,\r\n displayed: limitedContribs.length,\r\n contributions: limitedContribs\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get user contributions', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface UserInfo extends Record<string, any> {\r\n name: string;\r\n id: number;\r\n groups: string[];\r\n rights: string[];\r\n}\r\n\r\nexport function whoamiTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'whoami',\r\n 'Get information about the currently logged in user',\r\n {},\r\n {\r\n title: 'Who am I',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async () => handleWhoamiTool()\r\n );\r\n}\r\n\r\nasync function handleWhoamiTool(): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const userInfo = await promisifyBotMethod<UserInfo>(\r\n bot,\r\n 'whoami'\r\n );\r\n\r\n return jsonResult(userInfo);\r\n } catch ( error ) {\r\n return errorResult('Failed to get current user info', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface WhoisUserInfo extends Record<string, any> {\r\n name: string;\r\n userid: number;\r\n groups: string[];\r\n rights: string[];\r\n}\r\n\r\nexport function whoisTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'whois',\r\n 'Get information about a specific user',\r\n {\r\n username: z.string().describe('Username to look up')\r\n },\r\n {\r\n title: 'Whois',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { username } ) => handleWhoisTool( username )\r\n );\r\n}\r\n\r\nasync function handleWhoisTool(\r\n username: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const userInfo = await promisifyBotMethod<WhoisUserInfo & { missing?: string }>(\r\n bot,\r\n 'whois',\r\n username\r\n );\r\n\r\n if (userInfo.missing) {\r\n return errorResult(`User \"${username}\" not found.`);\r\n }\r\n\r\n return jsonResult(userInfo);\r\n } catch ( error ) {\r\n return errorResult('Failed to get user info', error as Error);\r\n }\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function whoareTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'whoare',\n 'Get information about multiple wiki users',\n {\n usernames: z.array( z.string() ).describe( 'Array of usernames to query' ),\n },\n {\n title: 'Who are',\n readOnlyHint: true,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleWhoareTool( params )\n );\n}\n\nasync function handleWhoareTool(\n params: {\n usernames: string[];\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n\n const users = await promisifyBotMethod<any[]>(\n bot,\n 'whoare',\n params.usernames\n );\n\n return jsonResult(users);\n } catch ( error ) {\n return errorResult('Failed to get user information', error as Error);\n }\n}\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Image extends Record<string, any> {\r\n name: string;\r\n img_timestamp: string;\r\n user: string;\r\n}\r\n\r\nexport function getImagesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-images',\r\n 'Get list of images starting from a specific name',\r\n {\r\n startFrom: z.string().optional().default('').describe('Start from this image name'),\r\n limit: z.number().optional().default(50).describe('Maximum number of images to return')\r\n },\r\n {\r\n title: 'Get images',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { startFrom, limit } ) => handleGetImagesTool( startFrom, limit )\r\n );\r\n}\r\n\r\nasync function handleGetImagesTool(\r\n startFrom: string,\r\n limit: number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n // getImages has a different callback signature - let's handle it manually\r\n const images = await new Promise<Image[]>((resolve, reject) => {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (bot as any).getImages(startFrom, (err: Error | null, ...args: any[]) => {\r\n if (err) {\r\n reject(err);\r\n } else {\r\n const imgs = args[0];\r\n resolve(Array.isArray(imgs) ? imgs : []);\r\n }\r\n });\r\n });\r\n\r\n // Limit results\r\n const limitedImages = images.slice(0, limit);\r\n\r\n return jsonResult({\r\n total: images.length,\r\n limit,\r\n startFrom,\r\n images: limitedImages\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get images', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ArticleImage extends Record<string, any> {\r\n title: string;\r\n ns: number;\r\n}\r\n\r\nexport function getImagesFromArticleTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-images-from-article',\r\n 'Get all images embedded in a specific article',\r\n {\r\n title: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n },\r\n {\r\n title: 'Get images from article',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetImagesFromArticleTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetImagesFromArticleTool(\r\n title: string | number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const images = await promisifyBotMethod<ArticleImage[]>(\r\n bot,\r\n 'getImagesFromArticle',\r\n title\r\n );\r\n\r\n return jsonResult({\r\n title,\r\n images,\r\n count: images.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get images from article', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type {CallToolResult, ToolAnnotations} from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ImageUsage extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n ns: number;\r\n}\r\n\r\nexport function getImageUsageTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-image-usage',\r\n 'Get all pages that use a specific image',\r\n {\r\n filename: z.string().describe('Image filename with File: prefix')\r\n },\r\n {\r\n title: 'Get image usage',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { filename } ) => handleGetImageUsageTool( filename )\r\n );\r\n}\r\n\r\nasync function handleGetImageUsageTool(\r\n filename: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const pages = await promisifyBotMethod<ImageUsage[]>(\r\n bot,\r\n 'getImageUsage',\r\n filename\r\n );\r\n\r\n return jsonResult({\r\n filename,\r\n pages,\r\n count: pages.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get image usage', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ImageInfo extends Record<string, any> {\r\n timestamp: string;\r\n user: string;\r\n width: number;\r\n height: number;\r\n size: number;\r\n url: string;\r\n descriptionurl: string;\r\n exif?: Record<string, string>;\r\n}\r\n\r\nexport function getImageInfoTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-image-info',\r\n 'Get detailed information about an image file',\r\n {\r\n filename: z.string().describe('Image filename with File: prefix')\r\n },\r\n {\r\n title: 'Get image info',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { filename } ) => handleGetImageInfoTool( filename )\r\n );\r\n}\r\n\r\nasync function handleGetImageInfoTool(\r\n filename: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const info = await promisifyBotMethod<ImageInfo | undefined>(\r\n bot,\r\n 'getImageInfo',\r\n filename\r\n );\r\n\r\n if (!info) {\r\n return errorResult(`Image \"${filename}\" not found.`);\r\n }\r\n\r\n return jsonResult({\r\n filename,\r\n info\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get image info', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface LogEntry extends Record<string, any> {\r\n title: string;\r\n timestamp: string;\r\n user: string;\r\n action: string;\r\n comment: string;\r\n}\r\n\r\nexport function getLogTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-log',\r\n 'Get log entries of a specific type',\r\n {\r\n type: z.string().describe('Log type (e.g. delete, block, move)'),\r\n start: z.string().optional().default('').describe('Start timestamp (YYYYMMDDHHMMSS format)'),\r\n limit: z.number().optional().default(50).describe('Maximum number of entries to return')\r\n },\r\n {\r\n title: 'Get log entries',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { type, start, limit } ) => handleGetLogTool( type, start, limit )\r\n );\r\n}\r\n\r\nasync function handleGetLogTool(\r\n type: string,\r\n start: string,\r\n limit: number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n // Handle getLog's callback signature manually\r\n const entries = await new Promise<LogEntry[]>((resolve, reject) => {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (bot as any).getLog(type, start, (err: Error | null, ...args: any[]) => {\r\n if (err) {\r\n reject(err);\r\n } else {\r\n const ents = args[0];\r\n resolve(Array.isArray(ents) ? ents : []);\r\n }\r\n });\r\n });\r\n\r\n // Limit results\r\n const limitedEntries = entries.slice(0, limit);\r\n\r\n return jsonResult({\r\n type,\r\n start,\r\n limit,\r\n total: entries.length,\r\n displayed: limitedEntries.length,\r\n entries: limitedEntries\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get log entries', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function expandTemplatesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'expand-templates',\r\n 'Expand templates in wikitext',\r\n {\r\n text: z.string().describe('Wikitext with templates to expand'),\r\n title: z.string().optional().describe('Context page title'),\r\n },\r\n {\r\n title: 'Expand templates',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { text, title } ) => handleExpandTemplatesTool( text, title )\r\n );\r\n}\r\n\r\nasync function handleExpandTemplatesTool(\r\n text: string,\r\n title?: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const expandedXml = await promisifyBotMethod<string>(\r\n bot,\r\n 'expandTemplates',\r\n text,\r\n title || ''\r\n );\r\n\r\n if (expandedXml == null) {\r\n return {\r\n content: [{ type: 'text', text: `Failed to expand templates for \"${text}\".` }],\r\n isError: true\r\n };\r\n }\r\n\r\n return {\r\n content: [ { type: 'text', text: expandedXml } ]\r\n };\r\n } catch ( error ) {\r\n return {\r\n content: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n isError: true\r\n };\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\n\r\nexport function parseTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'parse',\r\n 'Parse wikitext to HTML',\r\n {\r\n text: z.string().describe('Wikitext to parse'),\r\n title: z.string().optional().describe('Context page title')\r\n },\r\n {\r\n title: 'Parse wikitext',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { text, title } ) => handleParseTool( text, title )\r\n );\r\n}\r\n\r\nasync function handleParseTool(\r\n text: string,\r\n title?: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const callbackArgs = await promisifyBotMethod<[Error | null, string, string[]]>(\r\n bot,\r\n 'parse',\r\n text,\r\n title || ''\r\n );\r\n\r\n const xml = callbackArgs[1] || '';\r\n const images = Array.isArray(callbackArgs[2]) ? callbackArgs[2] : [];\r\n\r\n const output = [\r\n 'Parsed XML structure:',\r\n '',\r\n xml,\r\n '',\r\n `Images found: ${images.length > 0 ? images.join(', ') : 'none'}`\r\n ].join( '\\n' );\r\n\r\n return {\r\n content: [ { type: 'text', text: output } ]\r\n };\r\n } catch ( error ) {\r\n return {\r\n content: [ { type: 'text', text: `Error: ${ ( error as Error ).message }` } ],\r\n isError: true\r\n };\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface RecentChange extends Record<string, any> {\r\n title: string;\r\n timestamp: string;\r\n user: string;\r\n comment: string;\r\n}\r\n\r\nexport function getRecentChangesTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-recent-changes',\r\n 'Get recent changes on the wiki',\r\n {\r\n start: z.string().optional().describe('Start timestamp'),\r\n limit: z.number().optional().default(50).describe('Maximum number of changes to return')\r\n },\r\n {\r\n title: 'Get recent changes',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { start, limit } ) => handleGetRecentChangesTool( start, limit )\r\n );\r\n}\r\n\r\nasync function handleGetRecentChangesTool(\r\n start?: string,\r\n limit: number = 50\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n // Handle getRecentChanges's callback signature manually\r\n const changes = await new Promise<RecentChange[]>((resolve, reject) => {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (bot as any).getRecentChanges(start, (err: Error | null, ...args: any[]) => {\r\n if (err) {\r\n reject(err);\r\n } else {\r\n const chgs = args[0];\r\n resolve(Array.isArray(chgs) ? chgs : []);\r\n }\r\n });\r\n });\r\n\r\n // Limit results\r\n const limitedChanges = changes.slice(0, limit);\r\n\r\n return jsonResult({\r\n total: changes.length,\r\n limit,\r\n start,\r\n changes: limitedChanges\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get recent changes', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getSiteInfoTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-site-info',\r\n 'Get site information from MediaWiki',\r\n {\r\n properties: z.array(z.string()).describe('List of site information properties to retrieve')\r\n },\r\n {\r\n title: 'Get site info',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { properties } ) => handleGetSiteInfoTool( properties )\r\n );\r\n}\r\n\r\nasync function handleGetSiteInfoTool(\r\n properties: string[]\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const info = await promisifyBotMethod<Record<string, unknown>>(\r\n bot,\r\n 'getSiteInfo',\r\n properties\r\n );\r\n\r\n return jsonResult(info || {});\r\n } catch ( error ) {\r\n return errorResult('Failed to get site info', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface SiteStats extends Record<string, any> {\r\n pages: number;\r\n articles: number;\r\n edits: number;\r\n images: number;\r\n users: number;\r\n activeusers: number;\r\n admins: number;\r\n jobs: number;\r\n}\r\n\r\nexport function getSiteStatsTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-site-stats',\r\n 'Get site statistics',\r\n {},\r\n {\r\n title: 'Get site stats',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async () => handleGetSiteStatsTool()\r\n );\r\n}\r\n\r\nasync function handleGetSiteStatsTool(): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const stats = await promisifyBotMethod<SiteStats>(\r\n bot,\r\n 'getSiteStats'\r\n );\r\n\r\n return jsonResult(stats);\r\n } catch ( error ) {\r\n return errorResult('Failed to get site stats', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function getMediaWikiVersionTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-mediawiki-version',\r\n 'Get MediaWiki version running on the server',\r\n {},\r\n {\r\n title: 'Get MediaWiki version',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async () => handleGetMediaWikiVersionTool()\r\n );\r\n}\r\n\r\nasync function handleGetMediaWikiVersionTool(): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const version = await promisifyBotMethod<string>(\r\n bot,\r\n 'getMediaWikiVersion'\r\n );\r\n\r\n return jsonResult({ version });\r\n } catch ( error ) {\r\n return errorResult('Failed to get MediaWiki version', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface QueryPageResult extends Record<string, any> {\r\n title: string;\r\n value: number;\r\n}\r\n\r\nexport function getQueryPageTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-query-page',\r\n 'Get results from a query page (special page)',\r\n {\r\n name: z.string().describe('Name of the query page')\r\n },\r\n {\r\n title: 'Get query page results',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { name } ) => handleGetQueryPageTool( name )\r\n );\r\n}\r\n\r\nasync function handleGetQueryPageTool(\r\n name: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const results = await promisifyBotMethod<QueryPageResult[]>(\r\n bot,\r\n 'getQueryPage',\r\n name\r\n );\r\n\r\n return jsonResult({\r\n name,\r\n results,\r\n count: results.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get query page results', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface ExternalLink extends Record<string, any> {\r\n '*': string;\r\n}\r\n\r\nexport function getExternalLinksTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-external-links',\r\n 'Get all external links from an article',\r\n {\r\n title: z.union([z.string(), z.number()]).describe('Article title or page ID')\r\n },\r\n {\r\n title: 'Get external links',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetExternalLinksTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetExternalLinksTool(\r\n title: string | number\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const links = await promisifyBotMethod<ExternalLink[]>(\r\n bot,\r\n 'getExternalLinks',\r\n title\r\n );\r\n\r\n return jsonResult({\r\n title,\r\n links: links.map(link => link['*']),\r\n count: links.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get external links', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ninterface Backlink extends Record<string, any> {\r\n title: string;\r\n pageid: number;\r\n}\r\n\r\nexport function getBacklinksTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'get-backlinks',\r\n 'Get all backlinks to a specific page',\r\n {\r\n title: z.string().describe('Target page title to find backlinks for')\r\n },\r\n {\r\n title: 'Get backlinks',\r\n readOnlyHint: true,\r\n destructiveHint: false\r\n } as ToolAnnotations,\r\n async ( { title } ) => handleGetBacklinksTool( title )\r\n );\r\n}\r\n\r\nasync function handleGetBacklinksTool(\r\n title: string\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const backlinks = await promisifyBotMethod<Backlink[]>(\r\n bot,\r\n 'getBacklinks',\r\n title\r\n );\r\n\r\n return jsonResult({\r\n target: title,\r\n backlinks,\r\n count: backlinks.length\r\n });\r\n } catch ( error ) {\r\n return errorResult('Failed to get backlinks', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function editTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'edit',\r\n 'Edit a wiki page (requires authentication)',\r\n {\r\n title: z.string().describe( 'Page title to edit' ),\r\n content: z.string().describe( 'New content for the page' ),\r\n summary: z.string().describe( 'Edit summary' ),\r\n minor: z.boolean().optional().default( false ).describe( 'Mark as minor edit' )\r\n },\r\n {\r\n title: 'Edit page',\r\n readOnlyHint: false,\r\n destructiveHint: true\r\n } as ToolAnnotations,\r\n async ( params ) => handleEditTool( params )\r\n );\r\n}\r\n\r\nasync function handleEditTool(\r\n params: {\r\n title: string;\r\n content: string;\r\n summary: string;\r\n minor?: boolean;\r\n }\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const prefixedSummary = `[nodemw-mcp] ${params.summary}`;\r\n\r\n const result = await promisifyBotMethod<{\r\n title: string;\r\n pageid?: number;\r\n oldrevid?: number;\r\n newrevid?: number;\r\n }>(\r\n bot,\r\n 'edit',\r\n params.title,\r\n params.content,\r\n prefixedSummary,\r\n params.minor || false\r\n );\r\n\r\n return jsonResult(result);\r\n } catch ( error ) {\r\n return errorResult('Failed to edit page', error as Error);\r\n }\r\n}\r\n", "/*\r\n * SPDX-License-Identifier: BSD-2-Clause\r\n *\r\n * Copyright (c) 2026 Xie Youtian\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\n * POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\r\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\r\nimport { jsonResult, errorResult } from '../../common/utils.js';\r\n\r\nexport function appendTool( server: McpServer ): RegisteredTool {\r\n return server.tool(\r\n 'append',\r\n 'Append content to a wiki page (requires authentication)',\r\n {\r\n title: z.string().describe( 'Page title' ),\r\n content: z.string().describe( 'Content to append' ),\r\n summary: z.string().describe( 'Edit summary' )\r\n },\r\n {\r\n title: 'Append to page',\r\n readOnlyHint: false,\r\n destructiveHint: true\r\n } as ToolAnnotations,\r\n async ( params ) => handleAppendTool( params )\r\n );\r\n}\r\n\r\nasync function handleAppendTool(\r\n params: {\r\n title: string;\r\n content: string;\r\n summary: string;\r\n }\r\n): Promise<CallToolResult> {\r\n try {\r\n const bot = await getBot();\r\n const prefixedSummary = `[nodemw-mcp] ${params.summary}`;\r\n\r\n await promisifyBotMethod<void>(\r\n bot,\r\n 'append',\r\n params.title,\r\n params.content,\r\n prefixedSummary\r\n );\r\n\r\n return jsonResult({ success: true, title: params.title });\r\n } catch ( error ) {\r\n return errorResult('Failed to append to page', error as Error);\r\n }\r\n}\r\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function prependTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'prepend',\n 'Prepend content to a wiki page (requires authentication)',\n {\n title: z.string().describe( 'Page title to prepend to' ),\n content: z.string().describe( 'Content to prepend' ),\n summary: z.string().describe( 'Edit summary' ),\n },\n {\n title: 'Prepend to page',\n readOnlyHint: false,\n destructiveHint: true\n } as ToolAnnotations,\n async ( params ) => handlePrependTool( params )\n );\n}\n\nasync function handlePrependTool(\n params: {\n title: string;\n content: string;\n summary: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const prefixedSummary = `[nodemw-mcp] ${params.summary}`;\n\n const result = await promisifyBotMethod<{\n title: string;\n pageid?: number;\n oldrevid?: number;\n newrevid?: number;\n }>(\n bot,\n 'prepend',\n params.title,\n params.content,\n prefixedSummary\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to prepend to page', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function moveTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'move',\n 'Move (rename) a wiki page (requires authentication)',\n {\n from: z.string().describe( 'Current page title' ),\n to: z.string().describe( 'New page title' ),\n summary: z.string().describe( 'Move summary' ),\n },\n {\n title: 'Move page',\n readOnlyHint: false,\n destructiveHint: true\n } as ToolAnnotations,\n async ( params ) => handleMoveTool( params )\n );\n}\n\nasync function handleMoveTool(\n params: {\n from: string;\n to: string;\n summary: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const prefixedSummary = `[nodemw-mcp] ${params.summary}`;\n\n const result = await promisifyBotMethod<{\n from: string;\n to: string;\n reason: string;\n }>(\n bot,\n 'move',\n params.from,\n params.to,\n prefixedSummary\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to move page', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function deleteTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'delete',\n 'Delete a wiki page (requires authentication)',\n {\n title: z.string().describe( 'Page title to delete' ),\n reason: z.string().describe( 'Reason for deletion' ),\n },\n {\n title: 'Delete page',\n readOnlyHint: false,\n destructiveHint: true\n } as ToolAnnotations,\n async ( params ) => handleDeleteTool( params )\n );\n}\n\nasync function handleDeleteTool(\n params: {\n title: string;\n reason: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const prefixedReason = `[nodemw-mcp] ${params.reason}`;\n\n const result = await promisifyBotMethod<{\n title: string;\n reason: string;\n }>(\n bot,\n 'delete',\n params.title,\n prefixedReason\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to delete page', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function protectTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'protect',\n 'Protect a wiki page (requires authentication)',\n {\n title: z.string().describe( 'Page title to protect' ),\n protections: z.array(\n z.object({\n type: z.string().describe( 'Action type (e.g., edit, move)' ),\n level: z.string().optional().default('all').describe( 'Protection level (e.g., sysop, autoconfirmed)' ),\n expiry: z.string().optional().describe( 'Expiry time (e.g., 1 week, never)' )\n })\n ).describe( 'Protection settings' ),\n reason: z.string().optional().describe( 'Reason for protection' ),\n cascade: z.boolean().optional().default(false).describe( 'Apply cascade protection' )\n },\n {\n title: 'Protect page',\n readOnlyHint: false,\n destructiveHint: true\n } as ToolAnnotations,\n async ( params ) => handleProtectTool( params )\n );\n}\n\nasync function handleProtectTool(\n params: {\n title: string;\n protections: Array<{ type: string; level?: string; expiry?: string }>;\n reason?: string;\n cascade?: boolean;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const options: any = {};\n if (params.reason) {\n options.reason = `[nodemw-mcp] ${params.reason}`;\n }\n if (params.cascade) {\n options.cascade = params.cascade;\n }\n\n const result = await promisifyBotMethod<{\n title: string;\n protections: any[];\n }>(\n bot,\n 'protect',\n params.title,\n params.protections,\n options\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to protect page', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function purgeTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'purge',\n 'Purge cache for wiki pages',\n {\n titles: z.union([z.string(), z.array(z.string())]).describe( 'Page title(s) or category to purge' ),\n },\n {\n title: 'Purge pages',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handlePurgeTool( params )\n );\n}\n\nasync function handlePurgeTool(\n params: {\n titles: string | string[];\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n\n const result = await promisifyBotMethod<any[]>(\n bot,\n 'purge',\n params.titles\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to purge pages', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function sendEmailTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'send-email',\n 'Send email to a wiki user (requires authentication)',\n {\n username: z.string().describe( 'Username to email' ),\n subject: z.string().describe( 'Email subject' ),\n text: z.string().describe( 'Email content' ),\n },\n {\n title: 'Send email',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleSendEmailTool( params )\n );\n}\n\nasync function handleSendEmailTool(\n params: {\n username: string;\n subject: string;\n text: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n\n const result = await promisifyBotMethod<{\n result: string;\n }>(\n bot,\n 'sendEmail',\n params.username,\n params.subject,\n params.text\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to send email', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function uploadTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'upload',\n 'Upload a file to wiki (requires authentication)',\n {\n filename: z.string().describe( 'Destination filename on wiki' ),\n content: z.string().describe( 'File content as base64 string' ),\n comment: z.string().optional().describe( 'Upload comment' ),\n },\n {\n title: 'Upload file',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleUploadTool( params )\n );\n}\n\nasync function handleUploadTool(\n params: {\n filename: string;\n content: string;\n comment?: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const fileContent = Buffer.from(params.content, 'base64');\n const comment = params.comment ? `[nodemw-mcp] ${params.comment}` : '[nodemw-mcp] File upload';\n\n const result = await promisifyBotMethod<{\n result: string;\n filename: string;\n imageinfo?: any;\n }>(\n bot,\n 'upload',\n params.filename,\n fileContent,\n comment\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to upload file', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function uploadByUrlTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'upload-by-url',\n 'Upload a file to wiki from URL (requires authentication)',\n {\n filename: z.string().describe( 'Destination filename on wiki' ),\n url: z.string().url().describe( 'Source URL to download file from' ),\n summary: z.string().optional().describe( 'Upload summary' ),\n },\n {\n title: 'Upload file by URL',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleUploadByUrlTool( params )\n );\n}\n\nasync function handleUploadByUrlTool(\n params: {\n filename: string;\n url: string;\n summary?: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n const prefixedSummary = params.summary ? `[nodemw-mcp] ${params.summary}` : '[nodemw-mcp] File upload from URL';\n\n const result = await promisifyBotMethod<{\n result: string;\n filename: string;\n imageinfo?: any;\n }>(\n bot,\n 'uploadByUrl',\n params.filename,\n params.url,\n prefixedSummary\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to upload file by URL', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function addFlowTopicTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'add-flow-topic',\n 'Add a new Flow topic to a wiki page (requires authentication)',\n {\n title: z.string().describe( 'Page title to add topic to' ),\n subject: z.string().describe( 'Topic subject' ),\n content: z.string().describe( 'Topic content in wikitext' ),\n },\n {\n title: 'Add Flow topic',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleAddFlowTopicTool( params )\n );\n}\n\nasync function handleAddFlowTopicTool(\n params: {\n title: string;\n subject: string;\n content: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n\n const result = await promisifyBotMethod<{\n 'new-topic': {\n status: string;\n workflow: string;\n };\n }>(\n bot,\n 'addFlowTopic',\n params.title,\n params.subject,\n params.content\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to add Flow topic', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport { z } from 'zod';\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { getBot, promisifyBotMethod } from '../../common/nodemwBot.js';\nimport { jsonResult, errorResult } from '../../common/utils.js';\n\nexport function createAccountTool( server: McpServer ): RegisteredTool {\n return server.tool(\n 'create-account',\n 'Create a new MediaWiki user account (requires authentication)',\n {\n username: z.string().describe( 'New account username' ),\n password: z.string().describe( 'New account password' ),\n },\n {\n title: 'Create user account',\n readOnlyHint: false,\n destructiveHint: false\n } as ToolAnnotations,\n async ( params ) => handleCreateAccountTool( params )\n );\n}\n\nasync function handleCreateAccountTool(\n params: {\n username: string;\n password: string;\n }\n): Promise<CallToolResult> {\n try {\n const bot = await getBot();\n\n const result = await promisifyBotMethod<any>(\n bot,\n 'createAccount',\n params.username,\n params.password\n );\n\n return jsonResult(result);\n } catch ( error ) {\n return errorResult('Failed to create account', error as Error);\n }\n}\n", "/*\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * Copyright (c) 2026 Xie Youtian\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\n\n// Read tools\nimport { getArticleTool } from './ro/get-article.js';\nimport { searchTool } from './ro/search.js';\nimport { getPagesInCategoryTool } from './ro/get-pages-in-category.js';\nimport { getCategoriesTool } from './ro/get-categories.js';\nimport { getUsersTool } from './ro/get-users.js';\nimport { getAllPagesTool } from './ro/get-all-pages.js';\nimport { getPagesInNamespaceTool } from './ro/get-pages-in-namespace.js';\nimport { getPagesByPrefixTool } from './ro/get-pages-by-prefix.js';\nimport { getPagesTranscludingTool } from './ro/get-pages-transcluding.js';\nimport { getArticleRevisionsTool } from './ro/get-article-revisions.js';\nimport { getArticleCategoriesTool } from './ro/get-article-categories.js';\nimport { getArticlePropertiesTool } from './ro/get-article-properties.js';\nimport { getArticleInfoTool } from './ro/get-article-info.js';\nimport { getUserContribsTool } from './ro/get-user-contribs.js';\nimport { whoamiTool } from './ro/whoami.js';\nimport { whoisTool } from './ro/whois.js';\nimport { whoareTool } from './ro/whoare.js';\nimport { getImagesTool } from './ro/get-images.js';\nimport { getImagesFromArticleTool } from './ro/get-images-from-article.js';\nimport { getImageUsageTool } from './ro/get-image-usage.js';\nimport { getImageInfoTool } from './ro/get-image-info.js';\nimport { getLogTool } from './ro/get-log.js';\nimport { expandTemplatesTool } from './ro/expand-templates.js';\nimport { parseTool } from './ro/parse.js';\nimport { getRecentChangesTool } from './ro/get-recent-changes.js';\nimport { getSiteInfoTool } from './ro/get-site-info.js';\nimport { getSiteStatsTool } from './ro/get-site-stats.js';\nimport { getMediaWikiVersionTool } from './ro/get-mediawiki-version.js';\nimport { getQueryPageTool } from './ro/get-query-page.js';\nimport { getExternalLinksTool } from './ro/get-external-links.js';\nimport { getBacklinksTool } from './ro/get-backlinks.js';\n\n// Write tools\nimport { editTool } from './editing/edit.js';\nimport { appendTool } from './editing/append.js';\nimport { prependTool } from './editing/prepend.js';\nimport { moveTool } from './editing/move.js';\nimport { deleteTool } from './editing/delete.js';\nimport { protectTool } from './editing/protect.js';\nimport { purgeTool } from './editing/purge.js';\nimport { sendEmailTool } from './editing/send-email.js';\nimport { uploadTool } from './editing/upload.js';\nimport { uploadByUrlTool } from './editing/upload-by-url.js';\nimport { addFlowTopicTool } from './editing/add-flow-topic.js';\nimport { createAccountTool } from './editing/create-account.js';\n\nconst readToolRegistrars = [\n getArticleTool,\n searchTool,\n getPagesInCategoryTool,\n getCategoriesTool,\n getUsersTool,\n getAllPagesTool,\n getPagesInNamespaceTool,\n getPagesByPrefixTool,\n getPagesTranscludingTool,\n getArticleRevisionsTool,\n getArticleCategoriesTool,\n getArticlePropertiesTool,\n getArticleInfoTool,\n getUserContribsTool,\n whoamiTool,\n whoisTool,\n whoareTool,\n getImagesTool,\n getImagesFromArticleTool,\n getImageUsageTool,\n getImageInfoTool,\n getLogTool,\n expandTemplatesTool,\n parseTool,\n getRecentChangesTool,\n getSiteInfoTool,\n getSiteStatsTool,\n getMediaWikiVersionTool,\n getQueryPageTool,\n getExternalLinksTool,\n getBacklinksTool,\n];\n\nconst writeToolRegistrars = [\n editTool,\n appendTool,\n prependTool,\n moveTool,\n deleteTool,\n protectTool,\n purgeTool,\n sendEmailTool,\n uploadTool,\n uploadByUrlTool,\n addFlowTopicTool,\n createAccountTool,\n];\n\nexport function registerAllTools(server: McpServer, includeWriteTools = true): RegisteredTool[] {\n const registrars = includeWriteTools\n ? [...readToolRegistrars, ...writeToolRegistrars]\n : readToolRegistrars;\n\n const registeredTools: RegisteredTool[] = [];\n for (const registrar of registrars) {\n try {\n registeredTools.push(registrar(server));\n } catch (error) {\n console.error(`Error registering tool: ${(error as Error).message}`);\n }\n }\n return registeredTools;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["StdioServerTransport", "parseArgs", "McpServer", "USER_AGENT", "createServer", "siteInfo", "authenticated", "description", "authSuffix", "z", "Bot", "botInstance", "serverConfig", "authenticated", "initServerConfig", "config", "createBotFromConfig", "server", "path", "protocol", "port", "proxy", "userAgent", "concurrency", "debug", "username", "password", "domain", "dryRun", "Bot", "USER_AGENT", "testApiConnection", "bot", "promisifyBotMethod", "autoDetectPath", "baseConfig", "pathsToTry", "testConfig", "initBot", "resolve", "reject", "err", "getBot", "isAuthenticated", "authenticated", "promisifyBotMethod", "bot", "method", "args", "resolve", "reject", "callback", "err", "result", "getArticleTool", "server", "z", "title", "followRedirect", "redirectInfo", "handleGetArticleTool", "bot", "getBot", "result", "resolve", "reject", "callback", "err", "content", "redirect", "promisifyBotMethod", "error", "z", "jsonResult", "data", "errorResult", "message", "error", "searchTool", "server", "z", "keyword", "limit", "handleSearchTool", "bot", "getBot", "results", "promisifyBotMethod", "limitedResults", "jsonResult", "error", "errorResult", "z", "getPagesInCategoryTool", "server", "z", "category", "handleGetPagesInCategoryTool", "bot", "getBot", "cleanCategory", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getCategoriesTool", "server", "z", "prefix", "handleGetCategoriesTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getUsersTool", "server", "z", "prefix", "onlyWithEdits", "handleGetUsersTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getAllPagesTool", "server", "z", "limit", "handleGetAllPagesTool", "bot", "getBot", "allResults", "promisifyBotMethod", "results", "jsonResult", "error", "errorResult", "z", "getPagesInNamespaceTool", "server", "z", "namespace", "handleGetPagesInNamespaceTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getPagesByPrefixTool", "server", "z", "prefix", "handleGetPagesByPrefixTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getPagesTranscludingTool", "server", "z", "template", "handleGetPagesTranscludingTool", "bot", "getBot", "rawResults", "promisifyBotMethod", "results", "page", "jsonResult", "error", "errorResult", "z", "getArticleRevisionsTool", "server", "z", "title", "handleGetArticleRevisionsTool", "bot", "getBot", "revisions", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticleCategoriesTool", "server", "z", "title", "handleGetArticleCategoriesTool", "bot", "getBot", "categories", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticlePropertiesTool", "server", "z", "title", "handleGetArticlePropertiesTool", "bot", "getBot", "properties", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getArticleInfoTool", "server", "z", "title", "properties", "handleGetArticleInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "results", "jsonResult", "error", "errorResult", "z", "getUserContribsTool", "server", "z", "username", "namespace", "limit", "handleGetUserContribsTool", "bot", "getBot", "options", "callbackArgs", "promisifyBotMethod", "contribs", "limitedContribs", "jsonResult", "error", "errorResult", "whoamiTool", "server", "handleWhoamiTool", "bot", "getBot", "userInfo", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "whoisTool", "server", "z", "username", "handleWhoisTool", "bot", "getBot", "userInfo", "promisifyBotMethod", "errorResult", "jsonResult", "error", "z", "whoareTool", "server", "z", "params", "handleWhoareTool", "bot", "getBot", "users", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImagesTool", "server", "z", "startFrom", "limit", "handleGetImagesTool", "bot", "getBot", "images", "resolve", "reject", "err", "args", "imgs", "limitedImages", "jsonResult", "error", "errorResult", "z", "getImagesFromArticleTool", "server", "z", "title", "handleGetImagesFromArticleTool", "bot", "getBot", "images", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImageUsageTool", "server", "z", "filename", "handleGetImageUsageTool", "bot", "getBot", "pages", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getImageInfoTool", "server", "z", "filename", "handleGetImageInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "jsonResult", "errorResult", "error", "z", "getLogTool", "server", "z", "type", "start", "limit", "handleGetLogTool", "bot", "getBot", "entries", "resolve", "reject", "err", "args", "ents", "limitedEntries", "jsonResult", "error", "errorResult", "z", "expandTemplatesTool", "server", "z", "text", "title", "handleExpandTemplatesTool", "bot", "getBot", "expandedXml", "promisifyBotMethod", "error", "z", "parseTool", "server", "z", "text", "title", "handleParseTool", "bot", "getBot", "callbackArgs", "promisifyBotMethod", "xml", "images", "error", "z", "getRecentChangesTool", "server", "z", "start", "limit", "handleGetRecentChangesTool", "bot", "getBot", "changes", "resolve", "reject", "err", "args", "chgs", "limitedChanges", "jsonResult", "error", "errorResult", "z", "getSiteInfoTool", "server", "z", "properties", "handleGetSiteInfoTool", "bot", "getBot", "info", "promisifyBotMethod", "jsonResult", "error", "errorResult", "getSiteStatsTool", "server", "handleGetSiteStatsTool", "bot", "getBot", "stats", "promisifyBotMethod", "jsonResult", "error", "errorResult", "getMediaWikiVersionTool", "server", "handleGetMediaWikiVersionTool", "bot", "getBot", "version", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getQueryPageTool", "server", "z", "name", "handleGetQueryPageTool", "bot", "getBot", "results", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "getExternalLinksTool", "server", "z", "title", "handleGetExternalLinksTool", "bot", "getBot", "links", "promisifyBotMethod", "jsonResult", "link", "error", "errorResult", "z", "getBacklinksTool", "server", "z", "title", "handleGetBacklinksTool", "bot", "getBot", "backlinks", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "editTool", "server", "z", "params", "handleEditTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "appendTool", "server", "z", "params", "handleAppendTool", "bot", "getBot", "prefixedSummary", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "prependTool", "server", "z", "params", "handlePrependTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "moveTool", "server", "z", "params", "handleMoveTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "deleteTool", "server", "z", "params", "handleDeleteTool", "bot", "getBot", "prefixedReason", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "protectTool", "server", "z", "params", "handleProtectTool", "bot", "getBot", "options", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "purgeTool", "server", "z", "params", "handlePurgeTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "sendEmailTool", "server", "z", "params", "handleSendEmailTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "uploadTool", "server", "z", "params", "handleUploadTool", "bot", "getBot", "fileContent", "comment", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "uploadByUrlTool", "server", "z", "params", "handleUploadByUrlTool", "bot", "getBot", "prefixedSummary", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "addFlowTopicTool", "server", "z", "params", "handleAddFlowTopicTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "z", "createAccountTool", "server", "z", "params", "handleCreateAccountTool", "bot", "getBot", "result", "promisifyBotMethod", "jsonResult", "error", "errorResult", "readToolRegistrars", "getArticleTool", "searchTool", "getPagesInCategoryTool", "getCategoriesTool", "getUsersTool", "getAllPagesTool", "getPagesInNamespaceTool", "getPagesByPrefixTool", "getPagesTranscludingTool", "getArticleRevisionsTool", "getArticleCategoriesTool", "getArticlePropertiesTool", "getArticleInfoTool", "getUserContribsTool", "whoamiTool", "whoisTool", "whoareTool", "getImagesTool", "getImagesFromArticleTool", "getImageUsageTool", "getImageInfoTool", "getLogTool", "expandTemplatesTool", "parseTool", "getRecentChangesTool", "getSiteInfoTool", "getSiteStatsTool", "getMediaWikiVersionTool", "getQueryPageTool", "getExternalLinksTool", "getBacklinksTool", "writeToolRegistrars", "editTool", "appendTool", "prependTool", "moveTool", "deleteTool", "protectTool", "purgeTool", "sendEmailTool", "uploadTool", "uploadByUrlTool", "addFlowTopicTool", "createAccountTool", "registerAllTools", "server", "includeWriteTools", "registrars", "registeredTools", "registrar", "error", "parseCliArgs", "values", "positionals", "parseArgs", "serverUrl", "server", "protocol", "port", "url", "pathFromEnv", "pathExplicit", "main", "config", "autoDetectPath", "err", "initServerConfig", "initBot", "bot", "getBot", "siteInfo", "general", "promisifyBotMethod", "auth", "isAuthenticated", "createServer", "registerAllTools", "transport", "StdioServerTransport"]
|
|
7
7
|
}
|