Permissions working... ish

This commit is contained in:
Conrad Irwin
2025-08-27 01:00:44 -06:00
parent 58bb133b5d
commit c5b0e3c91c
5 changed files with 1105 additions and 36 deletions

999
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/acp-agent.js",
"start": "node dist/index.js",
"dev": "npm run build && npm run start",
"lint": "eslint src --ext .ts"
},
@@ -23,10 +23,15 @@
"license": "MIT",
"dependencies": {
"@anthropic-ai/claude-code": "^1.0.92",
"@zed-industries/agent-client-protocol": "0.0.32",
"@modelcontextprotocol/sdk": "^1.17.4",
"@types/express": "^5.0.3",
"@zed-industries/agent-client-protocol": "0.1.0",
"express": "^5.1.0",
"minimist": "^1.2.8",
"uuid": "11.1.0"
},
"devDependencies": {
"@types/minimist": "^1.2.5",
"@types/node": "^20.11.30",
"@types/uuid": "^10.0.0",
"eslint": "^8.56.0",

View File

@@ -30,6 +30,8 @@ import {
} from "./utils.js";
import { ContentBlock } from "@zed-industries/agent-client-protocol";
import { SessionNotification } from "@zed-industries/agent-client-protocol";
import { createMcpServer } from "./mcp-server.js";
import { AddressInfo } from "node:net";
// Implement the ACP Agent interface
class ClaudeAcpAgent implements Agent {
@@ -68,10 +70,27 @@ class ClaudeAcpAgent implements Agent {
}
// todo!() auth, permissionPromptToolName
let server = await createMcpServer();
let address = server.address() as AddressInfo;
mcpServers["acp"] = {
type: "http",
url: "http://127.0.0.1:" + address.port + "/mcp",
headers: {
"x-acp-proxy-session-id": sessionId,
},
};
console.error(mcpServers);
let q = query({
prompt: input,
options: { cwd: params.cwd, mcpServers },
options: {
cwd: params.cwd,
mcpServers,
executableArgs: ["--debug"],
strictMcpConfig: true,
permissionPromptToolName: "mcp__acp__permission",
stderr: (err) => console.error(err),
},
});
this.sessions[sessionId] = { query: q, input: input };
@@ -90,7 +109,6 @@ class ClaudeAcpAgent implements Agent {
}
const { query, input } = this.sessions[params.sessionId];
query.interrupt();
input.push(promptToClaude(params));
while (true) {
let { value: message, done } = await query.next();
@@ -269,20 +287,19 @@ function toAcpNotifications(
default:
throw new Error("unhandled chunk type: " + chunk.type);
}
output.push({ sessionId: message.session_id, update });
output.push({ sessionId, update });
}
return output;
}
new AgentSideConnection(
(client) => new ClaudeAcpAgent(client),
nodeToWebWritable(process.stdout),
nodeToWebReadable(process.stdin),
);
// Keep process alive
process.stdin.resume();
export function runAcp() {
new AgentSideConnection(
(client) => new ClaudeAcpAgent(client),
nodeToWebWritable(process.stdout),
nodeToWebReadable(process.stdin),
);
}
type ContentChunk =
| { type: "text"; text: string }

5
src/index.ts Normal file
View File

@@ -0,0 +1,5 @@
import { runAcp as runAcp } from "./acp-agent.js";
runAcp();
// Keep process alive
process.stdin.resume();

89
src/mcp-server.ts Normal file
View File

@@ -0,0 +1,89 @@
import express from "express";
import { randomUUID } from "node:crypto";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";
import { Server } from "node:http";
export function createMcpServer(): Promise<Server> {
// Create MCP server
const server = new McpServer({
name: "acp-mcp-server",
version: "1.0.0",
});
// Register a simple echo tool (for demonstration)
server.registerTool(
"permission",
{
title: "Permission Tool",
description: "Used to request tool permissions",
inputSchema: {
tool_name: z.string(),
input: z.any(),
tool_use_id: z.string().optional(),
},
},
async (input) => {
console.error("PERMISSION TOOl", input);
return {
content: [
{
type: "text",
text: JSON.stringify({
behavior: "allow",
updatedInput: input.input,
}),
},
],
};
},
);
const app = express();
app.use(express.json());
app.post("/mcp", async (req, res) => {
try {
const transport: StreamableHTTPServerTransport =
new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on("close", () => {
transport.close();
server.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error("Error handling MCP request:", error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: "2.0",
error: {
code: -32603,
message: "Internal server error",
},
id: null,
});
}
}
});
return new Promise((resolve, reject) => {
const listener = app.listen(0, "127.0.0.1", (error) => {
if (error) {
reject(error);
return;
}
const address = listener.address();
console.error(address);
if (typeof address === "object" && address && "port" in address) {
console.error(
`MCP HTTP server listening on http://127.0.0.1:${address.port}/mcp`,
);
}
resolve(listener);
});
});
}