{"version":"2.1.319","anchor":"sdk-mcp-call-new-check-permissions-option","canonical_anchor":"sdk-mcp-call-new-check-permissions-option","heading":"mcp_call can now run through Claude Code's permission checks","tier":"use","area":"SDK","scope":"individual","heads_up":false,"url":"https:\/\/changelogs.core-directive.com\/v\/2.1.319\/e\/sdk-mcp-call-new-check-permissions-option","release_url":"https:\/\/changelogs.core-directive.com\/v\/2.1.319","markdown":"### mcp_call can now run through Claude Code's permission checks\n\nPrograms controlling Claude Code can set check_permissions on mcp_call so a direct MCP tool call is checked like Claude's own, with clear refusals\n\n**What**\n\n`mcp_call` is a request that a program controlling Claude Code through the SDK can send. It calls a tool on an MCP server (an add-on that provides tools) directly. Such calls used to skip permission checks with no exception. The description now says permission checks are skipped unless `check_permissions` is set.\n\n- With `check_permissions` true, the call is decided like Claude's own call. Permission rules, the permission mode and managed settings all apply, as do `PreToolUse` and `PostToolUse` hooks (your own scripts that run before and after a tool call). Questions go to the host program as `can_use_tool`.\n\n- Refusals begin \"The tool did not run: \", for example \"no permission decision was reached.\" or \"nobody can be asked in this permission mode.\" Where the option cannot be used, the reply is \"The tool did not run: check_permissions is not available here.\" Refused calls raise `McpCallRefusedError`.\n\n- Refusals are capped per server in each conversation. Past the cap, the reply is \"too many calls to this server were refused, so no more will run in this conversation.\"\n\n- `check_permissions` must be a boolean, otherwise the call fails with \"mcp_call: check_permissions must be a boolean\". Only a CLI that reports `mcp_call_check_permissions_v1` honours it, and older CLIs ignore it.\n\n- The `timeout_ms` description now says it also limits how long hooks run and how long the call waits for an answer.\n\n- A new early check can reject the request with an error, and a cancelled call now stops with a `remote-cancel` reason. The `result_not_for_model` check now uses a helper shared with other code. The `tengu_ptc_enabled` kill switch for staged calls still falls back to true, and nothing has been read about it.\n\n- An `mcp_tool` hook is a hook that calls an MCP tool itself. These hooks now run a check on the server, tool and input before the call. Refusals return withheld results marked \"Hooks: mcp_tool hook refused\", and errors are turned into refusals too.\n\n- When an `mcp_tool` hook's call to a claude.ai connector is refused, the message starts \"An mcp_tool hook's call was refused.\" In one form, used when the check cannot tell, it suggests removing the hook or pointing it at a tool that is not a connector. In the other, it suggests removing the hook, using another tool, or leaving an argument out of its input.\n\n**Why**\n\nPrograms driving Claude Code can make their direct MCP calls obey the same rules, modes and hooks as Claude's own calls. People who write hooks that call claude.ai connectors get a clear reason when a call is blocked.\n\n- Flag `tengu_ptc_enabled`: Not enough to say (read for one account on one subscription tier against v2.1.319; this account: no value returned, anonymous baseline: no value returned, compiled default: on) These values were read against a different version of Claude Code, so treat them as the nearest reading available instead of one taken on this release.\n- Area: SDK\n- Names: `mcp_call`, `check_permissions`\n- Tier: Use it now\n- Useful: 4\/5\n- Signal: 3\/5\n- Scope: individual\n- Heads-up: no"}