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.

39 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, { method: "POST", headers: { ...headers }, body: JSON.stringify({ jsonrpc: "2.0", ...(id === undefined ? {} : { id }), method, params }), signal: AbortSignal.timeout(20_000) });
9 if (id === undefined) { assert.equal(response.status, 202); return; }
10 assert.equal(response.status, 200);
11 const value = await response.json();
12 assert.equal(value.id, id);
13 assert.ok(!value.error, "MCP returned an error");
14 if (response.headers.get("mcp-session-id")) headers["Mcp-Session-Id"] = response.headers.get("mcp-session-id");
15 return value.result;
16 }
17 const initialized = await post("initialize", { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "g1t-readiness-check", version: "1" } }, 1);
18 assert.equal(initialized.protocolVersion, "2025-03-26");
19 headers["MCP-Protocol-Version"] = initialized.protocolVersion;
20 await post("notifications/initialized", {});
21 const listed = await post("tools/list", {}, 2);
22 assert.ok(listed.tools.length > 0);
23 const response = await fetcher(endpoint, { signal: AbortSignal.timeout(20_000) });
24 assert.equal(response.status, 200);
25 const card = await response.json();
26 let actions = 0;
27 for (const tool of listed.tools) {
28 const published = card.tools.find((entry) => entry.name === tool.name);
29 assert.ok(published, `Undocumented tool ${tool.name}`);
30 assert.equal(tool.inputSchema.type, "object");
31 for (const name of tool.inputSchema.properties.action.enum) {
32 const action = published.actions.find((entry) => entry.name === name);
33 assert.ok(action, `Undocumented action on ${tool.name}`);
34 assert.ok(action.scope === null || card.scopes_supported.includes(action.scope), "Unknown action scope");
35 actions++;
36 }
37 }
38 return { tools: listed.tools.length, actions };
39}