atheneum-mcp 0.2.0 → 0.4.0

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/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] - 2026-02-18
11
+
12
+ ## [0.4.0] - 2026-02-18
13
+
14
+ ### Fixed
15
+
16
+ - `list_wiki_pages` and `get_pages_by_tag` returning fewer results than expected due to a buggy `limit` parameter in the Wiki.js GraphQL API; queries now fetch all results and limit client-side
17
+ - Path-scoped wiki instances silently losing results when the parent wiki had many pages outside the configured base path
18
+
19
+ ## [0.3.0] - 2026-02-18
20
+
21
+ ### Added
22
+
23
+ - Optional `description` field on wiki instances, surfaced in tool parameter hints and error messages
24
+ - `list_wiki_instances` tool for discovering configured wikis and their descriptions
25
+
10
26
  ## [0.2.0] - 2026-02-17
11
27
 
12
28
  ### Added
@@ -28,5 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
28
44
  - Google OAuth tokens now stored in `~/.config/atheneum-mcp/`
29
45
  - Configuration via YAML file or environment variables
30
46
 
31
- [Unreleased]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.2.0...main
47
+ [Unreleased]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.4.0...main
48
+ [0.4.0]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.3.0...v0.4.0
49
+ [0.4.0]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.3.0...v0.4.0
50
+ [0.3.0]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.2.0...v0.3.0
32
51
  [0.2.0]: https://gitlab.com/morgul/atheneum-mcp/-/compare/v0.1.0...v0.2.0
