Compare commits

...

5 Commits

Author SHA1 Message Date
Ben Brandt
ba513b190b Claude Code SDK 1.0.123 (#65)
- **Bump to claude code sdk v1.0.123**
- **Prep release**

---------

Signed-off-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-09-24 10:36:14 +02:00
Ben Brandt
a011363320 v0.4.3 (#63) 2025-09-19 12:16:16 +02:00
Ben Brandt
7737878dd2 Pull permissions into own server (#50)
This allows us to use the SDK version of an MCP server for all other
tool calls. Ideally the permission server goes away eventually.

Signed-off-by: Ben Brandt <benjamin.j.brandt@gmail.com>

---------

Signed-off-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-09-19 12:05:46 +02:00
Ben Brandt
2e53f1d3e4 Update to ACP TS library v0.4 (#59)
Signed-off-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-09-18 10:04:30 +00:00
Ben Brandt
aa7364d49b v0.4.2 (#55) 2025-09-15 18:48:44 +02:00
6 changed files with 387 additions and 322 deletions

View File

@@ -1,8 +1,21 @@
# Changelog
## v0.4.1
## v0.4.4
### What's New
- Update to @anthropic-ai/claude-code@v1.0.123
- Update to @zed-industries/agent-client-protocol@v0.4.2
## v0.4.3
- Move ACP tools over MCP from an "http" MCP server to an "sdk" one so more tool calls can stay in-memory.
- Update to @anthropic-ai/claude-code@v1.0.119
- Update to @zed-industries/agent-client-protocol@v0.4.0
## v0.4.2
- Fix missing package.json metadata
## v0.4.1
- Add support for /compact command [ecfd36a](https://github.com/zed-industries/claude-code-acp/commit/ecfd36afa6c4e31f12e1daf9b8a2bdc12dda1794)
- Add default limits to read tool [7bd1638](https://github.com/zed-industries/claude-code-acp/commit/7bd163818bb959b11fd2c933eff73ad83c57abb8)

587
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"bin": {
"claude-code-acp": "./dist/index.js"
},
"version": "0.4.1",
"version": "0.4.4",
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
"main": "dist/index.js",
"type": "module",
@@ -40,12 +40,20 @@
"sdk",
"code"
],
"homepage": "https://github.com/zed-industries/claude-code-acp#readme",
"bugs": {
"url": "https://github.com/zed-industries/claude-code-acp/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/zed-industries/claude-code-acp.git"
},
"author": "Zed Industries",
"license": "Apache-2.0",
"dependencies": {
"@anthropic-ai/claude-code": "1.0.113",
"@modelcontextprotocol/sdk": "1.18.0",
"@zed-industries/agent-client-protocol": "0.3.1",
"@anthropic-ai/claude-code": "1.0.123",
"@modelcontextprotocol/sdk": "1.18.1",
"@zed-industries/agent-client-protocol": "0.4.2",
"diff": "8.0.2",
"express": "5.1.0",
"minimist": "1.2.8",
@@ -54,12 +62,12 @@
"devDependencies": {
"@types/express": "5.0.3",
"@types/minimist": "1.2.5",
"@types/node": "24.4.0",
"@types/node": "24.5.2",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.43.0",
"@typescript-eslint/parser": "8.43.0",
"@typescript-eslint/eslint-plugin": "8.44.1",
"@typescript-eslint/parser": "8.44.1",
"@vitest/ui": "3.2.4",
"eslint": "9.35.0",
"eslint": "9.36.0",
"eslint-config-prettier": "10.1.8",
"globals": "16.4.0",
"prettier": "3.6.2",

View File

@@ -7,6 +7,7 @@ import {
ClientCapabilities,
InitializeRequest,
InitializeResponse,
ndJsonStream,
NewSessionRequest,
NewSessionResponse,
PromptRequest,
@@ -36,7 +37,12 @@ import * as os from "node:os";
import { v7 as uuidv7 } from "uuid";
import { nodeToWebReadable, nodeToWebWritable, Pushable, unreachable } from "./utils.js";
import { SessionNotification } from "@zed-industries/agent-client-protocol";
import { createMcpServer, toolNames } from "./mcp-server.js";
import {
createMcpServer,
createPermissionMcpServer,
PERMISSION_TOOL_NAME,
toolNames,
} from "./mcp-server.js";
import { AddressInfo } from "node:net";
import { toolInfoFromToolUse, planEntries, toolUpdateFromToolResult } from "./tools.js";
@@ -139,9 +145,17 @@ export class ClaudeAcpAgent implements Agent {
}
}
const server = await createMcpServer(this, sessionId, this.clientCapabilities);
const address = server.address() as AddressInfo;
const server = createMcpServer(this, sessionId, this.clientCapabilities);
mcpServers["acp"] = {
type: "sdk",
name: "acp",
instance: server,
};
// Ideally replace with `canUseTool`
const permissionServer = await createPermissionMcpServer(this, sessionId);
const address = permissionServer.address() as AddressInfo;
mcpServers["acpPermission"] = {
type: "http",
url: "http://127.0.0.1:" + address.port + "/mcp",
headers: {
@@ -152,7 +166,7 @@ export class ClaudeAcpAgent implements Agent {
const options: Options = {
cwd: params.cwd,
mcpServers,
permissionPromptToolName: toolNames.permission,
permissionPromptToolName: PERMISSION_TOOL_NAME,
stderr: (err) => console.error(err),
// note: although not documented by the types, passing an absolute path
// here works to find zed's managed node version.
@@ -414,7 +428,6 @@ async function getAvailableSlashCommands(query: Query): Promise<AvailableCommand
const input = command.argumentHint ? { hint: command.argumentHint } : null;
return {
name: command.name,
// @ts-expect-error type in the ts interface
description: command.description || "",
input,
};
@@ -608,11 +621,11 @@ export function toAcpNotifications(
}
export function runAcp() {
new AgentSideConnection(
(client) => new ClaudeAcpAgent(client),
nodeToWebWritable(process.stdout),
nodeToWebReadable(process.stdin),
);
const input = nodeToWebWritable(process.stdout);
const output = nodeToWebReadable(process.stdin);
const stream = ndJsonStream(input, output);
new AgentSideConnection((client) => new ClaudeAcpAgent(client), stream);
}
type ContentChunk =

View File

@@ -27,7 +27,6 @@ const unqualifiedToolNames = {
bash: "Bash",
killBash: "KillBash",
bashOutput: "BashOutput",
permission: "permission",
};
const SERVER_PREFIX = "mcp__acp__";
@@ -39,7 +38,6 @@ export const toolNames = {
bash: SERVER_PREFIX + unqualifiedToolNames.bash,
killBash: SERVER_PREFIX + unqualifiedToolNames.killBash,
bashOutput: SERVER_PREFIX + unqualifiedToolNames.bashOutput,
permission: SERVER_PREFIX + unqualifiedToolNames.permission,
};
const editToolNames = [toolNames.edit, toolNames.multiEdit, toolNames.write];
@@ -48,12 +46,9 @@ export function createMcpServer(
agent: ClaudeAcpAgent,
sessionId: string,
clientCapabilities: ClientCapabilities | undefined,
): Promise<Server> {
): McpServer {
// Create MCP server
const server = new McpServer({
name: "acp-mcp-server",
version: "1.0.0",
});
const server = new McpServer({ name: "acp", version: "1.0.0" }, { capabilities: { tools: {} } });
if (clientCapabilities?.fs?.readTextFile) {
server.registerTool(
@@ -625,9 +620,30 @@ File editing instructions:
);
}
return server;
}
const UNQUALIFIED_PERMISSION_TOOL_NAME = "permission";
const PERMISSION_SERVER_PREFIX = "mcp__acpPermission__";
export const PERMISSION_TOOL_NAME = PERMISSION_SERVER_PREFIX + UNQUALIFIED_PERMISSION_TOOL_NAME;
/**
* Separate permission tool. Needs to be an HTTP server for now, because Claude Code doesn't
* support permission tools via SDK servers.
* Ideally it moves to the `canUseTool` callback in the future.
*/
export function createPermissionMcpServer(
agent: ClaudeAcpAgent,
sessionId: string,
): Promise<Server> {
const server = new McpServer(
{ name: "acpPermission", version: "1.0.0" },
{ capabilities: { tools: {} } },
);
const alwaysAllowedTools: { [key: string]: boolean } = {};
server.registerTool(
unqualifiedToolNames.permission,
UNQUALIFIED_PERMISSION_TOOL_NAME,
{
title: "Permission Tool",
description: "Used to request tool permissions",

View File

@@ -5,6 +5,7 @@ import {
AvailableCommand,
Client,
ClientSideConnection,
ndJsonStream,
NewSessionResponse,
ReadTextFileRequest,
ReadTextFileResponse,
@@ -108,14 +109,13 @@ describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration"
newSessionResponse: NewSessionResponse;
}> {
let client;
const connection = new ClientSideConnection(
(agent) => {
client = new TestClient(agent);
return client;
},
nodeToWebWritable(child.stdin!),
nodeToWebReadable(child.stdout!),
);
const input = nodeToWebWritable(child.stdin!);
const output = nodeToWebReadable(child.stdout!);
const stream = ndJsonStream(input, output);
const connection = new ClientSideConnection((agent) => {
client = new TestClient(agent);
return client;
}, stream);
await connection.initialize({
protocolVersion: 1,