sih-br-mcp 0.18.0 → 1.0.1
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/discover.d.ts +59 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +91 -0
- package/dist/discover.js.map +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +67 -16
- package/dist/http.js.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/pagination.d.ts +70 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +100 -0
- package/dist/pagination.js.map +1 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +44 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `server/discover` anuncia TODAS as revisões que o servidor atende, não só as
|
|
3
|
+
* modernas.
|
|
4
|
+
*
|
|
5
|
+
* O ACHADO. O `mcpscore` reprovava `protocol_version_supported_versions_include_negotiated`:
|
|
6
|
+
* o servidor negocia 2025-11-25 pelo handshake `initialize` — é a revisão que o
|
|
7
|
+
* próprio auditor negocia, e a que a maioria dos clientes fala hoje — mas o
|
|
8
|
+
* `server/discover` anunciava só `["2026-07-28"]`. A mensagem do auditor é
|
|
9
|
+
* explícita sobre as duas saídas: "add it to supportedVersions, or disable the
|
|
10
|
+
* legacy lifecycle". Desligar o ciclo legado trocaria 1 ponto por uma regressão
|
|
11
|
+
* de compatibilidade com quase todos os clientes; sobra anunciar a verdade.
|
|
12
|
+
*
|
|
13
|
+
* NO SIH, A REGRA SÓ APARECE DEPOIS DA OUTRA. Até 25/09/2026 o contêiner
|
|
14
|
+
* atendia o HTTP por `server.connect(transport)` + `handleRequest`, o caminho
|
|
15
|
+
* LEGADO do SDK: não havia `server/discover` nenhum (HTTP 400 "Unsupported
|
|
16
|
+
* protocol version: 2026-07-28"), e o auditor reprovava a regra de cima,
|
|
17
|
+
* `protocol_version_latest` (MEDIUM, 2 pontos, `modern_lifecycle_support:
|
|
18
|
+
* false`). A entrada passou a ser `createMcpHandler` + `toNodeHandler`
|
|
19
|
+
* (src/http.ts), que serve as duas eras — e aí o discover existe, anuncia só a
|
|
20
|
+
* moderna, e este módulo completa o anúncio. No stdio o `serveStdio` já era
|
|
21
|
+
* dual-era, e a regra reprovava exatamente como no ilo.
|
|
22
|
+
*
|
|
23
|
+
* POR QUE O SDK NÃO FAZ ISSO. O `_ondiscover()` do
|
|
24
|
+
* `@modelcontextprotocol/server` 2.0.0 devolve
|
|
25
|
+
* `modernProtocolVersions(this._supportedProtocolVersions)`, um filtro que
|
|
26
|
+
* descarta por desenho toda revisão pré-2026 ("2025-era versions are negotiated
|
|
27
|
+
* via `initialize`"). Não há opção que o desligue. É uma leitura mais estrita
|
|
28
|
+
* que a do auditor, que se apoia em Basic §Versioning — onde o exemplo de
|
|
29
|
+
* `UnsupportedProtocolVersionError` lista revisões legadas em `supported`.
|
|
30
|
+
*
|
|
31
|
+
* POR QUE PATCH DE MÉTODO, E NÃO TROCA DE HANDLER. Registrar o nosso próprio
|
|
32
|
+
* handler de `server/discover` não gruda: a entrada HTTP do SDK instala
|
|
33
|
+
* `() => server._ondiscover()` na instância que a factory devolve, A CADA
|
|
34
|
+
* REQUEST, depois da nossa factory. Como o que ela instala é uma closure que
|
|
35
|
+
* chama o MÉTODO, trocar o método vale para os dois caminhos — o handler do
|
|
36
|
+
* construtor e o reinstalado — e sobrevive à reinstalação.
|
|
37
|
+
*
|
|
38
|
+
* A GUARDA. Isto mexe em `_ondiscover`, que é interno do SDK. O risco de um
|
|
39
|
+
* patch assim é virar silêncio: o SDK renomeia o método, o patch não aplica
|
|
40
|
+
* nada e ninguém percebe. Por isso `announceServedVersions` FALHA ALTO se a
|
|
41
|
+
* forma esperada não estiver lá — o servidor nem constrói — em vez de seguir
|
|
42
|
+
* com o anúncio antigo. `tests/discover.test.ts` prende o comportamento, e a
|
|
43
|
+
* catraca do mcpscore no CI (.github/workflows/mcpscore.yml) pega a regressão
|
|
44
|
+
* pelo lado de fora. Transplantado do ilo-mcp-server, a implementação de
|
|
45
|
+
* referência do portfólio (mesmo SDK 2.0.0).
|
|
46
|
+
*/
|
|
47
|
+
import type { McpServer } from "@modelcontextprotocol/server";
|
|
48
|
+
/**
|
|
49
|
+
* Ordena revisões datadas da mais nova para a mais antiga. São strings
|
|
50
|
+
* `AAAA-MM-DD`, então a ordem lexicográfica É a cronológica.
|
|
51
|
+
*/
|
|
52
|
+
export declare function maisNovaPrimeiro(versoes: readonly string[]): string[];
|
|
53
|
+
/**
|
|
54
|
+
* Troca o `_ondiscover` da instância por um que anuncia todas as revisões
|
|
55
|
+
* atendidas. Só a lista muda: capacidades e instruções continuam vindo do
|
|
56
|
+
* cálculo do próprio SDK.
|
|
57
|
+
*/
|
|
58
|
+
export declare function announceServedVersions(server: McpServer): void;
|
|
59
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAQ9D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAErE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsC9D"}
|
package/dist/discover.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `server/discover` anuncia TODAS as revisões que o servidor atende, não só as
|
|
3
|
+
* modernas.
|
|
4
|
+
*
|
|
5
|
+
* O ACHADO. O `mcpscore` reprovava `protocol_version_supported_versions_include_negotiated`:
|
|
6
|
+
* o servidor negocia 2025-11-25 pelo handshake `initialize` — é a revisão que o
|
|
7
|
+
* próprio auditor negocia, e a que a maioria dos clientes fala hoje — mas o
|
|
8
|
+
* `server/discover` anunciava só `["2026-07-28"]`. A mensagem do auditor é
|
|
9
|
+
* explícita sobre as duas saídas: "add it to supportedVersions, or disable the
|
|
10
|
+
* legacy lifecycle". Desligar o ciclo legado trocaria 1 ponto por uma regressão
|
|
11
|
+
* de compatibilidade com quase todos os clientes; sobra anunciar a verdade.
|
|
12
|
+
*
|
|
13
|
+
* NO SIH, A REGRA SÓ APARECE DEPOIS DA OUTRA. Até 25/09/2026 o contêiner
|
|
14
|
+
* atendia o HTTP por `server.connect(transport)` + `handleRequest`, o caminho
|
|
15
|
+
* LEGADO do SDK: não havia `server/discover` nenhum (HTTP 400 "Unsupported
|
|
16
|
+
* protocol version: 2026-07-28"), e o auditor reprovava a regra de cima,
|
|
17
|
+
* `protocol_version_latest` (MEDIUM, 2 pontos, `modern_lifecycle_support:
|
|
18
|
+
* false`). A entrada passou a ser `createMcpHandler` + `toNodeHandler`
|
|
19
|
+
* (src/http.ts), que serve as duas eras — e aí o discover existe, anuncia só a
|
|
20
|
+
* moderna, e este módulo completa o anúncio. No stdio o `serveStdio` já era
|
|
21
|
+
* dual-era, e a regra reprovava exatamente como no ilo.
|
|
22
|
+
*
|
|
23
|
+
* POR QUE O SDK NÃO FAZ ISSO. O `_ondiscover()` do
|
|
24
|
+
* `@modelcontextprotocol/server` 2.0.0 devolve
|
|
25
|
+
* `modernProtocolVersions(this._supportedProtocolVersions)`, um filtro que
|
|
26
|
+
* descarta por desenho toda revisão pré-2026 ("2025-era versions are negotiated
|
|
27
|
+
* via `initialize`"). Não há opção que o desligue. É uma leitura mais estrita
|
|
28
|
+
* que a do auditor, que se apoia em Basic §Versioning — onde o exemplo de
|
|
29
|
+
* `UnsupportedProtocolVersionError` lista revisões legadas em `supported`.
|
|
30
|
+
*
|
|
31
|
+
* POR QUE PATCH DE MÉTODO, E NÃO TROCA DE HANDLER. Registrar o nosso próprio
|
|
32
|
+
* handler de `server/discover` não gruda: a entrada HTTP do SDK instala
|
|
33
|
+
* `() => server._ondiscover()` na instância que a factory devolve, A CADA
|
|
34
|
+
* REQUEST, depois da nossa factory. Como o que ela instala é uma closure que
|
|
35
|
+
* chama o MÉTODO, trocar o método vale para os dois caminhos — o handler do
|
|
36
|
+
* construtor e o reinstalado — e sobrevive à reinstalação.
|
|
37
|
+
*
|
|
38
|
+
* A GUARDA. Isto mexe em `_ondiscover`, que é interno do SDK. O risco de um
|
|
39
|
+
* patch assim é virar silêncio: o SDK renomeia o método, o patch não aplica
|
|
40
|
+
* nada e ninguém percebe. Por isso `announceServedVersions` FALHA ALTO se a
|
|
41
|
+
* forma esperada não estiver lá — o servidor nem constrói — em vez de seguir
|
|
42
|
+
* com o anúncio antigo. `tests/discover.test.ts` prende o comportamento, e a
|
|
43
|
+
* catraca do mcpscore no CI (.github/workflows/mcpscore.yml) pega a regressão
|
|
44
|
+
* pelo lado de fora. Transplantado do ilo-mcp-server, a implementação de
|
|
45
|
+
* referência do portfólio (mesmo SDK 2.0.0).
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Ordena revisões datadas da mais nova para a mais antiga. São strings
|
|
49
|
+
* `AAAA-MM-DD`, então a ordem lexicográfica É a cronológica.
|
|
50
|
+
*/
|
|
51
|
+
export function maisNovaPrimeiro(versoes) {
|
|
52
|
+
return [...new Set(versoes)].sort().reverse();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Troca o `_ondiscover` da instância por um que anuncia todas as revisões
|
|
56
|
+
* atendidas. Só a lista muda: capacidades e instruções continuam vindo do
|
|
57
|
+
* cálculo do próprio SDK.
|
|
58
|
+
*/
|
|
59
|
+
export function announceServedVersions(server) {
|
|
60
|
+
const low = server.server;
|
|
61
|
+
if (typeof low._ondiscover !== "function") {
|
|
62
|
+
throw new Error("SDK mudou: Server._ondiscover sumiu — o anúncio de versões em src/discover.ts " +
|
|
63
|
+
"deixaria de aplicar em silêncio. Reveja o módulo contra a versão nova do " +
|
|
64
|
+
"@modelcontextprotocol/server antes de seguir.");
|
|
65
|
+
}
|
|
66
|
+
if (!Array.isArray(low._supportedProtocolVersions) ||
|
|
67
|
+
low._supportedProtocolVersions.some((v) => typeof v !== "string")) {
|
|
68
|
+
throw new Error("SDK mudou: Server._supportedProtocolVersions não é mais uma lista de strings — " +
|
|
69
|
+
"src/discover.ts não tem de onde tirar as revisões atendidas.");
|
|
70
|
+
}
|
|
71
|
+
const original = low._ondiscover.bind(low);
|
|
72
|
+
low._ondiscover = () => {
|
|
73
|
+
const base = original();
|
|
74
|
+
// LER NA HORA DA CHAMADA, não aqui na aplicação do patch. O
|
|
75
|
+
// `installDiscoverHandler` do SDK ACRESCENTA as revisões modernas a
|
|
76
|
+
// `_supportedProtocolVersions` por REATRIBUIÇÃO, já com o servidor
|
|
77
|
+
// construído: uma referência capturada agora ficaria presa ao array
|
|
78
|
+
// anterior. Foi o que aconteceu na primeira versão deste módulo no ilo — o
|
|
79
|
+
// anúncio saiu com as cinco revisões legadas e SEM a 2026-07-28, e a regra
|
|
80
|
+
// do auditor passou assim mesmo, porque ela só confere se a negociada está
|
|
81
|
+
// na lista. Trocar uma omissão por outra não é corrigir.
|
|
82
|
+
const agora = low._supportedProtocolVersions;
|
|
83
|
+
if (!Array.isArray(agora) || agora.some((v) => typeof v !== "string"))
|
|
84
|
+
return base;
|
|
85
|
+
// A lista vem do próprio SDK, nunca de literais nossas: anunciar uma
|
|
86
|
+
// revisão que o servidor não atende seria a mentira simétrica da que este
|
|
87
|
+
// módulo corrige.
|
|
88
|
+
return { ...base, supportedVersions: maisNovaPrimeiro(agora) };
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAUH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAwC,CAAC;IAE5D,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,gFAAgF;YAC9E,2EAA2E;YAC3E,+CAA+C,CAClD,CAAC;IACJ,CAAC;IACD,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QAC9C,GAAG,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EACjE,CAAC;QACD,MAAM,IAAI,KAAK,CACb,iFAAiF;YAC/E,8DAA8D,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,GAAG,CAAC,WAAW,GAAG,GAAG,EAAE;QACrB,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;QACxB,4DAA4D;QAC5D,oEAAoE;QACpE,mEAAmE;QACnE,oEAAoE;QACpE,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,yDAAyD;QACzD,MAAM,KAAK,GAAG,GAAG,CAAC,0BAA0B,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACnF,qEAAqE;QACrE,0EAA0E;QAC1E,kBAAkB;QAClB,OAAO,EAAE,GAAG,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,KAAiB,CAAC,EAAE,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAqDA,eAAO,MAAM,QAAQ,SAAS,CAAC"}
|
package/dist/http.js
CHANGED
|
@@ -5,16 +5,31 @@
|
|
|
5
5
|
* transporte.
|
|
6
6
|
*
|
|
7
7
|
* Rotas:
|
|
8
|
-
* POST/GET/DELETE /mcp — Streamable HTTP
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* POST/GET/DELETE /mcp — Streamable HTTP pelo `createMcpHandler` do SDK,
|
|
9
|
+
* adaptado ao node:http por `toNodeHandler`: serve
|
|
10
|
+
* as DUAS eras do protocolo — 2026-07-28 (envelope
|
|
11
|
+
* por request, `server/discover`) e 2025 pelo
|
|
12
|
+
* fallback STATELESS (McpServer e transporte novos
|
|
13
|
+
* por request, `sessionIdGenerator: undefined`, o
|
|
14
|
+
* mesmo modelo "API-style" de antes). Resposta em
|
|
15
|
+
* SSE nas duas eras (`responseMode: "sse"`), com
|
|
16
|
+
* keepalive: a série de 34 anos leva ~30 s e a
|
|
13
17
|
* conexão precisa ficar viva pelo proxy.
|
|
14
18
|
* GET /healthz — 200 com versão e anos em cache; NÃO abre o DuckDB
|
|
15
19
|
* nem baixa nada (é o que o Worker sonda antes de
|
|
16
20
|
* encaminhar).
|
|
17
21
|
*
|
|
22
|
+
* POR QUE `createMcpHandler`, E NÃO `server.connect(transport)` + `handleRequest`.
|
|
23
|
+
* Até 25/09/2026 era o segundo — o caminho LEGADO do SDK: só a era 2025, sem
|
|
24
|
+
* `server/discover`, e o cabeçalho MCP-Protocol-Version: 2026-07-28 voltava
|
|
25
|
+
* HTTP 400 "Unsupported protocol version". O mcpscore lia isso como
|
|
26
|
+
* `modern_lifecycle_support: false` e reprovava `protocol_version_latest`
|
|
27
|
+
* (MEDIUM, 2 dos 4 pontos que faltavam para 76/76). A entrada dual-era é a
|
|
28
|
+
* mesma dos seis irmãos em Worker (`createMcpHandler` direto) e a mesma do
|
|
29
|
+
* stdio deste pacote (`serveStdio`, que já era dual-era). O contêiner continua
|
|
30
|
+
* sem validar Host/Origin — a entrada é "deliberately validation-free", e o
|
|
31
|
+
* Worker é o único que fala com ele.
|
|
32
|
+
*
|
|
18
33
|
* O que NÃO fica aqui, de propósito: validação de Origin/Host, rate limit,
|
|
19
34
|
* bearer, Analytics Engine — tudo no Worker de borda, que é o único que fala
|
|
20
35
|
* com este processo (as opções allowedHosts/allowedOrigins do SDK estão
|
|
@@ -24,9 +39,11 @@
|
|
|
24
39
|
* (SIH_CACHE_DIR, SIH_DATA_DIR, SIH_CUBES_BASE_URL, SIH_FRESHNESS_CHECK...).
|
|
25
40
|
*/
|
|
26
41
|
import { createServer as createHttpServer } from "node:http";
|
|
27
|
-
import {
|
|
42
|
+
import { toNodeHandler } from "@modelcontextprotocol/node";
|
|
43
|
+
import { createMcpHandler } from "@modelcontextprotocol/server";
|
|
28
44
|
import { closeDatabase, getAvailableYears } from "./db/duckdb.js";
|
|
29
45
|
import { startFreshnessCheck } from "./freshness.js";
|
|
46
|
+
import { unknownCursorErrorFromText } from "./pagination.js";
|
|
30
47
|
import { SERVER_VERSION } from "./provenance.js";
|
|
31
48
|
import { createServer, SERVER_NAME } from "./server.js";
|
|
32
49
|
const PORT = Number(process.env.PORT ?? 8080);
|
|
@@ -36,17 +53,50 @@ function sendJson(res, status, body) {
|
|
|
36
53
|
res.writeHead(status, { "content-type": "application/json" });
|
|
37
54
|
res.end(JSON.stringify(body));
|
|
38
55
|
}
|
|
56
|
+
// UM handler por processo, UMA instância de servidor por request (a factory
|
|
57
|
+
// é chamada a cada exchange, nas duas eras). O handler fecha o que abre.
|
|
58
|
+
const mcpHandler = createMcpHandler(() => createServer(), {
|
|
59
|
+
legacy: "stateless",
|
|
60
|
+
responseMode: "sse",
|
|
61
|
+
onerror: (error) => console.error("[http] erro do handler MCP:", error),
|
|
62
|
+
});
|
|
63
|
+
const serveMcp = toNodeHandler(mcpHandler, {
|
|
64
|
+
onerror: (error) => console.error("[http] erro no adaptador node:", error),
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* Um `IncomingMessage` já lido, reapresentado ao adaptador do SDK como o
|
|
68
|
+
* mínimo que ele consome (método, URL, cabeçalhos e o corpo como iterável).
|
|
69
|
+
* O guarda de cursor precisa do corpo ANTES do handler, e o stream do Node só
|
|
70
|
+
* se lê uma vez.
|
|
71
|
+
*/
|
|
72
|
+
function reapresentado(req, corpo) {
|
|
73
|
+
return {
|
|
74
|
+
method: req.method,
|
|
75
|
+
url: req.url,
|
|
76
|
+
headers: req.headers,
|
|
77
|
+
async *[Symbol.asyncIterator]() {
|
|
78
|
+
yield corpo;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
39
82
|
async function handleMcp(req, res) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
83
|
+
if (req.method !== "POST") {
|
|
84
|
+
await serveMcp(req, res);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const pedacos = [];
|
|
88
|
+
for await (const pedaco of req)
|
|
89
|
+
pedacos.push(Buffer.isBuffer(pedaco) ? pedaco : Buffer.from(String(pedaco)));
|
|
90
|
+
const corpo = Buffer.concat(pedacos);
|
|
91
|
+
// Cursor de paginação inválido → -32602 (src/pagination.ts), a mesma recusa
|
|
92
|
+
// do stdio. 200 com o erro JSON-RPC no corpo: a falha é de protocolo, não de
|
|
93
|
+
// HTTP — é assim que o cliente MCP lê o código.
|
|
94
|
+
const recusa = unknownCursorErrorFromText(corpo.toString("utf8"));
|
|
95
|
+
if (recusa) {
|
|
96
|
+
sendJson(res, 200, recusa);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await serveMcp(reapresentado(req, corpo), res);
|
|
50
100
|
}
|
|
51
101
|
const httpServer = createHttpServer((req, res) => {
|
|
52
102
|
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
@@ -87,6 +137,7 @@ async function shutdown(signal) {
|
|
|
87
137
|
// consider calling start()" em toda chamada). Medido em 09/09/2026.
|
|
88
138
|
setTimeout(() => process.exit(0), 5_000).unref();
|
|
89
139
|
httpServer.close();
|
|
140
|
+
await mcpHandler.close().catch(() => undefined);
|
|
90
141
|
await closeDatabase();
|
|
91
142
|
process.exit(0);
|
|
92
143
|
}
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,14 +5,38 @@
|
|
|
5
5
|
* A construção do servidor vive em src/server.ts (factory sem efeito
|
|
6
6
|
* colateral); aqui só se liga ao transporte. stdout é o canal do protocolo,
|
|
7
7
|
* então todo log vai para o stderr. A entrada HTTP é src/http.ts.
|
|
8
|
+
*
|
|
9
|
+
* O transporte é construído À MÃO e entregue ao `serveStdio` pela opção
|
|
10
|
+
* `transport`, em vez de deixá-lo construir o dele: é a única forma de pôr o
|
|
11
|
+
* guarda de cursor (src/pagination.ts) na frente do `onmessage` SEM abrir mão
|
|
12
|
+
* do `serveStdio` — que é quem atende as duas eras do protocolo (2025 por
|
|
13
|
+
* `initialize`, 2026-07-28 por `server/discover`). `server.connect(transport)`
|
|
14
|
+
* direto atenderia só o ciclo legado e mediria menos regras no mcpscore
|
|
15
|
+
* (armadilha medida no senado em 30/08/2026: 127/144 contra 146/148).
|
|
8
16
|
*/
|
|
9
|
-
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
17
|
+
import { serveStdio, StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
10
18
|
import { closeDatabase } from "./db/duckdb.js";
|
|
11
19
|
import { startFreshnessCheck } from "./freshness.js";
|
|
20
|
+
import { unknownCursorError } from "./pagination.js";
|
|
12
21
|
import { createServer } from "./server.js";
|
|
22
|
+
const transport = new StdioServerTransport();
|
|
13
23
|
serveStdio(() => createServer(), {
|
|
24
|
+
transport,
|
|
14
25
|
onerror: (error) => console.error("Transport error:", error),
|
|
15
26
|
});
|
|
27
|
+
// Cursor de paginação inválido → -32602, o mesmo guarda que o contêiner aplica
|
|
28
|
+
// no POST (src/pagination.ts). Entra DEPOIS do serveStdio porque é ele que
|
|
29
|
+
// instala o `onmessage` do transporte (síncrono, na própria chamada):
|
|
30
|
+
// envolvê-lo antes só somaria um ouvinte, sem poder de interromper a entrega.
|
|
31
|
+
const entregaAoServidor = transport.onmessage;
|
|
32
|
+
transport.onmessage = (message) => {
|
|
33
|
+
const recusa = unknownCursorError(message);
|
|
34
|
+
if (recusa) {
|
|
35
|
+
void transport.send(recusa);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
entregaAoServidor?.(message);
|
|
39
|
+
};
|
|
16
40
|
console.error("SIH-BR-MCP Server iniciado");
|
|
17
41
|
// Frescor dos cubos: sonda o manifesto do espelho em segundo plano (512
|
|
18
42
|
// bytes; só baixa os 10 MB se o manifesto mudou), com timeout curto. Não
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,EAAE;IAC/B,SAAS;IACT,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC;CAC7D,CAAC,CAAC;AAEH,+EAA+E;AAC/E,2EAA2E;AAC3E,sEAAsE;AACtE,8EAA8E;AAC9E,MAAM,iBAAiB,GAAG,SAAS,CAAC,SAAS,CAAC;AAC9C,SAAS,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,EAAE;IAChC,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IACD,iBAAiB,EAAE,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAE5C,wEAAwE;AACxE,yEAAyE;AACzE,yEAAyE;AACzE,KAAK,mBAAmB,EAAE,CAAC;AAE3B,sBAAsB;AACtB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,aAAa,EAAE,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;IAC/B,MAAM,aAAa,EAAE,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor de paginação inválido — a recusa que o SDK não faz.
|
|
3
|
+
*
|
|
4
|
+
* O PROBLEMA. A única lista deste servidor (`tools/list`, doze ferramentas)
|
|
5
|
+
* cabe numa página só, então nenhuma resposta traz `nextCursor` e nenhum
|
|
6
|
+
* cursor emitido por este servidor existe. O handler de lista do
|
|
7
|
+
* `@modelcontextprotocol/server` 2.0.0 simplesmente IGNORA `params.cursor` e
|
|
8
|
+
* devolve a lista inteira — inclusive para um cursor que o servidor nunca
|
|
9
|
+
* emitiu. A spec (§Pagination, Error Handling, em toda revisão datada) diz que
|
|
10
|
+
* cursor inválido DEVE virar `-32602`, e o `mcpscore` reprovava
|
|
11
|
+
* `pagination_tools_invalid_cursor` nos dois transportes (medido em
|
|
12
|
+
* 25/09/2026: 72/76 em produção, 98/103 no stdio — esta era uma das três
|
|
13
|
+
* regras que faltavam).
|
|
14
|
+
*
|
|
15
|
+
* POR QUE AQUI, E NÃO NO HANDLER DO SDK. Sobrescrever `tools/list` exigiria
|
|
16
|
+
* reimplementar a listagem a partir do registro privado do McpServer
|
|
17
|
+
* (`_registeredTools`, com a conversão de schema junto) — trocar um defeito
|
|
18
|
+
* pequeno por uma cópia do SDK que envelhece sozinha. A recusa é uma decisão
|
|
19
|
+
* sobre a MENSAGEM, não sobre o conteúdo da lista, então mora na borda por onde
|
|
20
|
+
* a mensagem entra: o `onmessage` do transporte stdio (src/index.ts) e o POST
|
|
21
|
+
* do contêiner (src/http.ts). O predicado é o mesmo nos dois — este módulo,
|
|
22
|
+
* transplantado do ilo-mcp-server (a implementação de referência do portfólio,
|
|
23
|
+
* 182/182 com o mesmo SDK).
|
|
24
|
+
*
|
|
25
|
+
* NO CONTÊINER, E NÃO NO WORKER DE BORDA. O Worker (worker/src/index.ts) já lê
|
|
26
|
+
* uma cópia do corpo para a telemetria e poderia recusar ali — mas o
|
|
27
|
+
* `smoke:http` e o mcpscore `--stdio` medem o contêiner e o pacote SEM o
|
|
28
|
+
* Worker, e uma recusa que só existe na borda deixaria os dois canais medidos
|
|
29
|
+
* diferentes do que o usuário do domínio recebe.
|
|
30
|
+
*
|
|
31
|
+
* ENQUANTO NÃO HOUVER SEGUNDA PÁGINA. Se algum dia uma lista passar a paginar
|
|
32
|
+
* de verdade, este módulo deixa de valer: a recusa passa a ser "cursor que não
|
|
33
|
+
* decodifica", e quem emite o cursor é quem sabe reconhecê-lo. O teste
|
|
34
|
+
* tests/pagination.test.ts prende a premissa (nenhuma lista emite nextCursor)
|
|
35
|
+
* para que a mudança não passe em silêncio.
|
|
36
|
+
*/
|
|
37
|
+
/** Código JSON-RPC de parâmetro inválido (spec §Pagination, Error Handling). */
|
|
38
|
+
export declare const INVALID_PARAMS = -32602;
|
|
39
|
+
/**
|
|
40
|
+
* Os quatro métodos de lista paginável do MCP. O sih só serve `tools/list`
|
|
41
|
+
* (sem resources nem prompts), mas o guarda cobre os quatro: um cliente que
|
|
42
|
+
* pergunte `resources/list` com cursor recebe a recusa certa em vez de cair no
|
|
43
|
+
* "método não encontrado" do SDK — e se um dia entrarem resources ou prompts,
|
|
44
|
+
* a recusa já os cobre.
|
|
45
|
+
*/
|
|
46
|
+
export declare const PAGINATED_LIST_METHODS: readonly ["tools/list", "resources/list", "resources/templates/list", "prompts/list"];
|
|
47
|
+
/** Resposta de erro JSON-RPC — a forma que os dois transportes enviam. */
|
|
48
|
+
export interface JsonRpcErrorResponse {
|
|
49
|
+
jsonrpc: "2.0";
|
|
50
|
+
id: string | number;
|
|
51
|
+
error: {
|
|
52
|
+
code: number;
|
|
53
|
+
message: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Devolve a recusa `-32602` quando a mensagem é uma requisição de lista que
|
|
58
|
+
* carrega `cursor`; `undefined` em qualquer outro caso (inclusive notificação,
|
|
59
|
+
* lote e mensagem malformada — nenhum deles é assunto deste guarda, e o SDK
|
|
60
|
+
* responde por eles).
|
|
61
|
+
*/
|
|
62
|
+
export declare function unknownCursorError(message: unknown): JsonRpcErrorResponse | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Adaptador da borda HTTP do contêiner: recebe o corpo do POST já lido como
|
|
65
|
+
* texto e decide. Corpo que não é JSON não é assunto daqui — o handler do SDK
|
|
66
|
+
* dá o erro dele (-32700), e por isso o texto cru é devolvido intacto ao
|
|
67
|
+
* handler por quem chama (src/http.ts), nunca reinterpretado aqui.
|
|
68
|
+
*/
|
|
69
|
+
export declare function unknownCursorErrorFromText(text: string): JsonRpcErrorResponse | undefined;
|
|
70
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,gFAAgF;AAChF,eAAO,MAAM,cAAc,SAAS,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,YACjC,YAAY,EACZ,gBAAgB,EAChB,0BAA0B,EAC1B,cAAc,CACN,CAAC;AAEX,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AASD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAqBrF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAQzF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor de paginação inválido — a recusa que o SDK não faz.
|
|
3
|
+
*
|
|
4
|
+
* O PROBLEMA. A única lista deste servidor (`tools/list`, doze ferramentas)
|
|
5
|
+
* cabe numa página só, então nenhuma resposta traz `nextCursor` e nenhum
|
|
6
|
+
* cursor emitido por este servidor existe. O handler de lista do
|
|
7
|
+
* `@modelcontextprotocol/server` 2.0.0 simplesmente IGNORA `params.cursor` e
|
|
8
|
+
* devolve a lista inteira — inclusive para um cursor que o servidor nunca
|
|
9
|
+
* emitiu. A spec (§Pagination, Error Handling, em toda revisão datada) diz que
|
|
10
|
+
* cursor inválido DEVE virar `-32602`, e o `mcpscore` reprovava
|
|
11
|
+
* `pagination_tools_invalid_cursor` nos dois transportes (medido em
|
|
12
|
+
* 25/09/2026: 72/76 em produção, 98/103 no stdio — esta era uma das três
|
|
13
|
+
* regras que faltavam).
|
|
14
|
+
*
|
|
15
|
+
* POR QUE AQUI, E NÃO NO HANDLER DO SDK. Sobrescrever `tools/list` exigiria
|
|
16
|
+
* reimplementar a listagem a partir do registro privado do McpServer
|
|
17
|
+
* (`_registeredTools`, com a conversão de schema junto) — trocar um defeito
|
|
18
|
+
* pequeno por uma cópia do SDK que envelhece sozinha. A recusa é uma decisão
|
|
19
|
+
* sobre a MENSAGEM, não sobre o conteúdo da lista, então mora na borda por onde
|
|
20
|
+
* a mensagem entra: o `onmessage` do transporte stdio (src/index.ts) e o POST
|
|
21
|
+
* do contêiner (src/http.ts). O predicado é o mesmo nos dois — este módulo,
|
|
22
|
+
* transplantado do ilo-mcp-server (a implementação de referência do portfólio,
|
|
23
|
+
* 182/182 com o mesmo SDK).
|
|
24
|
+
*
|
|
25
|
+
* NO CONTÊINER, E NÃO NO WORKER DE BORDA. O Worker (worker/src/index.ts) já lê
|
|
26
|
+
* uma cópia do corpo para a telemetria e poderia recusar ali — mas o
|
|
27
|
+
* `smoke:http` e o mcpscore `--stdio` medem o contêiner e o pacote SEM o
|
|
28
|
+
* Worker, e uma recusa que só existe na borda deixaria os dois canais medidos
|
|
29
|
+
* diferentes do que o usuário do domínio recebe.
|
|
30
|
+
*
|
|
31
|
+
* ENQUANTO NÃO HOUVER SEGUNDA PÁGINA. Se algum dia uma lista passar a paginar
|
|
32
|
+
* de verdade, este módulo deixa de valer: a recusa passa a ser "cursor que não
|
|
33
|
+
* decodifica", e quem emite o cursor é quem sabe reconhecê-lo. O teste
|
|
34
|
+
* tests/pagination.test.ts prende a premissa (nenhuma lista emite nextCursor)
|
|
35
|
+
* para que a mudança não passe em silêncio.
|
|
36
|
+
*/
|
|
37
|
+
/** Código JSON-RPC de parâmetro inválido (spec §Pagination, Error Handling). */
|
|
38
|
+
export const INVALID_PARAMS = -32602;
|
|
39
|
+
/**
|
|
40
|
+
* Os quatro métodos de lista paginável do MCP. O sih só serve `tools/list`
|
|
41
|
+
* (sem resources nem prompts), mas o guarda cobre os quatro: um cliente que
|
|
42
|
+
* pergunte `resources/list` com cursor recebe a recusa certa em vez de cair no
|
|
43
|
+
* "método não encontrado" do SDK — e se um dia entrarem resources ou prompts,
|
|
44
|
+
* a recusa já os cobre.
|
|
45
|
+
*/
|
|
46
|
+
export const PAGINATED_LIST_METHODS = [
|
|
47
|
+
"tools/list",
|
|
48
|
+
"resources/list",
|
|
49
|
+
"resources/templates/list",
|
|
50
|
+
"prompts/list",
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Devolve a recusa `-32602` quando a mensagem é uma requisição de lista que
|
|
54
|
+
* carrega `cursor`; `undefined` em qualquer outro caso (inclusive notificação,
|
|
55
|
+
* lote e mensagem malformada — nenhum deles é assunto deste guarda, e o SDK
|
|
56
|
+
* responde por eles).
|
|
57
|
+
*/
|
|
58
|
+
export function unknownCursorError(message) {
|
|
59
|
+
if (typeof message !== "object" || message === null || Array.isArray(message))
|
|
60
|
+
return undefined;
|
|
61
|
+
const { jsonrpc, id, method, params } = message;
|
|
62
|
+
if (jsonrpc !== "2.0")
|
|
63
|
+
return undefined;
|
|
64
|
+
// Sem id é notificação: não existe resposta para devolver.
|
|
65
|
+
if (typeof id !== "string" && typeof id !== "number")
|
|
66
|
+
return undefined;
|
|
67
|
+
if (typeof method !== "string")
|
|
68
|
+
return undefined;
|
|
69
|
+
if (!PAGINATED_LIST_METHODS.includes(method))
|
|
70
|
+
return undefined;
|
|
71
|
+
if (params === null || typeof params !== "object" || params.cursor === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
return {
|
|
74
|
+
jsonrpc: "2.0",
|
|
75
|
+
id,
|
|
76
|
+
error: {
|
|
77
|
+
code: INVALID_PARAMS,
|
|
78
|
+
message: `Invalid params: unknown pagination cursor for ${method}. ` +
|
|
79
|
+
"This server returns every list in a single page and never issues a nextCursor, " +
|
|
80
|
+
"so no cursor value is valid — retry without one.",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Adaptador da borda HTTP do contêiner: recebe o corpo do POST já lido como
|
|
86
|
+
* texto e decide. Corpo que não é JSON não é assunto daqui — o handler do SDK
|
|
87
|
+
* dá o erro dele (-32700), e por isso o texto cru é devolvido intacto ao
|
|
88
|
+
* handler por quem chama (src/http.ts), nunca reinterpretado aqui.
|
|
89
|
+
*/
|
|
90
|
+
export function unknownCursorErrorFromText(text) {
|
|
91
|
+
let corpo;
|
|
92
|
+
try {
|
|
93
|
+
corpo = JSON.parse(text);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return unknownCursorError(corpo);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,gBAAgB;IAChB,0BAA0B;IAC1B,cAAc;CACN,CAAC;AAgBX;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAChG,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAA6B,CAAC;IACtE,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACxC,2DAA2D;IAC3D,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACvE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACjD,IAAI,CAAE,sBAA4C,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IACtF,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEnG,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE;QACF,KAAK,EAAE;YACL,IAAI,EAAE,cAAc;YACpB,OAAO,EACL,iDAAiD,MAAM,IAAI;gBAC3D,iFAAiF;gBACjF,kDAAkD;SACrD;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -15,6 +15,20 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
17
17
|
export declare const SERVER_NAME = "sih-br-mcp";
|
|
18
|
+
export declare const SERVER_WEBSITE_URL = "https://sih.sidneybissoli.com";
|
|
18
19
|
export declare const SERVER_TITLE = "DATASUS SIH/SUS \u2014 Brazil Hospital Admissions (AIH) MCP";
|
|
20
|
+
/**
|
|
21
|
+
* Instruções do handshake MCP (`initialize.result.instructions`): o que o
|
|
22
|
+
* servidor cobre, o fluxo típico entre as doze ferramentas e quando o cliente
|
|
23
|
+
* NÃO deve usá-lo (critério de review de conectores da Anthropic; regra
|
|
24
|
+
* `server_instructions_present` do mcpscore, reprovada até 25/09/2026). Em
|
|
25
|
+
* inglês, como o título e o server.json — é o texto que o modelo lê, e o
|
|
26
|
+
* vocabulário da pergunta em inglês ("hospital admissions", "ICD-10", "AIH") é
|
|
27
|
+
* o que a ação GEO de 13/09/2026 fixou para as superfícies públicas. As doze
|
|
28
|
+
* ferramentas são citadas pelo nome, e tests/instructions.test.ts prende os
|
|
29
|
+
* dois lados: todo nome citado existe, e toda ferramenta é citada — uma
|
|
30
|
+
* ferramenta nova sem lugar no fluxo reprova ali, não no chat.
|
|
31
|
+
*/
|
|
32
|
+
export declare const SERVER_INSTRUCTIONS: string;
|
|
19
33
|
export declare function createServer(): McpServer;
|
|
20
34
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,SAAS,EAOV,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,SAAS,EAOV,MAAM,8BAA8B,CAAC;AAOtC,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,kBAAkB,kCAAkC,CAAC;AASlE,eAAO,MAAM,YAAY,gEAA2D,CAAC;AAErF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,QAe8B,CAAC;AAiD/D,wBAAgB,YAAY,IAAI,SAAS,CAmCxC"}
|
package/dist/server.js
CHANGED
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer, fromJsonSchema, } from "@modelcontextprotocol/server";
|
|
17
17
|
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/server/validators/cf-worker";
|
|
18
|
+
import { announceServedVersions } from "./discover.js";
|
|
18
19
|
import { SERVER_VERSION } from "./provenance.js";
|
|
19
20
|
import { callTool, tools } from "./tools.js";
|
|
20
21
|
export const SERVER_NAME = "sih-br-mcp";
|
|
22
|
+
export const SERVER_WEBSITE_URL = "https://sih.sidneybissoli.com";
|
|
21
23
|
// O título canônico do produto, e ele mora em TRÊS superfícies que têm de
|
|
22
24
|
// concordar: este SERVER_TITLE (o que o cliente MCP mostra no handshake), o
|
|
23
25
|
// `title` do server.json (o que o registro oficial e os diretórios exibem) e o
|
|
@@ -27,6 +29,33 @@ export const SERVER_NAME = "sih-br-mcp";
|
|
|
27
29
|
// diretório outro. Passou despercebido por um dia porque os testes do worker,
|
|
28
30
|
// que comparam os três, não rodavam no CI (corrigido em 14/09).
|
|
29
31
|
export const SERVER_TITLE = "DATASUS SIH/SUS — Brazil Hospital Admissions (AIH) MCP";
|
|
32
|
+
/**
|
|
33
|
+
* Instruções do handshake MCP (`initialize.result.instructions`): o que o
|
|
34
|
+
* servidor cobre, o fluxo típico entre as doze ferramentas e quando o cliente
|
|
35
|
+
* NÃO deve usá-lo (critério de review de conectores da Anthropic; regra
|
|
36
|
+
* `server_instructions_present` do mcpscore, reprovada até 25/09/2026). Em
|
|
37
|
+
* inglês, como o título e o server.json — é o texto que o modelo lê, e o
|
|
38
|
+
* vocabulário da pergunta em inglês ("hospital admissions", "ICD-10", "AIH") é
|
|
39
|
+
* o que a ação GEO de 13/09/2026 fixou para as superfícies públicas. As doze
|
|
40
|
+
* ferramentas são citadas pelo nome, e tests/instructions.test.ts prende os
|
|
41
|
+
* dois lados: todo nome citado existe, e toda ferramenta é citada — uma
|
|
42
|
+
* ferramenta nova sem lugar no fluxo reprova ali, não no chat.
|
|
43
|
+
*/
|
|
44
|
+
export const SERVER_INSTRUCTIONS = "Brazilian hospital admissions from DATASUS SIH/SUS (AIH records, 1992-2025), read from " +
|
|
45
|
+
"pre-aggregated public cubes of the healthbr-data Parquet mirror, never from the FTP or " +
|
|
46
|
+
"TabNet: causes by ICD-10 chapter and group (ICD-9 before 1998), monthly series, ambulatory " +
|
|
47
|
+
"care sensitive conditions (ICSAP, the Brazilian list) and crude, age-specific or " +
|
|
48
|
+
"age-standardized rates per 100,000 by state and municipality. Every stratum carries " +
|
|
49
|
+
"admissions, length of stay, amount paid by SUS and deaths; every response carries a " +
|
|
50
|
+
"provenance block with the data vintage and the citation. Typical flow: get_available_years " +
|
|
51
|
+
"first (which years each cube covers), then get_hospitalizations for counts by cause, place, " +
|
|
52
|
+
"age, sex and race, get_hospitalization_trends for monthly or annual series, " +
|
|
53
|
+
"get_hospitalization_rates and compare_regions for rates; get_icsap, get_icsap_indicators, " +
|
|
54
|
+
"rank_csap_groups and compare_icsap_trends for ICSAP; list_cid_chapters, list_csap_groups and " +
|
|
55
|
+
"classify_as_csap resolve codes and groups before querying. Do not use this server for " +
|
|
56
|
+
"individual AIH records, for variables the cubes do not carry (procedure performed, facility " +
|
|
57
|
+
"CNES, secondary diagnosis) or for other DATASUS systems (SIM, SINASC, SIA, SINAN): use " +
|
|
58
|
+
"microdatasus, PySUS or the healthbr-data mirror for those.";
|
|
30
59
|
// Review de conectores do claude.ai (claude.com/docs/connectors/building/
|
|
31
60
|
// review-criteria, lido em 08/09/2026): toda ferramenta com `title` e
|
|
32
61
|
// `readOnlyHint`. As doze só leem: cubos agregados e população, do disco ou
|
|
@@ -72,7 +101,21 @@ const validadorPermissivo = {
|
|
|
72
101
|
},
|
|
73
102
|
};
|
|
74
103
|
export function createServer() {
|
|
75
|
-
const server = new McpServer({
|
|
104
|
+
const server = new McpServer({
|
|
105
|
+
name: SERVER_NAME,
|
|
106
|
+
version: SERVER_VERSION,
|
|
107
|
+
title: SERVER_TITLE,
|
|
108
|
+
// O site e o ícone no handshake (campos da revisão 2025-11-25). As
|
|
109
|
+
// MESMAS URLs do server.json: worker/tests/icon.test.ts prende os três
|
|
110
|
+
// lugares (bytes no Worker, serverInfo aqui, manifesto no registro)
|
|
111
|
+
// para o handshake e os diretórios nunca mostrarem imagens diferentes.
|
|
112
|
+
websiteUrl: SERVER_WEBSITE_URL,
|
|
113
|
+
icons: [{ src: `${SERVER_WEBSITE_URL}/icon.png`, mimeType: "image/png", sizes: ["512x512"] }],
|
|
114
|
+
}, { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS });
|
|
115
|
+
// server/discover anuncia todas as revisões atendidas, não só as modernas —
|
|
116
|
+
// ver src/discover.ts. Antes das tools: se o SDK mudar por baixo, o servidor
|
|
117
|
+
// falha ao construir e não meio-construído.
|
|
118
|
+
announceServedVersions(server);
|
|
76
119
|
for (const tool of tools) {
|
|
77
120
|
server.registerTool(tool.name, {
|
|
78
121
|
title: tool.title,
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,SAAS,EACT,cAAc,GAMf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAEhG,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAiB,MAAM,YAAY,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AACxC,0EAA0E;AAC1E,4EAA4E;AAC5E,+EAA+E;AAC/E,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,wDAAwD,CAAC;AAErF,0EAA0E;AAC1E,sEAAsE;AACtE,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,gCAAgC;AAChC,MAAM,SAAS,GAAoB;IACjC,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,kBAAkB,GAAG,IAAI,2BAA2B,EAAE,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAwB;IAC/C,YAAY;QACV,OAAO,CAAC,KAAc,EAAgC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAU,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;IACxH,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,SAAS,EACT,cAAc,GAMf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAEhG,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAiB,MAAM,YAAY,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AACxC,MAAM,CAAC,MAAM,kBAAkB,GAAG,+BAA+B,CAAC;AAClE,0EAA0E;AAC1E,4EAA4E;AAC5E,+EAA+E;AAC/E,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,wDAAwD,CAAC;AAErF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,yFAAyF;IACzF,yFAAyF;IACzF,6FAA6F;IAC7F,mFAAmF;IACnF,sFAAsF;IACtF,sFAAsF;IACtF,6FAA6F;IAC7F,8FAA8F;IAC9F,8EAA8E;IAC9E,4FAA4F;IAC5F,+FAA+F;IAC/F,wFAAwF;IACxF,8FAA8F;IAC9F,yFAAyF;IACzF,4DAA4D,CAAC;AAE/D,0EAA0E;AAC1E,sEAAsE;AACtE,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,gCAAgC;AAChC,MAAM,SAAS,GAAoB;IACjC,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,kBAAkB,GAAG,IAAI,2BAA2B,EAAE,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAwB;IAC/C,YAAY;QACV,OAAO,CAAC,KAAc,EAAgC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAU,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;IACxH,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;QACvB,KAAK,EAAE,YAAY;QACnB,mEAAmE;QACnE,uEAAuE;QACvE,oEAAoE;QACpE,uEAAuE;QACvE,UAAU,EAAE,kBAAkB;QAC9B,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,kBAAkB,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;KAC9F,EACD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CACnE,CAAC;IAEF,4EAA4E;IAC5E,6EAA6E;IAC7E,4CAA4C;IAC5C,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,cAAc,CAAW,IAAI,CAAC,WAA6B,EAAE,kBAAkB,CAAC;YAC7F,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,YAA8B,EAAE,mBAAmB,CAAC;YACtF,WAAW,EAAE,SAAS;SACvB,EACD,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sih-br-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"mcpName": "io.github.SidneyBissoli/sih-br-mcp",
|
|
5
5
|
"description": "Servidor MCP do DATASUS SIH/SUS: internações hospitalares do Brasil (AIH, 1992–2025) — causas CID-10 e CID-9, séries mensais, ICSAP e taxas por UF e município, sem baixar .dbc nem usar TabNet. Brazilian hospital admissions (SIH/SUS) MCP server.",
|
|
6
6
|
"repository": {
|