package/dist/config.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  declare const WikiConfigSchema: z.ZodObject<{
3
3
  name: z.ZodString;
4
+ description: z.ZodOptional<z.ZodString>;
4
5
  url: z.ZodString;
5
6
  token: z.ZodString;
6
7
  basePath: z.ZodDefault<z.ZodString>;
@@ -15,10 +16,12 @@ declare const WikiConfigSchema: z.ZodObject<{
15
16
  readOnly: boolean;
16
17
  strictPath: boolean;
17
18
  hidePaths: boolean;
19
+ description?: string | undefined;
18
20
  }, {
19
21
  name: string;
20
22
  url: string;
21
23
  token: string;
24
+ description?: string | undefined;
22
25
  basePath?: string | undefined;
23
26
  readOnly?: boolean | undefined;
24
27
  strictPath?: boolean | undefined;
@@ -46,6 +49,7 @@ declare const DriveConfigSchema: z.ZodObject<{
46
49
  declare const AtheneumConfigSchema: z.ZodObject<{
47
50
  wikis: z.ZodDefault<z.ZodArray<z.ZodObject<{
48
51
  name: z.ZodString;
52
+ description: z.ZodOptional<z.ZodString>;
49
53
  url: z.ZodString;
50
54
  token: z.ZodString;
51
55
  basePath: z.ZodDefault<z.ZodString>;
@@ -60,10 +64,12 @@ declare const AtheneumConfigSchema: z.ZodObject<{
60
64
  readOnly: boolean;
61
65
  strictPath: boolean;
62
66
  hidePaths: boolean;
67
+ description?: string | undefined;
63
68
  }, {
64
69
  name: string;
65
70
  url: string;
66
71
  token: string;
72
+ description?: string | undefined;
67
73
  basePath?: string | undefined;
68
74
  readOnly?: boolean | undefined;
69
75
  strictPath?: boolean | undefined;
@@ -97,6 +103,7 @@ declare const AtheneumConfigSchema: z.ZodObject<{
97
103
  readOnly: boolean;
98
104
  strictPath: boolean;
99
105
  hidePaths: boolean;
106
+ description?: string | undefined;
100
107
  }[];
101
108
  drive?: {
102
109
  folders: string[];
@@ -110,6 +117,7 @@ declare const AtheneumConfigSchema: z.ZodObject<{
110
117
  name: string;
111
118
  url: string;
112
119
  token: string;
120
+ description?: string | undefined;
113
121
  basePath?: string | undefined;
114
122
  readOnly?: boolean | undefined;
115
123
  strictPath?: boolean | undefined;
package/dist/config.js CHANGED
@@ -11,6 +11,7 @@ import { z } from 'zod';
11
11
  //----------------------------------------------------------------------------------------------------------------------
12
12
  const WikiConfigSchema = z.object({
13
13
  name: z.string(),
14
+ description: z.string().optional(),
14
15
  url: z.string().url(),
15
16
  token: z.string(),
16
17
  basePath: z.string().default('/'),
package/dist/server.js CHANGED
@@ -10,12 +10,21 @@ import { DriveClient } from "./driveClient.js";
10
10
  //----------------------------------------------------------------------------------------------------------------------
11
11
  // Wiki Tool Registration
12
12
  //----------------------------------------------------------------------------------------------------------------------
13
- function registerWikiTools(server, wikiClients) {
13
+ function registerWikiTools(server, wikiClients, wikiConfigs) {
14
14
  const multiWiki = wikiClients.size > 1;
15
+ // Format instance listing with optional descriptions
16
+ function formatInstanceList() {
17
+ const entries = [];
18
+ for (const [name] of wikiClients) {
19
+ const desc = wikiConfigs.get(name)?.description;
20
+ entries.push(desc ? `${name} (${desc})` : name);
21
+ }
22
+ return entries.join(', ');
23
+ }
15
24
  // Instance parameter -- only present when multiple wikis are configured
16
25
  const instanceParam = multiWiki
17
26
  ? {
18
- instance: z.string().optional().describe(`Wiki instance name. Available: ${[...wikiClients.keys()].join(', ')}`)
27
+ instance: z.string().optional().describe(`Wiki instance name. Available: ${formatInstanceList()}`)
19
28
  }
20
29
  : {};
21
30
  // Resolve which wiki client to use from the MCP tool args
@@ -28,13 +37,25 @@ function registerWikiTools(server, wikiClients) {
28
37
  if (instance) {
29
38
  const client = wikiClients.get(instance);
30
39
  if (!client) {
31
- throw new Error(`Wiki instance '${instance}' not found. `
32
- + `Available: ${[...wikiClients.keys()].join(', ')}`);
40
+ throw new Error(`Wiki instance '${instance}' not found. Available: ${formatInstanceList()}`);
33
41
  }
34
42
  return client;
35
43
  }
36
- throw new Error(`Multiple wikis configured. Specify instance: ${[...wikiClients.keys()].join(', ')}`);
44
+ throw new Error(`Multiple wikis configured. Specify instance: ${formatInstanceList()}`);
37
45
  }
46
+ // List available wiki instances -- always registered when wikis exist
47
+ server.tool('list_wiki_instances', 'List all configured wiki instances with their descriptions.', {}, async () => {
48
+ let text = `Available wiki instances (${wikiClients.size}):\n\n`;
49
+ for (const [name] of wikiClients) {
50
+ const desc = wikiConfigs.get(name)?.description;
51
+ text += `- **${name}**`;
52
+ if (desc) {
53
+ text += ` -- ${desc}`;
54
+ }
55
+ text += '\n';
56
+ }
57
+ return { content: [{ type: 'text', text }] };
58
+ });
38
59
  //------------------------------------------------------------------------------------------------------------------
39
60
  // Read Tools
40
61
  //------------------------------------------------------------------------------------------------------------------
@@ -509,14 +530,16 @@ export async function startServer(config) {
509
530
  });
510
531
  // Instantiate wiki clients
511
532
  const wikiClients = new Map();
533
+ const wikiConfigs = new Map();
512
534
  for (const wikiConfig of config.wikis) {
513
535
  wikiClients.set(wikiConfig.name, new WikiClient(wikiConfig));
536
+ wikiConfigs.set(wikiConfig.name, { description: wikiConfig.description });
514
537
  }
515
538
  // Instantiate drive client
516
539
  const driveClient = config.drive ? new DriveClient(config.drive) : null;
517
540
  // Register tools
518
541
  if (wikiClients.size > 0) {
519
- registerWikiTools(server, wikiClients);
542
+ registerWikiTools(server, wikiClients, wikiConfigs);
520
543
  }
521
544
  if (driveClient) {
522
545
  registerDriveTools(server, driveClient);
@@ -215,10 +215,12 @@ export class WikiClient {
215
215
  return data;
216
216
  }
217
217
  async listPages(limit = 50) {
218
+ // Wiki.js's limit parameter is buggy -- it returns fewer results than requested.
219
+ // Fetch all pages and limit client-side instead.
218
220
  const query = `
219
- query ListPages($limit: Int) {
221
+ query ListPages {
220
222
  pages {
221
- list(limit: $limit, orderBy: UPDATED, orderByDirection: DESC) {
223
+ list(orderBy: UPDATED, orderByDirection: DESC) {
222
224
  id
223
225
  path
224
226
  title
@@ -228,10 +230,10 @@ export class WikiClient {
228
230
  }
229
231
  }
230
232
  `;
231
- const data = await this.graphql(query, { limit });
233
+ const data = await this.graphql(query);
232
234
  const filtered = data.pages.list.filter((p) => this.isPathAllowed(p.path));
233
235
  const mapped = filtered.map((p) => ({ ...p, path: this.stripBasePath(p.path) }));
234
- return { pages: { list: mapped } };
236
+ return { pages: { list: mapped.slice(0, limit) } };
235
237
  }
236
238
  async getPageTree(parentId) {
237
239
  const query = `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atheneum-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for Wiki.js and Google Drive",
5
5
  "author": "Christopher S. Case <chris.case@g33xnexus.com>",
6
6
  "license": "WTFPL",