@nonz250/notepm-mcp-server 0.3.0 → 0.5.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.
Files changed (120) hide show
  1. package/README.md +2 -9
  2. package/dist/folders/__tests__/client.test.d.ts +2 -0
  3. package/dist/folders/__tests__/client.test.d.ts.map +1 -0
  4. package/dist/folders/__tests__/client.test.js +30 -0
  5. package/dist/folders/__tests__/client.test.js.map +1 -0
  6. package/dist/folders/__tests__/schemas.test.d.ts +2 -0
  7. package/dist/folders/__tests__/schemas.test.d.ts.map +1 -0
  8. package/dist/folders/__tests__/schemas.test.js +27 -0
  9. package/dist/folders/__tests__/schemas.test.js.map +1 -0
  10. package/dist/folders/client.d.ts +15 -0
  11. package/dist/folders/client.d.ts.map +1 -0
  12. package/dist/folders/client.js +14 -0
  13. package/dist/folders/client.js.map +1 -0
  14. package/dist/folders/handlers.d.ts +15 -0
  15. package/dist/folders/handlers.d.ts.map +1 -0
  16. package/dist/folders/handlers.js +47 -0
  17. package/dist/folders/handlers.js.map +1 -0
  18. package/dist/folders/index.d.ts +9 -0
  19. package/dist/folders/index.d.ts.map +1 -0
  20. package/dist/folders/index.js +9 -0
  21. package/dist/folders/index.js.map +1 -0
  22. package/dist/folders/schemas.d.ts +10 -0
  23. package/dist/folders/schemas.d.ts.map +1 -0
  24. package/dist/folders/schemas.js +11 -0
  25. package/dist/folders/schemas.js.map +1 -0
  26. package/dist/folders/tools.d.ts +6 -0
  27. package/dist/folders/tools.d.ts.map +1 -0
  28. package/dist/folders/tools.js +11 -0
  29. package/dist/folders/tools.js.map +1 -0
  30. package/dist/folders/types.d.ts +24 -0
  31. package/dist/folders/types.d.ts.map +1 -0
  32. package/dist/folders/types.js +8 -0
  33. package/dist/folders/types.js.map +1 -0
  34. package/dist/index.js +3 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp/__tests__/handler.test.js +32 -120
  37. package/dist/mcp/__tests__/handler.test.js.map +1 -1
  38. package/dist/mcp/__tests__/tools.test.js +5 -10
  39. package/dist/mcp/__tests__/tools.test.js.map +1 -1
  40. package/dist/mcp/handler.d.ts +2 -0
  41. package/dist/mcp/handler.d.ts.map +1 -1
  42. package/dist/mcp/handler.js +5 -1
  43. package/dist/mcp/handler.js.map +1 -1
  44. package/dist/mcp/tools.d.ts.map +1 -1
  45. package/dist/mcp/tools.js +2 -1
  46. package/dist/mcp/tools.js.map +1 -1
  47. package/dist/notes/__tests__/client.test.js +0 -50
  48. package/dist/notes/__tests__/client.test.js.map +1 -1
  49. package/dist/notes/__tests__/schemas.test.js +1 -194
  50. package/dist/notes/__tests__/schemas.test.js.map +1 -1
  51. package/dist/notes/client.d.ts +1 -31
  52. package/dist/notes/client.d.ts.map +1 -1
  53. package/dist/notes/client.js +0 -45
  54. package/dist/notes/client.js.map +1 -1
  55. package/dist/notes/handlers.d.ts +1 -1
  56. package/dist/notes/handlers.d.ts.map +1 -1
  57. package/dist/notes/handlers.js +9 -57
  58. package/dist/notes/handlers.js.map +1 -1
  59. package/dist/notes/schemas.d.ts +0 -45
  60. package/dist/notes/schemas.d.ts.map +1 -1
  61. package/dist/notes/schemas.js +0 -32
  62. package/dist/notes/schemas.js.map +1 -1
  63. package/dist/notes/tools.d.ts.map +1 -1
  64. package/dist/notes/tools.js +1 -31
  65. package/dist/notes/tools.js.map +1 -1
  66. package/dist/notes/types.d.ts +0 -22
  67. package/dist/notes/types.d.ts.map +1 -1
  68. package/dist/notes/types.js +0 -6
  69. package/dist/notes/types.js.map +1 -1
  70. package/dist/pages/__tests__/client.test.js +0 -7
  71. package/dist/pages/__tests__/client.test.js.map +1 -1
  72. package/dist/pages/__tests__/schemas.test.js +1 -23
  73. package/dist/pages/__tests__/schemas.test.js.map +1 -1
  74. package/dist/pages/client.d.ts +0 -5
  75. package/dist/pages/client.d.ts.map +1 -1
  76. package/dist/pages/client.js +0 -7
  77. package/dist/pages/client.js.map +1 -1
  78. package/dist/pages/handlers.d.ts.map +1 -1
  79. package/dist/pages/handlers.js +10 -7
  80. package/dist/pages/handlers.js.map +1 -1
  81. package/dist/pages/schemas.d.ts +0 -5
  82. package/dist/pages/schemas.d.ts.map +1 -1
  83. package/dist/pages/schemas.js +0 -3
  84. package/dist/pages/schemas.js.map +1 -1
  85. package/dist/pages/tools.d.ts.map +1 -1
  86. package/dist/pages/tools.js +1 -6
  87. package/dist/pages/tools.js.map +1 -1
  88. package/dist/pages/types.d.ts +0 -1
  89. package/dist/pages/types.d.ts.map +1 -1
  90. package/dist/pages/types.js +0 -1
  91. package/dist/pages/types.js.map +1 -1
  92. package/dist/shared/__tests__/fixtures.d.ts +9 -0
  93. package/dist/shared/__tests__/fixtures.d.ts.map +1 -1
  94. package/dist/shared/__tests__/fixtures.js +15 -0
  95. package/dist/shared/__tests__/fixtures.js.map +1 -1
  96. package/dist/shared/__tests__/http-client.test.js +1 -1
  97. package/dist/shared/__tests__/http-client.test.js.map +1 -1
  98. package/dist/tags/__tests__/client.test.js +0 -8
  99. package/dist/tags/__tests__/client.test.js.map +1 -1
  100. package/dist/tags/__tests__/schemas.test.js +1 -31
  101. package/dist/tags/__tests__/schemas.test.js.map +1 -1
  102. package/dist/tags/client.d.ts +1 -6
  103. package/dist/tags/client.d.ts.map +1 -1
  104. package/dist/tags/client.js +0 -7
  105. package/dist/tags/client.js.map +1 -1
  106. package/dist/tags/handlers.d.ts.map +1 -1
  107. package/dist/tags/handlers.js +1 -6
  108. package/dist/tags/handlers.js.map +1 -1
  109. package/dist/tags/schemas.d.ts +0 -5
  110. package/dist/tags/schemas.d.ts.map +1 -1
  111. package/dist/tags/schemas.js +0 -3
  112. package/dist/tags/schemas.js.map +1 -1
  113. package/dist/tags/tools.d.ts.map +1 -1
  114. package/dist/tags/tools.js +1 -6
  115. package/dist/tags/tools.js.map +1 -1
  116. package/dist/tags/types.d.ts +0 -5
  117. package/dist/tags/types.d.ts.map +1 -1
  118. package/dist/tags/types.js +0 -1
  119. package/dist/tags/types.js.map +1 -1
  120. package/package.json +1 -1
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  An unofficial [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for [NotePM](https://notepm.jp/) - a knowledge management and documentation platform.
22
22
 
23
- This server enables AI assistants like Claude to search, read, create, update, and delete pages in your NotePM workspace.
23
+ This server enables AI assistants like Claude to search, read, create, and update pages in your NotePM workspace.
24
24
 
25
25
  ## Requirements
26
26
 
@@ -115,21 +115,14 @@ If you installed globally, replace `npx` with the direct command:
115
115
 
116
116
  | Tool | Description |
117
117
  |------|-------------|
118
+ | `list_folders` | List folders in a note with hierarchy |
118
119
  | `list_notes` | List all notes in your workspace |
119
- | `get_note` | Get a note's details including name, description, and scope |
120
- | `create_note` | Create a new note with name, description, and access settings |
121
- | `update_note` | Update an existing note's name, description, or access settings |
122
- | `delete_note` | Delete a note and all its pages (irreversible) |
123
- | `archive_note` | Archive a note (hidden from default list but can be restored) |
124
- | `unarchive_note` | Restore an archived note back to the active list |
125
120
  | `search_pages` | Search pages by keyword, note, or tag |
126
121
  | `get_page` | Get a page's full content including title, body, and tags |
127
122
  | `create_page` | Create a new page in a specified note |
128
123
  | `update_page` | Update an existing page's content |
129
- | `delete_page` | Delete a page (irreversible) |
130
124
  | `list_tags` | List all tags in your workspace |
131
125
  | `create_tag` | Create a new tag |
132
- | `delete_tag` | Delete a tag (irreversible) |
133
126
 
134
127
  ## Environment Variables
135
128
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../../src/folders/__tests__/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * FolderClient Tests
3
+ */
4
+ import { beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { FolderClient } from "../client.js";
6
+ describe("FolderClient", () => {
7
+ let client;
8
+ let mockHttp;
9
+ beforeEach(() => {
10
+ mockHttp = { request: vi.fn() };
11
+ client = new FolderClient(mockHttp);
12
+ });
13
+ describe("list", () => {
14
+ it("should call GET /notes/:note_code/folders", async () => {
15
+ mockHttp.request.mockResolvedValue({ folders: [] });
16
+ await client.list({ note_code: "abc123" });
17
+ expect(mockHttp.request).toHaveBeenCalledWith("GET", "/notes/abc123/folders");
18
+ });
19
+ it("should return folders response", async () => {
20
+ const mockFolders = [
21
+ { folder_id: 1, name: "Folder 1", parent_folder_id: null },
22
+ { folder_id: 2, name: "Folder 2", parent_folder_id: 1 },
23
+ ];
24
+ mockHttp.request.mockResolvedValue({ folders: mockFolders });
25
+ const result = await client.list({ note_code: "abc123" });
26
+ expect(result.folders).toEqual(mockFolders);
27
+ });
28
+ });
29
+ });
30
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../../src/folders/__tests__/client.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG9D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,MAAoB,CAAC;IACzB,IAAI,QAA+C,CAAC;IAEpD,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;QAChC,MAAM,GAAG,IAAI,YAAY,CAAC,QAAiC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;QACpB,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;YAEpD,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YAE3C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,uBAAuB,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,WAAW,GAAG;gBAClB,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE;gBAC1D,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC,EAAE;aACxD,CAAC;YACF,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schemas.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.test.d.ts","sourceRoot":"","sources":["../../../src/folders/__tests__/schemas.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Folder Schema Validation Tests
3
+ */
4
+ import { describe, expect, it } from "vitest";
5
+ import { ListFoldersInputSchema } from "../schemas.js";
6
+ describe("ListFoldersInputSchema", () => {
7
+ it("should require note_code", () => {
8
+ const result = ListFoldersInputSchema.safeParse({});
9
+ expect(result.success).toBe(false);
10
+ });
11
+ it("should accept valid note_code", () => {
12
+ const result = ListFoldersInputSchema.safeParse({ note_code: "abc123" });
13
+ expect(result.success).toBe(true);
14
+ if (result.success) {
15
+ expect(result.data.note_code).toBe("abc123");
16
+ }
17
+ });
18
+ it("should reject empty note_code", () => {
19
+ const result = ListFoldersInputSchema.safeParse({ note_code: "" });
20
+ expect(result.success).toBe(false);
21
+ });
22
+ it("should reject non-string note_code", () => {
23
+ const result = ListFoldersInputSchema.safeParse({ note_code: 123 });
24
+ expect(result.success).toBe(false);
25
+ });
26
+ });
27
+ //# sourceMappingURL=schemas.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.test.js","sourceRoot":"","sources":["../../../src/folders/__tests__/schemas.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Folder domain API client
3
+ */
4
+ import { HttpClient } from "../shared/http-client.js";
5
+ import type { FoldersResponse, ListFoldersParams } from "./types.js";
6
+ export declare class FolderClient {
7
+ private http;
8
+ constructor(http: HttpClient);
9
+ /**
10
+ * List folders in a note
11
+ * GET /api/v1/notes/:note_code/folders
12
+ */
13
+ list(params: ListFoldersParams): Promise<FoldersResponse>;
14
+ }
15
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/folders/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAErE,qBAAa,YAAY;IACX,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAEpC;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;CAGhE"}
@@ -0,0 +1,14 @@
1
+ export class FolderClient {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ /**
7
+ * List folders in a note
8
+ * GET /api/v1/notes/:note_code/folders
9
+ */
10
+ async list(params) {
11
+ return this.http.request("GET", `/notes/${params.note_code}/folders`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/folders/client.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,YAAY;IACH;IAApB,YAAoB,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAExC;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,MAAyB;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAkB,KAAK,EAAE,UAAU,MAAM,CAAC,SAAS,UAAU,CAAC,CAAC;IACzF,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Folder domain handlers
3
+ */
4
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
5
+ import { FolderClient } from "./client.js";
6
+ import type { FolderToolName } from "./types.js";
7
+ /**
8
+ * Check if the tool name is a folder tool
9
+ */
10
+ export declare function isFolderToolName(name: string): name is FolderToolName;
11
+ /**
12
+ * Handle folder tool calls
13
+ */
14
+ export declare function handleFolderToolCall(client: FolderClient, _name: FolderToolName, args: unknown): Promise<CallToolResult>;
15
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/folders/handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAU,cAAc,EAAE,MAAM,YAAY,CAAC;AAiCzD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,cAAc,CAErE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,cAAc,CAAC,CAWzB"}
@@ -0,0 +1,47 @@
1
+ import { parseInput, success } from "../shared/result.js";
2
+ import { ListFoldersInputSchema } from "./schemas.js";
3
+ import { FOLDER_TOOL_NAMES } from "./types.js";
4
+ /**
5
+ * Build folder tree structure for display
6
+ */
7
+ function buildFolderTree(folders) {
8
+ // Get root folders (no parent)
9
+ const rootFolders = folders.filter((f) => f.parent_folder_id === null);
10
+ // Get child folders for a given parent
11
+ const getChildren = (parentId) => folders.filter((f) => f.parent_folder_id === parentId);
12
+ // Recursively format folder with children
13
+ const formatWithChildren = (folder, indent) => {
14
+ const prefix = " ".repeat(indent);
15
+ const lines = [`${prefix}- **${folder.name}** (id: ${String(folder.folder_id)})`];
16
+ const children = getChildren(folder.folder_id);
17
+ for (const child of children) {
18
+ lines.push(...formatWithChildren(child, indent + 1));
19
+ }
20
+ return lines;
21
+ };
22
+ const lines = [];
23
+ for (const root of rootFolders) {
24
+ lines.push(...formatWithChildren(root, 0));
25
+ }
26
+ return lines.join("\n");
27
+ }
28
+ /**
29
+ * Check if the tool name is a folder tool
30
+ */
31
+ export function isFolderToolName(name) {
32
+ return Object.values(FOLDER_TOOL_NAMES).includes(name);
33
+ }
34
+ /**
35
+ * Handle folder tool calls
36
+ */
37
+ export async function handleFolderToolCall(client, _name, args) {
38
+ // Currently only list_folders is supported
39
+ const { note_code } = parseInput(ListFoldersInputSchema, args);
40
+ const result = await client.list({ note_code });
41
+ if (result.folders.length === 0) {
42
+ return success("No folders found in this note.");
43
+ }
44
+ const folderTree = buildFolderTree(result.folders);
45
+ return success(`Folders in note "${note_code}":\n\n${folderTree}`);
46
+ }
47
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/folders/handlers.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C;;GAEG;AACH,SAAS,eAAe,CAAC,OAAiB;IACxC,+BAA+B;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,IAAI,CAAC,CAAC;IAEvE,uCAAuC;IACvC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAY,EAAE,CACjD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC;IAEzD,0CAA0C;IAC1C,MAAM,kBAAkB,GAAG,CAAC,MAAc,EAAE,MAAc,EAAY,EAAE;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,OAAO,MAAM,CAAC,IAAI,WAAW,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAClF,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,IAAsB,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,KAAqB,EACrB,IAAa;IAEb,2CAA2C;IAC3C,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IAEhD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC,oBAAoB,SAAS,SAAS,UAAU,EAAE,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Folders domain exports
3
+ */
4
+ export * from "./types.js";
5
+ export * from "./schemas.js";
6
+ export * from "./client.js";
7
+ export * from "./handlers.js";
8
+ export * from "./tools.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/folders/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Folders domain exports
3
+ */
4
+ export * from "./types.js";
5
+ export * from "./schemas.js";
6
+ export * from "./client.js";
7
+ export * from "./handlers.js";
8
+ export * from "./tools.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/folders/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Folder domain schemas (Zod)
3
+ */
4
+ import { z } from "zod";
5
+ export declare const ListFoldersInputSchema: z.ZodObject<{
6
+ note_code: z.ZodString;
7
+ }, z.core.$strip>;
8
+ /** Inferred type for list folders input */
9
+ export type ListFoldersInput = z.infer<typeof ListFoldersInputSchema>;
10
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/folders/schemas.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,sBAAsB;;iBAEjC,CAAC;AAMH,2CAA2C;AAC3C,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Folder domain schemas (Zod)
3
+ */
4
+ import { z } from "zod";
5
+ // ============================================================
6
+ // Zod Schemas
7
+ // ============================================================
8
+ export const ListFoldersInputSchema = z.object({
9
+ note_code: z.string().min(1).describe("Note code to list folders from"),
10
+ });
11
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/folders/schemas.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,+DAA+D;AAC/D,cAAc;AACd,+DAA+D;AAE/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACxE,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Folder domain tool definitions
3
+ */
4
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
5
+ export declare const FOLDER_TOOLS: Tool[];
6
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/folders/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAM/D,eAAO,MAAM,YAAY,EAAE,IAAI,EAM9B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { toInputSchema } from "../shared/index.js";
2
+ import { ListFoldersInputSchema } from "./schemas.js";
3
+ import { FOLDER_TOOL_NAMES } from "./types.js";
4
+ export const FOLDER_TOOLS = [
5
+ {
6
+ name: FOLDER_TOOL_NAMES.LIST_FOLDERS,
7
+ description: "List folders in a NotePM note. Returns folder hierarchy with IDs and names.",
8
+ inputSchema: toInputSchema(ListFoldersInputSchema),
9
+ },
10
+ ];
11
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/folders/tools.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC;QACE,IAAI,EAAE,iBAAiB,CAAC,YAAY;QACpC,WAAW,EAAE,6EAA6E;QAC1F,WAAW,EAAE,aAAa,CAAC,sBAAsB,CAAC;KACnD;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Folder domain types
3
+ */
4
+ /** Folder information */
5
+ export interface Folder {
6
+ folder_id: number;
7
+ name: string;
8
+ parent_folder_id: number | null;
9
+ }
10
+ /** Folders list response */
11
+ export interface FoldersResponse {
12
+ folders: Folder[];
13
+ }
14
+ /** List folders parameters */
15
+ export interface ListFoldersParams {
16
+ note_code: string;
17
+ }
18
+ /** Tool name constants for folders */
19
+ export declare const FOLDER_TOOL_NAMES: {
20
+ readonly LIST_FOLDERS: "list_folders";
21
+ };
22
+ /** Type representing valid folder tool names */
23
+ export type FolderToolName = (typeof FOLDER_TOOL_NAMES)[keyof typeof FOLDER_TOOL_NAMES];
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/folders/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,yBAAyB;AACzB,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,4BAA4B;AAC5B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,8BAA8B;AAC9B,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sCAAsC;AACtC,eAAO,MAAM,iBAAiB;;CAEpB,CAAC;AAEX,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Folder domain types
3
+ */
4
+ /** Tool name constants for folders */
5
+ export const FOLDER_TOOL_NAMES = {
6
+ LIST_FOLDERS: "list_folders",
7
+ };
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/folders/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH,sCAAsC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE,cAAc;CACpB,CAAC"}
package/dist/index.js CHANGED
@@ -13,7 +13,8 @@ import { createRequire } from "node:module";
13
13
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
14
14
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
15
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
16
- import { handleToolCall, TOOLS } from "./mcp/index.js";
16
+ import { FolderClient } from "./folders/index.js";
17
+ import { TOOLS, handleToolCall } from "./mcp/index.js";
17
18
  import { NoteClient } from "./notes/index.js";
18
19
  import { PageClient } from "./pages/index.js";
19
20
  import { HttpClient, loadConfig } from "./shared/index.js";
@@ -29,6 +30,7 @@ const packageJson = require("../package.json");
29
30
  const config = loadConfig();
30
31
  const httpClient = new HttpClient(config);
31
32
  const clients = {
33
+ folders: new FolderClient(httpClient),
32
34
  notes: new NoteClient(httpClient),
33
35
  pages: new PageClient(httpClient),
34
36
  tags: new TagClient(httpClient),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAEnG,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF,+DAA+D;AAC/D,4CAA4C;AAC5C,+DAA+D;AAE/D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAC1C,MAAM,OAAO,GAAG;IACd,KAAK,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC;IACjC,KAAK,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC;IACjC,IAAI,EAAE,IAAI,SAAS,CAAC,UAAU,CAAC;CAChC,CAAC;AAEF,+DAA+D;AAC/D,yBAAyB;AACzB,+DAA+D;AAE/D,uDAAuD;AACvD,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CAC7B,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;KACV;CACF,CACF,CAAC;AAEF,+DAA+D;AAC/D,0BAA0B;AAC1B,+DAA+D;AAE/D;;GAEG;AACH,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IACjD,OAAO,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,eAAe;AACf,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,8BAA8B,MAAM,CAAC,UAAU,aAAa,CAAC,CAAC;AAC9E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAEnG,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF,+DAA+D;AAC/D,4CAA4C;AAC5C,+DAA+D;AAE/D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAC1C,MAAM,OAAO,GAAG;IACd,OAAO,EAAE,IAAI,YAAY,CAAC,UAAU,CAAC;IACrC,KAAK,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC;IACjC,KAAK,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC;IACjC,IAAI,EAAE,IAAI,SAAS,CAAC,UAAU,CAAC;CAChC,CAAC;AAEF,+DAA+D;AAC/D,yBAAyB;AACzB,+DAA+D;AAE/D,uDAAuD;AACvD,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CAC7B,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;KACV;CACF,CACF,CAAC;AAEF,+DAA+D;AAC/D,0BAA0B;AAC1B,+DAA+D;AAE/D;;GAEG;AACH,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IACjD,OAAO,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,eAAe;AACf,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,8BAA8B,MAAM,CAAC,UAAU,aAAa,CAAC,CAAC;AAC9E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { createMockFolder, createMockFoldersResponse, createMockNote, createMockNotesResponse, createMockPage, createMockPagesResponse, createMockTag, createMockTagsResponse, } from "../../shared/__tests__/fixtures.js";
2
3
  import { NotePMAPIError } from "../../shared/errors.js";
3
- import { createMockNote, createMockNotesResponse, createMockPage, createMockPagesResponse, createMockTag, createMockTagsResponse, } from "../../shared/__tests__/fixtures.js";
4
4
  import { handleToolCall } from "../index.js";
5
5
  // ============================================================
6
6
  // Helper Functions
@@ -18,37 +18,35 @@ function getTextContent(result) {
18
18
  // ============================================================
19
19
  // Mock Setup
20
20
  // ============================================================
21
+ const createMockFolderClient = () => ({
22
+ list: vi.fn(),
23
+ });
21
24
  const createMockNoteClient = () => ({
22
25
  list: vi.fn(),
23
- get: vi.fn(),
24
- create: vi.fn(),
25
- update: vi.fn(),
26
- delete: vi.fn(),
27
- archive: vi.fn(),
28
- unarchive: vi.fn(),
29
26
  });
30
27
  const createMockPageClient = () => ({
31
28
  search: vi.fn(),
32
29
  get: vi.fn(),
33
30
  create: vi.fn(),
34
31
  update: vi.fn(),
35
- delete: vi.fn(),
36
32
  });
37
33
  const createMockTagClient = () => ({
38
34
  list: vi.fn(),
39
35
  create: vi.fn(),
40
- delete: vi.fn(),
41
36
  });
42
37
  describe("handleToolCall", () => {
38
+ let mockFolderClient;
43
39
  let mockNoteClient;
44
40
  let mockPageClient;
45
41
  let mockTagClient;
46
42
  let clients;
47
43
  beforeEach(() => {
44
+ mockFolderClient = createMockFolderClient();
48
45
  mockNoteClient = createMockNoteClient();
49
46
  mockPageClient = createMockPageClient();
50
47
  mockTagClient = createMockTagClient();
51
48
  clients = {
49
+ folders: mockFolderClient,
52
50
  notes: mockNoteClient,
53
51
  pages: mockPageClient,
54
52
  tags: mockTagClient,
@@ -157,14 +155,6 @@ describe("handleToolCall", () => {
157
155
  expect(getTextContent(result)).toContain("## Updated Page");
158
156
  });
159
157
  });
160
- describe("delete_page", () => {
161
- it("should return success message", async () => {
162
- mockPageClient.delete.mockResolvedValue(undefined);
163
- const result = await handleToolCall(clients, "delete_page", { page_code: "page123" });
164
- expect(result.isError).toBeUndefined();
165
- expect(getTextContent(result)).toBe("Page deleted: page123");
166
- });
167
- });
168
158
  // ============================================================
169
159
  // Note Tools Tests
170
160
  // ============================================================
@@ -208,104 +198,6 @@ describe("handleToolCall", () => {
208
198
  expect(getTextContent(result)).toContain("(No description)");
209
199
  });
210
200
  });
211
- describe("get_note", () => {
212
- it("should format note with all fields", async () => {
213
- const note = createMockNote();
214
- mockNoteClient.get.mockResolvedValue(note);
215
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
216
- expect(result.isError).toBeUndefined();
217
- expect(getTextContent(result)).toContain("## Test Note");
218
- expect(getTextContent(result)).toContain("Note code: note123");
219
- expect(getTextContent(result)).toContain("Scope: All members");
220
- expect(getTextContent(result)).toContain("Archived: No");
221
- });
222
- it("should handle scope as number 0 (open)", async () => {
223
- const note = createMockNote({ scope: 0 });
224
- mockNoteClient.get.mockResolvedValue(note);
225
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
226
- expect(result.isError).toBeUndefined();
227
- expect(getTextContent(result)).toContain("Scope: All members");
228
- });
229
- it("should handle private scope", async () => {
230
- const note = createMockNote({ scope: "private" });
231
- mockNoteClient.get.mockResolvedValue(note);
232
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
233
- expect(result.isError).toBeUndefined();
234
- expect(getTextContent(result)).toContain("Scope: Participating members only");
235
- });
236
- it("should handle archived note", async () => {
237
- const note = createMockNote({ archived: true });
238
- mockNoteClient.get.mockResolvedValue(note);
239
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
240
- expect(result.isError).toBeUndefined();
241
- expect(getTextContent(result)).toContain("Archived: Yes");
242
- });
243
- it("should handle note with no description", async () => {
244
- const note = createMockNote({ description: "" });
245
- mockNoteClient.get.mockResolvedValue(note);
246
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
247
- expect(result.isError).toBeUndefined();
248
- expect(getTextContent(result)).toContain("(No description)");
249
- });
250
- it("should handle note with missing dates", async () => {
251
- const note = createMockNote({ created_at: undefined, updated_at: undefined });
252
- mockNoteClient.get.mockResolvedValue(note);
253
- const result = await handleToolCall(clients, "get_note", { note_code: "note123" });
254
- expect(result.isError).toBeUndefined();
255
- expect(getTextContent(result)).toContain("Created at: N/A");
256
- expect(getTextContent(result)).toContain("Updated at: N/A");
257
- });
258
- });
259
- describe("create_note", () => {
260
- it("should return success message with note details", async () => {
261
- const note = createMockNote({ note_code: "new123", name: "New Note" });
262
- mockNoteClient.create.mockResolvedValue(note);
263
- const result = await handleToolCall(clients, "create_note", {
264
- name: "New Note",
265
- scope: "open",
266
- });
267
- expect(result.isError).toBeUndefined();
268
- expect(getTextContent(result)).toContain("Note created.");
269
- expect(getTextContent(result)).toContain("## New Note");
270
- });
271
- });
272
- describe("update_note", () => {
273
- it("should return success message with updated note details", async () => {
274
- const note = createMockNote({ note_code: "note123", name: "Updated Note" });
275
- mockNoteClient.update.mockResolvedValue(note);
276
- const result = await handleToolCall(clients, "update_note", {
277
- note_code: "note123",
278
- name: "Updated Note",
279
- });
280
- expect(result.isError).toBeUndefined();
281
- expect(getTextContent(result)).toContain("Note updated.");
282
- expect(getTextContent(result)).toContain("## Updated Note");
283
- });
284
- });
285
- describe("delete_note", () => {
286
- it("should return success message", async () => {
287
- mockNoteClient.delete.mockResolvedValue(undefined);
288
- const result = await handleToolCall(clients, "delete_note", { note_code: "note123" });
289
- expect(result.isError).toBeUndefined();
290
- expect(getTextContent(result)).toBe("Note deleted: note123");
291
- });
292
- });
293
- describe("archive_note", () => {
294
- it("should return success message", async () => {
295
- mockNoteClient.archive.mockResolvedValue(undefined);
296
- const result = await handleToolCall(clients, "archive_note", { note_code: "note123" });
297
- expect(result.isError).toBeUndefined();
298
- expect(getTextContent(result)).toBe("Note archived: note123");
299
- });
300
- });
301
- describe("unarchive_note", () => {
302
- it("should return success message", async () => {
303
- mockNoteClient.unarchive.mockResolvedValue(undefined);
304
- const result = await handleToolCall(clients, "unarchive_note", { note_code: "note123" });
305
- expect(result.isError).toBeUndefined();
306
- expect(getTextContent(result)).toBe("Note unarchived: note123");
307
- });
308
- });
309
201
  // ============================================================
310
202
  // Tag Tools Tests
311
203
  // ============================================================
@@ -333,12 +225,32 @@ describe("handleToolCall", () => {
333
225
  expect(getTextContent(result)).toBe("Tag created: new-tag");
334
226
  });
335
227
  });
336
- describe("delete_tag", () => {
337
- it("should return success message", async () => {
338
- mockTagClient.delete.mockResolvedValue(undefined);
339
- const result = await handleToolCall(clients, "delete_tag", { name: "tag-to-delete" });
228
+ // ============================================================
229
+ // Folder Tools Tests
230
+ // ============================================================
231
+ describe("list_folders", () => {
232
+ it("should return 'No folders found.' for empty results", async () => {
233
+ mockFolderClient.list.mockResolvedValue(createMockFoldersResponse([]));
234
+ const result = await handleToolCall(clients, "list_folders", { note_code: "note123" });
340
235
  expect(result.isError).toBeUndefined();
341
- expect(getTextContent(result)).toBe("Tag deleted: tag-to-delete");
236
+ expect(getTextContent(result)).toBe("No folders found in this note.");
237
+ });
238
+ it("should format folder list with hierarchy", async () => {
239
+ const folders = [
240
+ createMockFolder({ folder_id: 1, name: "Parent Folder", parent_folder_id: null }),
241
+ createMockFolder({ folder_id: 2, name: "Child Folder", parent_folder_id: 1 }),
242
+ ];
243
+ mockFolderClient.list.mockResolvedValue(createMockFoldersResponse(folders));
244
+ const result = await handleToolCall(clients, "list_folders", { note_code: "note123" });
245
+ expect(result.isError).toBeUndefined();
246
+ expect(getTextContent(result)).toContain('Folders in note "note123"');
247
+ expect(getTextContent(result)).toContain("**Parent Folder**");
248
+ expect(getTextContent(result)).toContain("**Child Folder**");
249
+ });
250
+ it("should require note_code parameter", async () => {
251
+ const result = await handleToolCall(clients, "list_folders", {});
252
+ expect(result.isError).toBe(true);
253
+ expect(getTextContent(result)).toContain("Input error:");
342
254
  });
343
255
  });
344
256
  });