import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { signHttpRequest, importPrivateKey } from "@belticlabs/agent-signer";
const server = new Server(
{ name: "beltic-signer", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Load credentials from environment
const privateKeyPem = process.env.AGENT_PRIVATE_KEY!;
const keyId = process.env.AGENT_KEY_ID!;
const keyDirectoryUrl = process.env.AGENT_KEY_DIRECTORY_URL!;
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "signed_fetch",
description: "Make a signed HTTP request that can be verified by the receiving service",
inputSchema: {
type: "object",
properties: {
url: { type: "string", description: "The URL to fetch" },
method: { type: "string", enum: ["GET", "POST", "PUT", "DELETE"], default: "GET" },
body: { type: "string", description: "Request body (for POST/PUT)" },
headers: { type: "object", description: "Additional headers" },
},
required: ["url"],
},
},
],
}));
server.setRequestHandler("tools/call", async (request) => {
if (request.params.name === "signed_fetch") {
const { url, method = "GET", body, headers = {} } = request.params.arguments as any;
try {
const privateKey = await importPrivateKey(privateKeyPem, "EdDSA");
const signedHeaders = await signHttpRequest({
method,
url,
headers: { "content-type": "application/json", ...headers },
body,
privateKey,
keyId,
keyDirectoryUrl,
});
const response = await fetch(url, {
method,
headers: { ...headers, ...signedHeaders },
body,
});
const data = await response.text();
return {
content: [
{
type: "text",
text: JSON.stringify({
status: response.status,
headers: Object.fromEntries(response.headers),
body: data,
}, null, 2),
},
],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error}` }],
isError: true,
};
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
const transport = new StdioServerTransport();
await server.connect(transport);