@noteplanco/noteplan-mcp 1.1.7 → 1.1.8

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 (60) hide show
  1. package/dist/noteplan/embeddings.d.ts +8 -0
  2. package/dist/noteplan/embeddings.d.ts.map +1 -1
  3. package/dist/noteplan/embeddings.js +3 -3
  4. package/dist/noteplan/embeddings.js.map +1 -1
  5. package/dist/noteplan/file-reader.d.ts +6 -0
  6. package/dist/noteplan/file-reader.d.ts.map +1 -1
  7. package/dist/noteplan/file-reader.js +15 -0
  8. package/dist/noteplan/file-reader.js.map +1 -1
  9. package/dist/noteplan/file-writer.d.ts.map +1 -1
  10. package/dist/noteplan/file-writer.js +13 -1
  11. package/dist/noteplan/file-writer.js.map +1 -1
  12. package/dist/noteplan/file-writer.test.js +4 -0
  13. package/dist/noteplan/file-writer.test.js.map +1 -1
  14. package/dist/noteplan/frontmatter-parser.d.ts +2 -2
  15. package/dist/noteplan/frontmatter-parser.d.ts.map +1 -1
  16. package/dist/noteplan/frontmatter-parser.js +9 -12
  17. package/dist/noteplan/frontmatter-parser.js.map +1 -1
  18. package/dist/noteplan/frontmatter-parser.test.js +92 -0
  19. package/dist/noteplan/frontmatter-parser.test.js.map +1 -1
  20. package/dist/noteplan/markdown-parser.d.ts.map +1 -1
  21. package/dist/noteplan/markdown-parser.js +4 -2
  22. package/dist/noteplan/markdown-parser.js.map +1 -1
  23. package/dist/noteplan/markdown-parser.test.js +37 -0
  24. package/dist/noteplan/markdown-parser.test.js.map +1 -1
  25. package/dist/noteplan/template-docs.d.ts +35 -0
  26. package/dist/noteplan/template-docs.d.ts.map +1 -0
  27. package/dist/noteplan/template-docs.js +184 -0
  28. package/dist/noteplan/template-docs.js.map +1 -0
  29. package/dist/noteplan/unified-store.d.ts +2 -0
  30. package/dist/noteplan/unified-store.d.ts.map +1 -1
  31. package/dist/noteplan/unified-store.js +22 -6
  32. package/dist/noteplan/unified-store.js.map +1 -1
  33. package/dist/server.d.ts.map +1 -1
  34. package/dist/server.js +275 -55
  35. package/dist/server.js.map +1 -1
  36. package/dist/tools/calendar.d.ts +2 -2
  37. package/dist/tools/notes.d.ts +81 -22
  38. package/dist/tools/notes.d.ts.map +1 -1
  39. package/dist/tools/notes.js +267 -21
  40. package/dist/tools/notes.js.map +1 -1
  41. package/dist/tools/notes.test.js +202 -0
  42. package/dist/tools/notes.test.js.map +1 -1
  43. package/dist/tools/plugins.d.ts.map +1 -1
  44. package/dist/tools/plugins.js +1 -0
  45. package/dist/tools/plugins.js.map +1 -1
  46. package/dist/tools/search.d.ts +2 -2
  47. package/dist/tools/search.d.ts.map +1 -1
  48. package/dist/tools/search.js +32 -4
  49. package/dist/tools/search.js.map +1 -1
  50. package/dist/tools/templates.d.ts +64 -3
  51. package/dist/tools/templates.d.ts.map +1 -1
  52. package/dist/tools/templates.js +73 -1
  53. package/dist/tools/templates.js.map +1 -1
  54. package/dist/utils/version.d.ts +1 -0
  55. package/dist/utils/version.d.ts.map +1 -1
  56. package/dist/utils/version.js +67 -23
  57. package/dist/utils/version.js.map +1 -1
  58. package/docs/templates.db.gz +0 -0
  59. package/docs/x-callback-url.md +318 -0
  60. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -27,6 +27,10 @@ import { initSqlite } from './noteplan/sqlite-loader.js';
27
27
  const __filename = fileURLToPath(import.meta.url);
28
28
  const __dirname = path.dirname(__filename);
29
29
  const PLUGIN_API_DOCS_DIR = path.join(__dirname, '../docs/plugin-api');
