remnote-mcp-server 0.5.0 → 0.6.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.
@@ -45,6 +45,19 @@ export declare const SEARCH_TOOL: {
45
45
  description: string;
46
46
  };
47
47
  includeContent: {
48
+ type: string;
49
+ enum: string[];
50
+ description: string;
51
+ };
52
+ depth: {
53
+ type: string;
54
+ description: string;
55
+ };
56
+ childLimit: {
57
+ type: string;
58
+ description: string;
59
+ };
60
+ maxContentLength: {
48
61
  type: string;
49
62
  description: string;
50
63
  };
@@ -68,8 +81,23 @@ export declare const SEARCH_TOOL: {
68
81
  type: string;
69
82
  description: string;
70
83
  };
71
- detail: {
84
+ headline: {
85
+ type: string;
86
+ description: string;
87
+ };
88
+ parentRemId: {
89
+ type: string;
90
+ description: string;
91
+ };
92
+ parentTitle: {
93
+ type: string;
94
+ description: string;
95
+ };
96
+ aliases: {
72
97
  type: string;
98
+ items: {
99
+ type: string;
100
+ };
73
101
  description: string;
74
102
  };
75
103
  remType: {
@@ -84,6 +112,218 @@ export declare const SEARCH_TOOL: {
84
112
  type: string;
85
113
  description: string;
86
114
  };
115
+ contentStructured: {
116
+ type: string;
117
+ description: string;
118
+ items: {
119
+ type: string;
120
+ properties: {
121
+ remId: {
122
+ type: string;
123
+ description: string;
124
+ };
125
+ title: {
126
+ type: string;
127
+ description: string;
128
+ };
129
+ headline: {
130
+ type: string;
131
+ description: string;
132
+ };
133
+ aliases: {
134
+ type: string;
135
+ items: {
136
+ type: string;
137
+ };
138
+ description: string;
139
+ };
140
+ remType: {
141
+ type: string;
142
+ description: string;
143
+ };
144
+ cardDirection: {
145
+ type: string;
146
+ description: string;
147
+ };
148
+ children: {
149
+ type: string;
150
+ description: string;
151
+ items: {
152
+ type: string;
153
+ };
154
+ };
155
+ };
156
+ required: string[];
157
+ };
158
+ };
159
+ contentProperties: {
160
+ type: string;
161
+ description: string;
162
+ properties: {
163
+ childrenRendered: {
164
+ type: string;
165
+ description: string;
166
+ };
167
+ childrenTotal: {
168
+ type: string;
169
+ description: string;
170
+ };
171
+ contentTruncated: {
172
+ type: string;
173
+ description: string;
174
+ };
175
+ };
176
+ };
177
+ };
178
+ };
179
+ };
180
+ };
181
+ };
182
+ };
183
+ export declare const SEARCH_BY_TAG_TOOL: {
184
+ name: string;
185
+ description: string;
186
+ inputSchema: {
187
+ type: "object";
188
+ properties: {
189
+ tag: {
190
+ type: string;
191
+ description: string;
192
+ };
193
+ limit: {
194
+ type: string;
195
+ description: string;
196
+ };
197
+ includeContent: {
198
+ type: string;
199
+ enum: string[];
200
+ description: string;
201
+ };
202
+ depth: {
203
+ type: string;
204
+ description: string;
205
+ };
206
+ childLimit: {
207
+ type: string;
208
+ description: string;
209
+ };
210
+ maxContentLength: {
211
+ type: string;
212
+ description: string;
213
+ };
214
+ };
215
+ required: string[];
216
+ };
217
+ outputSchema: {
218
+ type: "object";
219
+ properties: {
220
+ results: {
221
+ type: string;
222
+ description: string;
223
+ items: {
224
+ type: string;
225
+ properties: {
226
+ remId: {
227
+ type: string;
228
+ description: string;
229
+ };
230
+ title: {
231
+ type: string;
232
+ description: string;
233
+ };
234
+ headline: {
235
+ type: string;
236
+ description: string;
237
+ };
238
+ parentRemId: {
239
+ type: string;
240
+ description: string;
241
+ };
242
+ parentTitle: {
243
+ type: string;
244
+ description: string;
245
+ };
246
+ aliases: {
247
+ type: string;
248
+ items: {
249
+ type: string;
250
+ };
251
+ description: string;
252
+ };
253
+ remType: {
254
+ type: string;
255
+ description: string;
256
+ };
257
+ cardDirection: {
258
+ type: string;
259
+ description: string;
260
+ };
261
+ content: {
262
+ type: string;
263
+ description: string;
264
+ };
265
+ contentStructured: {
266
+ type: string;
267
+ description: string;
268
+ items: {
269
+ type: string;
270
+ properties: {
271
+ remId: {
272
+ type: string;
273
+ description: string;
274
+ };
275
+ title: {
276
+ type: string;
277
+ description: string;
278
+ };
279
+ headline: {
280
+ type: string;
281
+ description: string;
282
+ };
283
+ aliases: {
284
+ type: string;
285
+ items: {
286
+ type: string;
287
+ };
288
+ description: string;
289
+ };
290
+ remType: {
291
+ type: string;
292
+ description: string;
293
+ };
294
+ cardDirection: {
295
+ type: string;
296
+ description: string;
297
+ };
298
+ children: {
299
+ type: string;
300
+ description: string;
301
+ items: {
302
+ type: string;
303
+ };
304
+ };
305
+ };
306
+ required: string[];
307
+ };
308
+ };
309
+ contentProperties: {
310
+ type: string;
311
+ description: string;
312
+ properties: {
313
+ childrenRendered: {
314
+ type: string;
315
+ description: string;
316
+ };
317
+ childrenTotal: {
318
+ type: string;
319
+ description: string;
320
+ };
321
+ contentTruncated: {
322
+ type: string;
323
+ description: string;
324
+ };
325
+ };
326
+ };
87
327
  };
88
328
  };
89
329
  };
@@ -104,6 +344,19 @@ export declare const READ_NOTE_TOOL: {
104
344
  type: string;
105
345
  description: string;
106
346
  };
347
+ includeContent: {
348
+ type: string;
349
+ enum: string[];
350
+ description: string;
351
+ };
352
+ childLimit: {
353
+ type: string;
354
+ description: string;
355
+ };
356
+ maxContentLength: {
357
+ type: string;
358
+ description: string;
359
+ };
107
360
  };
108
361
  required: string[];
109
362
  };
@@ -118,10 +371,25 @@ export declare const READ_NOTE_TOOL: {
118
371
  type: string;
119
372
  description: string;
120
373
  };
121
- detail: {
374
+ headline: {
375
+ type: string;
376
+ description: string;
377
+ };
378
+ parentRemId: {
122
379
  type: string;
123
380
  description: string;
124
381
  };
382
+ parentTitle: {
383
+ type: string;
384
+ description: string;
385
+ };
386
+ aliases: {
387
+ type: string;
388
+ items: {
389
+ type: string;
390
+ };
391
+ description: string;
392
+ };
125
393
  remType: {
126
394
  type: string;
127
395
  description: string;
@@ -134,21 +402,21 @@ export declare const READ_NOTE_TOOL: {
134
402
  type: string;
135
403
  description: string;
136
404
  };
137
- children: {
405
+ contentProperties: {
138
406
  type: string;
139
407
  description: string;
140
- items: {
141
- type: string;
142
- properties: {
143
- remId: {
144
- type: string;
145
- };
146
- text: {
147
- type: string;
148
- };
149
- children: {
150
- type: string;
151
- };
408
+ properties: {
409
+ childrenRendered: {
410
+ type: string;
411
+ description: string;
412
+ };
413
+ childrenTotal: {
414
+ type: string;
415
+ description: string;
416
+ };
417
+ contentTruncated: {
418
+ type: string;
419
+ description: string;
152
420
  };
153
421
  };
154
422
  };
@@ -1,9 +1,11 @@
1
1
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { CreateNoteSchema } from '../schemas/remnote-schemas.js';
3
3
  import { SearchSchema } from '../schemas/remnote-schemas.js';
4
+ import { SearchByTagSchema } from '../schemas/remnote-schemas.js';
4
5
  import { ReadNoteSchema } from '../schemas/remnote-schemas.js';
5
6
  import { UpdateNoteSchema } from '../schemas/remnote-schemas.js';
6
7
  import { AppendJournalSchema } from '../schemas/remnote-schemas.js';
8
+ import { checkVersionCompatibility } from '../version-compat.js';
7
9
  export const CREATE_NOTE_TOOL = {
8
10
  name: 'remnote_create_note',
9
11
  description: 'Create a new note in RemNote with optional content, parent, and tags',
@@ -20,15 +22,28 @@ export const CREATE_NOTE_TOOL = {
20
22
  };
21
23
  export const SEARCH_TOOL = {
22
24
  name: 'remnote_search',
23
- description: 'Search the RemNote knowledge base. Results are sorted by type: documents first, then concepts, descriptors, portals, and plain text.',
25
+ description: 'Search the RemNote knowledge base. Results are sorted by type: documents first, then concepts, descriptors, portals, and plain text. Use includeContent: "markdown" for indented markdown previews or "structured" for nested child objects with remIds.',
24
26
  inputSchema: {
25
27
  type: 'object',
26
28
  properties: {
27
29
  query: { type: 'string', description: 'Search query text' },
28
30
  limit: { type: 'number', description: 'Maximum results (1-150, default: 50)' },
29
31
  includeContent: {
30
- type: 'boolean',
31
- description: 'Include first child bullets as content (default: false)',
32
+ type: 'string',
33
+ enum: ['none', 'markdown', 'structured'],
34
+ description: 'Content rendering mode: "none" omits content (default), "markdown" renders child subtree as indented markdown, "structured" returns nested child objects with remIds',
35
+ },
36
+ depth: {
37
+ type: 'number',
38
+ description: 'Depth of child hierarchy to render for markdown/structured content (0-10, default: 1)',
39
+ },
40
+ childLimit: {
41
+ type: 'number',
42
+ description: 'Maximum children per level (1-500, default: 20)',
43
+ },
44
+ maxContentLength: {
45
+ type: 'number',
46
+ description: 'Maximum character length for rendered content (default: 3000)',
32
47
  },
33
48
  },
34
49
  required: ['query'],
@@ -44,9 +59,22 @@ export const SEARCH_TOOL = {
44
59
  properties: {
45
60
  remId: { type: 'string', description: 'Unique Rem ID' },
46
61
  title: { type: 'string', description: 'Rendered title with markdown formatting' },
47
- detail: {
62
+ headline: {
63
+ type: 'string',
64
+ description: 'Display-oriented full line: title + type-aware delimiter + detail (e.g. "Term :: Definition")',
65
+ },
66
+ parentRemId: {
48
67
  type: 'string',
49
- description: 'Back text for CDF/flashcard Rems (omitted if none)',
68
+ description: 'Direct parent Rem ID (omitted for top-level Rems)',
69
+ },
70
+ parentTitle: {
71
+ type: 'string',
72
+ description: 'Direct parent title/front text (omitted for top-level Rems)',
73
+ },
74
+ aliases: {
75
+ type: 'array',
76
+ items: { type: 'string' },
77
+ description: 'Alternate names for the Rem (omitted if none)',
50
78
  },
51
79
  remType: {
52
80
  type: 'string',
@@ -58,7 +86,59 @@ export const SEARCH_TOOL = {
58
86
  },
59
87
  content: {
60
88
  type: 'string',
61
- description: 'Child content (only when includeContent=true)',
89
+ description: 'Rendered markdown content of child subtree (only when includeContent="markdown")',
90
+ },
91
+ contentStructured: {
92
+ type: 'array',
93
+ description: 'Structured child subtree with nested remIds and metadata (only when includeContent="structured")',
94
+ items: {
95
+ type: 'object',
96
+ properties: {
97
+ remId: { type: 'string', description: 'Child Rem ID' },
98
+ title: { type: 'string', description: 'Rendered child title' },
99
+ headline: {
100
+ type: 'string',
101
+ description: 'Display-oriented child line with type-aware delimiter',
102
+ },
103
+ aliases: {
104
+ type: 'array',
105
+ items: { type: 'string' },
106
+ description: 'Alternate names for the child Rem (omitted if none)',
107
+ },
108
+ remType: {
109
+ type: 'string',
110
+ description: 'Child Rem classification: document, dailyDocument, concept, descriptor, portal, or text',
111
+ },
112
+ cardDirection: {
113
+ type: 'string',
114
+ description: 'Child flashcard direction: forward, reverse, or bidirectional (omitted if not a flashcard)',
115
+ },
116
+ children: {
117
+ type: 'array',
118
+ description: 'Nested child nodes (same shape recursively)',
119
+ items: { type: 'object' },
120
+ },
121
+ },
122
+ required: ['remId', 'title', 'headline', 'remType', 'children'],
123
+ },
124
+ },
125
+ contentProperties: {
126
+ type: 'object',
127
+ description: 'Metadata about rendered content',
128
+ properties: {
129
+ childrenRendered: {
130
+ type: 'number',
131
+ description: 'Number of children included in rendered content',
132
+ },
133
+ childrenTotal: {
134
+ type: 'number',
135
+ description: 'Total children in subtree (capped at 2000)',
136
+ },
137
+ contentTruncated: {
138
+ type: 'boolean',
139
+ description: 'Whether content was truncated by maxContentLength',
140
+ },
141
+ },
62
142
  },
63
143
  },
64
144
  },
@@ -66,14 +146,63 @@ export const SEARCH_TOOL = {
66
146
  },
67
147
  },
68
148
  };
149
+ export const SEARCH_BY_TAG_TOOL = {
150
+ name: 'remnote_search_by_tag',
151
+ description: 'Find notes by tag and return resolved ancestor context targets (nearest document/daily document when available, otherwise nearest non-document ancestor). Supports the same includeContent modes as remnote_search.',
152
+ inputSchema: {
153
+ type: 'object',
154
+ properties: {
155
+ tag: {
156
+ type: 'string',
157
+ description: 'Tag name to search (with or without # prefix)',
158
+ },
159
+ limit: { type: 'number', description: 'Maximum results (1-150, default: 50)' },
160
+ includeContent: {
161
+ type: 'string',
162
+ enum: ['none', 'markdown', 'structured'],
163
+ description: 'Content rendering mode: "none" omits content (default), "markdown" renders child subtree as indented markdown, "structured" returns nested child objects with remIds',
164
+ },
165
+ depth: {
166
+ type: 'number',
167
+ description: 'Depth of child hierarchy to render for markdown/structured content (0-10, default: 1)',
168
+ },
169
+ childLimit: {
170
+ type: 'number',
171
+ description: 'Maximum children per level (1-500, default: 20)',
172
+ },
173
+ maxContentLength: {
174
+ type: 'number',
175
+ description: 'Maximum character length for rendered content (default: 3000)',
176
+ },
177
+ },
178
+ required: ['tag'],
179
+ },
180
+ outputSchema: SEARCH_TOOL.outputSchema,
181
+ };
69
182
  export const READ_NOTE_TOOL = {
70
183
  name: 'remnote_read_note',
71
- description: 'Read a specific note from RemNote by its Rem ID, including type classification and flashcard metadata',
184
+ description: 'Read a specific note from RemNote by its Rem ID. Returns metadata and rendered markdown content of the child subtree. Use includeContent: "none" to skip content rendering.',
72
185
  inputSchema: {
73
186
  type: 'object',
74
187
  properties: {
75
188
  remId: { type: 'string', description: 'The Rem ID to read' },
76
- depth: { type: 'number', description: 'Depth of children to include (0-10, default: 3)' },
189
+ depth: {
190
+ type: 'number',
191
+ description: 'Depth of child hierarchy to render (0-10, default: 5)',
192
+ },
193
+ includeContent: {
194
+ type: 'string',
195
+ enum: ['none', 'markdown'],
196
+ description: 'Content rendering mode: "markdown" renders child subtree (default), "none" omits content',
197
+ },
198
+ childLimit: {
199
+ type: 'number',
200
+ description: 'Maximum children per level (1-500, default: 100)',
201
+ },
202
+ maxContentLength: {
203
+ type: 'number',
204
+ description: 'Maximum character length for rendered content (default: 100000)',
205
+ },
77
206
  },
78
207
  required: ['remId'],
79
208
  },
@@ -82,9 +211,22 @@ export const READ_NOTE_TOOL = {
82
211
  properties: {
83
212
  remId: { type: 'string', description: 'Unique Rem ID' },
84
213
  title: { type: 'string', description: 'Rendered title with markdown formatting' },
85
- detail: {
214
+ headline: {
215
+ type: 'string',
216
+ description: 'Display-oriented full line: title + type-aware delimiter + detail (e.g. "Term :: Definition")',
217
+ },
218
+ parentRemId: {
219
+ type: 'string',
220
+ description: 'Direct parent Rem ID (omitted for top-level Rems)',
221
+ },
222
+ parentTitle: {
86
223
  type: 'string',
87
- description: 'Back text for CDF/flashcard Rems (omitted if none)',
224
+ description: 'Direct parent title/front text (omitted for top-level Rems)',
225
+ },
226
+ aliases: {
227
+ type: 'array',
228
+ items: { type: 'string' },
229
+ description: 'Alternate names for the Rem (omitted if none)',
88
230
  },
89
231
  remType: {
90
232
  type: 'string',
@@ -94,16 +236,25 @@ export const READ_NOTE_TOOL = {
94
236
  type: 'string',
95
237
  description: 'Flashcard direction: forward, reverse, or bidirectional (omitted if not a flashcard)',
96
238
  },
97
- content: { type: 'string', description: 'Rendered title text (same as title)' },
98
- children: {
99
- type: 'array',
100
- description: 'Child Rems up to requested depth',
101
- items: {
102
- type: 'object',
103
- properties: {
104
- remId: { type: 'string' },
105
- text: { type: 'string' },
106
- children: { type: 'array' },
239
+ content: {
240
+ type: 'string',
241
+ description: 'Rendered markdown content of child subtree (when includeContent="markdown", which is the default)',
242
+ },
243
+ contentProperties: {
244
+ type: 'object',
245
+ description: 'Metadata about rendered content',
246
+ properties: {
247
+ childrenRendered: {
248
+ type: 'number',
249
+ description: 'Number of children included in rendered content',
250
+ },
251
+ childrenTotal: {
252
+ type: 'number',
253
+ description: 'Total children in subtree (capped at 2000)',
254
+ },
255
+ contentTruncated: {
256
+ type: 'boolean',
257
+ description: 'Whether content was truncated by maxContentLength',
107
258
  },
108
259
  },
109
260
  },
@@ -165,6 +316,11 @@ export function registerAllTools(server, wsServer, logger) {
165
316
  result = await wsServer.sendRequest('search', args);
166
317
  break;
167
318
  }
319
+ case 'remnote_search_by_tag': {
320
+ const args = SearchByTagSchema.parse(request.params.arguments);
321
+ result = await wsServer.sendRequest('search_by_tag', args);
322
+ break;
323
+ }
168
324
  case 'remnote_read_note': {
169
325
  const args = ReadNoteSchema.parse(request.params.arguments);
170
326
  result = await wsServer.sendRequest('read_note', args);
@@ -182,12 +338,27 @@ export function registerAllTools(server, wsServer, logger) {
182
338
  }
183
339
  case 'remnote_status': {
184
340
  const connected = wsServer.isConnected();
341
+ const serverVersion = wsServer.getServerVersion();
342
+ const bridgeVersion = wsServer.getBridgeVersion();
185
343
  if (!connected) {
186
- result = { connected: false, message: 'RemNote plugin not connected' };
344
+ result = { connected: false, serverVersion, message: 'RemNote plugin not connected' };
187
345
  }
188
346
  else {
189
347
  const statusResult = await wsServer.sendRequest('get_status', {});
190
- result = { connected: true, ...(typeof statusResult === 'object' ? statusResult : {}) };
348
+ const statusObj = typeof statusResult === 'object' && statusResult !== null
349
+ ? statusResult
350
+ : {};
351
+ const fallbackBridgeVersion = typeof statusObj.pluginVersion === 'string' ? statusObj.pluginVersion : null;
352
+ const effectiveBridgeVersion = bridgeVersion ?? fallbackBridgeVersion;
353
+ const versionWarning = effectiveBridgeVersion
354
+ ? checkVersionCompatibility(serverVersion, effectiveBridgeVersion)
355
+ : null;
356
+ result = {
357
+ connected: true,
358
+ serverVersion,
359
+ ...statusObj,
360
+ ...(versionWarning ? { version_warning: versionWarning } : {}),
361
+ };
191
362
  }
192
363
  break;
193
364
  }
@@ -225,6 +396,7 @@ export function registerAllTools(server, wsServer, logger) {
225
396
  tools: [
226
397
  CREATE_NOTE_TOOL,
227
398
  SEARCH_TOOL,
399
+ SEARCH_BY_TAG_TOOL,
228
400
  READ_NOTE_TOOL,
229
401
  UPDATE_NOTE_TOOL,
230
402
  APPEND_JOURNAL_TOOL,