fix(claude-code): pre-authorize workflow MCP tools so interactive acceptEdits mode stops blocking GSD commands
Since 2.72.0 the interactive permission default is acceptEdits, which auto-approves built-in Edit/Write/Bash but leaves the SDK permission gate up for MCP tools. Without a canUseTool handler, every mcp__gsd-workflow__* call surfaces as "This command requires approval" and blocks GSD actions (#4099). Add allowedTools entries (mcp__<server>__*) for each registered workflow MCP server in buildSdkOptions so they run unattended while the rest of the acceptEdits safety gate stays intact. Env-overridden server names are handled by deriving the glob list from the built mcpServers keys. Fixes #4099
This commit is contained in:
parent
d4bddfadf5
commit
b92fdc7b6f
2 changed files with 10 additions and 0 deletions
|
|
@ -612,6 +612,13 @@ export function buildSdkOptions(
|
|||
const mcpServers = buildWorkflowMcpServers();
|
||||
const permissionMode = overrides?.permissionMode ?? "bypassPermissions";
|
||||
const disallowedTools = ["AskUserQuestion"];
|
||||
// Pre-authorize every registered workflow MCP server's tools. Without this,
|
||||
// `acceptEdits` mode (the interactive default) auto-approves built-in
|
||||
// Edit/Write/Bash but still gates MCP calls like `mcp__gsd-workflow__*`,
|
||||
// surfacing "This command requires approval" on every GSD action (#4099).
|
||||
const allowedTools = mcpServers
|
||||
? Object.keys(mcpServers).map((serverName) => `mcp__${serverName}__*`)
|
||||
: [];
|
||||
return {
|
||||
pathToClaudeCodeExecutable: getClaudePath(),
|
||||
model: modelId,
|
||||
|
|
@ -623,6 +630,7 @@ export function buildSdkOptions(
|
|||
settingSources: ["project"],
|
||||
systemPrompt: { type: "preset", preset: "claude_code" },
|
||||
disallowedTools,
|
||||
...(allowedTools.length > 0 ? { allowedTools } : {}),
|
||||
...(mcpServers ? { mcpServers } : {}),
|
||||
betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
|
||||
...extraOptions,
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|||
assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
|
||||
assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
|
||||
assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
|
||||
assert.deepEqual(options.allowedTools, ["mcp__gsd-workflow__*"]);
|
||||
} finally {
|
||||
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
||||
process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
|
||||
|
|
@ -397,6 +398,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|||
const mcpServers = options.mcpServers as Record<string, any>;
|
||||
assert.ok(mcpServers?.["custom-workflow"], "expected custom workflow server config");
|
||||
assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
|
||||
assert.deepEqual(options.allowedTools, ["mcp__custom-workflow__*"]);
|
||||
} finally {
|
||||
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
||||
process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue