@cyanheads/wikipedia-mcp-server 0.1.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.
Files changed (56) hide show
  1. package/AGENTS.md +394 -0
  2. package/CLAUDE.md +394 -0
  3. package/Dockerfile +99 -0
  4. package/LICENSE +201 -0
  5. package/README.md +294 -0
  6. package/changelog/0.1.x/0.1.0.md +18 -0
  7. package/changelog/0.1.x/0.1.1.md +22 -0
  8. package/changelog/0.1.x/0.1.2.md +13 -0
  9. package/changelog/0.1.x/0.1.3.md +31 -0
  10. package/changelog/template.md +119 -0
  11. package/dist/config/server-config.d.ts +13 -0
  12. package/dist/config/server-config.d.ts.map +1 -0
  13. package/dist/config/server-config.js +25 -0
  14. package/dist/config/server-config.js.map +1 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +25 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/mcp-server/tools/definitions/index.d.ts +168 -0
  20. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  21. package/dist/mcp-server/tools/definitions/index.js +19 -0
  22. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  23. package/dist/mcp-server/tools/definitions/wikipedia-get-article.tool.d.ts +34 -0
  24. package/dist/mcp-server/tools/definitions/wikipedia-get-article.tool.d.ts.map +1 -0
  25. package/dist/mcp-server/tools/definitions/wikipedia-get-article.tool.js +153 -0
  26. package/dist/mcp-server/tools/definitions/wikipedia-get-article.tool.js.map +1 -0
  27. package/dist/mcp-server/tools/definitions/wikipedia-get-languages.tool.d.ts +35 -0
  28. package/dist/mcp-server/tools/definitions/wikipedia-get-languages.tool.d.ts.map +1 -0
  29. package/dist/mcp-server/tools/definitions/wikipedia-get-languages.tool.js +105 -0
  30. package/dist/mcp-server/tools/definitions/wikipedia-get-languages.tool.js.map +1 -0
  31. package/dist/mcp-server/tools/definitions/wikipedia-get-sections.tool.d.ts +37 -0
  32. package/dist/mcp-server/tools/definitions/wikipedia-get-sections.tool.d.ts.map +1 -0
  33. package/dist/mcp-server/tools/definitions/wikipedia-get-sections.tool.js +109 -0
  34. package/dist/mcp-server/tools/definitions/wikipedia-get-sections.tool.js.map +1 -0
  35. package/dist/mcp-server/tools/definitions/wikipedia-get-summary.tool.d.ts +30 -0
  36. package/dist/mcp-server/tools/definitions/wikipedia-get-summary.tool.d.ts.map +1 -0
  37. package/dist/mcp-server/tools/definitions/wikipedia-get-summary.tool.js +107 -0
  38. package/dist/mcp-server/tools/definitions/wikipedia-get-summary.tool.js.map +1 -0
  39. package/dist/mcp-server/tools/definitions/wikipedia-search-nearby.tool.d.ts +42 -0
  40. package/dist/mcp-server/tools/definitions/wikipedia-search-nearby.tool.d.ts.map +1 -0
  41. package/dist/mcp-server/tools/definitions/wikipedia-search-nearby.tool.js +127 -0
  42. package/dist/mcp-server/tools/definitions/wikipedia-search-nearby.tool.js.map +1 -0
  43. package/dist/mcp-server/tools/definitions/wikipedia-search.tool.d.ts +32 -0
  44. package/dist/mcp-server/tools/definitions/wikipedia-search.tool.d.ts.map +1 -0
  45. package/dist/mcp-server/tools/definitions/wikipedia-search.tool.js +91 -0
  46. package/dist/mcp-server/tools/definitions/wikipedia-search.tool.js.map +1 -0
  47. package/dist/services/wikipedia/types.d.ts +110 -0
  48. package/dist/services/wikipedia/types.d.ts.map +1 -0
  49. package/dist/services/wikipedia/types.js +6 -0
  50. package/dist/services/wikipedia/types.js.map +1 -0
  51. package/dist/services/wikipedia/wikipedia-service.d.ts +81 -0
  52. package/dist/services/wikipedia/wikipedia-service.d.ts.map +1 -0
  53. package/dist/services/wikipedia/wikipedia-service.js +577 -0
  54. package/dist/services/wikipedia/wikipedia-service.js.map +1 -0
  55. package/package.json +86 -0
  56. package/server.json +99 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-languages.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-languages.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAG3E,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqHhC,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @fileoverview wikipedia_get_languages tool — list language editions available for a Wikipedia article.
