Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion packages/agent/src/adapters/claude/claude-agent.refresh.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,14 @@ function makeAgent(): Agent {
function installFakeSession(
agent: Agent,
sessionId: string,
overrides: Partial<{ modelId: string }> = {},
overrides: Partial<{ modelId: string; localToolsMcpServer: unknown }> = {},
) {
const oldQuery = makeQueryHandle();
const input = new Pushable();
const endSpy = vi.spyOn(input, "end");
const abortController = new AbortController();

const localToolsMcpServer = overrides.localToolsMcpServer;
const session = {
query: oldQuery,
queryOptions: {
Expand Down Expand Up @@ -105,6 +106,7 @@ function installFakeSession(
notificationHistory: [{ foo: "bar" }],
taskRunId: "run-1",
modelId: overrides.modelId,
localToolsMcpServer,
} as unknown as Parameters<typeof Object.assign>[0];

(agent as unknown as { session: unknown }).session = session;
Expand Down Expand Up @@ -278,6 +280,43 @@ describe("ClaudeAcpAgent.extMethod refresh_session", () => {
);
});

it("re-attaches the in-process posthog-local MCP server", async () => {
const agent = makeAgent();
const localServer = {
type: "sdk",
name: "posthog-local",
instance: { fakeServer: true },
};
installFakeSession(agent, "s-local-tools", {
localToolsMcpServer: localServer,
});

await agent.extMethod(POSTHOG_METHODS.REFRESH_SESSION, {
mcpServers: freshMcpServers,
});

expect(lastQueryCall.options?.mcpServers).toMatchObject({
posthog: { type: "http", url: "https://fresh" },
"posthog-local": localServer,
});
});

it("omits posthog-local when none was registered at session creation", async () => {
const agent = makeAgent();
installFakeSession(agent, "s-no-local-tools");

await agent.extMethod(POSTHOG_METHODS.REFRESH_SESSION, {
mcpServers: freshMcpServers,
});

const servers = lastQueryCall.options?.mcpServers as Record<
string,
unknown
>;
expect(servers).toBeDefined();
expect(servers["posthog-local"]).toBeUndefined();
});

it("re-fetches MCP tool metadata for the new query", async () => {
const agent = makeAgent();
installFakeSession(agent, "s-metadata");
Expand Down
12 changes: 10 additions & 2 deletions packages/agent/src/adapters/claude/claude-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,12 +889,19 @@ export class ClaudeAcpAgent extends BaseAcpAgent {

// Reuse every option from the running session; swap mcpServers, re-root
// identity on `resume` instead of `sessionId`, and give the new Query a
// fresh AbortController.
// fresh AbortController. Re-attach the in-process local-tools MCP server —
// `mcpServers` from the caller only carries external servers, so without
// this the rebuilt session would lose `git_signed_commit` and any future
// local tools.
const newAbortController = new AbortController();
const { sessionId: _drop, ...rest } = prev.queryOptions;
const mergedMcpServers: Record<string, McpServerConfig> = { ...mcpServers };
if (prev.localToolsMcpServer) {
mergedMcpServers[LOCAL_TOOLS_MCP_NAME] = prev.localToolsMcpServer;
}
const newOptions: Options = {
...rest,
mcpServers,
mcpServers: mergedMcpServers,
resume: this.sessionId,
forkSession: false,
abortController: newAbortController,
Expand Down Expand Up @@ -1226,6 +1233,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
cwd,
notificationHistory: [],
taskRunId: meta?.taskRunId,
localToolsMcpServer: localToolsServer,
};
this.session = session;
this.sessionId = sessionId;
Expand Down
8 changes: 8 additions & 0 deletions packages/agent/src/adapters/claude/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
TerminalOutputResponse,
} from "@agentclientprotocol/sdk";
import type {
McpSdkServerConfigWithInstance,
Options,
Query,
SDKUserMessage,
Expand Down Expand Up @@ -65,6 +66,13 @@ export type Session = BaseSession & {
pendingMessages: Map<string, PendingMessage>;
nextPendingOrder: number;
emitRawSDKMessages: boolean | SDKMessageFilter[];
/**
* In-process MCP server hosting PostHog-local tools (e.g. `git_signed_commit`).
* Stashed here so `refreshSession` can re-merge it into the rebuilt options —
* otherwise the cloud agent-server's pre-prompt TTL refresh would drop it and
* the model would lose access to tools registered at session creation.
*/
localToolsMcpServer?: McpSdkServerConfigWithInstance;
};

export type ToolUseCache = {
Expand Down
Loading