@sbissoli/mcp-surface 0.1.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/dist/replay.js ADDED
@@ -0,0 +1,220 @@
1
+ /**
2
+ * REPLAY RETROATIVO: cada versão publicada no npm, instalada num diretório
3
+ * temporário e interrogada por stdio, normalizada com a mesma função da trava;
4
+ * e o endpoint no ar comparado com a versão que o `/status` dele declara.
5
+ *
6
+ * A trava só protege daqui para a frente. A prova que achou o caso grave do
7
+ * leitor do dev.to (3g607) foi um replay — a superfície do dia da listagem
8
+ * contra a de hoje. Aqui o equivalente é rodar o histórico inteiro uma vez: o
9
+ * que mudou entre versões vizinhas, se alguma remoção saiu fora de major, e se
10
+ * o ar serve a superfície da versão que anuncia.
11
+ */
12
+ import { spawnSync } from "node:child_process";
13
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
14
+ import { tmpdir } from "node:os";
15
+ import { join } from "node:path";
16
+ import { capturarHttp, capturarStdio } from "./remoto.js";
17
+ import { impressaoDigital } from "./superficie.js";
18
+ const shell = process.platform === "win32";
19
+ function npmJson(...argv) {
20
+ const r = spawnSync("npm", argv, { encoding: "utf8", shell });
21
+ if (r.status !== 0)
22
+ throw new Error(`npm ${argv.join(" ")}: ${r.stderr}`);
23
+ return JSON.parse(r.stdout);
24
+ }
25
+ const lista = (sup, campo) => sup[campo] ?? [];
26
+ const nomes = (l, chave) => l.map(x => String(x[chave]));
27
+ const init = (sup) => sup["initialize"];
28
+ /** O que mudou de uma versão para a seguinte, e o que disso quebra cliente. */
29
+ export function diferenca(antes, depois) {
30
+ const r = {
31
+ tools: { mais: [], menos: [], mudou: [] },
32
+ resources: { mais: [], menos: [] },
33
+ prompts: { mais: [], menos: [] },
34
+ quebras: [],
35
+ instructions: false,
36
+ capabilities: false,
37
+ identidade: false,
38
+ };
39
+ const ta = new Map(lista(antes, "tools").map(t => [String(t["name"]), t]));
40
+ const td = new Map(lista(depois, "tools").map(t => [String(t["name"]), t]));
41
+ for (const n of td.keys())
42
+ if (!ta.has(n))
43
+ r.tools.mais.push(n);
44
+ for (const [n, a] of ta) {
45
+ const d = td.get(n);
46
+ if (!d) {
47
+ r.tools.menos.push(n);
48
+ r.quebras.push(`tool removida: ${n}`);
49
+ continue;
50
+ }
51
+ if (impressaoDigital(a) === impressaoDigital(d))
52
+ continue;
53
+ r.tools.mudou.push(n);
54
+ const sa = (a["inputSchema"] ?? {});
55
+ const sd = (d["inputSchema"] ?? {});
56
+ const pd = (sd["properties"] ?? {});
57
+ for (const p of Object.keys((sa["properties"] ?? {}))) {
58
+ if (!(p in pd))
59
+ r.quebras.push(`${n}: parâmetro removido \`${p}\``);
60
+ }
61
+ const ra = new Set(sa["required"] ?? []);
62
+ for (const p of sd["required"] ?? []) {
63
+ if (!ra.has(p))
64
+ r.quebras.push(`${n}: parâmetro passou a obrigatório \`${p}\``);
65
+ }
66
+ }
67
+ for (const [campo, chave] of [["resources", "uri"], ["prompts", "name"]]) {
68
+ const a = new Set(nomes(lista(antes, campo), chave));
69
+ const d = new Set(nomes(lista(depois, campo), chave));
70
+ for (const x of d)
71
+ if (!a.has(x))
72
+ r[campo].mais.push(x);
73
+ for (const x of a) {
74
+ if (!d.has(x)) {
75
+ r[campo].menos.push(x);
76
+ r.quebras.push(`${campo === "resources" ? "resource" : "prompt"} removido: ${x}`);
77
+ }
78
+ }
79
+ }
80
+ r.instructions = impressaoDigital(init(antes)["instructions"]) !== impressaoDigital(init(depois)["instructions"]);
81
+ r.capabilities = impressaoDigital(init(antes)["capabilities"]) !== impressaoDigital(init(depois)["capabilities"]);
82
+ r.identidade = impressaoDigital(init(antes)["serverInfo"]) !== impressaoDigital(init(depois)["serverInfo"]);
83
+ return r;
84
+ }
85
+ const major = (v) => Number(v.split(".")[0]);
86
+ export async function replay(o) {
87
+ const log = o.log ?? (() => { });
88
+ const versoes = npmJson("view", o.pacote, "versions", "--json");
89
+ const datas = npmJson("view", o.pacote, "time", "--json");
90
+ let registro = new Set();
91
+ if (o.nomeNoRegistro) {
92
+ try {
93
+ const res = await fetch(`https://registry.modelcontextprotocol.io/v0/servers?search=${encodeURIComponent(o.nomeNoRegistro)}&limit=100`);
94
+ const corpo = (await res.json());
95
+ registro = new Set((corpo.servers ?? []).filter(s => s.server.name === o.nomeNoRegistro).map(s => s.server.version));
96
+ }
97
+ catch {
98
+ /* registro fora: a coluna sai vazia, o replay segue */
99
+ }
100
+ }
101
+ const linhas = [];
102
+ for (const v of versoes) {
103
+ const base = { versao: v, data: datas[v]?.slice(0, 10), noRegistro: registro.has(v) };
104
+ const dir = mkdtempSync(join(tmpdir(), "mcp-surface-replay-"));
105
+ try {
106
+ const inst = spawnSync("npm", ["install", `${o.pacote}@${v}`, "--prefix", dir, "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund", "--loglevel=error"], { encoding: "utf8", shell });
107
+ if (inst.status !== 0)
108
+ throw new Error(inst.stderr.trim().split("\n").pop());
109
+ const pasta = join(dir, "node_modules", ...o.pacote.split("/"));
110
+ const pkg = JSON.parse(readFileSync(join(pasta, "package.json"), "utf8"));
111
+ const bin = typeof pkg.bin === "string" ? pkg.bin : (Object.values(pkg.bin ?? {})[0] ?? pkg.main ?? "index.js");
112
+ const sup = await capturarStdio(join(pasta, bin), o.env);
113
+ if (!sup["tools"])
114
+ throw new Error("tools/list não respondeu");
115
+ const sha256 = impressaoDigital(sup);
116
+ linhas.push({ ...base, sha256, sup });
117
+ log(`${v}: ${sha256.slice(0, 12)} — ${lista(sup, "tools").length} tools`);
118
+ }
119
+ catch (e) {
120
+ const erro = String(e.message ?? e);
121
+ linhas.push({ ...base, erro });
122
+ log(`${v}: ERRO ${erro}`);
123
+ }
124
+ finally {
125
+ rmSync(dir, { recursive: true, force: true });
126
+ }
127
+ }
128
+ let shaNoAr;
129
+ let statusVersion;
130
+ if (o.url) {
131
+ shaNoAr = impressaoDigital(await capturarHttp(o.url));
132
+ statusVersion = await fetch(new URL("/status", o.url))
133
+ .then(r => r.json())
134
+ .then(s => s.version)
135
+ .catch(() => undefined);
136
+ }
137
+ const hoje = new Date().toISOString().slice(0, 10);
138
+ const md = [];
139
+ md.push(`# Replay retroativo da superfície — ${o.pacote}, ${hoje}`, "");
140
+ md.push("Gerado por `mcp-surface replay` (`@sbissoli/mcp-surface`): cada versão publicada no npm instalada e interrogada por stdio, normalizada pela mesma função da trava (`initialize` com instructions e capabilities, tools, resources, templates e prompts; a versão do servidor fica de fora).", "");
141
+ if (o.url && shaNoAr) {
142
+ const declarada = linhas.find(l => l.versao === statusVersion);
143
+ md.push("## O que está no ar", "");
144
+ md.push(`- Endpoint: \`${o.url}\` — \`/status\` declara **${statusVersion ?? "?"}**.`);
145
+ md.push(`- Superfície servida: \`${shaNoAr.slice(0, 12)}\`.`);
146
+ if (declarada?.sha256) {
147
+ md.push(declarada.sha256 === shaNoAr
148
+ ? `- **Confere:** é a superfície da ${statusVersion} publicada no npm.`
149
+ : `- **NÃO confere:** a ${statusVersion} publicada no npm tem \`${declarada.sha256.slice(0, 12)}\`.`);
150
+ }
151
+ const iguais = linhas.filter(l => l.sha256 === shaNoAr).map(l => l.versao);
152
+ md.push(`- Versões publicadas com exatamente esta superfície: ${iguais.join(", ") || "nenhuma"}.`, "");
153
+ }
154
+ md.push("## Versão a versão", "");
155
+ md.push("| versão | data | MCP Registry | sha256 | tools | o que mudou em relação à anterior |");
156
+ md.push("|:--|:--|:--:|:--|--:|:--|");
157
+ const quebras = [];
158
+ let anterior;
159
+ for (const l of linhas) {
160
+ if (!l.sup || !l.sha256) {
161
+ md.push(`| ${l.versao} | ${l.data} | ${l.noRegistro ? "sim" : "—"} | erro | — | ${(l.erro ?? "").replaceAll("|", "\\|")} |`);
162
+ continue;
163
+ }
164
+ let mudou = "(primeira)";
165
+ if (anterior?.sup) {
166
+ const d = diferenca(anterior.sup, l.sup);
167
+ const partes = [];
168
+ if (d.tools.mais.length)
169
+ partes.push(`+${d.tools.mais.length} tools (${d.tools.mais.join(", ")})`);
170
+ if (d.tools.menos.length)
171
+ partes.push(`−${d.tools.menos.length} tools (${d.tools.menos.join(", ")})`);
172
+ if (d.tools.mudou.length)
173
+ partes.push(`${d.tools.mudou.length} tools alteradas`);
174
+ if (d.resources.mais.length || d.resources.menos.length)
175
+ partes.push(`resources +${d.resources.mais.length}/−${d.resources.menos.length}`);
176
+ if (d.prompts.mais.length || d.prompts.menos.length)
177
+ partes.push(`prompts +${d.prompts.mais.length}/−${d.prompts.menos.length}`);
178
+ if (d.instructions)
179
+ partes.push("instructions");
180
+ if (d.capabilities)
181
+ partes.push("capabilities");
182
+ if (d.identidade)
183
+ partes.push("identidade");
184
+ mudou = l.sha256 === anterior.sha256 ? "nada" : partes.join("; ") || "detalhe de normalização";
185
+ if (d.quebras.length && major(l.versao) === major(anterior.versao)) {
186
+ quebras.push({ de: anterior.versao, para: l.versao, itens: d.quebras });
187
+ }
188
+ }
189
+ md.push(`| ${l.versao} | ${l.data} | ${l.noRegistro ? "sim" : "—"} | \`${l.sha256.slice(0, 12)}\` | ${lista(l.sup, "tools").length} | ${mudou} |`);
190
+ anterior = l;
191
+ }
192
+ md.push("", "## Remoções fora de versão major", "");
193
+ md.push("Tool, resource ou prompt removido, parâmetro removido ou parâmetro que passou a obrigatório quebra o cliente que dependia dele; pela convenção de versão isso pede major. Listado sem julgamento — cada caso pode ter tido razão registrada no CHANGELOG.", "");
194
+ if (!quebras.length)
195
+ md.push("Nenhuma.");
196
+ for (const q of quebras)
197
+ md.push(`- **${q.de} → ${q.para}:** ${q.itens.join("; ")}`);
198
+ md.push("", "## Limites", "");
199
+ md.push("- O replay mede o PACOTE de cada versão (stdio). O que o endpoint hospedado serviu no passado não é reconstituível; o que se mede é o de hoje contra a versão que ele declara.", "- A cópia do MCP Registry não carrega superfície (só nome, versão, pacotes e remotos): a coluna diz só se a versão foi registrada.", "- Quem responde sem token não entra no replay: é comportamento da borda HTTP, medido pela trava daqui para a frente.");
200
+ const json = {
201
+ gerado: new Date().toISOString(),
202
+ pacote: o.pacote,
203
+ endpoint: o.url ?? null,
204
+ statusVersion: statusVersion ?? null,
205
+ sha256NoAr: shaNoAr ?? null,
206
+ versoes: linhas.map(({ sup, ...l }) => ({
207
+ ...l,
208
+ ...(sup
209
+ ? {
210
+ tools: nomes(lista(sup, "tools"), "name"),
211
+ resources: nomes(lista(sup, "resources"), "uri"),
212
+ prompts: nomes(lista(sup, "prompts"), "name"),
213
+ instructionsSha256: impressaoDigital(init(sup)["instructions"]),
214
+ }
215
+ : {}),
216
+ })),
217
+ };
218
+ return { markdown: `${md.join("\n")}\n`, json };
219
+ }
220
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Quem responde SEM CREDENCIAL — o comportamento que nenhuma listagem mostra.
3
+ * O caso que o leitor do dev.to achou (comentário 3g5m4) foi exatamente
4
+ * `tools/list` passando a responder sem token sem que nada na superfície
5
+ * declarada mudasse. Só a borda HTTP sabe medir isso, então a medição recebe
6
+ * do servidor um `responder` que monta a requisição do jeito da borda dele.
7
+ */
8
+ export interface Pedido {
9
+ method: string;
10
+ params?: Record<string, unknown>;
11
+ }
12
+ /** Uma chamada de tool que NÃO toca a rede da origem (catálogo local, dado empacotado). */
13
+ export interface ChamadaLocal {
14
+ name: string;
15
+ arguments: Record<string, unknown>;
16
+ }
17
+ /**
18
+ * Os métodos que um cliente sem credencial pode tentar. `tools/call` entra só
19
+ * com uma tool que não vai à rede — a sonda mede a borda, não o humor da fonte.
20
+ */
21
+ export declare function sondaSemToken(chamada?: ChamadaLocal): Pedido[];
22
+ /** Lê o corpo de uma resposta MCP por HTTP (JSON puro ou SSE com uma mensagem). */
23
+ export declare function lerCorpoJsonRpc(texto: string): {
24
+ result?: Record<string, unknown>;
25
+ error?: unknown;
26
+ } | undefined;
27
+ /** "Responde" = HTTP 200 com `result` no corpo JSON-RPC. */
28
+ export declare function respondeu(res: Response): Promise<boolean>;
29
+ /** O corpo JSON-RPC de um pedido da sonda, pronto para `fetch`. */
30
+ export declare function corpoDoPedido(pedido: Pedido, id?: number): string;
31
+ export declare const CABECALHOS_MCP: Readonly<Record<string, string>>;
32
+ /**
33
+ * Mede a sonda em cada configuração × rota. `responder(config, rota, pedido)`
34
+ * devolve a `Response` da borda — o servidor decide como montar a requisição e
35
+ * o `env` de cada configuração. Saída: `{ config: { rota: { método: bool } } }`,
36
+ * a forma da seção `semToken` do `surface.lock.json`.
37
+ */
38
+ export declare function medirSemToken(configuracoes: readonly string[], rotas: readonly string[], sonda: readonly Pedido[], responder: (config: string, rota: string, pedido: Pedido) => Promise<Response>): Promise<Record<string, Record<string, Record<string, boolean>>>>;
39
+ /**
40
+ * A requisição com o `Host` que o runtime real (workerd) teria posto. O
41
+ * `Request` do Node (undici) trata `host` como cabeçalho proibido e o descarta
42
+ * em silêncio; sem isto, um handler que valida `Host` responde 403/"Missing
43
+ * Host header" a tudo e a sonda mede a ausência do cabeçalho, não a
44
+ * autenticação. Nada além do cabeçalho é simulado.
45
+ */
46
+ export declare function comHost(request: Request, host: string): Request;
47
+ /**
48
+ * Um IP de documentação (RFC 5737) por chamada: a sonda faz dezenas de
49
+ * requisições e um rate limit por IP (burst 20 nos servidores do portfólio)
50
+ * responderia 429 no meio — mediria o limitador, não a autenticação.
51
+ */
52
+ export declare function ipDaSonda(): string;
53
+ //# sourceMappingURL=sonda.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sonda.d.ts","sourceRoot":"","sources":["../src/sonda.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,EAAE,CAW9D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAYhH;AAED,4DAA4D;AAC5D,wBAAsB,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAG/D;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,SAAI,GAAG,MAAM,CAE5D;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG3D,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,GAC7E,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAYlE;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAU/D;AAGD;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAGlC"}
package/dist/sonda.js ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Quem responde SEM CREDENCIAL — o comportamento que nenhuma listagem mostra.
3
+ * O caso que o leitor do dev.to achou (comentário 3g5m4) foi exatamente
4
+ * `tools/list` passando a responder sem token sem que nada na superfície
5
+ * declarada mudasse. Só a borda HTTP sabe medir isso, então a medição recebe
6
+ * do servidor um `responder` que monta a requisição do jeito da borda dele.
7
+ */
8
+ import { paramsDoInitialize } from "./superficie.js";
9
+ /**
10
+ * Os métodos que um cliente sem credencial pode tentar. `tools/call` entra só
11
+ * com uma tool que não vai à rede — a sonda mede a borda, não o humor da fonte.
12
+ */
13
+ export function sondaSemToken(chamada) {
14
+ const sonda = [
15
+ { method: "initialize", params: paramsDoInitialize("surface-lock") },
16
+ { method: "ping" },
17
+ { method: "tools/list" },
18
+ { method: "resources/list" },
19
+ { method: "resources/templates/list" },
20
+ { method: "prompts/list" },
21
+ ];
22
+ if (chamada)
23
+ sonda.push({ method: "tools/call", params: { name: chamada.name, arguments: chamada.arguments } });
24
+ return sonda;
25
+ }
26
+ /** Lê o corpo de uma resposta MCP por HTTP (JSON puro ou SSE com uma mensagem). */
27
+ export function lerCorpoJsonRpc(texto) {
28
+ const t = texto.trim();
29
+ try {
30
+ if (t.startsWith("{"))
31
+ return JSON.parse(t);
32
+ const dados = t
33
+ .split("\n")
34
+ .filter(l => l.startsWith("data:"))
35
+ .pop();
36
+ return dados ? JSON.parse(dados.slice(5).trim()) : undefined;
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ /** "Responde" = HTTP 200 com `result` no corpo JSON-RPC. */
43
+ export async function respondeu(res) {
44
+ if (res.status !== 200)
45
+ return false;
46
+ return lerCorpoJsonRpc(await res.text())?.result !== undefined;
47
+ }
48
+ /** O corpo JSON-RPC de um pedido da sonda, pronto para `fetch`. */
49
+ export function corpoDoPedido(pedido, id = 1) {
50
+ return JSON.stringify({ jsonrpc: "2.0", id, method: pedido.method, params: pedido.params });
51
+ }
52
+ export const CABECALHOS_MCP = {
53
+ "Content-Type": "application/json",
54
+ Accept: "application/json, text/event-stream",
55
+ };
56
+ /**
57
+ * Mede a sonda em cada configuração × rota. `responder(config, rota, pedido)`
58
+ * devolve a `Response` da borda — o servidor decide como montar a requisição e
59
+ * o `env` de cada configuração. Saída: `{ config: { rota: { método: bool } } }`,
60
+ * a forma da seção `semToken` do `surface.lock.json`.
61
+ */
62
+ export async function medirSemToken(configuracoes, rotas, sonda, responder) {
63
+ const saida = {};
64
+ for (const config of configuracoes) {
65
+ const porRota = {};
66
+ for (const rota of rotas) {
67
+ const porMetodo = {};
68
+ for (const pedido of sonda)
69
+ porMetodo[pedido.method] = await respondeu(await responder(config, rota, pedido));
70
+ porRota[rota] = porMetodo;
71
+ }
72
+ saida[config] = porRota;
73
+ }
74
+ return saida;
75
+ }
76
+ /**
77
+ * A requisição com o `Host` que o runtime real (workerd) teria posto. O
78
+ * `Request` do Node (undici) trata `host` como cabeçalho proibido e o descarta
79
+ * em silêncio; sem isto, um handler que valida `Host` responde 403/"Missing
80
+ * Host header" a tudo e a sonda mede a ausência do cabeçalho, não a
81
+ * autenticação. Nada além do cabeçalho é simulado.
82
+ */
83
+ export function comHost(request, host) {
84
+ const headers = new Headers(request.headers);
85
+ headers.set("host", host);
86
+ return new Proxy(request, {
87
+ get(alvo, prop) {
88
+ if (prop === "headers")
89
+ return headers;
90
+ const valor = Reflect.get(alvo, prop, alvo);
91
+ return typeof valor === "function" ? valor.bind(alvo) : valor;
92
+ },
93
+ });
94
+ }
95
+ let ip = 0;
96
+ /**
97
+ * Um IP de documentação (RFC 5737) por chamada: a sonda faz dezenas de
98
+ * requisições e um rate limit por IP (burst 20 nos servidores do portfólio)
99
+ * responderia 429 no meio — mediria o limitador, não a autenticação.
100
+ */
101
+ export function ipDaSonda() {
102
+ ip = (ip % 250) + 1;
103
+ return `192.0.2.${ip}`;
104
+ }
105
+ //# sourceMappingURL=sonda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sonda.js","sourceRoot":"","sources":["../src/sonda.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A superfície de um servidor MCP — o que um cliente vê dele —, reduzida a um
3
+ * objeto normalizado e a um sha256.
4
+ *
5
+ * Por que existe. A cópia do MCP Registry carrega só a versão (medido em
6
+ * 30/09/2026 nas 26 versões publicadas do bcb-br-mcp: `name`, `version`,
7
+ * `packages`, `remotes`), então a versão é a ÚNICA coisa que um cliente
8
+ * consegue comparar com o servidor — e isso só vale se TODA mudança de
9
+ * superfície subir a versão. Proposta de um leitor (dev.to, comentários 3g5m4
10
+ * e 3g607), que achou o caso grave no servidor dele: registro dizendo 0.1.0 com
11
+ * 4 tools só-leitura, servidor com 6, duas escrevendo pelo usuário.
12
+ *
13
+ * A normalização é a mesma em todo caminho — em memória, HTTP e stdio de uma
14
+ * versão antiga (replay) — porque todos passam por `normalizarSuperficie`. Ela
15
+ * nasceu no bcb-br-mcp (1.15.1) e foi trazida para cá sem mudar um byte: o
16
+ * sha256 travado lá continua valendo aqui.
17
+ */
18
+ /** O protocolo pedido no `initialize` de toda captura — fixo, para o eco não variar. */
19
+ export declare const PROTOCOLO_DA_CAPTURA = "2025-06-18";
20
+ /** Resultados crus, como saem do JSON-RPC. Lista ausente = método não servido. */
21
+ export interface SuperficieBruta {
22
+ initialize: Record<string, unknown> | undefined;
23
+ tools: unknown[] | undefined;
24
+ resources: unknown[] | undefined;
25
+ resourceTemplates: unknown[] | undefined;
26
+ prompts: unknown[] | undefined;
27
+ }
28
+ /**
29
+ * Forma canônica da superfície. A versão do servidor sai — ela muda a cada
30
+ * release e é justamente o que se compara contra a superfície. O resto do
31
+ * `serverInfo` (nome, título, site, ícones) fica: é declaração de identidade.
32
+ * Arrays internos (`required`, `enum`) mantêm a ordem: ela é parte do que se
33
+ * publica. Método não servido vira `null`, não lista vazia: "não serve" e
34
+ * "serve nada" são superfícies diferentes.
35
+ */
36
+ export declare function normalizarSuperficie(bruta: SuperficieBruta): Record<string, unknown>;
37
+ /** sha256 do JSON canônico (chaves ordenadas) — a impressão digital. */
38
+ export declare function impressaoDigital(valor: unknown): string;
39
+ /** Os parâmetros do `initialize` de toda captura. */
40
+ export declare function paramsDoInitialize(cliente: string): Record<string, unknown>;
41
+ /**
42
+ * Captura a superfície por qualquer transporte: `pedir` faz uma requisição
43
+ * JSON-RPC e devolve o `result` (ou `undefined` em erro). `notificar`, quando
44
+ * o transporte tem sessão, manda o `notifications/initialized`.
45
+ */
46
+ export declare function capturarPor(pedir: (method: string, params?: Record<string, unknown>) => Promise<Record<string, unknown> | undefined>, cliente: string, notificar?: () => void): Promise<Record<string, unknown>>;
47
+ //# sourceMappingURL=superficie.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"superficie.d.ts","sourceRoot":"","sources":["../src/superficie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAChD,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IACjC,iBAAiB,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IACzC,OAAO,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;CAChC;AAqBD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAepF;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEvD;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM3E;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EACzG,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,IAAI,GACrB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAWlC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * A superfície de um servidor MCP — o que um cliente vê dele —, reduzida a um
3
+ * objeto normalizado e a um sha256.
4
+ *
5
+ * Por que existe. A cópia do MCP Registry carrega só a versão (medido em
6
+ * 30/09/2026 nas 26 versões publicadas do bcb-br-mcp: `name`, `version`,
7
+ * `packages`, `remotes`), então a versão é a ÚNICA coisa que um cliente
8
+ * consegue comparar com o servidor — e isso só vale se TODA mudança de
9
+ * superfície subir a versão. Proposta de um leitor (dev.to, comentários 3g5m4
10
+ * e 3g607), que achou o caso grave no servidor dele: registro dizendo 0.1.0 com
11
+ * 4 tools só-leitura, servidor com 6, duas escrevendo pelo usuário.
12
+ *
13
+ * A normalização é a mesma em todo caminho — em memória, HTTP e stdio de uma
14
+ * versão antiga (replay) — porque todos passam por `normalizarSuperficie`. Ela
15
+ * nasceu no bcb-br-mcp (1.15.1) e foi trazida para cá sem mudar um byte: o
16
+ * sha256 travado lá continua valendo aqui.
17
+ */
18
+ import { createHash } from "node:crypto";
19
+ /** O protocolo pedido no `initialize` de toda captura — fixo, para o eco não variar. */
20
+ export const PROTOCOLO_DA_CAPTURA = "2025-06-18";
21
+ function ordenarChaves(valor) {
22
+ if (Array.isArray(valor))
23
+ return valor.map(ordenarChaves);
24
+ if (valor && typeof valor === "object") {
25
+ return Object.fromEntries(Object.keys(valor)
26
+ .sort()
27
+ .map(k => [k, ordenarChaves(valor[k])]));
28
+ }
29
+ return valor;
30
+ }
31
+ function porChave(lista, chave) {
32
+ if (!lista)
33
+ return null;
34
+ return [...lista].sort((a, b) => String(a[chave]).localeCompare(String(b[chave])));
35
+ }
36
+ /**
37
+ * Forma canônica da superfície. A versão do servidor sai — ela muda a cada
38
+ * release e é justamente o que se compara contra a superfície. O resto do
39
+ * `serverInfo` (nome, título, site, ícones) fica: é declaração de identidade.
40
+ * Arrays internos (`required`, `enum`) mantêm a ordem: ela é parte do que se
41
+ * publica. Método não servido vira `null`, não lista vazia: "não serve" e
42
+ * "serve nada" são superfícies diferentes.
43
+ */
44
+ export function normalizarSuperficie(bruta) {
45
+ const init = bruta.initialize ?? {};
46
+ const { version: _versao, ...serverInfo } = (init["serverInfo"] ?? {});
47
+ return ordenarChaves({
48
+ initialize: {
49
+ protocolVersion: init["protocolVersion"] ?? null,
50
+ capabilities: init["capabilities"] ?? null,
51
+ instructions: init["instructions"] ?? null,
52
+ serverInfo,
53
+ },
54
+ tools: porChave(bruta.tools, "name"),
55
+ resources: porChave(bruta.resources, "uri"),
56
+ resourceTemplates: porChave(bruta.resourceTemplates, "uriTemplate"),
57
+ prompts: porChave(bruta.prompts, "name"),
58
+ });
59
+ }
60
+ /** sha256 do JSON canônico (chaves ordenadas) — a impressão digital. */
61
+ export function impressaoDigital(valor) {
62
+ return createHash("sha256").update(JSON.stringify(ordenarChaves(valor))).digest("hex");
63
+ }
64
+ /** Os parâmetros do `initialize` de toda captura. */
65
+ export function paramsDoInitialize(cliente) {
66
+ return {
67
+ protocolVersion: PROTOCOLO_DA_CAPTURA,
68
+ capabilities: {},
69
+ clientInfo: { name: cliente, version: "1.0.0" },
70
+ };
71
+ }
72
+ /**
73
+ * Captura a superfície por qualquer transporte: `pedir` faz uma requisição
74
+ * JSON-RPC e devolve o `result` (ou `undefined` em erro). `notificar`, quando
75
+ * o transporte tem sessão, manda o `notifications/initialized`.
76
+ */
77
+ export async function capturarPor(pedir, cliente, notificar) {
78
+ const initialize = await pedir("initialize", paramsDoInitialize(cliente));
79
+ notificar?.();
80
+ const lista = async (method, chave) => (await pedir(method, {}))?.[chave];
81
+ return normalizarSuperficie({
82
+ initialize,
83
+ tools: await lista("tools/list", "tools"),
84
+ resources: await lista("resources/list", "resources"),
85
+ resourceTemplates: await lista("resources/templates/list", "resourceTemplates"),
86
+ prompts: await lista("prompts/list", "prompts"),
87
+ });
88
+ }
89
+ //# sourceMappingURL=superficie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"superficie.js","sourceRoot":"","sources":["../src/superficie.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A regra do `surface.lock.json`.
3
+ *
4
+ * Cada seção (`declarada`, `semToken`) guarda a versão do `package.json` em que
5
+ * foi travada e o sha256 do conteúdo. Se o medido diverge do travado:
6
+ * - versão igual à da trava → FALHA: a superfície mudou sem subir a versão;
7
+ * - versão diferente → FALHA pedindo para regravar (`mcp-surface travar`).
8
+ * O modo de escrita (`SURFACE_LOCK_ESCREVER=1`, posto pelo `mcp-surface
9
+ * travar`) obedece à mesma regra: ele se RECUSA a travar superfície nova sob a
10
+ * versão antiga. É isso que transforma a disciplina da receita de release em
11
+ * teste. O sha gravado também denuncia edição à mão do conteúdo.
12
+ */
13
+ export type NomeDaSecao = "declarada" | "semToken";
14
+ /** Variável de ambiente do modo de escrita. */
15
+ export declare const VAR_ESCRITA = "SURFACE_LOCK_ESCREVER";
16
+ interface Secao {
17
+ versao: string;
18
+ sha256: string;
19
+ conteudo: unknown;
20
+ }
21
+ export type Trava = Partial<Record<NomeDaSecao, Secao>> & {
22
+ $comentario?: string;
23
+ };
24
+ export interface Veredito {
25
+ ok: boolean;
26
+ mensagem: string;
27
+ }
28
+ export declare function lerTrava(caminho: string): Trava;
29
+ /** O modo de escrita está ligado neste processo? */
30
+ export declare function modoEscrita(): boolean;
31
+ /**
32
+ * Confere (e, em modo de escrita, regrava) UMA seção da trava contra o medido.
33
+ * Devolve o veredito em vez de lançar, para o teste mostrar a mensagem inteira:
34
+ * `expect(v.ok, v.mensagem).toBe(true)`.
35
+ */
36
+ export declare function conferirSecao(caminhoDaTrava: string, secao: NomeDaSecao, medido: unknown, versaoDoPacote: string, escrever?: boolean): Veredito;
37
+ export {};
38
+ //# sourceMappingURL=trava.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trava.d.ts","sourceRoot":"","sources":["../src/trava.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAEnD,+CAA+C;AAC/C,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAKnF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAM/C;AAED,oDAAoD;AACpD,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,OAAO,EACf,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,OAAuB,GAChC,QAAQ,CAyCV"}