innov-mcp-tasks 1.1.0 → 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 +16 -25
- package/index.mjs +133 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,18 +6,16 @@ Servidor [MCP](https://modelcontextprotocol.io) em **stdio** para ferramentas de
|
|
|
6
6
|
|
|
7
7
|
## Variáveis obrigatórias
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
| -------------------- | -------------------------------------------------------------------------------- |
|
|
9
|
+
| Variável | Descrição |
|
|
10
|
+
|----------|-----------|
|
|
12
11
|
| `INNOV_API_BASE_URL` | URL base **sem** `/api/v1` (definida por ti: dev local, staging, produção, etc.) |
|
|
13
|
-
| `INNOV_API_TOKEN`
|
|
14
|
-
|
|
12
|
+
| `INNOV_API_TOKEN` | Token pessoal Sanctum (ex.: **Perfil** → Tokens de API na app Innov) |
|
|
15
13
|
|
|
16
|
-
Copia
|
|
14
|
+
Copia [`.env.example`](./.env.example) para um ficheiro `.env` à tua escolha e preenche (esse ficheiro **não** vem do npm com valores; no repo monorepo, mantém `.env` fora do Git).
|
|
17
15
|
|
|
18
16
|
## Cursor com pacote npm (`npx`)
|
|
19
17
|
|
|
20
|
-
Nome do pacote no npm:
|
|
18
|
+
Nome do pacote no npm: **`innov-mcp-tasks`** (se o nome estiver ocupado, publica como scoped, ex. `@tua-org/innov-mcp-tasks`, e ajusta os exemplos).
|
|
21
19
|
|
|
22
20
|
```json
|
|
23
21
|
{
|
|
@@ -35,20 +33,18 @@ Nome do pacote no npm: `**innov-mcp-tasks`** (se o nome estiver ocupado, publica
|
|
|
35
33
|
}
|
|
36
34
|
```
|
|
37
35
|
|
|
38
|
-
Segredos: prefere
|
|
36
|
+
Segredos: prefere [`${env:INNOV_API_TOKEN}`](https://cursor.com/docs/mcp) apontando para variáveis já definidas no SO, ou `envFile` para um `.env` **fora** do repositório (ex. `C:\\Users\\…\\.config\\innov\\mcp.env`).
|
|
39
37
|
|
|
40
38
|
Também podes apontar o binário instalado globalmente: `"command": "innov-mcp-tasks"` (após `npm install -g innov-mcp-tasks`).
|
|
41
39
|
|
|
42
40
|
## Monorepo (desenvolvimento)
|
|
43
41
|
|
|
44
|
-
Na raiz do repo existe
|
|
42
|
+
Na raiz do repo existe [`.cursor/mcp.json`](../.cursor/mcp.json) com **dois** servidores que partilham o mesmo `mcp-tasks/.env`:
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
| ------------------- | -------------------------------------------------------- |
|
|
44
|
+
| Servidor | Uso |
|
|
45
|
+
|----------|-----|
|
|
49
46
|
| `innov-tasks-local` | Corre o `index.mjs` do clon (óptimo para alterar o MCP). |
|
|
50
|
-
| `innov-tasks-npm`
|
|
51
|
-
|
|
47
|
+
| `innov-tasks-npm` | Usa `npx -y innov-mcp-tasks` (testa o pacote publicado). |
|
|
52
48
|
|
|
53
49
|
**Ativa só um** em *Settings → Features → Model Context Protocol* (dois ao mesmo tempo duplicam ferramentas com o mesmo nome). Se publicares com scope (`@org/innov-mcp-tasks`), edita os `args` em `innov-tasks-npm` para esse nome.
|
|
54
50
|
|
|
@@ -72,6 +68,12 @@ Na raiz do repo existe `[.cursor/mcp.json](../.cursor/mcp.json)` com **dois** se
|
|
|
72
68
|
- `notes_trashed`, `note_restore`
|
|
73
69
|
- `annotations_search` — busca em cadernos, notas e fontes (`q` ≥ 2 caracteres)
|
|
74
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
|
+
|
|
75
77
|
## Publicar no npm (mantenedor)
|
|
76
78
|
|
|
77
79
|
1. Define o **nome** em `package.json` (`innov-mcp-tasks` ou `@scope/innov-mcp-tasks` se o nome simples estiver tomado).
|
|
@@ -84,16 +86,6 @@ npm test
|
|
|
84
86
|
npm publish --access public
|
|
85
87
|
```
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Se estiver deslogado para logar faça o comando
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npm login
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
89
|
Para **scoped** (`@org/pkg`): a primeira vez costuma precisar de `--access public` se for pacote OSS.
|
|
98
90
|
|
|
99
91
|
## Testes
|
|
@@ -101,4 +93,3 @@ Para **scoped** (`@org/pkg`): a primeira vez costuma precisar de `--access publi
|
|
|
101
93
|
```bash
|
|
102
94
|
npm test
|
|
103
95
|
```
|
|
104
|
-
|
package/index.mjs
CHANGED
|
@@ -496,5 +496,138 @@ server.registerTool(
|
|
|
496
496
|
},
|
|
497
497
|
);
|
|
498
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
|
+
|
|
499
632
|
const transport = new StdioServerTransport();
|
|
500
633
|
await server.connect(transport);
|