1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
61
62
// vendored from atlibs-asyncai 94afa33 modules/asyncai/mcp-stub.mjs
// Test MCP servers: mcpServer(tools) answers one JSON-RPC message (the in-process hook's contract);
// streamableHttp(server) serves it as a Streamable HTTP endpoint for ctx.http.fetch stubs.
/** tools: { name: (arguments) => CallToolResult }. Returns (message) => response, or null for a notification. */
export function mcpServer(tools, { version, pageSize = Infinity } = {}) {
const names = Object.keys(tools);
const ok = (id, result) => ({ jsonrpc: "2.0", id, result });
const fail = (id, code, message) => ({ jsonrpc: "2.0", id, error: { code, message } });
return (message) => {
const { id, method, params = {} } = message;
if (id === undefined) return null;
if (method === "initialize") return ok(id, { protocolVersion: version ?? params.protocolVersion, capabilities: { tools: {} }, serverInfo: { name: "stub", version: "0" } });
if (method === "ping") return ok(id, {});
if (method === "tools/list") {
const from = Number(params.cursor ?? 0);
const page = names.slice(from, from + pageSize).map((name) => ({ name, description: name, inputSchema: { type: "object" } }));
return ok(id, { tools: page, ...(from + pageSize < names.length && { nextCursor: String(from + pageSize) }) });
}
if (method === "tools/call") return tools[params.name] ? ok(id, tools[params.name](params.arguments ?? {})) : fail(id, -32602, `unknown tool ${params.name}`);
return fail(id, -32601, `no method ${method}`);
};
}
/** server as a Streamable HTTP endpoint: { handle(init) -> Response, seen: the requests }; sse answers as an event stream. */
export function streamableHttp(server, { sse = false, session } = {}) {
const seen = [];
const handle = async (init) => {
const message = JSON.parse(init.body);
const h = init.headers;
seen.push({ method: message.method, params: message.params, session: h["mcp-session-id"], version: h["mcp-protocol-version"], accept: h.accept });
const answer = server(message);
if (message.id === undefined) return new Response(null, { status: 202 });
const headers = { ...(message.method === "initialize" && session && { "mcp-session-id": session }) };
if (!sse) return Response.json(answer, { headers });
return new Response(`event: message\ndata: ${JSON.stringify(answer)}\n\n`, { headers: { ...headers, "content-type": "text/event-stream" } });
};
return { handle, seen };
}
/** handle as a host scheme fetcher (runModule's `fetchers`): { method, url, headers, body } -> { status, headers, body },
* the headers cased as a Go server sends them (the guest agent's); `urls` gets each request's URL. */
export function fetcher(handle) {
const urls = [];
const fetch = async (request) => {
urls.push(request.url);
const response = await handle(request);
const headers = Object.fromEntries([...response.headers].map(([k, v]) => [k.replace(/(^|-)[a-z]/g, (c) => c.toUpperCase()), v]));
return { status: response.status, headers, body: await response.text() };
};
return { fetch, urls };
}
/** A reason to skip while this atlibs core routes no webrtc:// URL to a host fetcher (contract v2.2 section 3), else false. */
export async function noFetchers(runModule, ctx, mod) {
const probe = { ...ctx, http: { fetch: async () => Response.json({ content: [], stop_reason: "end_turn" }) } };
const input = { prompt: "-", endpoint: "https://inference.test", mcp: [{ name: "vm", url: "webrtc:///probe/shell/mcp" }] };
const options = { http: { "https://inference.test": {}, "webrtc://*": {} }, fetchers: { "webrtc:": fetcher(streamableHttp(mcpServer({})).handle).fetch } };
const ran = await runModule(probe, mod, "run", input, async () => {}, options).catch((e) => ({ error: e.message }));
const server = ran.result?.servers?.[0];
return server?.phase !== "ready" && `atlibs core routes no webrtc:// URL to a host fetcher yet (${server?.error ?? ran.error})`;
}