3
+ * @module mcp-server/tools/definitions/wikipedia-get-languages.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getWikipediaService } from '../../../services/wikipedia/wikipedia-service.js';
8
+ export const wikipediaGetLanguages = tool('wikipedia_get_languages', {
9
+ title: 'Get Wikipedia Article Languages',
10
+ description: 'List the language editions available for a Wikipedia article. Returns language codes, article titles in each language, and full URLs. Useful for cross-language research and for discovering the correct article title in a target language before fetching it. The language parameter specifies which edition to query from.',
11
+ annotations: { readOnlyHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ title: z.string().describe('Article title in the source language edition.'),
14
+ language: z
15
+ .string()
16
+ .default('en')
17
+ .describe('Wikipedia language edition to query from (default "en"). Examples: "fr", "de", "ja".'),
18
+ }),
19
+ output: z.object({
20
+ source_title: z.string().describe('Article title in the source language edition.'),
21
+ source_language: z.string().describe('The language edition that was queried.'),
22
+ languages: z
23
+ .array(z
24
+ .object({
25
+ language_code: z.string().describe('BCP 47 language code (e.g. "fr", "de").'),
26
+ title: z.string().describe('Article title in this language edition.'),
27
+ url: z.string().describe('Full URL to the article in this language edition.'),
28
+ })
29
+ .describe('A single language edition entry.'))
30
+ .describe('Available language editions excluding the source language.'),
31
+ total_languages: z.number().describe('Total number of other language editions available.'),
32
+ }),
33
+ errors: [
34
+ {
35
+ reason: 'not_found',
36
+ code: JsonRpcErrorCode.NotFound,
37
+ when: 'No Wikipedia article exists for the title in the specified language.',
38
+ recovery: 'Use wikipedia_search to discover the correct article title and try again.',
39
+ },
40
+ {
41
+ reason: 'no_other_languages',
42
+ code: JsonRpcErrorCode.NotFound,
43
+ when: 'Article exists but has no other language editions.',
44
+ recovery: 'The article may be too new or too regional to have been translated yet.',
45
+ },
46
+ {
47
+ reason: 'invalid_language',
48
+ code: JsonRpcErrorCode.InvalidParams,
49
+ when: 'The language code is not a valid BCP 47 code.',
50
+ recovery: 'Use a valid BCP 47 language code such as "fr", "de", or "ja".',
51
+ },
52
+ ],
53
+ async handler(input, ctx) {
54
+ const { language } = input;
55
+ if (!/^[a-z]{2,3}(-[a-z0-9]+)*$/i.test(language)) {
56
+ throw ctx.fail('invalid_language', `Invalid language code "${language}". Use a BCP 47 language code such as "fr", "de", or "ja".`, { language, ...ctx.recoveryFor('invalid_language') });
57
+ }
58
+ ctx.log.info('Fetching language links', { title: input.title, language });
59
+ const svc = getWikipediaService();
60
+ let getLanguagesResult;
61
+ try {
62
+ getLanguagesResult = await svc.getLanguages(input.title, language, ctx);
63
+ }
64
+ catch (err) {
65
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound) {
66
+ throw ctx.fail('not_found', err.message, {
67
+ title: input.title,
68
+ language,
69
+ recovery: { hint: 'Use wikipedia_search to find the correct article title.' },
70
+ });
71
+ }
72
+ throw err;
73
+ }
74
+ const { languages } = getLanguagesResult;
75
+ if (languages.length === 0) {
76
+ throw ctx.fail('no_other_languages', `Article "${input.title}" in language "${language}" has no other language editions.`, {
77
+ title: input.title,
78
+ language,
79
+ ...ctx.recoveryFor('no_other_languages'),
80
+ });
81
+ }
82
+ ctx.log.info('Language links fetched', { title: input.title, count: languages.length });
83
+ return {
84
+ source_title: input.title,
85
+ source_language: language,
86
+ languages: languages.map((l) => ({
87
+ language_code: l.languageCode,
88
+ title: l.title,
89
+ url: l.url,
90
+ })),
91
+ total_languages: languages.length,
92
+ };
93
+ },
94
+ format: (result) => {
95
+ const lines = [
96
+ `## Language editions for "${result.source_title}" (${result.source_language})`,
97
+ `**${result.total_languages} languages available**\n`,
98
+ ];
99
+ for (const lang of result.languages) {
100
+ lines.push(`- **${lang.language_code}**: [${lang.title}](${lang.url})`);
101
+ }
102
+ return [{ type: 'text', text: lines.join('\n') }];
103
+ },
104
+ });
105
+ //# sourceMappingURL=wikipedia-get-languages.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-languages.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-languages.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @fileoverview wikipedia_get_sections tool — fetch the table of contents for a Wikipedia article.
3
+ * @module mcp-server/tools/definitions/wikipedia-get-sections.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const wikipediaGetSections: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ title: z.ZodString;
9
+ language: z.ZodDefault<z.ZodString>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ title: z.ZodString;
12
+ pageid: z.ZodOptional<z.ZodNumber>;
13
+ sections: z.ZodArray<z.ZodObject<{
14
+ index: z.ZodNumber;
15
+ number: z.ZodString;
16
+ title: z.ZodString;
17
+ level: z.ZodNumber;
18
+ }, z.core.$strip>>;
19
+ total_sections: z.ZodNumber;
20
+ language: z.ZodString;
21
+ }, z.core.$strip>, readonly [{
22
+ readonly reason: "not_found";
23
+ readonly code: JsonRpcErrorCode.NotFound;
24
+ readonly when: "No Wikipedia article exists for the given title.";
25
+ readonly recovery: "Use wikipedia_search to discover the correct article title and try again.";
26
+ }, {
27
+ readonly reason: "no_sections";
28
+ readonly code: JsonRpcErrorCode.NotFound;
29
+ readonly when: "Article exists but has no sections (stub or very short article).";
30
+ readonly recovery: "Use wikipedia_get_article without section_index to read the full short article.";
31
+ }, {
32
+ readonly reason: "invalid_language";
33
+ readonly code: JsonRpcErrorCode.InvalidParams;
34
+ readonly when: "The language code is not a valid BCP 47 code.";
35
+ readonly recovery: "Use a valid BCP 47 language code such as \"fr\", \"de\", or \"ja\".";
36
+ }]>;
37
+ //# sourceMappingURL=wikipedia-get-sections.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-sections.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-sections.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAG3E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuH/B,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview wikipedia_get_sections tool — fetch the table of contents for a Wikipedia article.
3
+ * @module mcp-server/tools/definitions/wikipedia-get-sections.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getWikipediaService } from '../../../services/wikipedia/wikipedia-service.js';
8
+ export const wikipediaGetSections = tool('wikipedia_get_sections', {
9
+ title: 'Get Wikipedia Article Sections',
10
+ description: 'Fetch the table of contents for a Wikipedia article. Returns section titles, heading levels, section numbering (e.g. "2.1"), and section_index values. Pass a section_index to wikipedia_get_article to retrieve just that section. Useful for enumerating article structure before doing a targeted section read.',
11
+ annotations: { readOnlyHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ title: z.string().describe('Article title (e.g. "Python (programming language)").'),
14
+ language: z
15
+ .string()
16
+ .default('en')
17
+ .describe('Wikipedia language edition code (default "en"). Examples: "fr", "de", "ja".'),
18
+ }),
19
+ output: z.object({
20
+ title: z.string().describe('Article title as resolved by Wikipedia.'),
21
+ pageid: z.number().optional().describe('Wikipedia page ID. Absent for stub articles.'),
22
+ sections: z
23
+ .array(z
24
+ .object({
25
+ index: z
26
+ .number()
27
+ .describe('Section index — pass to wikipedia_get_article as section_index.'),
28
+ number: z.string().describe('Section number (e.g. "2.1") for hierarchical navigation.'),
29
+ title: z.string().describe('Section heading text.'),
30
+ level: z.number().describe('Heading depth: 2 = ==, 3 = ===, etc.'),
31
+ })
32
+ .describe('A single table-of-contents entry.'))
33
+ .describe('Ordered list of article sections with index values for targeted reads.'),
34
+ total_sections: z.number().describe('Total number of sections in the article.'),
35
+ language: z.string().describe('Language edition queried.'),
36
+ }),
37
+ errors: [
38
+ {
39
+ reason: 'not_found',
40
+ code: JsonRpcErrorCode.NotFound,
41
+ when: 'No Wikipedia article exists for the given title.',
42
+ recovery: 'Use wikipedia_search to discover the correct article title and try again.',
43
+ },
44
+ {
45
+ reason: 'no_sections',
46
+ code: JsonRpcErrorCode.NotFound,
47
+ when: 'Article exists but has no sections (stub or very short article).',
48
+ recovery: 'Use wikipedia_get_article without section_index to read the full short article.',
49
+ },
50
+ {
51
+ reason: 'invalid_language',
52
+ code: JsonRpcErrorCode.InvalidParams,
53
+ when: 'The language code is not a valid BCP 47 code.',
54
+ recovery: 'Use a valid BCP 47 language code such as "fr", "de", or "ja".',
55
+ },
56
+ ],
57
+ async handler(input, ctx) {
58
+ const { language } = input;
59
+ if (!/^[a-z]{2,3}(-[a-z0-9]+)*$/i.test(language)) {
60
+ throw ctx.fail('invalid_language', `Invalid language code "${language}". Use a BCP 47 language code such as "fr", "de", or "ja".`, { language, ...ctx.recoveryFor('invalid_language') });
61
+ }
62
+ ctx.log.info('Fetching sections', { title: input.title, language });
63
+ const svc = getWikipediaService();
64
+ let result;
65
+ try {
66
+ result = await svc.getSections(input.title, language, ctx);
67
+ }
68
+ catch (err) {
69
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound) {
70
+ throw ctx.fail('not_found', err.message, {
71
+ title: input.title,
72
+ language,
73
+ recovery: { hint: 'Use wikipedia_search to find the correct article title.' },
74
+ });
75
+ }
76
+ throw err;
77
+ }
78
+ if (result.sections.length === 0) {
79
+ throw ctx.fail('no_sections', `Article "${input.title}" exists but has no sections. It may be a stub.`, {
80
+ title: input.title,
81
+ recovery: {
82
+ hint: 'Use wikipedia_get_article without section_index to read the full article content.',
83
+ },
84
+ });
85
+ }
86
+ ctx.log.info('Sections fetched', { title: input.title, count: result.sections.length });
87
+ return {
88
+ title: input.title,
89
+ pageid: result.pageid,
90
+ sections: result.sections,
91
+ total_sections: result.sections.length,
92
+ language,
93
+ };
94
+ },
95
+ format: (result) => {
96
+ const lines = [
97
+ `## Table of Contents — ${result.title} (${result.language})`,
98
+ `${result.total_sections} sections` +
99
+ (result.pageid != null ? ` | Page ID: ${result.pageid}` : ''),
100
+ '',
101
+ ];
102
+ for (const s of result.sections) {
103
+ const indent = ' '.repeat(Math.max(0, s.level - 2));
104
+ lines.push(`${indent}${s.number}. **${s.title}** (index: ${s.index}, level: ${s.level})`);
105
+ }
106
+ return [{ type: 'text', text: lines.join('\n') }];
107
+ },
108
+ });
109
+ //# sourceMappingURL=wikipedia-get-sections.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-sections.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-sections.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview wikipedia_get_summary tool — fetch the lead section summary for a Wikipedia article.
3
+ * @module mcp-server/tools/definitions/wikipedia-get-summary.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const wikipediaGetSummary: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ title: z.ZodString;
9
+ language: z.ZodDefault<z.ZodString>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ title: z.ZodString;
12
+ page_type: z.ZodString;
13
+ pageid: z.ZodOptional<z.ZodNumber>;
14
+ wikibase_item: z.ZodOptional<z.ZodString>;
15
+ description: z.ZodOptional<z.ZodString>;
16
+ extract: z.ZodString;
17
+ thumbnail_url: z.ZodOptional<z.ZodString>;
18
+ language: z.ZodString;
19
+ }, z.core.$strip>, readonly [{
20
+ readonly reason: "not_found";
21
+ readonly code: JsonRpcErrorCode.NotFound;
22
+ readonly when: "No Wikipedia article exists for the given title.";
23
+ readonly recovery: "Use wikipedia_search to discover the correct article title and try again.";
24
+ }, {
25
+ readonly reason: "invalid_language";
26
+ readonly code: JsonRpcErrorCode.InvalidParams;
27
+ readonly when: "The language code is not a valid BCP 47 code.";
28
+ readonly recovery: "Use a valid BCP 47 language code such as \"fr\", \"de\", or \"ja\".";
29
+ }]>;
30
+ //# sourceMappingURL=wikipedia-get-summary.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-summary.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-summary.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAG3E,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;GA8G9B,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview wikipedia_get_summary tool — fetch the lead section summary for a Wikipedia article.
3
+ * @module mcp-server/tools/definitions/wikipedia-get-summary.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getWikipediaService } from '../../../services/wikipedia/wikipedia-service.js';
8
+ export const wikipediaGetSummary = tool('wikipedia_get_summary', {
9
+ title: 'Get Wikipedia Summary',
10
+ description: 'Fetch the lead-section summary for a Wikipedia article — the 2–4 paragraph intro that answers "what is X?". Returns plain-text extract, Wikidata QID (wikibase_item) for cross-referencing with wikidata-mcp-server, short description, and thumbnail URL. Redirect pages are followed automatically. When page_type is "disambiguation", the title matched a disambiguation page — call wikipedia_search with a more specific query to find the intended article. Prefer this over wikipedia_get_article unless full article depth is needed.',
11
+ annotations: { readOnlyHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ title: z
14
+ .string()
15
+ .describe('Article title (URL-decoded), e.g. "Python (programming language)".'),
16
+ language: z
17
+ .string()
18
+ .default('en')
19
+ .describe('Wikipedia language edition code (default "en"). Examples: "fr", "de", "ja".'),
20
+ }),
21
+ output: z.object({
22
+ title: z.string().describe('Resolved article title (may differ from input for redirects).'),
23
+ page_type: z
24
+ .string()
25
+ .describe('Page type from the Wikipedia REST API. Common values: "standard" (regular article), "disambiguation" (disambiguation page), "no-extract" (article with no extract). When "disambiguation", call wikipedia_search with a more specific query.'),
26
+ pageid: z.number().optional().describe('Wikipedia page ID. Absent when the API omits it.'),
27
+ wikibase_item: z
28
+ .string()
29
+ .optional()
30
+ .describe('Wikidata QID (e.g. "Q28865"). Use to chain into wikidata-mcp-server without a separate lookup.'),
31
+ description: z.string().optional().describe('Short description of the article subject.'),
32
+ extract: z.string().describe('Plain-text lead-section extract.'),
33
+ thumbnail_url: z
34
+ .string()
35
+ .optional()
36
+ .describe('URL of the article thumbnail image, if available.'),
37
+ language: z.string().describe('Language edition queried.'),
38
+ }),
39
+ errors: [
40
+ {
41
+ reason: 'not_found',
42
+ code: JsonRpcErrorCode.NotFound,
43
+ when: 'No Wikipedia article exists for the given title.',
44
+ recovery: 'Use wikipedia_search to discover the correct article title and try again.',
45
+ },
46
+ {
47
+ reason: 'invalid_language',
48
+ code: JsonRpcErrorCode.InvalidParams,
49
+ when: 'The language code is not a valid BCP 47 code.',
50
+ recovery: 'Use a valid BCP 47 language code such as "fr", "de", or "ja".',
51
+ },
52
+ ],
53
+ async handler(input, ctx) {
54
+ const { language } = input;
55
+ if (!/^[a-z]{2,3}(-[a-z0-9]+)*$/i.test(language)) {
56
+ throw ctx.fail('invalid_language', `Invalid language code "${language}". Use a BCP 47 language code such as "fr", "de", or "ja".`, { language, ...ctx.recoveryFor('invalid_language') });
57
+ }
58
+ ctx.log.info('Fetching summary', { title: input.title, language });
59
+ const svc = getWikipediaService();
60
+ let result;
61
+ try {
62
+ result = await svc.getSummary(input.title, language, ctx);
63
+ }
64
+ catch (err) {
65
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound) {
66
+ throw ctx.fail('not_found', err.message, {
67
+ title: input.title,
68
+ language,
69
+ recovery: { hint: 'Use wikipedia_search to find the correct article title.' },
70
+ });
71
+ }
72
+ throw err;
73
+ }
74
+ ctx.log.info('Summary fetched', {
75
+ title: result.title,
76
+ pageType: result.pageType,
77
+ hasQid: Boolean(result.wikidataQid),
78
+ });
79
+ return {
80
+ title: result.title,
81
+ page_type: result.pageType,
82
+ pageid: result.pageid,
83
+ wikibase_item: result.wikidataQid,
84
+ description: result.description,
85
+ extract: result.extract,
86
+ thumbnail_url: result.thumbnailUrl,
87
+ language,
88
+ };
89
+ },
90
+ format: (result) => {
91
+ const lines = [];
92
+ lines.push(`# ${result.title}`);
93
+ if (result.description)
94
+ lines.push(`*${result.description}*`);
95
+ lines.push(`**Type:** ${result.page_type} | **Language:** ${result.language}`);
96
+ if (result.pageid != null)
97
+ lines.push(`**Page ID:** ${result.pageid}`);
98
+ if (result.wikibase_item)
99
+ lines.push(`**Wikidata QID:** ${result.wikibase_item}`);
100
+ if (result.thumbnail_url)
101
+ lines.push(`**Thumbnail:** ${result.thumbnail_url}`);
102
+ lines.push('');
103
+ lines.push(result.extract);
104
+ return [{ type: 'text', text: lines.join('\n') }];
105
+ },
106
+ });
107
+ //# sourceMappingURL=wikipedia-get-summary.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-get-summary.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-get-summary.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview wikipedia_search_nearby tool — find geotagged Wikipedia articles near a coordinate.
3
+ * @module mcp-server/tools/definitions/wikipedia-search-nearby.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const wikipediaSearchNearby: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ latitude: z.ZodNumber;
9
+ longitude: z.ZodNumber;
10
+ radius_meters: z.ZodDefault<z.ZodNumber>;
11
+ limit: z.ZodDefault<z.ZodNumber>;
12
+ language: z.ZodDefault<z.ZodString>;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ results: z.ZodArray<z.ZodObject<{
15
+ title: z.ZodString;
16
+ pageid: z.ZodNumber;
17
+ latitude: z.ZodNumber;
18
+ longitude: z.ZodNumber;
19
+ distance_meters: z.ZodNumber;
20
+ }, z.core.$strip>>;
21
+ total_results: z.ZodNumber;
22
+ query_latitude: z.ZodNumber;
23
+ query_longitude: z.ZodNumber;
24
+ radius_meters_used: z.ZodNumber;
25
+ language: z.ZodString;
26
+ }, z.core.$strip>, readonly [{
27
+ readonly reason: "no_results";
28
+ readonly code: JsonRpcErrorCode.NotFound;
29
+ readonly when: "No geotagged articles found within the search radius.";
30
+ readonly recovery: "Increase radius_meters or verify the coordinates are correct and retry.";
31
+ }, {
32
+ readonly reason: "invalid_coordinates";
33
+ readonly code: JsonRpcErrorCode.InvalidParams;
34
+ readonly when: "Latitude or longitude is outside valid WGS 84 range.";
35
+ readonly recovery: "Latitude must be between −90 and 90; longitude between −180 and 180.";
36
+ }, {
37
+ readonly reason: "invalid_language";
38
+ readonly code: JsonRpcErrorCode.InvalidParams;
39
+ readonly when: "The language code is not a valid BCP 47 code.";
40
+ readonly recovery: "Use a valid BCP 47 language code such as \"fr\", \"de\", or \"ja\".";
41
+ }]>;
42
+ //# sourceMappingURL=wikipedia-search-nearby.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-search-nearby.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-search-nearby.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8JhC,CAAC"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @fileoverview wikipedia_search_nearby tool — find geotagged Wikipedia articles near a coordinate.
3
+ * @module mcp-server/tools/definitions/wikipedia-search-nearby.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getWikipediaService } from '../../../services/wikipedia/wikipedia-service.js';
8
+ export const wikipediaSearchNearby = tool('wikipedia_search_nearby', {
9
+ title: 'Search Wikipedia Nearby',
10
+ description: 'Find Wikipedia articles about places near a geographic coordinate. Returns articles sorted by distance from the query point, with titles, page IDs, coordinates, and distance in meters. Useful for "what is notable near X?" research workflows. Only articles with geographic coordinates in their Wikidata record are returned — not all articles about locations are geotagged.',
11
+ annotations: { readOnlyHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ latitude: z.number().describe('WGS 84 latitude in decimal degrees (range: −90 to 90).'),
14
+ longitude: z.number().describe('WGS 84 longitude in decimal degrees (range: −180 to 180).'),
15
+ radius_meters: z
16
+ .number()
17
+ .int()
18
+ .min(1)
19
+ .default(1000)
20
+ .describe('Search radius in meters (default 1000, max 10000). Must be a positive integer.'),
21
+ limit: z
22
+ .number()
23
+ .int()
24
+ .min(1)
25
+ .default(10)
26
+ .describe('Maximum number of results to return (default 10, max 50). Must be a positive integer.'),
27
+ language: z
28
+ .string()
29
+ .default('en')
30
+ .describe('Wikipedia language edition code (default "en"). Examples: "fr", "de", "ja".'),
31
+ }),
32
+ output: z.object({
33
+ results: z
34
+ .array(z
35
+ .object({
36
+ title: z.string().describe('Article title (e.g. "Eiffel Tower").'),
37
+ pageid: z.number().describe('Wikipedia page ID — use as input to other tools.'),
38
+ latitude: z.number().describe('Article subject latitude in decimal degrees.'),
39
+ longitude: z.number().describe('Article subject longitude in decimal degrees.'),
40
+ distance_meters: z.number().describe('Distance from the query coordinate in meters.'),
41
+ })
42
+ .describe('A single geotagged article result.'))
43
+ .describe('Geotagged articles sorted ascending by distance_meters.'),
44
+ total_results: z.number().describe('Number of results returned.'),
45
+ query_latitude: z.number().describe('Latitude used for the search.'),
46
+ query_longitude: z.number().describe('Longitude used for the search.'),
47
+ radius_meters_used: z.number().describe('Radius in meters used for the search.'),
48
+ language: z.string().describe('Language edition queried.'),
49
+ }),
50
+ errors: [
51
+ {
52
+ reason: 'no_results',
53
+ code: JsonRpcErrorCode.NotFound,
54
+ when: 'No geotagged articles found within the search radius.',
55
+ recovery: 'Increase radius_meters or verify the coordinates are correct and retry.',
56
+ },
57
+ {
58
+ reason: 'invalid_coordinates',
59
+ code: JsonRpcErrorCode.InvalidParams,
60
+ when: 'Latitude or longitude is outside valid WGS 84 range.',
61
+ recovery: 'Latitude must be between −90 and 90; longitude between −180 and 180.',
62
+ },
63
+ {
64
+ reason: 'invalid_language',
65
+ code: JsonRpcErrorCode.InvalidParams,
66
+ when: 'The language code is not a valid BCP 47 code.',
67
+ recovery: 'Use a valid BCP 47 language code such as "fr", "de", or "ja".',
68
+ },
69
+ ],
70
+ async handler(input, ctx) {
71
+ // Validate coordinate ranges
72
+ if (input.latitude < -90 || input.latitude > 90) {
73
+ throw ctx.fail('invalid_coordinates', `Latitude ${input.latitude} is out of range (−90 to 90).`, {
74
+ latitude: input.latitude,
75
+ ...ctx.recoveryFor('invalid_coordinates'),
76
+ });
77
+ }
78
+ if (input.longitude < -180 || input.longitude > 180) {
79
+ throw ctx.fail('invalid_coordinates', `Longitude ${input.longitude} is out of range (−180 to 180).`, { longitude: input.longitude, ...ctx.recoveryFor('invalid_coordinates') });
80
+ }
81
+ const radiusMeters = Math.min(input.radius_meters, 10_000);
82
+ const limit = Math.min(input.limit, 50);
83
+ const { language } = input;
84
+ if (!/^[a-z]{2,3}(-[a-z0-9]+)*$/i.test(language)) {
85
+ throw ctx.fail('invalid_language', `Invalid language code "${language}". Use a BCP 47 language code such as "fr", "de", or "ja".`, { language, ...ctx.recoveryFor('invalid_language') });
86
+ }
87
+ ctx.log.info('Geo search', {
88
+ latitude: input.latitude,
89
+ longitude: input.longitude,
90
+ radiusMeters,
91
+ limit,
92
+ language,
93
+ });
94
+ const svc = getWikipediaService();
95
+ const { results } = await svc.searchNearby(input.latitude, input.longitude, radiusMeters, limit, language, ctx);
96
+ if (results.length === 0) {
97
+ throw ctx.fail('no_results', `No geotagged Wikipedia articles found within ${radiusMeters}m of (${input.latitude}, ${input.longitude}).`, {
98
+ latitude: input.latitude,
99
+ longitude: input.longitude,
100
+ radiusMeters,
101
+ recovery: {
102
+ hint: `Increase radius_meters beyond ${radiusMeters} or verify the coordinates are correct.`,
103
+ },
104
+ });
105
+ }
106
+ ctx.log.info('Geo search complete', { count: results.length, language });
107
+ return {
108
+ results,
109
+ total_results: results.length,
110
+ query_latitude: input.latitude,
111
+ query_longitude: input.longitude,
112
+ radius_meters_used: radiusMeters,
113
+ language,
114
+ };
115
+ },
116
+ format: (result) => {
117
+ const lines = [
118
+ `**${result.total_results} articles** near (${result.query_latitude}, ${result.query_longitude}) within ${result.radius_meters_used}m (${result.language})\n`,
119
+ ];
120
+ for (const item of result.results) {
121
+ lines.push(`### ${item.title}`);
122
+ lines.push(`**Page ID:** ${item.pageid} | **Distance:** ${item.distance_meters}m | **Coords:** (${item.latitude}, ${item.longitude})`);
123
+ }
124
+ return [{ type: 'text', text: lines.join('\n') }];
125
+ },
126
+ });
127
+ //# sourceMappingURL=wikipedia-search-nearby.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikipedia-search-nearby.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/wikipedia-search-nearby.tool.ts"],"names":[],"mappings":"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"}