@semacode/mcp 1.2.18 → 1.2.20
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/dist/index.js +77 -59
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,13 +4,15 @@ import { spawnSync } from "node:child_process";
|
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
7
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
function chamarSema(args, cwd) {
|
|
9
|
-
const
|
|
10
|
+
const isWindows = process.platform === "win32";
|
|
11
|
+
const resultado = spawnSync(isWindows ? "sema.cmd" : "sema", args, {
|
|
10
12
|
encoding: "utf-8",
|
|
11
13
|
cwd: cwd ?? process.cwd(),
|
|
12
14
|
env: process.env,
|
|
13
|
-
shell:
|
|
15
|
+
shell: isWindows,
|
|
14
16
|
});
|
|
15
17
|
const saida = (resultado.stdout ?? "").trim();
|
|
16
18
|
const erro = (resultado.stderr ?? "").trim();
|
|
@@ -19,81 +21,75 @@ function chamarSema(args, cwd) {
|
|
|
19
21
|
}
|
|
20
22
|
return [saida, erro].filter(Boolean).join("\n");
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
saida: z.string().optional().describe("Pasta de saida dos artefatos gerados"),
|
|
61
|
-
}, async ({ projeto, saida }) => {
|
|
62
|
-
const args = ["verificar", projeto, ...(saida ? ["--saida", saida] : [])];
|
|
63
|
-
return { content: [{ type: "text", text: chamarSema(args) }] };
|
|
64
|
-
});
|
|
65
|
-
server.tool("sema_inspecionar", "Inspeciona um arquivo .sema e mostra detalhes do modulo: rotas, tarefas, eventos, politicas.", { arquivo: z.string().describe("Caminho para o arquivo .sema") }, async ({ arquivo }) => ({
|
|
66
|
-
content: [{ type: "text", text: chamarSema(["inspecionar", arquivo]) }],
|
|
67
|
-
}));
|
|
24
|
+
function registrarFerramentas(s) {
|
|
25
|
+
s.tool("sema_validar", "Valida um arquivo .sema e retorna diagnosticos de erro ou sucesso.", { arquivo: z.string().describe("Caminho absoluto ou relativo para o arquivo .sema") }, async ({ arquivo }) => ({
|
|
26
|
+
content: [{ type: "text", text: chamarSema(["validar", arquivo]) }],
|
|
27
|
+
}));
|
|
28
|
+
s.tool("sema_ir", "Compila um arquivo .sema e retorna a representacao intermediaria (IR) em JSON.", { arquivo: z.string().describe("Caminho para o arquivo .sema") }, async ({ arquivo }) => ({
|
|
29
|
+
content: [{ type: "text", text: chamarSema(["ir", arquivo, "--json"]) }],
|
|
30
|
+
}));
|
|
31
|
+
s.tool("sema_drift", "Analisa o drift entre o contrato .sema e o codigo do projeto. Retorna divergencias encontradas.", {
|
|
32
|
+
projeto: z.string().optional().describe("Caminho do projeto (padrao: diretorio atual)"),
|
|
33
|
+
json: z.boolean().optional().describe("Retornar saida em JSON"),
|
|
34
|
+
}, async ({ projeto, json }) => {
|
|
35
|
+
const args = ["drift", ...(projeto ? [projeto] : []), ...(json ? ["--json"] : [])];
|
|
36
|
+
return { content: [{ type: "text", text: chamarSema(args, projeto) }] };
|
|
37
|
+
});
|
|
38
|
+
s.tool("sema_resumo", "Gera um resumo IA-first do projeto Sema com modulos, riscos e lacunas.", {
|
|
39
|
+
projeto: z.string().optional().describe("Caminho do projeto (padrao: diretorio atual)"),
|
|
40
|
+
tamanho: z.enum(["micro", "curto", "medio"]).optional().describe("Tamanho do resumo (padrao: curto)"),
|
|
41
|
+
}, async ({ projeto, tamanho }) => {
|
|
42
|
+
const args = ["resumo", ...(tamanho ? [`--tamanho=${tamanho}`] : [])];
|
|
43
|
+
return { content: [{ type: "text", text: chamarSema(args, projeto) }] };
|
|
44
|
+
});
|
|
45
|
+
s.tool("sema_prompt_ia", "Gera o prompt-curto IA-first do projeto para briefar um agente sobre o estado atual.", { projeto: z.string().optional().describe("Caminho do projeto") }, async ({ projeto }) => ({
|
|
46
|
+
content: [{ type: "text", text: chamarSema(["prompt-curto"], projeto) }],
|
|
47
|
+
}));
|
|
48
|
+
s.tool("sema_contexto_ia", "Gera o pacote completo de contexto IA para um modulo ou projeto (briefing, drift, IR, artefatos).", { arquivo: z.string().describe("Caminho para o arquivo .sema do modulo") }, async ({ arquivo }) => ({
|
|
49
|
+
content: [{ type: "text", text: chamarSema(["contexto-ia", arquivo]) }],
|
|
50
|
+
}));
|
|
51
|
+
s.tool("sema_verificar", "Verifica todos os alvos de geracao de um projeto Sema (compila, gera e testa cada alvo).", {
|
|
52
|
+
projeto: z.string().describe("Caminho do projeto a verificar"),
|
|
53
|
+
saida: z.string().optional().describe("Pasta de saida dos artefatos gerados"),
|
|
54
|
+
}, async ({ projeto, saida }) => {
|
|
55
|
+
const args = ["verificar", projeto, ...(saida ? ["--saida", saida] : [])];
|
|
56
|
+
return { content: [{ type: "text", text: chamarSema(args) }] };
|
|
57
|
+
});
|
|
58
|
+
s.tool("sema_inspecionar", "Inspeciona um arquivo .sema e mostra detalhes do modulo: rotas, tarefas, eventos, politicas.", { arquivo: z.string().describe("Caminho para o arquivo .sema") }, async ({ arquivo }) => ({
|
|
59
|
+
content: [{ type: "text", text: chamarSema(["inspecionar", arquivo]) }],
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
68
62
|
const porta = process.env["MCP_PORT"] ? parseInt(process.env["MCP_PORT"]) : null;
|
|
69
63
|
if (porta) {
|
|
70
|
-
// Modo
|
|
71
|
-
const
|
|
64
|
+
// Modo HTTP remoto — suporta Streamable HTTP (/mcp) e SSE legado (/sse)
|
|
65
|
+
const httpTransportes = new Map();
|
|
66
|
+
const sseTransportes = new Map();
|
|
72
67
|
const http = createServer(async (req, res) => {
|
|
73
68
|
const url = req.url ?? "/";
|
|
69
|
+
// Streamable HTTP — protocolo MCP moderno
|
|
74
70
|
if (url === "/mcp") {
|
|
75
71
|
if (req.method === "POST") {
|
|
76
|
-
// Sessao stateless ou nova sessao stateful
|
|
77
72
|
const sessionId = req.headers["mcp-session-id"];
|
|
78
|
-
let transport = sessionId ?
|
|
73
|
+
let transport = sessionId ? httpTransportes.get(sessionId) : undefined;
|
|
79
74
|
if (!transport) {
|
|
80
|
-
// Nova sessao
|
|
81
75
|
transport = new StreamableHTTPServerTransport({
|
|
82
76
|
sessionIdGenerator: () => crypto.randomUUID(),
|
|
83
|
-
onsessioninitialized: (id) => {
|
|
77
|
+
onsessioninitialized: (id) => { httpTransportes.set(id, transport); },
|
|
84
78
|
});
|
|
85
79
|
transport.onclose = () => {
|
|
86
80
|
if (transport.sessionId)
|
|
87
|
-
|
|
81
|
+
httpTransportes.delete(transport.sessionId);
|
|
88
82
|
};
|
|
89
|
-
|
|
83
|
+
const s = new McpServer({ name: "sema", version: "1.2.18" });
|
|
84
|
+
registrarFerramentas(s);
|
|
85
|
+
await s.connect(transport);
|
|
90
86
|
}
|
|
91
87
|
await transport.handleRequest(req, res);
|
|
92
88
|
return;
|
|
93
89
|
}
|
|
94
90
|
if (req.method === "GET" || req.method === "DELETE") {
|
|
95
91
|
const sessionId = req.headers["mcp-session-id"];
|
|
96
|
-
const transport = sessionId ?
|
|
92
|
+
const transport = sessionId ? httpTransportes.get(sessionId) : undefined;
|
|
97
93
|
if (!transport) {
|
|
98
94
|
res.writeHead(404).end("Sessao nao encontrada");
|
|
99
95
|
return;
|
|
@@ -102,14 +98,36 @@ if (porta) {
|
|
|
102
98
|
return;
|
|
103
99
|
}
|
|
104
100
|
}
|
|
101
|
+
// SSE legado — compatibilidade com GPT e clientes antigos
|
|
102
|
+
if (req.method === "GET" && url === "/sse") {
|
|
103
|
+
const sseTransport = new SSEServerTransport("/message", res);
|
|
104
|
+
sseTransportes.set(sseTransport.sessionId, sseTransport);
|
|
105
|
+
res.on("close", () => sseTransportes.delete(sseTransport.sessionId));
|
|
106
|
+
const s = new McpServer({ name: "sema", version: "1.2.18" });
|
|
107
|
+
registrarFerramentas(s);
|
|
108
|
+
await s.connect(sseTransport);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (req.method === "POST" && url.startsWith("/message")) {
|
|
112
|
+
const sessionId = new URL(url, "http://localhost").searchParams.get("sessionId") ?? "";
|
|
113
|
+
const sseTransport = sseTransportes.get(sessionId);
|
|
114
|
+
if (!sseTransport) {
|
|
115
|
+
res.writeHead(404).end("Sessao nao encontrada");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await sseTransport.handlePostMessage(req, res);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
105
121
|
res.writeHead(404).end();
|
|
106
122
|
});
|
|
107
123
|
http.listen(porta, () => {
|
|
108
|
-
process.stderr.write(`sema-mcp rodando
|
|
124
|
+
process.stderr.write(`sema-mcp rodando na porta ${porta} (HTTP: /mcp | SSE: /sse)\n`);
|
|
109
125
|
});
|
|
110
126
|
}
|
|
111
127
|
else {
|
|
112
|
-
// Modo stdio —
|
|
128
|
+
// Modo stdio — uso local com Claude Code, Cursor, VS Code
|
|
129
|
+
const server = new McpServer({ name: "sema", version: "1.2.18" });
|
|
130
|
+
registrarFerramentas(server);
|
|
113
131
|
const transport = new StdioServerTransport();
|
|
114
132
|
await server.connect(transport);
|
|
115
133
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semacode/mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Servidor MCP da Sema — expoe validacao, drift e contexto IA como ferramentas para agentes.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.10.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^22.
|
|
40
|
+
"@types/node": "^22.19.17",
|
|
41
41
|
"typescript": "^5.8.3"
|
|
42
42
|
}
|
|
43
43
|
}
|