@xiedada/nodemw-mcp-server 0.0.12 → 0.1.1
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 +74 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
37
37
|
// package.json
|
|
38
38
|
var package_default = {
|
|
39
39
|
name: "@xiedada/nodemw-mcp-server",
|
|
40
|
-
version: "0.
|
|
40
|
+
version: "0.1.1",
|
|
41
41
|
description: "MCP server for nodemw - MediaWiki API client",
|
|
42
42
|
type: "module",
|
|
43
43
|
main: "dist/index.js",
|
|
@@ -334,7 +334,7 @@ async function handleGetArticleTool(title, followRedirect, redirectInfo, revisio
|
|
|
334
334
|
const [content, redirect] = result;
|
|
335
335
|
if (content == null) {
|
|
336
336
|
return {
|
|
337
|
-
content: [{ type: "text", text: `Page "${title}" not found
|
|
337
|
+
content: [{ type: "text", text: `Page "${title}" not found.` }],
|
|
338
338
|
isError: true
|
|
339
339
|
};
|
|
340
340
|
}
|
|
@@ -344,7 +344,7 @@ ${content}
|
|
|
344
344
|
|
|
345
345
|
Redirect Information:
|
|
346
346
|
|
|
347
|
-
${JSON.stringify(redirect, null, 2)}` : content;
|
|
347
|
+
${JSON.stringify(redirect, null, 2)}` : content === "" ? "(empty page)" : content;
|
|
348
348
|
await recordReadState(title);
|
|
349
349
|
return {
|
|
350
350
|
content: [{ type: "text", text: responseText }]
|
|
@@ -358,13 +358,13 @@ ${JSON.stringify(redirect, null, 2)}` : content;
|
|
|
358
358
|
);
|
|
359
359
|
if (result == null) {
|
|
360
360
|
return {
|
|
361
|
-
content: [{ type: "text", text: `Page "${title}" not found
|
|
361
|
+
content: [{ type: "text", text: `Page "${title}" not found.` }],
|
|
362
362
|
isError: true
|
|
363
363
|
};
|
|
364
364
|
}
|
|
365
365
|
await recordReadState(title);
|
|
366
366
|
return {
|
|
367
|
-
content: [{ type: "text", text: result }]
|
|
367
|
+
content: [{ type: "text", text: result === "" ? "(empty page)" : result }]
|
|
368
368
|
};
|
|
369
369
|
}
|
|
370
370
|
} catch (error) {
|
|
@@ -809,7 +809,7 @@ async function handleGetArticlePropertiesTool(title) {
|
|
|
809
809
|
);
|
|
810
810
|
return jsonResult({
|
|
811
811
|
title,
|
|
812
|
-
properties
|
|
812
|
+
properties: properties || {}
|
|
813
813
|
});
|
|
814
814
|
} catch (error) {
|
|
815
815
|
return errorResult("Failed to get article properties", error);
|
|
@@ -866,41 +866,79 @@ import { z as z14 } from "zod";
|
|
|
866
866
|
function getUserContribsTool(server) {
|
|
867
867
|
const tool = server.tool(
|
|
868
868
|
"get-user-contribs",
|
|
869
|
-
"Get contributions made by a specific user",
|
|
869
|
+
"Get contributions made by a specific user. Pagination: the response includes total (matching edits found) and displayed (returned in this batch). If displayed < total, more results exist \u2014 use the timestamp of the LAST returned contribution as the start parameter for the next page. Repeat until displayed < limit to get all results.",
|
|
870
870
|
{
|
|
871
871
|
username: z14.string().describe("Username to get contributions for"),
|
|
872
872
|
namespace: z14.number().optional().describe("Filter contributions by namespace"),
|
|
873
|
-
limit: z14.number().optional().default(50).describe("Maximum number of contributions to return")
|
|
873
|
+
limit: z14.number().optional().default(50).describe("Maximum number of contributions to return"),
|
|
874
|
+
start: z14.string().optional().describe(
|
|
875
|
+
'Timestamp to start listing from \u2014 only return edits before this time (not inclusive). Accepts ISO 8601 (e.g. "2026-05-10T22:54:37Z"), MediaWiki format "YYYYMMDDHHMMSS", or unix timestamp. All times are UTC \u2014 MW ignores timezone offsets. To paginate: pass the timestamp of the LAST item from the previous page as start. The returned contributions are guaranteed to be strictly older than this timestamp.'
|
|
876
|
+
)
|
|
874
877
|
},
|
|
875
878
|
{
|
|
876
879
|
title: "Get user contributions",
|
|
877
880
|
readOnlyHint: true,
|
|
878
881
|
destructiveHint: false
|
|
879
882
|
},
|
|
880
|
-
async ({ username, namespace, limit }) => handleGetUserContribsTool(username, namespace, limit)
|
|
883
|
+
async ({ username, namespace, limit, start }) => handleGetUserContribsTool(username, namespace, limit, start)
|
|
881
884
|
);
|
|
882
|
-
tool.update({ outputSchema: { username: z14.string(), namespace: z14.number().optional(), limit: z14.number(), total: z14.number(), displayed: z14.number(), contributions: z14.array(z14.record(z14.unknown())) } });
|
|
885
|
+
tool.update({ outputSchema: { username: z14.string(), namespace: z14.number().optional(), limit: z14.number(), start: z14.string().optional(), total: z14.number(), displayed: z14.number(), contributions: z14.array(z14.record(z14.unknown())) } });
|
|
883
886
|
return tool;
|
|
884
887
|
}
|
|
885
|
-
async function handleGetUserContribsTool(username, namespace, limit = 50) {
|
|
888
|
+
async function handleGetUserContribsTool(username, namespace, limit = 50, start) {
|
|
886
889
|
try {
|
|
887
890
|
const bot = await getBot();
|
|
888
|
-
const
|
|
889
|
-
user: username,
|
|
890
|
-
...namespace !== void 0 && { namespace }
|
|
891
|
-
};
|
|
892
|
-
const callbackArgs = await promisifyBotMethod(
|
|
891
|
+
const userInfo = await promisifyBotMethod(
|
|
893
892
|
bot,
|
|
894
|
-
"
|
|
895
|
-
|
|
893
|
+
"whois",
|
|
894
|
+
username
|
|
896
895
|
);
|
|
897
|
-
|
|
898
|
-
|
|
896
|
+
if (userInfo.missing !== void 0) {
|
|
897
|
+
return errorResult(`User "${username}" not found.`);
|
|
898
|
+
}
|
|
899
|
+
const allContribs = [];
|
|
900
|
+
const perPage = Math.min(limit, 500);
|
|
901
|
+
const baseParams = {
|
|
902
|
+
action: "query",
|
|
903
|
+
list: "usercontribs",
|
|
904
|
+
ucuser: username,
|
|
905
|
+
uclimit: perPage,
|
|
906
|
+
ucprop: "ids|title|timestamp|comment|size|flags",
|
|
907
|
+
...namespace !== void 0 && { ucnamespace: namespace },
|
|
908
|
+
...start && { ucstart: start }
|
|
909
|
+
};
|
|
910
|
+
let continueParams;
|
|
911
|
+
do {
|
|
912
|
+
const params = { ...baseParams, ...continueParams || {} };
|
|
913
|
+
const rawData = await new Promise((resolve, reject) => {
|
|
914
|
+
bot.api.call(params, (_err, _info, _next, raw) => {
|
|
915
|
+
if (_err) reject(_err);
|
|
916
|
+
else resolve(raw);
|
|
917
|
+
});
|
|
918
|
+
});
|
|
919
|
+
const usercontribs = rawData.query?.usercontribs;
|
|
920
|
+
if (usercontribs) {
|
|
921
|
+
allContribs.push(...usercontribs);
|
|
922
|
+
}
|
|
923
|
+
if (allContribs.length >= limit) {
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
if (rawData.continue) {
|
|
927
|
+
continueParams = rawData.continue;
|
|
928
|
+
} else if (rawData["query-continue"]) {
|
|
929
|
+
const qc = rawData["query-continue"];
|
|
930
|
+
continueParams = qc.usercontribs || qc[Object.keys(qc)[0]];
|
|
931
|
+
} else {
|
|
932
|
+
continueParams = void 0;
|
|
933
|
+
}
|
|
934
|
+
} while (continueParams);
|
|
935
|
+
const limitedContribs = allContribs.slice(0, limit);
|
|
899
936
|
return jsonResult({
|
|
900
937
|
username,
|
|
901
938
|
namespace,
|
|
902
939
|
limit,
|
|
903
|
-
|
|
940
|
+
start,
|
|
941
|
+
total: allContribs.length,
|
|
904
942
|
displayed: limitedContribs.length,
|
|
905
943
|
contributions: limitedContribs
|
|
906
944
|
});
|
|
@@ -1002,7 +1040,10 @@ async function handleWhoareTool(params) {
|
|
|
1002
1040
|
"whoare",
|
|
1003
1041
|
params.usernames
|
|
1004
1042
|
);
|
|
1005
|
-
|
|
1043
|
+
const normalized = users.map(
|
|
1044
|
+
(u) => u && u.missing !== void 0 ? { ...u, missing: true } : u
|
|
1045
|
+
);
|
|
1046
|
+
return jsonResult({ users: normalized, count: normalized.length });
|
|
1006
1047
|
} catch (error) {
|
|
1007
1048
|
return errorResult("Failed to get user information", error);
|
|
1008
1049
|
}
|
|
@@ -1171,10 +1212,12 @@ import { z as z22 } from "zod";
|
|
|
1171
1212
|
function getLogTool(server) {
|
|
1172
1213
|
const tool = server.tool(
|
|
1173
1214
|
"get-log",
|
|
1174
|
-
"Get log entries of a specific type",
|
|
1215
|
+
"Get log entries of a specific type (e.g. delete, block, move). Pagination: the response includes total (matching entries found) and displayed (returned in this batch). If displayed < total, more results exist \u2014 use the timestamp of the LAST returned entry as the start parameter for the next page.",
|
|
1175
1216
|
{
|
|
1176
1217
|
type: z22.string().describe("Log type (e.g. delete, block, move)"),
|
|
1177
|
-
start: z22.string().optional().
|
|
1218
|
+
start: z22.string().optional().describe(
|
|
1219
|
+
'Timestamp to start listing from \u2014 only return entries before this time. Accepts ISO 8601 (e.g. "2026-05-10T22:54:37Z"), MediaWiki format "YYYYMMDDHHMMSS", or unix timestamp. All times are UTC \u2014 MW ignores timezone offsets. To paginate: pass the timestamp of the LAST item from the previous page as start.'
|
|
1220
|
+
),
|
|
1178
1221
|
limit: z22.number().optional().default(50).describe("Maximum number of entries to return")
|
|
1179
1222
|
},
|
|
1180
1223
|
{
|
|
@@ -1184,14 +1227,14 @@ function getLogTool(server) {
|
|
|
1184
1227
|
},
|
|
1185
1228
|
async ({ type, start, limit }) => handleGetLogTool(type, start, limit)
|
|
1186
1229
|
);
|
|
1187
|
-
tool.update({ outputSchema: { type: z22.string(), start: z22.string(), limit: z22.number(), total: z22.number(), displayed: z22.number(), entries: z22.array(z22.record(z22.unknown())) } });
|
|
1230
|
+
tool.update({ outputSchema: { type: z22.string(), start: z22.string().optional(), limit: z22.number(), total: z22.number(), displayed: z22.number(), entries: z22.array(z22.record(z22.unknown())) } });
|
|
1188
1231
|
return tool;
|
|
1189
1232
|
}
|
|
1190
|
-
async function handleGetLogTool(type, start, limit) {
|
|
1233
|
+
async function handleGetLogTool(type, start, limit = 50) {
|
|
1191
1234
|
try {
|
|
1192
1235
|
const bot = await getBot();
|
|
1193
1236
|
const entries = await new Promise((resolve, reject) => {
|
|
1194
|
-
bot.getLog(type, start, (err, ...args) => {
|
|
1237
|
+
bot.getLog(type, start || "", (err, ...args) => {
|
|
1195
1238
|
if (err) {
|
|
1196
1239
|
reject(err);
|
|
1197
1240
|
} else {
|
|
@@ -1310,9 +1353,11 @@ import { z as z25 } from "zod";
|
|
|
1310
1353
|
function getRecentChangesTool(server) {
|
|
1311
1354
|
const tool = server.tool(
|
|
1312
1355
|
"get-recent-changes",
|
|
1313
|
-
"Get recent changes on the wiki",
|
|
1356
|
+
"Get recent changes on the wiki. Pagination: the response includes total (matching changes found) and displayed (returned in this batch). If displayed < total, more results exist \u2014 use the timestamp of the LAST returned change as the start parameter for the next page.",
|
|
1314
1357
|
{
|
|
1315
|
-
start: z25.string().optional().describe(
|
|
1358
|
+
start: z25.string().optional().describe(
|
|
1359
|
+
'Timestamp to start listing from \u2014 only return changes before this time. Accepts ISO 8601 (e.g. "2026-05-10T22:54:37Z"), MediaWiki format "YYYYMMDDHHMMSS", or unix timestamp. All times are UTC \u2014 MW ignores timezone offsets. To paginate: pass the timestamp of the LAST item from the previous page as start.'
|
|
1360
|
+
),
|
|
1316
1361
|
limit: z25.number().optional().default(50).describe("Maximum number of changes to return")
|
|
1317
1362
|
},
|
|
1318
1363
|
{
|