Files
oh-my-pi/packages/coding-agent/test/acp-mcp-isolation.test.ts
T
roboomp 185615497c fix(acp): disable host MCP discovery in ACP session factory
ACP clients own MCP server configuration via session/new.mcpServers and AcpAgent#configureMcpServers. The ACP session factory previously left enableMCP at its default (true), so createAgentSession ran discoverAndLoadMCPTools on every session/new and the resulting host MCP tools landed in the session tool registry alongside the client-supplied ones. search_tool_bm25 then surfaced only the host tools.

Force enableMCP: false on every session created through createAcpSessionFactory so on-disk discovery is bypassed in ACP mode. Non-ACP modes (omp interactive, print, RPC) keep auto-discovery.

Fixes #1234
2026-05-20 21:40:43 +00:00

77 lines
2.9 KiB
TypeScript

/**
* Regression test for issue #1234.
*
* `omp acp` must not auto-discover host `.mcp.json` servers when creating a
* session for an ACP client. MCP server ownership belongs entirely to the ACP
* client (`session/new.mcpServers` → `AcpAgent#configureMcpServers`); letting
* `createAgentSession` run on-disk discovery in parallel registers host MCP
* tools that shadow the client-supplied ones in the session tool registry.
*
* The contract enforced here is narrow on purpose: every call routed through
* the ACP session factory must reach `createAgentSession` with
* `enableMCP: false`, regardless of what `baseOptions` carries.
*/
import { describe, expect, it } from "bun:test";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { Snowflake } from "@oh-my-pi/pi-utils";
import { ModelRegistry } from "../src/config/model-registry";
import { Settings } from "../src/config/settings";
import { createAcpSessionFactory } from "../src/main";
import type { CreateAgentSessionOptions, CreateAgentSessionResult } from "../src/sdk";
import type { AgentSession } from "../src/session/agent-session";
import { AuthStorage } from "../src/session/auth-storage";
describe("createAcpSessionFactory MCP isolation (issue #1234)", () => {
it("forces enableMCP=false even when baseOptions opts in", async () => {
const tempDir = path.join(os.tmpdir(), `pi-acp-mcp-isolation-${Snowflake.next()}`);
fs.mkdirSync(tempDir, { recursive: true });
const authStorage = await AuthStorage.create(path.join(tempDir, "auth.db"));
try {
const modelRegistry = new ModelRegistry(authStorage);
const settings = Settings.isolated({});
const fakeSession = {} as AgentSession;
const captured: CreateAgentSessionOptions[] = [];
const createSession = async (options: CreateAgentSessionOptions): Promise<CreateAgentSessionResult> => {
captured.push(options);
return {
session: fakeSession,
extensionsResult: {
extensions: [],
errors: [],
runner: undefined,
} as unknown as CreateAgentSessionResult["extensionsResult"],
setToolUIContext: () => {},
eventBus: {
emit: () => {},
on: () => () => {},
off: () => {},
} as unknown as CreateAgentSessionResult["eventBus"],
};
};
// baseOptions deliberately sets enableMCP=true to prove the factory ignores it.
const factory = createAcpSessionFactory({
baseOptions: { enableMCP: true } as CreateAgentSessionOptions,
settings,
sessionDir: path.join(tempDir, "sessions"),
authStorage,
modelRegistry,
parsedArgs: {},
rawArgs: [],
createSession,
});
const result = await factory(tempDir);
expect(result).toBe(fakeSession);
expect(captured).toHaveLength(1);
expect(captured[0].enableMCP).toBe(false);
} finally {
authStorage.close();
fs.rmSync(tempDir, { recursive: true, force: true });
}
});
});