30
+ const DOCS_DIR = path.join(__dirname, '../docs');
31
+ const GENERAL_DOC_RESOURCES = [
32
+ { file: 'x-callback-url.md', name: 'x-callback-url Reference', desc: 'NotePlan URL scheme — all actions (openNote, addText, addNote, addQuickTask, search, runPlugin, etc.), parameters, and encoding examples' },
33
+ ];
30
34
  const PLUGIN_API_RESOURCES = [
31
35
  { file: 'plugin-api-condensed.md', name: 'Plugin API Reference (Condensed)', desc: 'Complete NotePlan plugin API — all signatures, types, and patterns in one reference. Read this first.' },
32
36
  { file: 'getting-started.md', name: 'Getting Started Guide', desc: 'How to create NotePlan plugins — structure, setup, first plugin, testing, HTML views' },
@@ -818,12 +822,59 @@ function withDuration(result, durationMs, includeTiming) {
818
822
  export function createServer() {
819
823
  const server = new Server({
820
824
  name: 'NotePlan',
821
- version: '1.1.4',
825
+ version: '1.1.7',
822
826
  }, {
823
827
  capabilities: {
824
828
  tools: {},
825
829
  resources: {},
826
830
  },
831
+ instructions: [
832
+ 'You have access to NotePlan — a markdown-based note-taking and task management app for macOS/iOS.',
833
+ 'All tools use action-based dispatch: one tool per domain, with an `action` parameter to select the operation.',
834
+ '',
835
+ '## Workflow',
836
+ '',
837
+ 'Prefer granular edits over full-note rewrites to avoid large context payloads and accidental data loss.',
838
+ '',
839
+ '1. **Find** the note: `noteplan_get_notes` (by id/title/filename/date) or `noteplan_search`',
840
+ '2. **Inspect** content: `noteplan_paragraphs(action: get)` for line metadata, `noteplan_paragraphs(action: search)` for text lookup',
841
+ '3. **Edit** with targeted mutations:',
842
+ ' - `noteplan_edit_content(action: edit_line)` — single-line change',
843
+ ' - `noteplan_edit_content(action: insert/append)` — add content at a position or heading',
844
+ ' - `noteplan_edit_content(action: delete_lines)` — remove lines',
845
+ '4. Only use `noteplan_manage_note(action: update)` for intentional full-note rewrites',
846
+ '',
847
+ '## Tasks',
848
+ '',
849
+ '- Add tasks via `noteplan_paragraphs(action: add)` — the server auto-formats the task marker to match the user\'s NotePlan settings. Never write raw markers like `- [ ]` or `* [ ]`; just pass the task text.',
850
+ '- Find tasks: `noteplan_paragraphs(action: search)` in one note, or `search_global` across all notes',
851
+ '- Complete/update: `noteplan_paragraphs(action: complete/update)`',
852
+ '- Use `heading` parameter to target a specific section (e.g., heading: "Tasks")',
853
+ '',
854
+ '## Destructive Operations',
855
+ '',
856
+ 'Delete, move, rename, and restore use a 2-step safety flow:',
857
+ '1. Call with `dryRun=true` → get a preview and `confirmationToken`',
858
+ '2. Call again with that `confirmationToken` to execute',
859
+ '',
860
+ '## Key Behaviors',
861
+ '',
862
+ '- Calendar notes (daily/weekly/etc.) are auto-created when targeted by date — no need to create them first',
863
+ '- Notes can be targeted by `id`, `filename`, `title`, `date`, or `query` — prefer `id` or `filename` when available for precision',
864
+ '- Errors include a `hint` and often a `suggestedTool` to guide recovery',
865
+ '- The `noteplan_memory` tool stores user preferences (formatting, style, workflow) persistently across sessions',
866
+ '',
867
+ '## Templates',
868
+ '',
869
+ '- IMPORTANT: Before writing or editing templates, ALWAYS search the built-in documentation first: `noteplan_templates(action: "search_docs", query: "your topic")`',
870
+ '- Use `get_doc` to read the full text of a doc chunk returned by `search_docs`',
871
+ '- Then use `render` to test/debug your template code',
872
+ '',
873
+ '## Action Discovery',
874
+ '',
875
+ '- Every tool supports `action: "list_actions"` — call it to get a list of all available actions with descriptions',
876
+ '- Use `list_actions` when you are unsure what a tool can do or need to discover capabilities',
877
+ ].join('\n'),
827
878
  });
828
879
  let embeddingsToolsEnabled = false;
829
880
  try {
@@ -1003,8 +1054,8 @@ export function createServer() {
1003
1054
  properties: {
1004
1055
  action: {
1005
1056
  type: 'string',
1006
- enum: ['create', 'update', 'delete', 'move', 'restore', 'rename', 'set_property', 'remove_property'],
1007
- description: 'Action: create | update | delete | move | restore | rename | set_property | remove_property',
1057
+ enum: ['create', 'update', 'delete', 'move', 'restore', 'rename', 'set_property', 'remove_property', 'list_actions'],
1058
+ description: 'Action: create | update | delete | move | restore | rename | set_property | remove_property | list_actions (discover all actions)',
1008
1059
  },
1009
1060
  id: {
1010
1061
  type: 'string',
@@ -1100,8 +1151,8 @@ export function createServer() {
1100
1151
  properties: {
1101
1152
  action: {
1102
1153
  type: 'string',
1103
- enum: ['insert', 'append', 'delete_lines', 'edit_line', 'replace_lines'],
1104
- description: 'Action: insert | append | delete_lines | edit_line | replace_lines',
1154
+ enum: ['insert', 'append', 'delete_lines', 'edit_line', 'replace_lines', 'list_actions'],
1155
+ description: 'Action: insert | append | delete_lines | edit_line | replace_lines | list_actions (discover all actions)',
1105
1156
  },
1106
1157
  id: {
1107
1158
  type: 'string',
@@ -1207,8 +1258,8 @@ export function createServer() {
1207
1258
  properties: {
1208
1259
  action: {
1209
1260
  type: 'string',
1210
- enum: ['get', 'search', 'search_global', 'add', 'complete', 'update'],
1211
- description: 'Action: get | search | search_global | add | complete | update',
1261
+ enum: ['get', 'search', 'search_global', 'add', 'complete', 'update', 'list_actions'],
1262
+ description: 'Action: get | search | search_global | add | complete | update | list_actions (discover all actions)',
1212
1263
  },
1213
1264
  id: {
1214
1265
  type: 'string',
@@ -1354,8 +1405,8 @@ export function createServer() {
1354
1405
  properties: {
1355
1406
  action: {
1356
1407
  type: 'string',
1357
- enum: ['list', 'find', 'resolve', 'create', 'move', 'rename', 'delete', 'list_spaces'],
1358
- description: 'Action: list | find | resolve | create | move | rename | delete | list_spaces',
1408
+ enum: ['list', 'find', 'resolve', 'create', 'move', 'rename', 'delete', 'list_spaces', 'list_actions'],
1409
+ description: 'Action: list | find | resolve | create | move | rename | delete | list_spaces | list_actions (discover all actions)',
1359
1410
  },
1360
1411
  path: {
1361
1412
  type: 'string',
@@ -1457,8 +1508,8 @@ export function createServer() {
1457
1508
  properties: {
1458
1509
  action: {
1459
1510
  type: 'string',
1460
- enum: ['list', 'get', 'get_tasks', 'list_parameters', 'save', 'rename'],
1461
- description: 'Action: list | get | get_tasks | list_parameters | save | rename',
1511
+ enum: ['list', 'get', 'get_tasks', 'list_parameters', 'save', 'rename', 'list_actions'],
1512
+ description: 'Action: list | get | get_tasks | list_parameters | save | rename | list_actions (discover all actions)',
1462
1513
  },
1463
1514
  name: {
1464
1515
  type: 'string',
@@ -1542,8 +1593,8 @@ export function createServer() {
1542
1593
  },
1543
1594
  action: {
1544
1595
  type: 'string',
1545
- enum: ['get_events', 'list_calendars', 'create_event', 'update_event', 'delete_event', 'get', 'list_lists', 'create', 'complete', 'update', 'delete'],
1546
- description: 'Action: get_events | list_calendars | create_event | update_event | delete_event | get | list_lists | create | complete | update | delete',
1596
+ enum: ['get_events', 'list_calendars', 'create_event', 'update_event', 'delete_event', 'get', 'list_lists', 'create', 'complete', 'update', 'delete', 'list_actions'],
1597
+ description: 'Action: get_events | list_calendars | create_event | update_event | delete_event | get | list_lists | create | complete | update | delete | list_actions (discover all actions)',
1547
1598
  },
1548
1599
  // Calendar params
1549
1600
  eventId: {
@@ -1644,8 +1695,8 @@ export function createServer() {
1644
1695
  properties: {
1645
1696
  action: {
1646
1697
  type: 'string',
1647
- enum: ['list', 'save', 'update', 'delete'],
1648
- description: 'Action: list | save | update | delete',
1698
+ enum: ['list', 'save', 'update', 'delete', 'list_actions'],
1699
+ description: 'Action: list | save | update | delete | list_actions (discover all actions)',
1649
1700
  },
1650
1701
  id: {
1651
1702
  type: 'string',
@@ -1691,8 +1742,8 @@ export function createServer() {
1691
1742
  properties: {
1692
1743
  action: {
1693
1744
  type: 'string',
1694
- enum: ['search', 'list_tags'],
1695
- description: 'Action to perform (default: search)',
1745
+ enum: ['search', 'list_tags', 'list_actions'],
1746
+ description: 'Action to perform (default: search) | list_actions (discover all actions)',
1696
1747
  },
1697
1748
  query: {
1698
1749
  type: 'string',
@@ -1780,8 +1831,8 @@ export function createServer() {
1780
1831
  properties: {
1781
1832
  action: {
1782
1833
  type: 'string',
1783
- enum: ['status', 'search', 'sync', 'reset'],
1784
- description: 'Action: status | search | sync | reset',
1834
+ enum: ['status', 'search', 'sync', 'reset', 'list_actions'],
1835
+ description: 'Action: status | search | sync | reset | list_actions (discover all actions)',
1785
1836
  },
1786
1837
  query: {
1787
1838
  type: 'string',
@@ -1867,8 +1918,8 @@ export function createServer() {
1867
1918
  properties: {
1868
1919
  action: {
1869
1920
  type: 'string',
1870
- enum: ['open_note', 'open_today', 'search', 'run_plugin', 'open_view', 'toggle_sidebar', 'close_plugin_window', 'list_plugin_windows', 'backup'],
1871
- description: 'Action: open_note | open_today | search | run_plugin | open_view | toggle_sidebar | close_plugin_window | list_plugin_windows | backup',
1921
+ enum: ['open_note', 'open_today', 'search', 'run_plugin', 'open_view', 'toggle_sidebar', 'close_plugin_window', 'list_plugin_windows', 'backup', 'list_actions'],
1922
+ description: 'Action: open_note | open_today | search | run_plugin | open_view | toggle_sidebar | close_plugin_window | list_plugin_windows | backup | list_actions (discover all actions)',
1872
1923
  },
1873
1924
  title: {
1874
1925
  type: 'string',
@@ -1924,8 +1975,8 @@ export function createServer() {
1924
1975
  properties: {
1925
1976
  action: {
1926
1977
  type: 'string',
1927
- enum: ['list', 'list_available', 'create', 'delete', 'install', 'log', 'source', 'update_html', 'screenshot'],
1928
- description: 'Action: list | list_available | create | delete | install | log | source | update_html | screenshot',
1978
+ enum: ['list', 'list_available', 'create', 'delete', 'install', 'log', 'source', 'update_html', 'screenshot', 'list_actions'],
1979
+ description: 'Action: list | list_available | create | delete | install | log | source | update_html | screenshot | list_actions (discover all actions)',
1929
1980
  },
1930
1981
  pluginId: {
1931
1982
  type: 'string',
@@ -2015,8 +2066,8 @@ export function createServer() {
2015
2066
  properties: {
2016
2067
  action: {
2017
2068
  type: 'string',
2018
- enum: ['list', 'get', 'save', 'set_active'],
2019
- description: 'Action: list | get | save | set_active',
2069
+ enum: ['list', 'get', 'save', 'set_active', 'list_actions'],
2070
+ description: 'Action: list | get | save | set_active | list_actions (discover all actions)',
2020
2071
  },
2021
2072
  filename: {
2022
2073
  type: 'string',
@@ -2051,14 +2102,14 @@ export function createServer() {
2051
2102
  },
2052
2103
  }, {
2053
2104
  name: 'noteplan_templates',
2054
- description: 'Template operations: list available templates or render a template.\n\nActions:\n- list: List templates from @Templates folder with their types and preview\n- render: Render a template by title (saved template) or raw content string (for debugging). Rendering requires a recent NotePlan build.\n\nDebugging workflow: After creating or editing a template, use render with its title or raw content to verify the output. Check variables, date formatting, and logic. If rendering fails or produces unexpected output, read the plugin log via noteplan_plugins(action: "log", pluginId: "np.Templating") for error details.\n\nTemplate syntax: <%- expr %> (output), <% code %> (logic), <%= expr %> (escaped output). Common helpers: date.now("YYYY-MM-DD"), web.weather(), date.tomorrow("format").',
2105
+ description: 'Template operations: list available templates, render a template, or search template documentation.\n\nActions:\n- list: List templates from @Templates folder with their types and preview\n- render: Render a template by title (saved template) or raw content string (for debugging). Rendering requires a recent NotePlan build.\n- search_docs: Semantic search over bundled NotePlan template documentation. Requires query param. Uses embeddings API or NotePlan built-in embedding. Returns matched doc chunks ranked by relevance — use this to look up template syntax, helpers, and examples before writing templates.\n- get_doc: Retrieve the full text of a doc chunk by noteTitle and chunkIndex (from search_docs results). Use this to read complete method signatures, format tokens, and examples that may be truncated in search_docs previews.\n\nDebugging workflow: After creating or editing a template, use render with its title or raw content to verify the output. Check variables, date formatting, and logic. If rendering fails or produces unexpected output, read the plugin log via noteplan_plugins(action: "log", pluginId: "np.Templating") for error details.\n\nTemplate syntax: <%- expr %> (output), <% code %> (logic), <%= expr %> (escaped output). Common helpers: date.now("YYYY-MM-DD"), web.weather(), date.tomorrow("format").',
2055
2106
  inputSchema: {
2056
2107
  type: 'object',
2057
2108
  properties: {
2058
2109
  action: {
2059
2110
  type: 'string',
2060
- enum: ['list', 'render'],
2061
- description: 'Action: list | render',
2111
+ enum: ['list', 'render', 'search_docs', 'get_doc', 'list_actions'],
2112
+ description: 'Action: list | render | search_docs | get_doc | list_actions (discover all actions)',
2062
2113
  },
2063
2114
  templateTitle: {
2064
2115
  type: 'string',
@@ -2084,6 +2135,22 @@ export function createServer() {
2084
2135
  type: 'string',
2085
2136
  description: 'Cursor from previous page — used by list',
2086
2137
  },
2138
+ query: {
2139
+ type: 'string',
2140
+ description: 'Search query — used by search_docs',
2141
+ },
2142
+ includeContent: {
2143
+ type: 'boolean',
2144
+ description: 'Include full chunk text in results — used by search_docs',
2145
+ },
2146
+ noteTitle: {
2147
+ type: 'string',
2148
+ description: 'Doc note title — used by get_doc (from search_docs results)',
2149
+ },
2150
+ chunkIndex: {
2151
+ type: 'number',
2152
+ description: 'Chunk index — used by get_doc (from search_docs results, default 0)',
2153
+ },
2087
2154
  },
2088
2155
  required: ['action'],
2089
2156
  },
@@ -2095,8 +2162,8 @@ export function createServer() {
2095
2162
  properties: {
2096
2163
  action: {
2097
2164
  type: 'string',
2098
- enum: ['add', 'list', 'get', 'move'],
2099
- description: 'Action: add | list | get | move',
2165
+ enum: ['add', 'list', 'get', 'move', 'list_actions'],
2166
+ description: 'Action: add | list | get | move | list_actions (discover all actions)',
2100
2167
  },
2101
2168
  id: { type: 'string', description: 'Source note ID — used by all actions' },
2102
2169
  filename: { type: 'string', description: 'Source note filename/path — used by all actions' },
@@ -2134,42 +2201,178 @@ export function createServer() {
2134
2201
  });
2135
2202
  // Register resource listing handler
2136
2203
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
2137
- return {
2138
- resources: PLUGIN_API_RESOURCES.map((r) => ({
2139
- uri: `noteplan://plugin-api/${r.file}`,
2140
- name: r.name,
2141
- description: r.desc,
2142
- mimeType: r.file.endsWith('.md') ? 'text/markdown' : r.file.endsWith('.json') ? 'application/json' : 'text/javascript',
2143
- })),
2144
- };
2204
+ const pluginResources = PLUGIN_API_RESOURCES.map((r) => ({
2205
+ uri: `noteplan://plugin-api/${r.file}`,
2206
+ name: r.name,
2207
+ description: r.desc,
2208
+ mimeType: r.file.endsWith('.md') ? 'text/markdown' : r.file.endsWith('.json') ? 'application/json' : 'text/javascript',
2209
+ }));
2210
+ const generalResources = GENERAL_DOC_RESOURCES.map((r) => ({
2211
+ uri: `noteplan://docs/${r.file}`,
2212
+ name: r.name,
2213
+ description: r.desc,
2214
+ mimeType: 'text/markdown',
2215
+ }));
2216
+ return { resources: [...pluginResources, ...generalResources] };
2145
2217
  });
2146
2218
  // Register resource read handler
2147
2219
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
2148
2220
  const uri = request.params.uri;
2149
- const prefix = 'noteplan://plugin-api/';
2150
- if (!uri.startsWith(prefix)) {
2151
- throw new Error(`Unknown resource URI: ${uri}`);
2221
+ const pluginPrefix = 'noteplan://plugin-api/';
2222
+ const docsPrefix = 'noteplan://docs/';
2223
+ let filePath;
2224
+ if (uri.startsWith(pluginPrefix)) {
2225
+ const filename = uri.slice(pluginPrefix.length);
2226
+ const entry = PLUGIN_API_RESOURCES.find((r) => r.file === filename);
2227
+ if (!entry) {
2228
+ throw new Error(`Unknown resource: ${filename}. Available: ${PLUGIN_API_RESOURCES.map((r) => r.file).join(', ')}`);
2229
+ }
2230
+ filePath = path.join(PLUGIN_API_DOCS_DIR, entry.file);
2231
+ }
2232
+ else if (uri.startsWith(docsPrefix)) {
2233
+ const filename = uri.slice(docsPrefix.length);
2234
+ const entry = GENERAL_DOC_RESOURCES.find((r) => r.file === filename);
2235
+ if (!entry) {
2236
+ throw new Error(`Unknown resource: ${filename}. Available: ${GENERAL_DOC_RESOURCES.map((r) => r.file).join(', ')}`);
2237
+ }
2238
+ filePath = path.join(DOCS_DIR, entry.file);
2152
2239
  }
2153
- const filename = uri.slice(prefix.length);
2154
- const entry = PLUGIN_API_RESOURCES.find((r) => r.file === filename);
2155
- if (!entry) {
2156
- throw new Error(`Unknown resource: ${filename}. Available: ${PLUGIN_API_RESOURCES.map((r) => r.file).join(', ')}`);
2240
+ else {
2241
+ throw new Error(`Unknown resource URI: ${uri}`);
2157
2242
  }
2158
- const filePath = path.join(PLUGIN_API_DOCS_DIR, entry.file);
2159
2243
  if (!fs.existsSync(filePath)) {
2160
2244
  throw new Error(`Resource file not found on disk: ${filePath}`);
2161
2245
  }
2162
2246
  const content = fs.readFileSync(filePath, 'utf-8');
2247
+ const mimeType = filePath.endsWith('.md') ? 'text/markdown' : filePath.endsWith('.json') ? 'application/json' : 'text/javascript';
2163
2248
  return {
2164
- contents: [
2165
- {
2166
- uri,
2167
- mimeType: entry.file.endsWith('.md') ? 'text/markdown' : entry.file.endsWith('.json') ? 'application/json' : 'text/javascript',
2168
- text: content,
2169
- },
2170
- ],
2249
+ contents: [{ uri, mimeType, text: content }],
2171
2250
  };
2172
2251
  });
2252
+ // ── Action registry for list_actions discovery ──
2253
+ const TOOL_ACTIONS = {
2254
+ noteplan_get_notes: [
2255
+ { action: 'get', description: 'Get a single note by id, filename, title, date, or query' },
2256
+ { action: 'list', description: 'List notes with optional folder/type/date filtering' },
2257
+ { action: 'resolve', description: 'Resolve a reference (title, filename, query) to a single note' },
2258
+ { action: 'today', description: 'Get today\'s daily note' },
2259
+ { action: 'calendar', description: 'Get a calendar note by date' },
2260
+ { action: 'periodic', description: 'Get a periodic note (week, month, quarter, year)' },
2261
+ { action: 'range', description: 'Get calendar notes in a date range' },
2262
+ ],
2263
+ noteplan_search: [
2264
+ { action: 'search', description: 'Full-text or metadata search across notes' },
2265
+ { action: 'list_tags', description: 'List all tags/hashtags with optional filtering' },
2266
+ ],
2267
+ noteplan_manage_note: [
2268
+ { action: 'create', description: 'Create a project note (requires title)' },
2269
+ { action: 'update', description: 'Replace note content (requires filename, content, fullReplace + confirmationToken)' },
2270
+ { action: 'delete', description: 'Delete a note (requires dryRun/confirmationToken)' },
2271
+ { action: 'move', description: 'Move a note to another folder (requires dryRun/confirmationToken)' },
2272
+ { action: 'restore', description: 'Restore a trashed note (requires dryRun/confirmationToken)' },
2273
+ { action: 'rename', description: 'Rename a note (requires newTitle)' },
2274
+ { action: 'set_property', description: 'Set a frontmatter property (requires key + value)' },
2275
+ { action: 'remove_property', description: 'Remove a frontmatter property (requires key)' },
2276
+ ],
2277
+ noteplan_edit_content: [
2278
+ { action: 'insert', description: 'Insert content at a position. Use heading param to scope to a section' },
2279
+ { action: 'append', description: 'Append content at end of note or section' },
2280
+ { action: 'delete_lines', description: 'Delete a line range (requires startLine + endLine, 1-indexed)' },
2281
+ { action: 'edit_line', description: 'Edit a single line (requires line + content)' },
2282
+ { action: 'replace_lines', description: 'Replace a line range (requires startLine + endLine + content)' },
2283
+ ],
2284
+ noteplan_paragraphs: [
2285
+ { action: 'get', description: 'Get note lines with metadata (requires filename)' },
2286
+ { action: 'search', description: 'Search for matching lines in a note (requires query + note ref)' },
2287
+ { action: 'search_global', description: 'Search tasks across all notes (requires query, supports "*" wildcard)' },
2288
+ { action: 'add', description: 'Add a task (requires target + content)' },
2289
+ { action: 'complete', description: 'Mark task done (requires filename + lineIndex or line)' },
2290
+ { action: 'update', description: 'Update task content/status (requires filename + lineIndex or line)' },
2291
+ ],
2292
+ noteplan_folders: [
2293
+ { action: 'list', description: 'List folders with optional filtering' },
2294
+ { action: 'find', description: 'Find folder matches for exploration' },
2295
+ { action: 'resolve', description: 'Resolve to one canonical folder path' },
2296
+ { action: 'create', description: 'Create a folder' },
2297
+ { action: 'move', description: 'Move a folder (requires dryRun/confirmationToken)' },
2298
+ { action: 'rename', description: 'Rename a folder (requires dryRun/confirmationToken)' },
2299
+ { action: 'delete', description: 'Delete folder to trash (requires dryRun/confirmationToken)' },
2300
+ { action: 'list_spaces', description: 'List spaces/workspaces' },
2301
+ ],
2302
+ noteplan_filters: [
2303
+ { action: 'list', description: 'List saved filters' },
2304
+ { action: 'get', description: 'Get one filter with parsed params (requires name)' },
2305
+ { action: 'get_tasks', description: 'Execute a filter against tasks (requires name)' },
2306
+ { action: 'list_parameters', description: 'List supported filter parameter keys' },
2307
+ { action: 'save', description: 'Create or update a filter (requires name + items)' },
2308
+ { action: 'rename', description: 'Rename a filter (requires oldName + newName)' },
2309
+ ],
2310
+ noteplan_eventkit: [
2311
+ { action: 'get_events', description: 'Get events for a date/range (source: calendar)' },
2312
+ { action: 'list_calendars', description: 'List all calendars (source: calendar)' },
2313
+ { action: 'create_event', description: 'Create event (source: calendar, requires title + startDate)' },
2314
+ { action: 'update_event', description: 'Update event (source: calendar, requires eventId)' },
2315
+ { action: 'delete_event', description: 'Delete event (source: calendar, requires eventId + dryRun/confirmationToken)' },
2316
+ { action: 'get', description: 'Get reminders (source: reminders, optional list/query filter)' },
2317
+ { action: 'list_lists', description: 'List reminder lists (source: reminders)' },
2318
+ { action: 'create', description: 'Create reminder (source: reminders, requires title)' },
2319
+ { action: 'complete', description: 'Mark reminder done (source: reminders, requires reminderId)' },
2320
+ { action: 'update', description: 'Update reminder (source: reminders, requires reminderId)' },
2321
+ { action: 'delete', description: 'Delete reminder (source: reminders, requires reminderId + dryRun/confirmationToken)' },
2322
+ ],
2323
+ noteplan_memory: [
2324
+ { action: 'list', description: 'List/search stored memories' },
2325
+ { action: 'save', description: 'Save a new memory (requires content)' },
2326
+ { action: 'update', description: 'Update memory content/tags (requires id)' },
2327
+ { action: 'delete', description: 'Delete a memory (requires id)' },
2328
+ ],
2329
+ noteplan_ui: [
2330
+ { action: 'open_note', description: 'Open a note by title or filename' },
2331
+ { action: 'open_today', description: 'Open today\'s note' },
2332
+ { action: 'search', description: 'Search in UI' },
2333
+ { action: 'run_plugin', description: 'Run a plugin command (requires pluginId + command)' },
2334
+ { action: 'open_view', description: 'Open a named view' },
2335
+ { action: 'toggle_sidebar', description: 'Toggle sidebar visibility' },
2336
+ { action: 'close_plugin_window', description: 'Close plugin window (by windowID/title, or omit both to close all)' },
2337
+ { action: 'list_plugin_windows', description: 'List open plugin windows' },
2338
+ { action: 'backup', description: 'Create a full backup of all notes, calendars, themes, filters, and plugin data' },
2339
+ ],
2340
+ noteplan_plugins: [
2341
+ { action: 'list', description: 'List installed plugins' },
2342
+ { action: 'list_available', description: 'List plugins from online repository' },
2343
+ { action: 'create', description: 'Create plugin with HTML view (requires pluginId, pluginName, commandName, html)' },
2344
+ { action: 'delete', description: 'Delete plugin (requires pluginId + confirmationToken)' },
2345
+ { action: 'install', description: 'Install from repository (requires pluginId)' },
2346
+ { action: 'log', description: 'Read plugin console log (requires pluginId)' },
2347
+ { action: 'source', description: 'Read plugin source (requires pluginId)' },
2348
+ { action: 'update_html', description: 'Apply find/replace patches (requires pluginId + patches)' },
2349
+ { action: 'screenshot', description: 'Capture plugin WebView screenshot (requires pluginId)' },
2350
+ ],
2351
+ noteplan_themes: [
2352
+ { action: 'list', description: 'List all themes and active theme names' },
2353
+ { action: 'get', description: 'Read a custom theme JSON (requires filename)' },
2354
+ { action: 'save', description: 'Create/update a custom theme (requires filename + theme)' },
2355
+ { action: 'set_active', description: 'Activate a theme (requires name)' },
2356
+ ],
2357
+ noteplan_embeddings: [
2358
+ { action: 'status', description: 'Get embeddings config and index status' },
2359
+ { action: 'search', description: 'Semantic search over indexed notes (requires query)' },
2360
+ { action: 'sync', description: 'Build/refresh embeddings index' },
2361
+ { action: 'reset', description: 'Delete index rows (requires dryRun/confirmationToken)' },
2362
+ ],
2363
+ noteplan_templates: [
2364
+ { action: 'list', description: 'List templates from @Templates folder with types and preview' },
2365
+ { action: 'render', description: 'Render a template by title or raw content string' },
2366
+ { action: 'search_docs', description: 'Semantic search over bundled template documentation (requires query). Use this to look up template syntax, helpers, and examples before writing templates' },
2367
+ { action: 'get_doc', description: 'Get full text of a doc chunk by noteTitle + chunkIndex (from search_docs results)' },
2368
+ ],
2369
+ noteplan_attachments: [
2370
+ { action: 'add', description: 'Write a file to the note\'s _attachments folder (requires data + attachmentFilename)' },
2371
+ { action: 'list', description: 'List all attachments for a note' },
2372
+ { action: 'get', description: 'Get attachment metadata. Set includeData=true for base64 content' },
2373
+ { action: 'move', description: 'Move an attachment between notes' },
2374
+ ],
2375
+ };
2173
2376
  // Register tool call handler
2174
2377
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
2175
2378
  const { name, arguments: args } = request.params;
@@ -2178,6 +2381,12 @@ export function createServer() {
2178
2381
  const startTime = Date.now();
2179
2382
  try {
2180
2383
  let result;
2384
+ // ── Intercept list_actions for any tool with an action registry ──
2385
+ if (args?.action === 'list_actions' && TOOL_ACTIONS[normalizedName]) {
2386
+ result = { success: true, tool: normalizedName, actions: TOOL_ACTIONS[normalizedName] };
2387
+ const resultWithDuration = withDuration(result, Date.now() - startTime, includeTiming);
2388
+ return { content: [{ type: 'text', text: JSON.stringify(resultWithDuration, null, 2) }] };
2389
+ }
2181
2390
  switch (normalizedName) {
2182
2391
  // ── Primary consolidated tools ──
2183
2392
  case 'noteplan_get_notes':
@@ -2283,7 +2492,7 @@ export function createServer() {
2283
2492
  result = noteTools.searchParagraphs(a);
2284
2493
  break;
2285
2494
  case 'search_global':
2286
- result = taskTools.searchTasksGlobal(a);
2495
+ result = noteTools.searchParagraphsGlobal(a);
2287
2496
  break;
2288
2497
  case 'add':
2289
2498
  result = taskTools.addTaskToNote(a);
@@ -2599,6 +2808,12 @@ export function createServer() {
2599
2808
  case 'render':
2600
2809
  result = templateTools.renderTemplate(args);
2601
2810
  break;
2811
+ case 'search_docs':
2812
+ result = await templateTools.searchDocs(args);
2813
+ break;
2814
+ case 'get_doc':
2815
+ result = templateTools.getDoc(args);
2816
+ break;
2602
2817
  default: throw new Error(`Unknown action: ${action}`);
2603
2818
  }
2604
2819
  break;
@@ -2662,7 +2877,12 @@ export function createServer() {
2662
2877
  };
2663
2878
  }
2664
2879
  catch (error) {
2665
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
2880
+ let errorMessage = error instanceof Error ? error.message : 'Unknown error';
2881
+ // Append list_actions hint for unknown action errors
2882
+ if (errorMessage.includes('Unknown action') && TOOL_ACTIONS[normalizedName]) {
2883
+ const validActions = TOOL_ACTIONS[normalizedName].map(a => a.action).join(', ');
2884
+ errorMessage += `. Valid actions: ${validActions}. Tip: use action "list_actions" to discover all actions with descriptions.`;
2885
+ }
2666
2886
  const meta = inferToolErrorMeta(normalizedName, errorMessage, registeredToolNames);
2667
2887
  const errorResult = {
2668
2888
  success: false,