Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

51 linesCodeBlameRaw
1import assert from "node:assert/strict";
2
3/** Read-only MCP lifecycle and tool/schema check; credentials never enter reports. */
4export async function verifyMcp(token, fetcher = fetch) {
5 const endpoint = "https://mcp.g1t.sh";
6 const headers = { authorization: `Bearer ${token}`, "content-type": "application/json", accept: "application/json, text/event-stream" };
7 async function post(method, params, id) {
8 const response = await fetcher(endpoint, {
9 method: "POST",
10 headers: { ...headers },
11 body: JSON.stringify({ jsonrpc: "2.0", ...(id === undefined ? {} : { id }), method, params }),
12 signal: AbortSignal.timeout(20_000),
13 });
14 if (id === undefined) {
15 assert.equal(response.status, 202);
16 return;
17 }
18 assert.equal(response.status, 200);
19 const value = await response.json();
20 assert.equal(value.id, id);
21 assert.ok(!value.error, "MCP returned an error");
22 if (response.headers.get("mcp-session-id")) headers["Mcp-Session-Id"] = response.headers.get("mcp-session-id");
23 return value.result;
24 }
25 const initialized = await post(
26 "initialize",
27 { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "g1t-readiness-check", version: "1" } },
28 1,
29 );
30 assert.equal(initialized.protocolVersion, "2025-03-26");
31 headers["MCP-Protocol-Version"] = initialized.protocolVersion;
32 await post("notifications/initialized", {});
33 const listed = await post("tools/list", {}, 2);
34 assert.ok(listed.tools.length > 0);
35 const response = await fetcher(endpoint, { signal: AbortSignal.timeout(20_000) });
36 assert.equal(response.status, 200);
37 const card = await response.json();
38 let actions = 0;
39 for (const tool of listed.tools) {
40 const published = card.tools.find((entry) => entry.name === tool.name);
41 assert.ok(published, `Undocumented tool ${tool.name}`);
42 assert.equal(tool.inputSchema.type, "object");
43 for (const name of tool.inputSchema.properties.action.enum) {
44 const action = published.actions.find((entry) => entry.name === name);
45 assert.ok(action, `Undocumented action on ${tool.name}`);
46 assert.ok(action.scope === null || card.scopes_supported.includes(action.scope), "Unknown action scope");
47 actions++;
48 }
49 }
50 return { tools: listed.tools.length, actions };
51}