@xiedada/nodemw-mcp-server 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -122,3 +122,128 @@ npm test # Run tests
122
122
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
123
123
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
124
124
 
125
+ ---
126
+
127
+ # Nodemw MCP Server(中文)
128
+
129
+ 一个为 [nodemw](https://github.com/macbre/nodemw)(Node.js MediaWiki API 客户端)构建的 [Model Context Protocol (MCP)](https://modelcontextprotocol.org) 服务器。
130
+
131
+ ## 快速开始
132
+
133
+ ```bash
134
+ # 安装
135
+ npm install
136
+ npm run build
137
+
138
+ # 以游客身份连接
139
+ node dist/index.js zh.minecraft.wiki
140
+
141
+ # 使用账号密码连接
142
+ node dist/index.js -u myuser -p mypass mywiki.example.com
143
+ ```
144
+
145
+ ## CLI 用法
146
+
147
+ ```
148
+ nodemw-mcp-server [options] [server]
149
+ ```
150
+
151
+ **参数说明**:
152
+
153
+ | 参数 | 简写 | 说明 |
154
+ |--------|-------|-------------|
155
+ | `[server]` | (位置参数) | 目标 MediaWiki 服务器,如 `en.wikipedia.org` |
156
+ | `--server` | `-s` | 同上,显式形式 |
157
+ | `--path` | | API 脚本路径(默认:自动检测;先尝试 `/w`,再尝试根路径) |
158
+ | `--user` | `-u` | 登录用户名 |
159
+ | `--pass` | `-p` | 登录密码 |
160
+ | `--dry-run` | | 干运行模式(不执行实际编辑) |
161
+
162
+ **示例**:
163
+
164
+ ```bash
165
+ # 游客访问,自动检测 API 路径
166
+ nodemw-mcp-server zh.minecraft.wiki
167
+
168
+ # 认证访问,手动指定 API 路径
169
+ nodemw-mcp-server -u editor -p secret --path /w mywiki.example.com
170
+
171
+ # 使用完整 URL
172
+ nodemw-mcp-server -s https://en.wikipedia.org
173
+
174
+ # 干运行模式,安全测试
175
+ nodemw-mcp-server --dry-run -u editor -p secret mywiki.example.com
176
+ ```
177
+
178
+ ## 环境变量
179
+
180
+ 所有设置都可以通过环境变量配置,CLI 参数优先级更高。
181
+
182
+ | 变量 | 等效参数 |
183
+ |----------|------------|
184
+ | `NODEMW_MCP_SERVER` | `--server` / 位置参数 |
185
+ | `NODEMW_MCP_ENDPOINT_PATH` | `--path` |
186
+ | `NODEMW_MCP_MW_USER` | `--user` / `-u` |
187
+ | `NODEMW_MCP_MW_PASS` | `--pass` / `-p` |
188
+
189
+ ## 配合配置文件使用
190
+
191
+ ```json
192
+ {
193
+ "mcpServers": {
194
+ "nodemw": {
195
+ "command": "npx",
196
+ "args": ["@xiedada/nodemw-mcp-server"],
197
+ "env": {
198
+ "NODEMW_MCP_SERVER": "mywiki.example.com",
199
+ "NODEMW_MCP_MW_USER": "editor",
200
+ "NODEMW_MCP_MW_PASS": "secret"
201
+ }
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ ## 可用工具
208
+
209
+ ### 读取操作(29 个工具)
210
+
211
+ `get-article`、`search`、`get-pages-in-category`、`get-categories`、`get-users`、`get-all-pages`、`get-pages-in-namespace`、`get-pages-by-prefix`、`get-pages-transcluding`、`get-article-revisions`、`get-article-categories`、`get-article-properties`、`get-article-info`、`get-user-contribs`、`whoami`、`whois`、`whoare`、`get-images`、`get-images-from-article`、`get-image-usage`、`get-image-info`、`get-log`、`expand-templates`、`parse`、`get-recent-changes`、`get-site-info`、`get-site-stats`、`get-mediawiki-version`、`get-external-links`、`get-backlinks`、`get-query-page`
212
+
213
+ ### 写入操作(12 个工具,需要认证)
214
+
215
+ `edit`、`append`、`prepend`、`move`、`delete`、`protect`、`purge`、`send-email`、`upload`、`upload-by-url`、`add-flow-topic`、`create-account`
216
+
217
+ ## 开发
218
+
219
+ ```bash
220
+ npm run build # 构建 dist/index.js
221
+ npm run dev # 监视模式
222
+ npm run clean # 删除 dist/
223
+ npm test # 运行测试
224
+ ```
225
+
226
+ ## 许可协议
227
+
228
+ Copyright (c) 2026 Xie Youtian
229
+
230
+ Redistribution and use in source and binary forms, with or without
231
+ modification, are permitted provided that the following conditions are met:
232
+
233
+ 1. Redistributions of source code must retain the above copyright notice, this
234
+ list of conditions and the following disclaimer.
235
+
236
+ 2. Redistributions in binary form must reproduce the above copyright notice,
237
+ this list of conditions and the following disclaimer in the documentation
238
+ and/or other materials provided with the distribution.
239
+
240
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
241
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
243
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
244
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
245
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
246
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
247
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
248
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
249
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 Ze}from"@modelcontextprotocol/sdk/server/stdio.js";import{parseArgs as to}from"util";import{McpServer as ne}from"@modelcontextprotocol/sdk/server/mcp.js";var K="nodemw-mcp-server/1.0";function Z(e,t=!1){let o,r=t?" Write operations are available.":" Running in guest mode \u2014 only read operations are available.";return e?o=`Connected to ${e.sitename} (${e.base}). Running ${e.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 ne({name:"nodemw-mcp-server",version:"1.0.0",description:o},{capabilities:{tools:{}}})}import{z as q}from"zod";import se from"nodemw";var F=null,ie=null,tt=!1;function et(e){ie=e}function ot(e){let{server:t,path:o,protocol:r,port:a,proxy:c,userAgent:m,concurrency:p,debug:u,username:g,password:M,domain:U,dryRun:D}=e;return new se({server:t,protocol:r||"https",port:a,path:o,proxy:c,userAgent:m||K,concurrency:p,debug:u,username:g||void 0,password:M||void 0,domain:U,dryRun:D})}async function le(e){try{return await s(e,"getSiteInfo",["general"]),!0}catch{return!1}}async function rt(e){let t=["/w",""];for(let o of t){let r={...e,path:o},a=ot(r);if(await le(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 nt(e){F=ot(e);let{username:t,password:o}=e;return t&&o&&await new Promise((r,a)=>{F.logIn(c=>{c?a(new Error(`Login failed for user '${t}': ${c.message}`)):(tt=!0,r())})}),F}function n(){if(!F)throw new Error("Bot not initialized. Server must be started first.");return F}function st(){return tt}function s(e,t,...o){return new Promise((r,a)=>{let c=(m,p)=>{m?a(m):r(p)};e[t](...o,c)})}function it(e){return e.tool("get-article","Retrieve the content of a wiki article",{title:q.string().describe("Article title"),followRedirect:q.boolean().optional().default(!0).describe("Follow redirects"),redirectInfo:q.boolean().optional().default(!1).describe("Include information about redirects")},{title:"Get article",readOnlyHint:!0,destructiveHint:!1},async({title:t,followRedirect:o,redirectInfo:r})=>ae(t,o,r))}async function ae(e,t,o){try{let r=await n();if(o){let a=await new Promise((u,g)=>{let M=(U,D,re)=>{U?g(U):u([D,re])};r.getArticle(e,t,M)}),[c,m]=a;return c==null?{content:[{type:"text",text:`Page "${e}" not found or has no content.`}],isError:!0}:{content:[{type:"text",text:m?`Content:
29
+ import{StdioServerTransport as Ze}from"@modelcontextprotocol/sdk/server/stdio.js";import{parseArgs as to}from"util";import{McpServer as re}from"@modelcontextprotocol/sdk/server/mcp.js";var X="nodemw-mcp-server/1.0";function K(e,t=!1){let o,r=t?" Write operations are available.":" Running in guest mode \u2014 only read operations are available.";return e?o=`Connected to ${e.sitename} (${e.base}). Running ${e.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 re({name:"nodemw-mcp-server",version:"1.0.0",description:o},{capabilities:{tools:{}}})}import{z as D}from"zod";import ne from"nodemw";var O=null,se=null,Z=!1;function tt(e){se=e}function et(e){let{server:t,path:o,protocol:r,port:a,proxy:c,userAgent:m,concurrency:p,debug:u,username:g,password:f,domain:h,dryRun:L}=e;return new ne({server:t,protocol:r||"https",port:a,path:o,proxy:c,userAgent:m||X,concurrency:p,debug:u,username:g||void 0,password:f||void 0,domain:h,dryRun:L})}async function ie(e){try{return await s(e,"getSiteInfo",["general"]),!0}catch{return!1}}async function ot(e){let t=["/w",""];for(let o of t){let r={...e,path:o},a=et(r);if(await ie(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 rt(e){O=et(e);let{username:t,password:o}=e;return t&&o&&await new Promise((r,a)=>{O.logIn(c=>{c?a(new Error(`Login failed for user '${t}': ${c.message}`)):(Z=!0,r())})}),O}function n(){if(!O)throw new Error("Bot not initialized. Server must be started first.");return O}function nt(){return Z}function s(e,t,...o){return new Promise((r,a)=>{let c=(m,p)=>{m?a(m):r(p)};e[t](...o,c)})}function st(e){return e.tool("get-article","Retrieve the content of a wiki article",{title:D.string().describe("Article title"),followRedirect:D.boolean().optional().default(!0).describe("Follow redirects"),redirectInfo:D.boolean().optional().default(!1).describe("Include information about redirects")},{title:"Get article",readOnlyHint:!0,destructiveHint:!1},async({title:t,followRedirect:o,redirectInfo:r})=>le(t,o,r))}async function le(e,t,o){try{let r=await n();if(o){let a=await new Promise((u,g)=>{let f=(h,L,oe)=>{h?g(h):u([L,oe])};r.getArticle(e,t,f)}),[c,m]=a;return c==null?{content:[{type:"text",text:`Page "${e}" 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{let a=await s(r,"getArticle",e,t);return a==null?{content:[{type:"text",text:`Page "${e}" 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 T}from"zod";function l(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}],structuredContent:e}}function i(e,t){return{content:[{type:"text",text:JSON.stringify({error:e,details:t?.message},null,2)}],isError:!0}}function lt(e){let t=e.tool("search","Search for wiki pages by keyword",{keyword:T.string().describe("Search keyword"),limit:T.number().optional().default(10).describe("Maximum number of results")},{title:"Search",readOnlyHint:!0,destructiveHint:!1},async({keyword:o,limit:r})=>ce(o,r));return t.update({outputSchema:{total:T.number(),limit:T.number(),keyword:T.string(),results:T.array(T.record(T.unknown()))}}),t}async function ce(e,t){try{let o=await n(),r=await s(o,"search",e),a=r.slice(0,t);return l({total:r.length,limit:t,keyword:e,results:a})}catch(o){return i("Failed to search",o)}}import{z as C}from"zod";function at(e){let t=e.tool("get-pages-in-category","Get all pages in a category",{category:C.string().describe("Category name (with or without Category: prefix)")},{title:"Get pages in category",readOnlyHint:!0,destructiveHint:!1},async({category:o})=>me(o));return t.update({outputSchema:{category:C.string(),pages:C.array(C.record(C.unknown())),count:C.number()}}),t}async function me(e){try{let t=await n(),o=e.replace(/^Category:/i,""),r=await s(t,"getPagesInCategory",o);return l({category:o,pages:r,count:r.length})}catch(t){return i("Failed to get pages in category",t)}}import{z as P}from"zod";function ct(e){let t=e.tool("get-categories","Get all categories matching a prefix",{prefix:P.string().optional().default("").describe("Prefix to filter categories")},{title:"Get categories",readOnlyHint:!0,destructiveHint:!1},async({prefix:o})=>pe(o));return t.update({outputSchema:{prefix:P.string(),categories:P.array(P.record(P.unknown())),count:P.number()}}),t}async function pe(e){try{let t=await n(),o=await s(t,"getCategories",e);return l({prefix:e,categories:o,count:o.length})}catch(t){return i("Failed to get categories",t)}}import{z as h}from"zod";function mt(e){let t=e.tool("get-users","Get all users matching a prefix",{prefix:h.string().optional().default("").describe("Prefix to filter usernames"),onlyWithEdits:h.boolean().optional().default(!1).describe("Only include users with at least one edit")},{title:"Get users",readOnlyHint:!0,destructiveHint:!1},async({prefix:o,onlyWithEdits:r})=>ue(o,r));return t.update({outputSchema:{prefix:h.string(),onlyWithEdits:h.boolean(),users:h.array(h.record(h.unknown())),count:h.number()}}),t}async function ue(e,t){try{let o=await n(),r=await s(o,"getUsers",{prefix:e,witheditsonly:t});return l({prefix:e,onlyWithEdits:t,users:r,count:r.length})}catch(o){return i("Failed to get users",o)}}import{z as A}from"zod";function pt(e){let t=e.tool("get-all-pages","Get all non-redirect pages from the wiki",{limit:A.number().optional().default(500).describe("Maximum number of pages to return")},{title:"Get all pages",readOnlyHint:!0,destructiveHint:!1},async({limit:o})=>de(o));return t.update({outputSchema:{total:A.number(),displayed:A.number(),pages:A.array(A.record(A.unknown())),limit:A.number()}}),t}async function de(e){try{let t=await n(),o=await s(t,"getAllPages"),r=o.slice(0,e);return l({total:o.length,displayed:r.length,pages:r,limit:e})}catch(t){return i("Failed to get all pages",t)}}import{z as j}from"zod";function ut(e){let t=e.tool("get-pages-in-namespace","Get all non-redirect pages in a specific namespace",{namespace:j.number().describe("Namespace number to filter pages")},{title:"Get pages in namespace",readOnlyHint:!0,destructiveHint:!1},async({namespace:o})=>ge(o));return t.update({outputSchema:{namespace:j.number(),pages:j.array(j.record(j.unknown())),count:j.number()}}),t}async function ge(e){try{let t=await n(),o=await s(t,"getPagesInNamespace",e);return l({namespace:e,pages:o,count:o.length})}catch(t){return i("Failed to get pages in namespace",t)}}import{z as B}from"zod";function dt(e){let t=e.tool("get-pages-by-prefix","Get pages starting with a specific prefix",{prefix:B.string().describe("Prefix to match page titles")},{title:"Get pages by prefix",readOnlyHint:!0,destructiveHint:!1},async({prefix:o})=>fe(o));return t.update({outputSchema:{prefix:B.string(),pages:B.array(B.record(B.unknown())),count:B.number()}}),t}async function fe(e){try{let t=await n(),o=await s(t,"getPagesByPrefix",e);return l({prefix:e,pages:o,count:o.length})}catch(t){return i("Failed to get pages by prefix",t)}}import{z as E}from"zod";function gt(e){let t=e.tool("get-pages-transcluding","Get all pages that transclude (include) a specific template",{template:E.string().describe("Template title to find transclusions")},{title:"Get pages transcluding template",readOnlyHint:!0,destructiveHint:!1},async({template:o})=>ye(o));return t.update({outputSchema:{template:E.string(),pages:E.array(E.record(E.unknown())),count:E.number()}}),t}async function ye(e){try{let t=await n(),r=(await s(t,"getPagesTranscluding",e))[1],a=Array.isArray(r)?r.filter(c=>c!=null&&typeof c=="object"&&"title"in c):[];return l({template:e,pages:a,count:a.length})}catch(t){return i("Failed to get pages transcluding template",t)}}import{z as R}from"zod";function ft(e){let t=e.tool("get-article-revisions","Get all revisions of a wiki article",{title:R.union([R.string(),R.number()]).describe("Article title or page ID")},{title:"Get article revisions",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Te(o));return t.update({outputSchema:{title:R.string(),revisions:R.array(R.record(R.unknown())),count:R.number()}}),t}async function Te(e){try{let t=await n(),r=(await s(t,"getArticleRevisions",e)).flat();return l({title:e,revisions:r,count:r.length})}catch(t){return i("Failed to get article revisions",t)}}import{z as b}from"zod";function yt(e){let t=e.tool("get-article-categories","Get all categories that an article belongs to",{title:b.union([b.string(),b.number()]).describe("Article title or page ID")},{title:"Get article categories",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>he(o));return t.update({outputSchema:{title:b.string(),categories:b.array(b.record(b.unknown())),count:b.number()}}),t}async function he(e){try{let t=await n(),o=await s(t,"getArticleCategories",e);return l({title:e,categories:o,count:o.length})}catch(t){return i("Failed to get article categories",t)}}import{z as W}from"zod";function Tt(e){let t=e.tool("get-article-properties","Get page properties for a wiki article",{title:W.string().describe("Article title")},{title:"Get article properties",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Re(o));return t.update({outputSchema:{title:W.string(),properties:W.record(W.unknown())}}),t}async function Re(e){try{let t=await n(),o=await s(t,"getArticleProperties",e);return l({title:e,properties:o})}catch(t){return i("Failed to get article properties",t)}}import{z as d}from"zod";function ht(e){let t=e.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:o,properties:r})=>be(o,r));return t.update({outputSchema:{title:d.string(),results:d.array(d.record(d.unknown())),count:d.number()}}),t}async function be(e,t){try{let o=await n(),a=await s(o,"getArticleInfo",e,t?{inprop:t}:{}),c=Array.isArray(a)?a:[a];return l({title:e,results:c,count:c.length})}catch(o){return i("Failed to get article info",o)}}import{z as f}from"zod";function Rt(e){let t=e.tool("get-user-contribs","Get contributions made by a specific user",{username:f.string().describe("Username to get contributions for"),namespace:f.number().optional().describe("Filter contributions by namespace"),limit:f.number().optional().default(50).describe("Maximum number of contributions to return")},{title:"Get user contributions",readOnlyHint:!0,destructiveHint:!1},async({username:o,namespace:r,limit:a})=>xe(o,r,a));return t.update({outputSchema:{username:f.string(),namespace:f.number(),limit:f.number(),total:f.number(),displayed:f.number(),contributions:f.array(f.record(f.unknown()))}}),t}async function xe(e,t,o=50){try{let r=await n(),a={user:e,...t!==void 0&&{namespace:t}},c=await s(r,"getUserContribs",a),m=Array.isArray(c[1])?c[1]:[],p=m.slice(0,o);return l({username:e,namespace:t,limit:o,total:m.length,displayed:p.length,contributions:p})}catch(r){return i("Failed to get user contributions",r)}}function bt(e){let t=e.tool("whoami","Get information about the currently logged in user",{},{title:"Who am I",readOnlyHint:!0,destructiveHint:!1},async()=>ve());return t.update({outputSchema:{}}),t}async function ve(){try{let e=await n(),t=await s(e,"whoami");return l(t)}catch(e){return i("Failed to get current user info",e)}}import{z as we}from"zod";function xt(e){let t=e.tool("whois","Get information about a specific user",{username:we.string().describe("Username to look up")},{title:"Whois",readOnlyHint:!0,destructiveHint:!1},async({username:o})=>ke(o));return t.update({outputSchema:{}}),t}async function ke(e){try{let t=await n(),o=await s(t,"whois",e);return o.missing?i(`User "${e}" not found.`):l(o)}catch(t){return i("Failed to get user info",t)}}import{z as vt}from"zod";function wt(e){let t=e.tool("whoare","Get information about multiple wiki users",{usernames:vt.array(vt.string()).describe("Array of usernames to query")},{title:"Who are",readOnlyHint:!0,destructiveHint:!1},async o=>Se(o));return t.update({outputSchema:{}}),t}async function Se(e){try{let t=await n(),o=await s(t,"whoare",e.usernames);return l(o)}catch(t){return i("Failed to get user information",t)}}import{z as x}from"zod";function kt(e){let t=e.tool("get-images","Get list of images starting from a specific name",{startFrom:x.string().optional().default("").describe("Start from this image name"),limit:x.number().optional().default(50).describe("Maximum number of images to return")},{title:"Get images",readOnlyHint:!0,destructiveHint:!1},async({startFrom:o,limit:r})=>Ae(o,r));return t.update({outputSchema:{total:x.number(),limit:x.number(),startFrom:x.string(),images:x.array(x.record(x.unknown()))}}),t}async function Ae(e,t){try{let o=await n(),r=await new Promise((c,m)=>{o.getImages(e,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,t);return l({total:r.length,limit:t,startFrom:e,images:a})}catch(o){return i("Failed to get images",o)}}import{z as v}from"zod";function St(e){let t=e.tool("get-images-from-article","Get all images embedded in a specific article",{title:v.union([v.string(),v.number()]).describe("Article title or page ID")},{title:"Get images from article",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Me(o));return t.update({outputSchema:{title:v.string(),images:v.array(v.record(v.unknown())),count:v.number()}}),t}async function Me(e){try{let t=await n(),o=await s(t,"getImagesFromArticle",e);return l({title:e,images:o,count:o.length})}catch(t){return i("Failed to get images from article",t)}}import{z as H}from"zod";function At(e){let t=e.tool("get-image-usage","Get all pages that use a specific image",{filename:H.string().describe("Image filename with File: prefix")},{title:"Get image usage",readOnlyHint:!0,destructiveHint:!1},async({filename:o})=>Ce(o));return t.update({outputSchema:{filename:H.string(),pages:H.array(H.record(H.unknown())),count:H.number()}}),t}async function Ce(e){try{let t=await n(),o=await s(t,"getImageUsage",e);return l({filename:e,pages:o,count:o.length})}catch(t){return i("Failed to get image usage",t)}}import{z as $}from"zod";function Mt(e){let t=e.tool("get-image-info","Get detailed information about an image file",{filename:$.string().describe("Image filename with File: prefix")},{title:"Get image info",readOnlyHint:!0,destructiveHint:!1},async({filename:o})=>Pe(o));return t.update({outputSchema:{filename:$.string(),info:$.record($.unknown())}}),t}async function Pe(e){try{let t=await n(),o=await s(t,"getImageInfo",e);return o?l({filename:e,info:o}):i(`Image "${e}" not found.`)}catch(t){return i("Failed to get image info",t)}}import{z as y}from"zod";function Ct(e){let t=e.tool("get-log","Get log entries of a specific type",{type:y.string().describe("Log type (e.g. delete, block, move)"),start:y.string().optional().default("").describe("Start timestamp (YYYYMMDDHHMMSS format)"),limit:y.number().optional().default(50).describe("Maximum number of entries to return")},{title:"Get log entries",readOnlyHint:!0,destructiveHint:!1},async({type:o,start:r,limit:a})=>je(o,r,a));return t.update({outputSchema:{type:y.string(),start:y.string(),limit:y.number(),total:y.number(),displayed:y.number(),entries:y.array(y.record(y.unknown()))}}),t}async function je(e,t,o){try{let r=await n(),a=await new Promise((m,p)=>{r.getLog(e,t,(u,...g)=>{if(u)p(u);else{let M=g[0];m(Array.isArray(M)?M:[])}})}),c=a.slice(0,o);return l({type:e,start:t,limit:o,total:a.length,displayed:c.length,entries:c})}catch(r){return i("Failed to get log entries",r)}}import{z as Pt}from"zod";function jt(e){return e.tool("expand-templates","Expand templates in wikitext",{text:Pt.string().describe("Wikitext with templates to expand"),title:Pt.string().optional().describe("Context page title")},{title:"Expand templates",readOnlyHint:!0,destructiveHint:!1},async({text:t,title:o})=>Be(t,o))}async function Be(e,t){try{let o=await n(),r=await s(o,"expandTemplates",e,t||"");return r==null?{content:[{type:"text",text:`Failed to expand templates for "${e}".`}],isError:!0}:{content:[{type:"text",text:r}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as Bt}from"zod";function Et(e){return e.tool("parse","Parse wikitext to HTML",{text:Bt.string().describe("Wikitext to parse"),title:Bt.string().optional().describe("Context page title")},{title:"Parse wikitext",readOnlyHint:!0,destructiveHint:!1},async({text:t,title:o})=>Ee(t,o))}async function Ee(e,t){try{let o=await n(),r=await s(o,"parse",e,t||""),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 w}from"zod";function Ht(e){let t=e.tool("get-recent-changes","Get recent changes on the wiki",{start:w.string().optional().describe("Start timestamp"),limit:w.number().optional().default(50).describe("Maximum number of changes to return")},{title:"Get recent changes",readOnlyHint:!0,destructiveHint:!1},async({start:o,limit:r})=>He(o,r));return t.update({outputSchema:{total:w.number(),limit:w.number(),start:w.string(),changes:w.array(w.record(w.unknown()))}}),t}async function He(e,t=50){try{let o=await n(),r=await new Promise((c,m)=>{o.getRecentChanges(e,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,t);return l({total:r.length,limit:t,start:e,changes:a})}catch(o){return i("Failed to get recent changes",o)}}import{z as It}from"zod";function Gt(e){let t=e.tool("get-site-info","Get site information from MediaWiki",{properties:It.array(It.string()).describe("List of site information properties to retrieve")},{title:"Get site info",readOnlyHint:!0,destructiveHint:!1},async({properties:o})=>Ie(o));return t.update({outputSchema:{}}),t}async function Ie(e){try{let t=await n(),o=await s(t,"getSiteInfo",e);return l(o||{})}catch(t){return i("Failed to get site info",t)}}function Ft(e){let t=e.tool("get-site-stats","Get site statistics",{},{title:"Get site stats",readOnlyHint:!0,destructiveHint:!1},async()=>Ge());return t.update({outputSchema:{}}),t}async function Ge(){try{let e=await n(),t=await s(e,"getSiteStats");return l(t)}catch(e){return i("Failed to get site stats",e)}}function Ot(e){let t=e.tool("get-mediawiki-version","Get MediaWiki version running on the server",{},{title:"Get MediaWiki version",readOnlyHint:!0,destructiveHint:!1},async()=>Fe());return t.update({outputSchema:{version:z.string()}}),t}async function Fe(){try{let e=await n(),t=await s(e,"getMediaWikiVersion");return l({version:t})}catch(e){return i("Failed to get MediaWiki version",e)}}import{z as I}from"zod";function Ut(e){let t=e.tool("get-query-page","Get results from a query page (special page)",{name:I.string().describe("Name of the query page")},{title:"Get query page results",readOnlyHint:!0,destructiveHint:!1},async({name:o})=>Oe(o));return t.update({outputSchema:{name:I.string(),results:I.array(I.record(I.unknown())),count:I.number()}}),t}async function Oe(e){try{let t=await n(),o=await s(t,"getQueryPage",e);return l({name:e,results:o,count:o.length})}catch(t){return i("Failed to get query page results",t)}}import{z as k}from"zod";function zt(e){let t=e.tool("get-external-links","Get all external links from an article",{title:k.union([k.string(),k.number()]).describe("Article title or page ID")},{title:"Get external links",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Ue(o));return t.update({outputSchema:{title:k.string(),links:k.array(k.record(k.unknown())),count:k.number()}}),t}async function Ue(e){try{let t=await n(),o=await s(t,"getExternalLinks",e);return l({title:e,links:o.map(r=>r["*"]),count:o.length})}catch(t){return i("Failed to get external links",t)}}import{z as G}from"zod";function Wt(e){let t=e.tool("get-backlinks","Get all backlinks to a specific page",{title:G.string().describe("Target page title to find backlinks for")},{title:"Get backlinks",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>ze(o));return t.update({outputSchema:{target:G.string(),backlinks:G.array(G.record(G.unknown())),count:G.number()}}),t}async function ze(e){try{let t=await n(),o=await s(t,"getBacklinks",e);return l({target:e,backlinks:o,count:o.length})}catch(t){return i("Failed to get backlinks",t)}}import{z as N}from"zod";function $t(e){let t=e.tool("edit","Edit a wiki page (requires authentication)",{title:N.string().describe("Page title to edit"),content:N.string().describe("New content for the page"),summary:N.string().describe("Edit summary"),minor:N.boolean().optional().default(!1).describe("Mark as minor edit")},{title:"Edit page",readOnlyHint:!1,destructiveHint:!0},async o=>We(o));return t.update({outputSchema:{}}),t}async function We(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"edit",e.title,e.content,o,e.minor||!1);return l(r)}catch(t){return i("Failed to edit page",t)}}import{z as O}from"zod";function Nt(e){let t=e.tool("append","Append content to a wiki page (requires authentication)",{title:O.string().describe("Page title"),content:O.string().describe("Content to append"),summary:O.string().describe("Edit summary")},{title:"Append to page",readOnlyHint:!1,destructiveHint:!0},async o=>$e(o));return t.update({outputSchema:{success:O.boolean(),title:O.string()}}),t}async function $e(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`;return await s(t,"append",e.title,e.content,o),l({success:!0,title:e.title})}catch(t){return i("Failed to append to page",t)}}import{z as _}from"zod";function Lt(e){let t=e.tool("prepend","Prepend content to a wiki page (requires authentication)",{title:_.string().describe("Page title to prepend to"),content:_.string().describe("Content to prepend"),summary:_.string().describe("Edit summary")},{title:"Prepend to page",readOnlyHint:!1,destructiveHint:!0},async o=>Ne(o));return t.update({outputSchema:{}}),t}async function Ne(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"prepend",e.title,e.content,o);return l(r)}catch(t){return i("Failed to prepend to page",t)}}import{z as Q}from"zod";function Dt(e){let t=e.tool("move","Move (rename) a wiki page (requires authentication)",{from:Q.string().describe("Current page title"),to:Q.string().describe("New page title"),summary:Q.string().describe("Move summary")},{title:"Move page",readOnlyHint:!1,destructiveHint:!0},async o=>Le(o));return t.update({outputSchema:{}}),t}async function Le(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"move",e.from,e.to,o);return l(r)}catch(t){return i("Failed to move page",t)}}import{z as qt}from"zod";function _t(e){let t=e.tool("delete","Delete a wiki page (requires authentication)",{title:qt.string().describe("Page title to delete"),reason:qt.string().describe("Reason for deletion")},{title:"Delete page",readOnlyHint:!1,destructiveHint:!0},async o=>De(o));return t.update({outputSchema:{}}),t}async function De(e){try{let t=await n(),o=`[nodemw-mcp] ${e.reason}`,r=await s(t,"delete",e.title,o);return l(r)}catch(t){return i("Failed to delete page",t)}}import{z as S}from"zod";function Qt(e){let t=e.tool("protect","Protect a wiki page (requires authentication)",{title:S.string().describe("Page title to protect"),protections:S.array(S.object({type:S.string().describe("Action type (e.g., edit, move)"),level:S.string().optional().default("all").describe("Protection level (e.g., sysop, autoconfirmed)"),expiry:S.string().optional().describe("Expiry time (e.g., 1 week, never)")})).describe("Protection settings"),reason:S.string().optional().describe("Reason for protection"),cascade:S.boolean().optional().default(!1).describe("Apply cascade protection")},{title:"Protect page",readOnlyHint:!1,destructiveHint:!0},async o=>qe(o));return t.update({outputSchema:{}}),t}async function qe(e){try{let t=await n(),o={};e.reason&&(o.reason=`[nodemw-mcp] ${e.reason}`),e.cascade&&(o.cascade=e.cascade);let r=await s(t,"protect",e.title,e.protections,o);return l(r)}catch(t){return i("Failed to protect page",t)}}import{z as L}from"zod";function Vt(e){let t=e.tool("purge","Purge cache for wiki pages",{titles:L.union([L.string(),L.array(L.string())]).describe("Page title(s) or category to purge")},{title:"Purge pages",readOnlyHint:!1,destructiveHint:!1},async o=>_e(o));return t.update({outputSchema:{}}),t}async function _e(e){try{let t=await n(),o=await s(t,"purge",e.titles);return l(o)}catch(t){return i("Failed to purge pages",t)}}import{z as V}from"zod";function Yt(e){let t=e.tool("send-email","Send email to a wiki user (requires authentication)",{username:V.string().describe("Username to email"),subject:V.string().describe("Email subject"),text:V.string().describe("Email content")},{title:"Send email",readOnlyHint:!1,destructiveHint:!1},async o=>Qe(o));return t.update({outputSchema:{}}),t}async function Qe(e){try{let t=await n(),o=await s(t,"sendEmail",e.username,e.subject,e.text);return l(o)}catch(t){return i("Failed to send email",t)}}import{z as Y}from"zod";function Jt(e){let t=e.tool("upload","Upload a file to wiki (requires authentication)",{filename:Y.string().describe("Destination filename on wiki"),content:Y.string().describe("File content as base64 string"),comment:Y.string().optional().describe("Upload comment")},{title:"Upload file",readOnlyHint:!1,destructiveHint:!1},async o=>Ve(o));return t.update({outputSchema:{}}),t}async function Ve(e){try{let t=await n(),o=Buffer.from(e.content,"base64"),r=e.comment?`[nodemw-mcp] ${e.comment}`:"[nodemw-mcp] File upload",a=await s(t,"upload",e.filename,o,r);return l(a)}catch(t){return i("Failed to upload file",t)}}import{z as J}from"zod";function Xt(e){let t=e.tool("upload-by-url","Upload a file to wiki from URL (requires authentication)",{filename:J.string().describe("Destination filename on wiki"),url:J.string().url().describe("Source URL to download file from"),summary:J.string().optional().describe("Upload summary")},{title:"Upload file by URL",readOnlyHint:!1,destructiveHint:!1},async o=>Ye(o));return t.update({outputSchema:{}}),t}async function Ye(e){try{let t=await n(),o=e.summary?`[nodemw-mcp] ${e.summary}`:"[nodemw-mcp] File upload from URL",r=await s(t,"uploadByUrl",e.filename,e.url,o);return l(r)}catch(t){return i("Failed to upload file by URL",t)}}import{z as X}from"zod";function Kt(e){let t=e.tool("add-flow-topic","Add a new Flow topic to a wiki page (requires authentication)",{title:X.string().describe("Page title to add topic to"),subject:X.string().describe("Topic subject"),content:X.string().describe("Topic content in wikitext")},{title:"Add Flow topic",readOnlyHint:!1,destructiveHint:!1},async o=>Je(o));return t.update({outputSchema:{}}),t}async function Je(e){try{let t=await n(),o=await s(t,"addFlowTopic",e.title,e.subject,e.content);return l(o)}catch(t){return i("Failed to add Flow topic",t)}}import{z as Zt}from"zod";function te(e){let t=e.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 o=>Xe(o));return t.update({outputSchema:{}}),t}async function Xe(e){try{let t=await n(),o=await s(t,"createAccount",e.username,e.password);return l(o)}catch(t){return i("Failed to create account",t)}}var ee=[it,lt,at,ct,mt,pt,ut,dt,gt,ft,yt,Tt,ht,Rt,bt,xt,wt,kt,St,At,Mt,Ct,jt,Et,Ht,Gt,Ft,Ot,Ut,zt,Wt],Ke=[$t,Nt,Lt,Dt,_t,Qt,Vt,Yt,Jt,Xt,Kt,te];function oe(e,t=!0){let o=t?[...ee,...Ke]:ee,r=[];for(let a of o)try{r.push(a(e))}catch(c){console.error(`Error registering tool: ${c.message}`)}return r}function eo(){let{values:e,positionals:t}=to({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=e.server??t[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=!!(e.path??e.endpoint??m);return{config:{server:r,protocol:a,port:c,path:e.path??e.endpoint??m??"/w",username:e.user??process.env.NODEMW_MCP_MW_USER,password:e.pass??process.env.NODEMW_MCP_MW_PASS,token:e.token,dryRun:e["dry-run"]},pathExplicit:p}}async function oo(){let{config:e,pathExplicit:t}=eo();if(!t)try{e.path=await rt(e),console.error(`Auto-detected API path: ${e.path}`)}catch(p){console.error("Error:",p.message),process.exit(1)}et(e);try{await nt(e)}catch(p){console.error("Error:",p.message),process.exit(1)}let o=n(),r;try{let u=(await s(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=st(),c=Z(r,a);oe(c,a);let m=new Ze;await c.connect(m)}oo().catch(console.error);
35
+ ${JSON.stringify(m,null,2)}`:c}]}}else{let a=await s(r,"getArticle",e,t);return a==null?{content:[{type:"text",text:`Page "${e}" 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 R}from"zod";function l(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}],structuredContent:e}}function i(e,t){return{content:[{type:"text",text:JSON.stringify({error:e,details:t?.message},null,2)}],isError:!0}}function it(e){let t=e.tool("search","Search for wiki pages by keyword",{keyword:R.string().describe("Search keyword"),limit:R.number().optional().default(10).describe("Maximum number of results")},{title:"Search",readOnlyHint:!0,destructiveHint:!1},async({keyword:o,limit:r})=>ae(o,r));return t.update({outputSchema:{total:R.number(),limit:R.number(),keyword:R.string(),results:R.array(R.record(R.unknown()))}}),t}async function ae(e,t){try{let o=await n(),r=await s(o,"search",e),a=r.slice(0,t);return l({total:r.length,limit:t,keyword:e,results:a})}catch(o){return i("Failed to search",o)}}import{z as P}from"zod";function lt(e){let t=e.tool("get-pages-in-category","Get all pages in a category",{category:P.string().describe("Category name (with or without Category: prefix)")},{title:"Get pages in category",readOnlyHint:!0,destructiveHint:!1},async({category:o})=>ce(o));return t.update({outputSchema:{category:P.string(),pages:P.array(P.record(P.unknown())),count:P.number()}}),t}async function ce(e){try{let t=await n(),o=e.replace(/^Category:/i,""),r=await s(t,"getPagesInCategory",o);return l({category:o,pages:r,count:r.length})}catch(t){return i("Failed to get pages in category",t)}}import{z as j}from"zod";function at(e){let t=e.tool("get-categories","Get all categories matching a prefix",{prefix:j.string().optional().default("").describe("Prefix to filter categories")},{title:"Get categories",readOnlyHint:!0,destructiveHint:!1},async({prefix:o})=>me(o));return t.update({outputSchema:{prefix:j.string(),categories:j.array(j.record(j.unknown())),count:j.number()}}),t}async function me(e){try{let t=await n(),o=await s(t,"getCategories",e);return l({prefix:e,categories:o,count:o.length})}catch(t){return i("Failed to get categories",t)}}import{z as b}from"zod";function ct(e){let t=e.tool("get-users","Get all users matching a prefix",{prefix:b.string().optional().default("").describe("Prefix to filter usernames"),onlyWithEdits:b.boolean().optional().default(!1).describe("Only include users with at least one edit")},{title:"Get users",readOnlyHint:!0,destructiveHint:!1},async({prefix:o,onlyWithEdits:r})=>pe(o,r));return t.update({outputSchema:{prefix:b.string(),onlyWithEdits:b.boolean(),users:b.array(b.record(b.unknown())),count:b.number()}}),t}async function pe(e,t){try{let o=await n(),r=await s(o,"getUsers",{prefix:e,witheditsonly:t});return l({prefix:e,onlyWithEdits:t,users:r,count:r.length})}catch(o){return i("Failed to get users",o)}}import{z as C}from"zod";function mt(e){let t=e.tool("get-all-pages","Get all non-redirect pages from the wiki",{limit:C.number().optional().default(500).describe("Maximum number of pages to return")},{title:"Get all pages",readOnlyHint:!0,destructiveHint:!1},async({limit:o})=>ue(o));return t.update({outputSchema:{total:C.number(),displayed:C.number(),pages:C.array(C.record(C.unknown())),limit:C.number()}}),t}async function ue(e){try{let t=await n(),o=await s(t,"getAllPages"),r=o.slice(0,e);return l({total:o.length,displayed:r.length,pages:r,limit:e})}catch(t){return i("Failed to get all pages",t)}}import{z as B}from"zod";function pt(e){let t=e.tool("get-pages-in-namespace","Get all non-redirect pages in a specific namespace",{namespace:B.number().describe("Namespace number to filter pages")},{title:"Get pages in namespace",readOnlyHint:!0,destructiveHint:!1},async({namespace:o})=>de(o));return t.update({outputSchema:{namespace:B.number(),pages:B.array(B.record(B.unknown())),count:B.number()}}),t}async function de(e){try{let t=await n(),o=await s(t,"getPagesInNamespace",e);return l({namespace:e,pages:o,count:o.length})}catch(t){return i("Failed to get pages in namespace",t)}}import{z as E}from"zod";function ut(e){let t=e.tool("get-pages-by-prefix","Get pages starting with a specific prefix",{prefix:E.string().describe("Prefix to match page titles")},{title:"Get pages by prefix",readOnlyHint:!0,destructiveHint:!1},async({prefix:o})=>ge(o));return t.update({outputSchema:{prefix:E.string(),pages:E.array(E.record(E.unknown())),count:E.number()}}),t}async function ge(e){try{let t=await n(),o=await s(t,"getPagesByPrefix",e);return l({prefix:e,pages:o,count:o.length})}catch(t){return i("Failed to get pages by prefix",t)}}import{z as H}from"zod";function dt(e){let t=e.tool("get-pages-transcluding","Get all pages that transclude (include) a specific template",{template:H.string().describe("Template title to find transclusions")},{title:"Get pages transcluding template",readOnlyHint:!0,destructiveHint:!1},async({template:o})=>fe(o));return t.update({outputSchema:{template:H.string(),pages:H.array(H.record(H.unknown())),count:H.number()}}),t}async function fe(e){try{let t=await n(),r=(await s(t,"getPagesTranscluding",e))[1],a=Array.isArray(r)?r.filter(c=>c!=null&&typeof c=="object"&&"title"in c):[];return l({template:e,pages:a,count:a.length})}catch(t){return i("Failed to get pages transcluding template",t)}}import{z as x}from"zod";function gt(e){let t=e.tool("get-article-revisions","Get all revisions of a wiki article",{title:x.union([x.string(),x.number()]).describe("Article title or page ID")},{title:"Get article revisions",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>ye(o));return t.update({outputSchema:{title:x.string(),revisions:x.array(x.record(x.unknown())),count:x.number()}}),t}async function ye(e){try{let t=await n(),r=(await s(t,"getArticleRevisions",e)).flat();return l({title:e,revisions:r,count:r.length})}catch(t){return i("Failed to get article revisions",t)}}import{z as v}from"zod";function ft(e){let t=e.tool("get-article-categories","Get all categories that an article belongs to",{title:v.union([v.string(),v.number()]).describe("Article title or page ID")},{title:"Get article categories",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Te(o));return t.update({outputSchema:{title:v.string(),categories:v.array(v.record(v.unknown())),count:v.number()}}),t}async function Te(e){try{let t=await n(),o=await s(t,"getArticleCategories",e);return l({title:e,categories:o,count:o.length})}catch(t){return i("Failed to get article categories",t)}}import{z}from"zod";function yt(e){let t=e.tool("get-article-properties","Get page properties for a wiki article",{title:z.string().describe("Article title")},{title:"Get article properties",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>he(o));return t.update({outputSchema:{title:z.string(),properties:z.record(z.unknown())}}),t}async function he(e){try{let t=await n(),o=await s(t,"getArticleProperties",e);return l({title:e,properties:o})}catch(t){return i("Failed to get article properties",t)}}import{z as d}from"zod";function Tt(e){let t=e.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:o,properties:r})=>Re(o,r));return t.update({outputSchema:{title:d.string(),results:d.array(d.record(d.unknown())),count:d.number()}}),t}async function Re(e,t){try{let o=await n(),a=await s(o,"getArticleInfo",e,t?{inprop:t}:{}),c=Array.isArray(a)?a:[a];return l({title:e,results:c,count:c.length})}catch(o){return i("Failed to get article info",o)}}import{z as y}from"zod";function ht(e){let t=e.tool("get-user-contribs","Get contributions made by a specific user",{username:y.string().describe("Username to get contributions for"),namespace:y.number().optional().describe("Filter contributions by namespace"),limit:y.number().optional().default(50).describe("Maximum number of contributions to return")},{title:"Get user contributions",readOnlyHint:!0,destructiveHint:!1},async({username:o,namespace:r,limit:a})=>be(o,r,a));return t.update({outputSchema:{username:y.string(),namespace:y.number(),limit:y.number(),total:y.number(),displayed:y.number(),contributions:y.array(y.record(y.unknown()))}}),t}async function be(e,t,o=50){try{let r=await n(),a={user:e,...t!==void 0&&{namespace:t}},c=await s(r,"getUserContribs",a),m=Array.isArray(c[1])?c[1]:[],p=m.slice(0,o);return l({username:e,namespace:t,limit:o,total:m.length,displayed:p.length,contributions:p})}catch(r){return i("Failed to get user contributions",r)}}function Rt(e){let t=e.tool("whoami","Get information about the currently logged in user",{},{title:"Who am I",readOnlyHint:!0,destructiveHint:!1},async()=>xe());return t.update({outputSchema:{}}),t}async function xe(){try{let e=await n(),t=await s(e,"whoami");return l(t)}catch(e){return i("Failed to get current user info",e)}}import{z as ve}from"zod";function bt(e){let t=e.tool("whois","Get information about a specific user",{username:ve.string().describe("Username to look up")},{title:"Whois",readOnlyHint:!0,destructiveHint:!1},async({username:o})=>we(o));return t.update({outputSchema:{}}),t}async function we(e){try{let t=await n(),o=await s(t,"whois",e);return o.missing?i(`User "${e}" not found.`):l(o)}catch(t){return i("Failed to get user info",t)}}import{z as xt}from"zod";function vt(e){let t=e.tool("whoare","Get information about multiple wiki users",{usernames:xt.array(xt.string()).describe("Array of usernames to query")},{title:"Who are",readOnlyHint:!0,destructiveHint:!1},async o=>ke(o));return t.update({outputSchema:{}}),t}async function ke(e){try{let t=await n(),o=await s(t,"whoare",e.usernames);return l(o)}catch(t){return i("Failed to get user information",t)}}import{z as w}from"zod";function wt(e){let t=e.tool("get-images","Get list of images starting from a specific name",{startFrom:w.string().optional().default("").describe("Start from this image name"),limit:w.number().optional().default(50).describe("Maximum number of images to return")},{title:"Get images",readOnlyHint:!0,destructiveHint:!1},async({startFrom:o,limit:r})=>Se(o,r));return t.update({outputSchema:{total:w.number(),limit:w.number(),startFrom:w.string(),images:w.array(w.record(w.unknown()))}}),t}async function Se(e,t){try{let o=await n(),r=await new Promise((c,m)=>{o.getImages(e,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,t);return l({total:r.length,limit:t,startFrom:e,images:a})}catch(o){return i("Failed to get images",o)}}import{z as k}from"zod";function kt(e){let t=e.tool("get-images-from-article","Get all images embedded in a specific article",{title:k.union([k.string(),k.number()]).describe("Article title or page ID")},{title:"Get images from article",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Ae(o));return t.update({outputSchema:{title:k.string(),images:k.array(k.record(k.unknown())),count:k.number()}}),t}async function Ae(e){try{let t=await n(),o=await s(t,"getImagesFromArticle",e);return l({title:e,images:o,count:o.length})}catch(t){return i("Failed to get images from article",t)}}import{z as I}from"zod";function St(e){let t=e.tool("get-image-usage","Get all pages that use a specific image",{filename:I.string().describe("Image filename with File: prefix")},{title:"Get image usage",readOnlyHint:!0,destructiveHint:!1},async({filename:o})=>Me(o));return t.update({outputSchema:{filename:I.string(),pages:I.array(I.record(I.unknown())),count:I.number()}}),t}async function Me(e){try{let t=await n(),o=await s(t,"getImageUsage",e);return l({filename:e,pages:o,count:o.length})}catch(t){return i("Failed to get image usage",t)}}import{z as W}from"zod";function At(e){let t=e.tool("get-image-info","Get detailed information about an image file",{filename:W.string().describe("Image filename with File: prefix")},{title:"Get image info",readOnlyHint:!0,destructiveHint:!1},async({filename:o})=>Ce(o));return t.update({outputSchema:{filename:W.string(),info:W.record(W.unknown())}}),t}async function Ce(e){try{let t=await n(),o=await s(t,"getImageInfo",e);return o?l({filename:e,info:o}):i(`Image "${e}" not found.`)}catch(t){return i("Failed to get image info",t)}}import{z as T}from"zod";function Mt(e){let t=e.tool("get-log","Get log entries of a specific type",{type:T.string().describe("Log type (e.g. delete, block, move)"),start:T.string().optional().default("").describe("Start timestamp (YYYYMMDDHHMMSS format)"),limit:T.number().optional().default(50).describe("Maximum number of entries to return")},{title:"Get log entries",readOnlyHint:!0,destructiveHint:!1},async({type:o,start:r,limit:a})=>Pe(o,r,a));return t.update({outputSchema:{type:T.string(),start:T.string(),limit:T.number(),total:T.number(),displayed:T.number(),entries:T.array(T.record(T.unknown()))}}),t}async function Pe(e,t,o){try{let r=await n(),a=await new Promise((m,p)=>{r.getLog(e,t,(u,...g)=>{if(u)p(u);else{let f=g[0];m(Array.isArray(f)?f:[])}})}),c=a.slice(0,o);return l({type:e,start:t,limit:o,total:a.length,displayed:c.length,entries:c})}catch(r){return i("Failed to get log entries",r)}}import{z as Ct}from"zod";function Pt(e){return e.tool("expand-templates","Expand templates in wikitext",{text:Ct.string().describe("Wikitext with templates to expand"),title:Ct.string().optional().describe("Context page title")},{title:"Expand templates",readOnlyHint:!0,destructiveHint:!1},async({text:t,title:o})=>je(t,o))}async function je(e,t){try{let o=await n(),r=await s(o,"expandTemplates",e,t||"");return r==null?{content:[{type:"text",text:`Failed to expand templates for "${e}".`}],isError:!0}:{content:[{type:"text",text:r}]}}catch(o){return{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0}}}import{z as jt}from"zod";function Bt(e){return e.tool("parse","Parse wikitext to HTML",{text:jt.string().describe("Wikitext to parse"),title:jt.string().optional().describe("Context page title")},{title:"Parse wikitext",readOnlyHint:!0,destructiveHint:!1},async({text:t,title:o})=>Be(t,o))}async function Be(e,t){try{let o=await n(),r=await s(o,"parse",e,t||""),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 S}from"zod";function Et(e){let t=e.tool("get-recent-changes","Get recent changes on the wiki",{start:S.string().optional().describe("Start timestamp"),limit:S.number().optional().default(50).describe("Maximum number of changes to return")},{title:"Get recent changes",readOnlyHint:!0,destructiveHint:!1},async({start:o,limit:r})=>Ee(o,r));return t.update({outputSchema:{total:S.number(),limit:S.number(),start:S.string(),changes:S.array(S.record(S.unknown()))}}),t}async function Ee(e,t=50){try{let o=await n(),r=await new Promise((c,m)=>{o.getRecentChanges(e,(p,...u)=>{if(p)m(p);else{let g=u[0];c(Array.isArray(g)?g:[])}})}),a=r.slice(0,t);return l({total:r.length,limit:t,start:e,changes:a})}catch(o){return i("Failed to get recent changes",o)}}import{z as Ht}from"zod";function It(e){let t=e.tool("get-site-info","Get site information from MediaWiki",{properties:Ht.array(Ht.string()).describe("List of site information properties to retrieve")},{title:"Get site info",readOnlyHint:!0,destructiveHint:!1},async({properties:o})=>He(o));return t.update({outputSchema:{}}),t}async function He(e){try{let t=await n(),o=await s(t,"getSiteInfo",e);return l(o||{})}catch(t){return i("Failed to get site info",t)}}function Gt(e){let t=e.tool("get-site-stats","Get site statistics",{},{title:"Get site stats",readOnlyHint:!0,destructiveHint:!1},async()=>Ie());return t.update({outputSchema:{}}),t}async function Ie(){try{let e=await n(),t=await s(e,"getSiteStats");return l(t)}catch(e){return i("Failed to get site stats",e)}}import{z as Ge}from"zod";function Ft(e){let t=e.tool("get-mediawiki-version","Get MediaWiki version running on the server",{},{title:"Get MediaWiki version",readOnlyHint:!0,destructiveHint:!1},async()=>Fe());return t.update({outputSchema:{version:Ge.string()}}),t}async function Fe(){try{let e=await n(),t=await s(e,"getMediaWikiVersion");return l({version:t})}catch(e){return i("Failed to get MediaWiki version",e)}}import{z as G}from"zod";function Ot(e){let t=e.tool("get-query-page","Get results from a query page (special page)",{name:G.string().describe("Name of the query page")},{title:"Get query page results",readOnlyHint:!0,destructiveHint:!1},async({name:o})=>Oe(o));return t.update({outputSchema:{name:G.string(),results:G.array(G.record(G.unknown())),count:G.number()}}),t}async function Oe(e){try{let t=await n(),o=await s(t,"getQueryPage",e);return l({name:e,results:o,count:o.length})}catch(t){return i("Failed to get query page results",t)}}import{z as A}from"zod";function Ut(e){let t=e.tool("get-external-links","Get all external links from an article",{title:A.union([A.string(),A.number()]).describe("Article title or page ID")},{title:"Get external links",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>Ue(o));return t.update({outputSchema:{title:A.string(),links:A.array(A.record(A.unknown())),count:A.number()}}),t}async function Ue(e){try{let t=await n(),o=await s(t,"getExternalLinks",e);return l({title:e,links:o.map(r=>r["*"]),count:o.length})}catch(t){return i("Failed to get external links",t)}}import{z as F}from"zod";function zt(e){let t=e.tool("get-backlinks","Get all backlinks to a specific page",{title:F.string().describe("Target page title to find backlinks for")},{title:"Get backlinks",readOnlyHint:!0,destructiveHint:!1},async({title:o})=>ze(o));return t.update({outputSchema:{target:F.string(),backlinks:F.array(F.record(F.unknown())),count:F.number()}}),t}async function ze(e){try{let t=await n(),o=await s(t,"getBacklinks",e);return l({target:e,backlinks:o,count:o.length})}catch(t){return i("Failed to get backlinks",t)}}import{z as $}from"zod";function Wt(e){let t=e.tool("edit","Edit a wiki page (requires authentication)",{title:$.string().describe("Page title to edit"),content:$.string().describe("New content for the page"),summary:$.string().describe("Edit summary"),minor:$.boolean().optional().default(!1).describe("Mark as minor edit")},{title:"Edit page",readOnlyHint:!1,destructiveHint:!0},async o=>We(o));return t.update({outputSchema:{}}),t}async function We(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"edit",e.title,e.content,o,e.minor||!1);return l(r)}catch(t){return i("Failed to edit page",t)}}import{z as U}from"zod";function $t(e){let t=e.tool("append","Append content to a wiki page (requires authentication)",{title:U.string().describe("Page title"),content:U.string().describe("Content to append"),summary:U.string().describe("Edit summary")},{title:"Append to page",readOnlyHint:!1,destructiveHint:!0},async o=>$e(o));return t.update({outputSchema:{success:U.boolean(),title:U.string()}}),t}async function $e(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`;return await s(t,"append",e.title,e.content,o),l({success:!0,title:e.title})}catch(t){return i("Failed to append to page",t)}}import{z as q}from"zod";function Nt(e){let t=e.tool("prepend","Prepend content to a wiki page (requires authentication)",{title:q.string().describe("Page title to prepend to"),content:q.string().describe("Content to prepend"),summary:q.string().describe("Edit summary")},{title:"Prepend to page",readOnlyHint:!1,destructiveHint:!0},async o=>Ne(o));return t.update({outputSchema:{}}),t}async function Ne(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"prepend",e.title,e.content,o);return l(r)}catch(t){return i("Failed to prepend to page",t)}}import{z as _}from"zod";function Lt(e){let t=e.tool("move","Move (rename) a wiki page (requires authentication)",{from:_.string().describe("Current page title"),to:_.string().describe("New page title"),summary:_.string().describe("Move summary")},{title:"Move page",readOnlyHint:!1,destructiveHint:!0},async o=>Le(o));return t.update({outputSchema:{}}),t}async function Le(e){try{let t=await n(),o=`[nodemw-mcp] ${e.summary}`,r=await s(t,"move",e.from,e.to,o);return l(r)}catch(t){return i("Failed to move page",t)}}import{z as Dt}from"zod";function qt(e){let t=e.tool("delete","Delete a wiki page (requires authentication)",{title:Dt.string().describe("Page title to delete"),reason:Dt.string().describe("Reason for deletion")},{title:"Delete page",readOnlyHint:!1,destructiveHint:!0},async o=>De(o));return t.update({outputSchema:{}}),t}async function De(e){try{let t=await n(),o=`[nodemw-mcp] ${e.reason}`,r=await s(t,"delete",e.title,o);return l(r)}catch(t){return i("Failed to delete page",t)}}import{z as M}from"zod";function _t(e){let t=e.tool("protect","Protect a wiki page (requires authentication)",{title:M.string().describe("Page title to protect"),protections:M.array(M.object({type:M.string().describe("Action type (e.g., edit, move)"),level:M.string().optional().default("all").describe("Protection level (e.g., sysop, autoconfirmed)"),expiry:M.string().optional().describe("Expiry time (e.g., 1 week, never)")})).describe("Protection settings"),reason:M.string().optional().describe("Reason for protection"),cascade:M.boolean().optional().default(!1).describe("Apply cascade protection")},{title:"Protect page",readOnlyHint:!1,destructiveHint:!0},async o=>qe(o));return t.update({outputSchema:{}}),t}async function qe(e){try{let t=await n(),o={};e.reason&&(o.reason=`[nodemw-mcp] ${e.reason}`),e.cascade&&(o.cascade=e.cascade);let r=await s(t,"protect",e.title,e.protections,o);return l(r)}catch(t){return i("Failed to protect page",t)}}import{z as N}from"zod";function Qt(e){let t=e.tool("purge","Purge cache for wiki pages",{titles:N.union([N.string(),N.array(N.string())]).describe("Page title(s) or category to purge")},{title:"Purge pages",readOnlyHint:!1,destructiveHint:!1},async o=>_e(o));return t.update({outputSchema:{}}),t}async function _e(e){try{let t=await n(),o=await s(t,"purge",e.titles);return l(o)}catch(t){return i("Failed to purge pages",t)}}import{z as Q}from"zod";function Vt(e){let t=e.tool("send-email","Send email to a wiki user (requires authentication)",{username:Q.string().describe("Username to email"),subject:Q.string().describe("Email subject"),text:Q.string().describe("Email content")},{title:"Send email",readOnlyHint:!1,destructiveHint:!1},async o=>Qe(o));return t.update({outputSchema:{}}),t}async function Qe(e){try{let t=await n(),o=await s(t,"sendEmail",e.username,e.subject,e.text);return l(o)}catch(t){return i("Failed to send email",t)}}import{z as V}from"zod";function Yt(e){let t=e.tool("upload","Upload a file to wiki (requires authentication)",{filename:V.string().describe("Destination filename on wiki"),content:V.string().describe("File content as base64 string"),comment:V.string().optional().describe("Upload comment")},{title:"Upload file",readOnlyHint:!1,destructiveHint:!1},async o=>Ve(o));return t.update({outputSchema:{}}),t}async function Ve(e){try{let t=await n(),o=Buffer.from(e.content,"base64"),r=e.comment?`[nodemw-mcp] ${e.comment}`:"[nodemw-mcp] File upload",a=await s(t,"upload",e.filename,o,r);return l(a)}catch(t){return i("Failed to upload file",t)}}import{z as Y}from"zod";function Jt(e){let t=e.tool("upload-by-url","Upload a file to wiki from URL (requires authentication)",{filename:Y.string().describe("Destination filename on wiki"),url:Y.string().url().describe("Source URL to download file from"),summary:Y.string().optional().describe("Upload summary")},{title:"Upload file by URL",readOnlyHint:!1,destructiveHint:!1},async o=>Ye(o));return t.update({outputSchema:{}}),t}async function Ye(e){try{let t=await n(),o=e.summary?`[nodemw-mcp] ${e.summary}`:"[nodemw-mcp] File upload from URL",r=await s(t,"uploadByUrl",e.filename,e.url,o);return l(r)}catch(t){return i("Failed to upload file by URL",t)}}import{z as J}from"zod";function Xt(e){let t=e.tool("add-flow-topic","Add a new Flow topic to a wiki page (requires authentication)",{title:J.string().describe("Page title to add topic to"),subject:J.string().describe("Topic subject"),content:J.string().describe("Topic content in wikitext")},{title:"Add Flow topic",readOnlyHint:!1,destructiveHint:!1},async o=>Je(o));return t.update({outputSchema:{}}),t}async function Je(e){try{let t=await n(),o=await s(t,"addFlowTopic",e.title,e.subject,e.content);return l(o)}catch(t){return i("Failed to add Flow topic",t)}}import{z as Kt}from"zod";function Zt(e){let t=e.tool("create-account","Create a new MediaWiki user account (requires authentication)",{username:Kt.string().describe("New account username"),password:Kt.string().describe("New account password")},{title:"Create user account",readOnlyHint:!1,destructiveHint:!1},async o=>Xe(o));return t.update({outputSchema:{}}),t}async function Xe(e){try{let t=await n(),o=await s(t,"createAccount",e.username,e.password);return l(o)}catch(t){return i("Failed to create account",t)}}var te=[st,it,lt,at,ct,mt,pt,ut,dt,gt,ft,yt,Tt,ht,Rt,bt,vt,wt,kt,St,At,Mt,Pt,Bt,Et,It,Gt,Ft,Ot,Ut,zt],Ke=[Wt,$t,Nt,Lt,qt,_t,Qt,Vt,Yt,Jt,Xt,Zt];function ee(e,t=!0){let o=t?[...te,...Ke]:te,r=[];for(let a of o)try{r.push(a(e))}catch(c){console.error(`Error registering tool: ${c.message}`)}return r}function eo(){let{values:e,positionals:t}=to({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=e.server??t[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=!!(e.path??e.endpoint??m);return{config:{server:r,protocol:a,port:c,path:e.path??e.endpoint??m??"/w",username:e.user??process.env.NODEMW_MCP_MW_USER,password:e.pass??process.env.NODEMW_MCP_MW_PASS,token:e.token,dryRun:e["dry-run"]},pathExplicit:p}}async function oo(){let{config:e,pathExplicit:t}=eo();if(!t)try{e.path=await ot(e),console.error(`Auto-detected API path: ${e.path}`)}catch(f){console.error("Error:",f.message),process.exit(1)}tt(e);try{await rt(e)}catch(f){console.error("Error:",f.message),process.exit(1)}let o=n(),r;try{let h=(await s(o,"getSiteInfo",["general"]))?.general;h&&(r={sitename:h.sitename||"Unknown",base:h.base||"",generator:h.generator||"MediaWiki"})}catch{console.error("Warning: Could not fetch site info for server description.")}let a=nt(),c=K(r,a);ee(c,a);let m=new Ze;await c.connect(m);let u=`${e.protocol??"https"}://${e.server}${e.path}/api.php`,g=r?.sitename??e.server;console.error(`Ready to operate on "${g}" <${u}>`)}oo().catch(console.error);
37
37
  //# sourceMappingURL=index.js.map