@ds9-solutions/mcp 0.1.0 → 0.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/content/agents/code-reviewer.agent.md +52 -22
- package/content/agents/db-analyser.agent.md +121 -0
- package/content/agents/security-reviewer.agent.md +119 -37
- package/content/agents/test-writer.agent.md +84 -35
- package/content/skills/dart/SKILL.md +139 -0
- package/content/skills/dart/examples/entity.dart +37 -0
- package/content/skills/dart/examples/error_handling.dart +36 -0
- package/content/skills/dart/examples/order_test.dart +34 -0
- package/content/skills/dart/examples/repository.dart +57 -0
- package/content/skills/dart/references/checklist.md +12 -0
- package/content/skills/dart/references/documentation.md +26 -0
- package/content/skills/dart/references/naming.md +27 -0
- package/content/skills/dart-frog/SKILL.md +208 -0
- package/content/skills/dart-frog/examples/auth_middleware.dart +50 -0
- package/content/skills/dart-frog/examples/controller.dart +75 -0
- package/content/skills/dart-frog/examples/dto.dart +41 -0
- package/content/skills/dart-frog/examples/error_response.dart +35 -0
- package/content/skills/dart-frog/examples/exceptions.dart +60 -0
- package/content/skills/dart-frog/examples/middleware_composition.dart +34 -0
- package/content/skills/dart-frog/examples/model.dart +20 -0
- package/content/skills/dart-frog/examples/port.dart +17 -0
- package/content/skills/dart-frog/examples/repository.dart +56 -0
- package/content/skills/dart-frog/examples/route_collection.dart +25 -0
- package/content/skills/dart-frog/examples/route_item.dart +24 -0
- package/content/skills/dart-frog/examples/route_test.dart +33 -0
- package/content/skills/dart-frog/examples/service.dart +51 -0
- package/content/skills/dart-frog/examples/service_test.dart +55 -0
- package/content/skills/dart-frog/references/checklist.md +31 -0
- package/content/skills/dart-frog/references/error-handling.md +48 -0
- package/content/skills/dart-frog/references/fpdart-taskeither.md +53 -0
- package/content/skills/dart-frog/references/layers.md +43 -0
- package/content/skills/dart-frog/references/middlewares-di.md +45 -0
- package/content/skills/dart-frog/references/project-structure.md +67 -0
- package/content/skills/dart-frog/references/routing.md +53 -0
- package/content/skills/dart-frog/references/testing.md +24 -0
- package/content/skills/docker/SKILL.md +3 -3
- package/content/skills/driftorm/SKILL.md +249 -0
- package/content/skills/flutter/SKILL.md +419 -0
- package/content/skills/hex-pattern-dart/SKILL.md +83 -0
- package/content/skills/hex-pattern-dart/examples/adapter-in.md +24 -0
- package/content/skills/hex-pattern-dart/examples/adapter-out.md +20 -0
- package/content/skills/hex-pattern-dart/examples/errors.md +25 -0
- package/content/skills/hex-pattern-dart/examples/port.md +11 -0
- package/content/skills/hex-pattern-dart/examples/service.md +20 -0
- package/content/skills/hex-pattern-dart/examples/structure-tree.md +28 -0
- package/content/skills/hex-pattern-dart/references/anti-patterns.md +16 -0
- package/content/skills/hex-pattern-dart/references/checklist.md +34 -0
- package/content/skills/hex-pattern-dart/references/dependency-injection.md +32 -0
- package/content/skills/hex-pattern-dart/references/error-layers.md +27 -0
- package/content/skills/hex-pattern-dart/references/layers-and-dependency-rule.md +29 -0
- package/content/skills/hex-pattern-dart/references/persistence.md +23 -0
- package/content/skills/hex-pattern-dart/references/ports-and-adapters.md +33 -0
- package/content/skills/hex-pattern-dart/references/testing.md +30 -0
- package/content/skills/mysql/SKILL.md +3 -3
- package/content/skills/typescript/SKILL.md +4 -4
- package/dist/src/content.js +10 -2
- package/dist/src/init.js +1 -0
- package/dist/src/search.js +20 -12
- package/dist/src/server.js +60 -4
- package/dist/src/skill-files.js +125 -0
- package/package.json +2 -2
- package/content/agents/db-specialist.agent.md +0 -78
- package/content/agents/nestjs-api-designer.agent.md +0 -61
- package/content/skills/hexagonal/SKILL.md +0 -156
- package/content/skills/jest-testing/SKILL.md +0 -88
- package/content/skills/nestjs/SKILL.md +0 -100
- package/content/skills/typeorm/SKILL.md +0 -119
- package/dist/test/mcp.test.js +0 -112
package/dist/test/mcp.test.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Testes do pacote, com o runner nativo do Node (`node:test`).
|
|
3
|
-
*
|
|
4
|
-
* Por que `node:test`: evita configurar Jest + ts-jest com ESM e não adiciona dependência.
|
|
5
|
-
* Os testes usam o conteúdo REAL do plugin, então também falham se alguém quebrar o frontmatter
|
|
6
|
-
* de uma skill ou agente (ex.: remover a `description`).
|
|
7
|
-
*/
|
|
8
|
-
import { test } from "node:test";
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
|
-
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
14
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
15
|
-
import { loadEntries, parseFrontmatter } from "../src/content.js";
|
|
16
|
-
import { createServer } from "../src/server.js";
|
|
17
|
-
import { rankByMetadata, searchBodies } from "../src/search.js";
|
|
18
|
-
import { TARGETS, mergeServerConfig, runInit, upsertAgentsBlock } from "../src/init.js";
|
|
19
|
-
const entries = loadEntries();
|
|
20
|
-
/**
|
|
21
|
-
* Conecta um cliente MCP de verdade ao servidor, em memória (sem processo nem stdio). Assim os
|
|
22
|
-
* testes exercitam o protocolo completo — o mesmo caminho que uma IDE usaria.
|
|
23
|
-
*/
|
|
24
|
-
async function connect() {
|
|
25
|
-
const [a, b] = InMemoryTransport.createLinkedPair();
|
|
26
|
-
const client = new Client({ name: "test", version: "0" });
|
|
27
|
-
await Promise.all([createServer(entries).connect(a), client.connect(b)]);
|
|
28
|
-
return client;
|
|
29
|
-
}
|
|
30
|
-
// Extrai o texto da primeira parte de uma resposta de tool.
|
|
31
|
-
const firstText = (r) => r.content[0].text;
|
|
32
|
-
test("parseFrontmatter separa frontmatter e corpo", () => {
|
|
33
|
-
const { data, body } = parseFrontmatter("---\nname: x\ndescription: d\n---\n\n# Corpo\n");
|
|
34
|
-
assert.equal(data.name, "x");
|
|
35
|
-
assert.equal(body, "# Corpo");
|
|
36
|
-
});
|
|
37
|
-
test("loader carrega skills e agentes reais", () => {
|
|
38
|
-
assert.ok(entries.some((e) => e.kind === "skill" && e.id === "nestjs"));
|
|
39
|
-
assert.ok(entries.some((e) => e.kind === "agent" && e.id === "code-reviewer"));
|
|
40
|
-
// A description alimenta o ranking do `recommend_for_task`; sem ela a entrada fica invisível.
|
|
41
|
-
assert.ok(entries.every((e) => e.description.length > 0));
|
|
42
|
-
});
|
|
43
|
-
test("rankByMetadata prioriza a skill relevante", () => {
|
|
44
|
-
const top = rankByMetadata(entries, "criar Dockerfile multi-stage", "skill")[0];
|
|
45
|
-
assert.equal(top.entry.id, "docker");
|
|
46
|
-
});
|
|
47
|
-
test("searchBodies encontra trechos", () => {
|
|
48
|
-
assert.ok(searchBodies(entries, "migration").length > 0);
|
|
49
|
-
// "a" é stopword/1 letra: a consulta vira vazia e não deve devolver tudo.
|
|
50
|
-
assert.deepEqual(searchBodies(entries, "a"), []);
|
|
51
|
-
});
|
|
52
|
-
test("tools: list, get, erro em id inexistente, recommend", async () => {
|
|
53
|
-
const client = await connect();
|
|
54
|
-
const tools = (await client.listTools()).tools.map((t) => t.name);
|
|
55
|
-
for (const n of [
|
|
56
|
-
"list_skills",
|
|
57
|
-
"get_skill",
|
|
58
|
-
"list_agents",
|
|
59
|
-
"get_agent",
|
|
60
|
-
"search_guidelines",
|
|
61
|
-
"recommend_for_task",
|
|
62
|
-
]) {
|
|
63
|
-
assert.ok(tools.includes(n), n);
|
|
64
|
-
}
|
|
65
|
-
assert.match(firstText(await client.callTool({ name: "list_skills", arguments: {} })), /hexagonal/);
|
|
66
|
-
assert.match(firstText(await client.callTool({ name: "get_skill", arguments: { name: "docker" } })), /Skill: docker/);
|
|
67
|
-
// Id inexistente deve ser um erro "de uso" (isError), não uma exceção do protocolo.
|
|
68
|
-
const missing = await client.callTool({ name: "get_agent", arguments: { name: "nope" } });
|
|
69
|
-
assert.equal(missing.isError, true);
|
|
70
|
-
assert.match(firstText(await client.callTool({
|
|
71
|
-
name: "recommend_for_task",
|
|
72
|
-
arguments: { task: "revisar segurança de código" },
|
|
73
|
-
})), /security-reviewer/);
|
|
74
|
-
});
|
|
75
|
-
test("prompts e resources expostos", async () => {
|
|
76
|
-
const client = await connect();
|
|
77
|
-
assert.ok((await client.listPrompts()).prompts.some((p) => p.name === "skill-nestjs"));
|
|
78
|
-
const res = await client.listResources();
|
|
79
|
-
assert.ok(res.resources.some((r) => r.uri === "ds9://skills/typeorm"));
|
|
80
|
-
const read = await client.readResource({ uri: "ds9://agents/test-writer" });
|
|
81
|
-
assert.match(read.contents[0].text, /Agente: test-writer/);
|
|
82
|
-
});
|
|
83
|
-
test("mergeServerConfig preserva outros servidores e é idempotente", () => {
|
|
84
|
-
const cursor = TARGETS.find((t) => t.id === "cursor");
|
|
85
|
-
const once = mergeServerConfig({ mcpServers: { outro: { command: "x" } } }, cursor, "linux");
|
|
86
|
-
// O servidor que o usuário já tinha ("outro") não pode ser perdido.
|
|
87
|
-
assert.deepEqual(Object.keys(once.mcpServers).sort(), ["ds9", "outro"]);
|
|
88
|
-
// Rodar de novo não pode mudar nada.
|
|
89
|
-
assert.deepEqual(mergeServerConfig(once, cursor, "linux"), once);
|
|
90
|
-
// VS Code usa `servers` + `type: stdio`; no Windows o comando passa por `cmd /c`.
|
|
91
|
-
const vscode = TARGETS.find((t) => t.id === "vscode");
|
|
92
|
-
const v = mergeServerConfig({}, vscode, "win32");
|
|
93
|
-
assert.equal(v.servers.ds9.type, "stdio");
|
|
94
|
-
assert.equal(v.servers.ds9.command, "cmd");
|
|
95
|
-
});
|
|
96
|
-
test("upsertAgentsBlock insere uma vez e atualiza sem duplicar", () => {
|
|
97
|
-
const once = upsertAgentsBlock("# Meu projeto\n");
|
|
98
|
-
assert.match(once, /# Meu projeto/); // conteúdo prévio preservado
|
|
99
|
-
assert.equal(upsertAgentsBlock(once), once); // segunda execução não muda nada
|
|
100
|
-
assert.equal(once.match(/ds9-mcp:start/g)?.length, 1); // bloco nunca duplica
|
|
101
|
-
});
|
|
102
|
-
test("runInit grava config e AGENTS.md; recusa JSON inválido", () => {
|
|
103
|
-
// Diretório temporário: o teste nunca toca em arquivos reais do usuário.
|
|
104
|
-
const dir = mkdtempSync(join(tmpdir(), "ds9-init-"));
|
|
105
|
-
const cursor = TARGETS.find((t) => t.id === "cursor");
|
|
106
|
-
const r = runInit(cursor, dir);
|
|
107
|
-
assert.ok(JSON.parse(readFileSync(r.configFile, "utf8")).mcpServers.ds9);
|
|
108
|
-
assert.match(readFileSync(r.agentsFile, "utf8"), /recommend_for_task/);
|
|
109
|
-
// Arquivo com comentário (JSONC) não pode ser sobrescrito: deve falhar com orientação.
|
|
110
|
-
writeFileSync(join(dir, ".mcp.json"), "{ // comentário\n}");
|
|
111
|
-
assert.throws(() => runInit(TARGETS[0], dir), /não é JSON puro/);
|
|
112
|
-
});
|