innov-mcp-tasks 1.0.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/index.mjs +381 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -50,11 +50,30 @@ Na raiz do repo existe [`.cursor/mcp.json`](../.cursor/mcp.json) com **dois** se
|
|
|
50
50
|
|
|
51
51
|
## Ferramentas
|
|
52
52
|
|
|
53
|
+
### Tarefas e projetos
|
|
54
|
+
|
|
53
55
|
- `tasks_list` — opcional `project_id`
|
|
54
56
|
- `my_tasks` — tarefas do utilizador do token (endpoint “minhas” da API)
|
|
57
|
+
- `projects_list` — lista projetos visíveis (`GET /api/v1/projects`)
|
|
55
58
|
- `project_create` — cria projeto (`POST /api/v1/projects`)
|
|
56
59
|
- `task_get`, `task_create`, `task_update_status`, `task_assign`, `task_assign_to_me`
|
|
57
60
|
|
|
61
|
+
### Anotações / documentação
|
|
62
|
+
|
|
63
|
+
- `notes_list` — lista com filtros opcionais (`project_id`, `note_type`, `notebook_id`)
|
|
64
|
+
- `notes_personal` — anotações pessoais
|
|
65
|
+
- `notes_by_project` — anotações de um projeto (inclui criador em `user`)
|
|
66
|
+
- `note_get`, `note_create`, `note_update`
|
|
67
|
+
- `note_delete` — soft delete (lixeira)
|
|
68
|
+
- `notes_trashed`, `note_restore`
|
|
69
|
+
- `annotations_search` — busca em cadernos, notas e fontes (`q` ≥ 2 caracteres)
|
|
70
|
+
|
|
71
|
+
### Cadernos (notebooks)
|
|
72
|
+
|
|
73
|
+
- `notebooks_list` — lista com filtro opcional `project_id`
|
|
74
|
+
- `notebook_get`, `notebook_create`, `notebook_update`, `notebook_delete`
|
|
75
|
+
- `notebook_documentation` — notas + fontes do caderno
|
|
76
|
+
|
|
58
77
|
## Publicar no npm (mantenedor)
|
|
59
78
|
|
|
60
79
|
1. Define o **nome** em `package.json` (`innov-mcp-tasks` ou `@scope/innov-mcp-tasks` se o nome simples estiver tomado).
|
package/index.mjs
CHANGED
|
@@ -105,6 +105,23 @@ server.registerTool(
|
|
|
105
105
|
},
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
+
server.registerTool(
|
|
109
|
+
'projects_list',
|
|
110
|
+
{
|
|
111
|
+
description:
|
|
112
|
+
'Lista projetos visíveis ao utilizador do token (GET /projects). Inclui creator, tasks, team e allowedUsers.',
|
|
113
|
+
inputSchema: {},
|
|
114
|
+
},
|
|
115
|
+
async () => {
|
|
116
|
+
try {
|
|
117
|
+
const data = await apiFetch('/api/v1/projects');
|
|
118
|
+
return jsonText(data);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
108
125
|
server.registerTool(
|
|
109
126
|
'project_create',
|
|
110
127
|
{
|
|
@@ -248,5 +265,369 @@ server.registerTool(
|
|
|
248
265
|
},
|
|
249
266
|
);
|
|
250
267
|
|
|
268
|
+
function notesQueryString(filters) {
|
|
269
|
+
const params = new URLSearchParams();
|
|
270
|
+
if (filters.project_id != null) {
|
|
271
|
+
params.set('project_id', String(filters.project_id));
|
|
272
|
+
}
|
|
273
|
+
if (filters.note_type != null) {
|
|
274
|
+
params.set('note_type', filters.note_type);
|
|
275
|
+
}
|
|
276
|
+
if (filters.notebook_id != null) {
|
|
277
|
+
params.set('notebook_id', String(filters.notebook_id));
|
|
278
|
+
}
|
|
279
|
+
const qs = params.toString();
|
|
280
|
+
return qs ? `?${qs}` : '';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
server.registerTool(
|
|
284
|
+
'notes_list',
|
|
285
|
+
{
|
|
286
|
+
description:
|
|
287
|
+
'Lista anotações do utilizador do token (GET /notes). Filtros opcionais: project_id, note_type (personal|project), notebook_id.',
|
|
288
|
+
inputSchema: {
|
|
289
|
+
project_id: z.number().int().positive().optional(),
|
|
290
|
+
note_type: z.enum(['personal', 'project']).optional(),
|
|
291
|
+
notebook_id: z.number().int().positive().optional(),
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
async (args) => {
|
|
295
|
+
try {
|
|
296
|
+
const data = await apiFetch(`/api/v1/notes${notesQueryString(args)}`);
|
|
297
|
+
return jsonText(data);
|
|
298
|
+
} catch (e) {
|
|
299
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
server.registerTool(
|
|
305
|
+
'notes_personal',
|
|
306
|
+
{
|
|
307
|
+
description: 'Anotações pessoais do utilizador do token (GET /notes/personal).',
|
|
308
|
+
inputSchema: {},
|
|
309
|
+
},
|
|
310
|
+
async () => {
|
|
311
|
+
try {
|
|
312
|
+
const data = await apiFetch('/api/v1/notes/personal');
|
|
313
|
+
return jsonText(data);
|
|
314
|
+
} catch (e) {
|
|
315
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
server.registerTool(
|
|
321
|
+
'notes_by_project',
|
|
322
|
+
{
|
|
323
|
+
description:
|
|
324
|
+
'Anotações de um projeto visível (GET /notes/project/{project_id}). Inclui user (criador).',
|
|
325
|
+
inputSchema: { project_id: z.number().int().positive() },
|
|
326
|
+
},
|
|
327
|
+
async (args) => {
|
|
328
|
+
try {
|
|
329
|
+
const data = await apiFetch(
|
|
330
|
+
`/api/v1/notes/project/${args.project_id}`,
|
|
331
|
+
);
|
|
332
|
+
return jsonText(data);
|
|
333
|
+
} catch (e) {
|
|
334
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
server.registerTool(
|
|
340
|
+
'note_get',
|
|
341
|
+
{
|
|
342
|
+
description: 'Obtém uma anotação por id (GET /notes/{id}). Só o autor.',
|
|
343
|
+
inputSchema: { note_id: z.number().int().positive() },
|
|
344
|
+
},
|
|
345
|
+
async (args) => {
|
|
346
|
+
try {
|
|
347
|
+
const data = await apiFetch(`/api/v1/notes/${args.note_id}`);
|
|
348
|
+
return jsonText(data);
|
|
349
|
+
} catch (e) {
|
|
350
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
server.registerTool(
|
|
356
|
+
'note_create',
|
|
357
|
+
{
|
|
358
|
+
description:
|
|
359
|
+
'Cria anotação (POST /notes). Pessoal sem project_id; de projeto com note_type project + project_id; opcional notebook_id.',
|
|
360
|
+
inputSchema: {
|
|
361
|
+
content: z.string().min(1),
|
|
362
|
+
title: z.string().max(255).optional(),
|
|
363
|
+
note_type: z.enum(['personal', 'project']).optional(),
|
|
364
|
+
project_id: z.number().int().positive().optional(),
|
|
365
|
+
notebook_id: z.number().int().positive().optional(),
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
async (args) => {
|
|
369
|
+
try {
|
|
370
|
+
const body = {
|
|
371
|
+
content: args.content,
|
|
372
|
+
title: args.title ?? null,
|
|
373
|
+
note_type: args.note_type ?? null,
|
|
374
|
+
project_id: args.project_id ?? null,
|
|
375
|
+
notebook_id: args.notebook_id ?? null,
|
|
376
|
+
};
|
|
377
|
+
const data = await apiFetch('/api/v1/notes', {
|
|
378
|
+
method: 'POST',
|
|
379
|
+
body: JSON.stringify(body),
|
|
380
|
+
});
|
|
381
|
+
return jsonText(data);
|
|
382
|
+
} catch (e) {
|
|
383
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
server.registerTool(
|
|
389
|
+
'note_update',
|
|
390
|
+
{
|
|
391
|
+
description: 'Atualiza anotação (PUT /notes/{id}). Só o autor.',
|
|
392
|
+
inputSchema: {
|
|
393
|
+
note_id: z.number().int().positive(),
|
|
394
|
+
title: z.string().max(255).optional(),
|
|
395
|
+
content: z.string().optional(),
|
|
396
|
+
note_type: z.enum(['personal', 'project']).optional(),
|
|
397
|
+
project_id: z.number().int().positive().optional(),
|
|
398
|
+
notebook_id: z.number().int().positive().optional(),
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
async (args) => {
|
|
402
|
+
try {
|
|
403
|
+
const { note_id, ...fields } = args;
|
|
404
|
+
const body = Object.fromEntries(
|
|
405
|
+
Object.entries(fields).filter(([, v]) => v !== undefined),
|
|
406
|
+
);
|
|
407
|
+
const data = await apiFetch(`/api/v1/notes/${note_id}`, {
|
|
408
|
+
method: 'PUT',
|
|
409
|
+
body: JSON.stringify(body),
|
|
410
|
+
});
|
|
411
|
+
return jsonText(data);
|
|
412
|
+
} catch (e) {
|
|
413
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
server.registerTool(
|
|
419
|
+
'note_delete',
|
|
420
|
+
{
|
|
421
|
+
description:
|
|
422
|
+
'Remove anotação para a lixeira — soft delete (DELETE /notes/{id}). Só o autor.',
|
|
423
|
+
inputSchema: { note_id: z.number().int().positive() },
|
|
424
|
+
},
|
|
425
|
+
async (args) => {
|
|
426
|
+
try {
|
|
427
|
+
const data = await apiFetch(`/api/v1/notes/${args.note_id}`, {
|
|
428
|
+
method: 'DELETE',
|
|
429
|
+
});
|
|
430
|
+
return jsonText(data);
|
|
431
|
+
} catch (e) {
|
|
432
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
server.registerTool(
|
|
438
|
+
'notes_trashed',
|
|
439
|
+
{
|
|
440
|
+
description:
|
|
441
|
+
'Lista anotações na lixeira do utilizador (GET /notes/trashed). Filtros opcionais como notes_list.',
|
|
442
|
+
inputSchema: {
|
|
443
|
+
project_id: z.number().int().positive().optional(),
|
|
444
|
+
note_type: z.enum(['personal', 'project']).optional(),
|
|
445
|
+
notebook_id: z.number().int().positive().optional(),
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
async (args) => {
|
|
449
|
+
try {
|
|
450
|
+
const data = await apiFetch(
|
|
451
|
+
`/api/v1/notes/trashed${notesQueryString(args)}`,
|
|
452
|
+
);
|
|
453
|
+
return jsonText(data);
|
|
454
|
+
} catch (e) {
|
|
455
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
server.registerTool(
|
|
461
|
+
'note_restore',
|
|
462
|
+
{
|
|
463
|
+
description:
|
|
464
|
+
'Restaura anotação da lixeira (POST /notes/{id}/restore). Só o autor.',
|
|
465
|
+
inputSchema: { note_id: z.number().int().positive() },
|
|
466
|
+
},
|
|
467
|
+
async (args) => {
|
|
468
|
+
try {
|
|
469
|
+
const data = await apiFetch(
|
|
470
|
+
`/api/v1/notes/${args.note_id}/restore`,
|
|
471
|
+
{ method: 'POST' },
|
|
472
|
+
);
|
|
473
|
+
return jsonText(data);
|
|
474
|
+
} catch (e) {
|
|
475
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
server.registerTool(
|
|
481
|
+
'annotations_search',
|
|
482
|
+
{
|
|
483
|
+
description:
|
|
484
|
+
'Busca em cadernos, anotações e fontes (GET /annotations/search?q=). Mínimo 2 caracteres.',
|
|
485
|
+
inputSchema: { q: z.string().min(2) },
|
|
486
|
+
},
|
|
487
|
+
async (args) => {
|
|
488
|
+
try {
|
|
489
|
+
const data = await apiFetch(
|
|
490
|
+
`/api/v1/annotations/search?q=${encodeURIComponent(args.q)}`,
|
|
491
|
+
);
|
|
492
|
+
return jsonText(data);
|
|
493
|
+
} catch (e) {
|
|
494
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
server.registerTool(
|
|
500
|
+
'notebooks_list',
|
|
501
|
+
{
|
|
502
|
+
description:
|
|
503
|
+
'Lista cadernos visíveis ao utilizador do token (GET /notebooks). Filtro opcional project_id.',
|
|
504
|
+
inputSchema: {
|
|
505
|
+
project_id: z.number().int().positive().optional(),
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
async (args) => {
|
|
509
|
+
try {
|
|
510
|
+
const qs =
|
|
511
|
+
args.project_id != null
|
|
512
|
+
? `?project_id=${encodeURIComponent(String(args.project_id))}`
|
|
513
|
+
: '';
|
|
514
|
+
const data = await apiFetch(`/api/v1/notebooks${qs}`);
|
|
515
|
+
return jsonText(data);
|
|
516
|
+
} catch (e) {
|
|
517
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
server.registerTool(
|
|
523
|
+
'notebook_get',
|
|
524
|
+
{
|
|
525
|
+
description: 'Obtém um caderno por id (GET /notebooks/{id}).',
|
|
526
|
+
inputSchema: { notebook_id: z.number().int().positive() },
|
|
527
|
+
},
|
|
528
|
+
async (args) => {
|
|
529
|
+
try {
|
|
530
|
+
const data = await apiFetch(`/api/v1/notebooks/${args.notebook_id}`);
|
|
531
|
+
return jsonText(data);
|
|
532
|
+
} catch (e) {
|
|
533
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
server.registerTool(
|
|
539
|
+
'notebook_create',
|
|
540
|
+
{
|
|
541
|
+
description:
|
|
542
|
+
'Cria caderno (POST /notebooks). Pessoal sem project_id; de projeto com project_id. name obrigatório.',
|
|
543
|
+
inputSchema: {
|
|
544
|
+
name: z.string().min(1).max(255),
|
|
545
|
+
description: z.string().optional(),
|
|
546
|
+
project_id: z.number().int().positive().optional(),
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
async (args) => {
|
|
550
|
+
try {
|
|
551
|
+
const body = {
|
|
552
|
+
name: args.name,
|
|
553
|
+
description: args.description ?? null,
|
|
554
|
+
project_id: args.project_id ?? null,
|
|
555
|
+
};
|
|
556
|
+
const data = await apiFetch('/api/v1/notebooks', {
|
|
557
|
+
method: 'POST',
|
|
558
|
+
body: JSON.stringify(body),
|
|
559
|
+
});
|
|
560
|
+
return jsonText(data);
|
|
561
|
+
} catch (e) {
|
|
562
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
server.registerTool(
|
|
568
|
+
'notebook_update',
|
|
569
|
+
{
|
|
570
|
+
description: 'Atualiza caderno (PATCH /notebooks/{id}). Só cadernos do utilizador.',
|
|
571
|
+
inputSchema: {
|
|
572
|
+
notebook_id: z.number().int().positive(),
|
|
573
|
+
name: z.string().min(1).max(255).optional(),
|
|
574
|
+
description: z.string().optional(),
|
|
575
|
+
project_id: z.number().int().positive().optional(),
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
async (args) => {
|
|
579
|
+
try {
|
|
580
|
+
const { notebook_id, ...fields } = args;
|
|
581
|
+
const body = Object.fromEntries(
|
|
582
|
+
Object.entries(fields).filter(([, v]) => v !== undefined),
|
|
583
|
+
);
|
|
584
|
+
const data = await apiFetch(`/api/v1/notebooks/${notebook_id}`, {
|
|
585
|
+
method: 'PATCH',
|
|
586
|
+
body: JSON.stringify(body),
|
|
587
|
+
});
|
|
588
|
+
return jsonText(data);
|
|
589
|
+
} catch (e) {
|
|
590
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
server.registerTool(
|
|
596
|
+
'notebook_delete',
|
|
597
|
+
{
|
|
598
|
+
description: 'Apaga caderno (DELETE /notebooks/{id}). Só cadernos do utilizador.',
|
|
599
|
+
inputSchema: { notebook_id: z.number().int().positive() },
|
|
600
|
+
},
|
|
601
|
+
async (args) => {
|
|
602
|
+
try {
|
|
603
|
+
const data = await apiFetch(`/api/v1/notebooks/${args.notebook_id}`, {
|
|
604
|
+
method: 'DELETE',
|
|
605
|
+
});
|
|
606
|
+
return jsonText(data);
|
|
607
|
+
} catch (e) {
|
|
608
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
server.registerTool(
|
|
614
|
+
'notebook_documentation',
|
|
615
|
+
{
|
|
616
|
+
description:
|
|
617
|
+
'Documentação agregada do caderno: notas do utilizador + fontes (GET /notebooks/{id}/documentation).',
|
|
618
|
+
inputSchema: { notebook_id: z.number().int().positive() },
|
|
619
|
+
},
|
|
620
|
+
async (args) => {
|
|
621
|
+
try {
|
|
622
|
+
const data = await apiFetch(
|
|
623
|
+
`/api/v1/notebooks/${args.notebook_id}/documentation`,
|
|
624
|
+
);
|
|
625
|
+
return jsonText(data);
|
|
626
|
+
} catch (e) {
|
|
627
|
+
return jsonError(e instanceof Error ? e.message : String(e));
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
);
|
|
631
|
+
|
|
251
632
|
const transport = new StdioServerTransport();
|
|
252
633
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "innov-mcp-tasks",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "MCP stdio —
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "MCP stdio — tarefas e anotações Innov (INNOV_API_BASE_URL + token Sanctum)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
7
7
|
"bin": {
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"mcp",
|
|
27
27
|
"modelcontextprotocol",
|
|
28
28
|
"tasks",
|
|
29
|
+
"notes",
|
|
30
|
+
"annotations",
|
|
29
31
|
"innov"
|
|
30
32
|
],
|
|
31
33
|
"author": "",
|