Skip to main content
制御と安全性

権限制御

Qoder Agent SDK の権限制御機能は、1回の query() セッション内でモデルが何を実行できるかを管理します。モデルに見えるツールの制限、デフォルト認可ポリシーの設定、ツール実行前のホストアプリケーションによる承認、ユーザー承認後の新しいルールの適用などが可能です。 権限制御は単独の API ではなく、options に配置される設定の集合です。通常、まず今回のセッションでモデルが使えるツールを決め、次にそれらのツールがどの条件で実行可能かを決め、最後に必要に応じてランタイム承認、動的ルール更新、settings、hooks を接続します。
const messages = query({
  prompt: 'Inspect the repository and summarize risky changes.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    tools: ['Read', 'Grep', 'Bash'],
    allowedTools: ['Read', 'Grep'],
    disallowedTools: ['Bash'],
    permissionMode: 'default',
  },
});

for await (const message of messages) {
  console.log(message);
}
上の例はよくあるポリシーを表現しています:モデルは ReadGrepBash を見ることができ、ReadGrep は事前承認、Bash は実行禁止です。実際のプロジェクトでは、さらに権限コールバック(canUseTool / can_use_tool)を加え、事前承認されていない操作を自社のプロダクト UI、承認システム、リスク管理サービスに委ねられます。

機能概要

権限関連の options はおおまかに4種類に分かれます。第1はデフォルトポリシーの決定(plan モード、編集自動許可、対話的確認の禁止など)。第2はツールの範囲とルール。第3はホストアプリケーションによるランタイム承認。第4はより高度な settings、hooks、MCP ツールポリシーです。
解決したい問題推奨エントリ(TypeScript / Python)説明
セッションのデフォルト権限動作を設定permissionMode / permission_mode明示ルールに一致しないツール呼び出しの処理方法を決定
権限チェックのスキップを明示的に確認allowDangerouslySkipPermissions / allow_dangerously_skip_permissionsbypassPermissions または yolo と併用時のみ
今回のセッションで参照可能なツールを制限tools含まれていないツールは利用可能ツールとしてモデルに提供されない
特定のツールを事前承認allowedTools / allowed_tools一致すると通常は認可の確認に入らない
特定のツールを禁止disallowedTools / disallowed_tools一致すると拒否。allow より優先
ホストアプリでツール呼び出しを承認canUseTool / can_use_toolSDK ホストがランタイムで allow / deny を返す
承認を外部 prompt tool に委ねるpermissionPromptToolName / permission_prompt_tool_name実行環境が permission prompt tool を提供済みの場合に適する
承認後に現在のセッションルールを更新PermissionUpdate「今回のみ許可」「このセッションで常に許可」によく使う
cwd 外のディレクトリへのアクセスを許可additionalDirectories / add_dirsセッションのアクセス可能ディレクトリを拡張
settings から権限ルールを設定settingsセッション開始時に静的な権限設定を提供するのに適する
ライフサイクルでインターセプトまたは監査hooks高度なインターセプト、監査、アラートに適する
MCP server にツールポリシーを宣言MCP tool policyMCP server 設定でツールレベルの allow/ask/deny を宣言
権限設定に焦点を当てるため、以降の例ではメッセージ走査のコードを省略します。実際の使用では、返される非同期メッセージストリームを消費する必要があります。

クイックスタート:ホストアプリケーションによるツール呼び出し承認

ツール呼び出しを自前の承認ロジックに接続する場合は、権限コールバックを使います。SDK はランタイムでツール名、ツール入力、表示可能な承認情報一式をコールバックに渡します。allow を返すとツールは実行を続け、deny を返すと拒否されます。
const readOrder = tool(
  'read_order',
  'Read an order by ID.',
  { orderId: z.string() },
  async ({ orderId }) => ({
    content: [{ type: 'text', text: `order:${orderId}` }],
  }),
);

const server = createSdkMcpServer({
  name: 'orders',
  tools: [readOrder],
});

query({
  prompt: 'Read order 1001.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: { orders: server },
    permissionMode: 'default',
    async canUseTool(toolName, input, options) {
      if (toolName !== 'mcp__orders__read_order') {
        return {
          behavior: 'deny',
          message: 'Only order reads are allowed in this workflow.',
          toolUseID: options.toolUseID,
        };
      }

      return {
        behavior: 'allow',
        updatedInput: input,
        toolUseID: options.toolUseID,
      };
    },
  },
});
この例の read_order は SDK MCP ツールです。モデルが呼び出すときの完全ツール名は mcp__orders__read_order になります。権限コールバックはこのツールだけを許可し、元の入力を更新後の入力として返します。TypeScript では toolUseID を返すと、ランタイムが承認結果をこのツール呼び出しに正確に対応付けられます。

デフォルトポリシーの制御:permissionMode

権限モード(permissionMode / permission_mode)はセッションのデフォルト権限ポリシーを決めます。「このセッション全体がどのモードにあるか」——まず計画、編集の自動承認、確認せず拒否、管理された環境での権限チェックスキップ——を表現するのに適しています。
query({
  prompt: 'Plan the migration. Do not edit files yet.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'plan',
  },
});
plan モードは、変更を行う前にモデルに計画を出力させるためのモードです。
モード動作
default標準権限動作。ツール呼び出しは tools、allow/deny ルール、動的承認、ランタイムポリシーに従って処理
acceptEditsファイル編集操作を自動受け入れ。ワークスペースの変更が確認済みの場合に適する
bypassPermissions権限チェックをスキップ。明示的なスキップ確認も同時に必要
yolobypassPermissions の互換エイリアス。同じく明示的な確認が必要
plan計画モード。実行計画の出力に適し、デフォルトでは実際の変更を行わない
dontAsk対話的確認を行わない。事前承認されていない、ルールで許可されていない操作は拒否される
autoランタイム機能により自動的に allow または deny を判断。安全なワークスペース内ファイル編集は自動通過の可能性あり
同一セッション内でモードを切り替えるには、ランタイム制御メソッドを使います:
const q = query({
  prompt: 'Plan the change first.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'plan',
  },
});

await q.setPermissionMode('default');
bypassPermissionsyolo は高リスクモードです。SDK は明示的な allowDangerouslySkipPermissions: true(Python は allow_dangerously_skip_permissions=True)を要求し、通常のセッションが誤って権限チェックをスキップするのを防ぎます。
query({
  prompt: 'Run the trusted local maintenance task.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'bypassPermissions',
    allowDangerouslySkipPermissions: true,
  },
});

ツール範囲の制御:tools、allowedTools、disallowedTools

ツール制御が答えるのは「モデルがどのツールを見えるか、どのツールがデフォルトで許可・禁止されるか」です。3つのフィールドはよく併記されますが、セマンティクスは異なります。
query({
  prompt: 'Inspect the repo without modifying it.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    tools: ['Read', 'Grep', 'Bash'],
    allowedTools: ['Read', 'Grep'],
    disallowedTools: ['Bash'],
  },
});
この設定の意味:今回のセッションでは ReadGrepBash の3つのツールのみ提供され、ReadGrep は事前承認済み、Bash は禁止(モデルが呼び出そうとしても実行されない)。
フィールド(TypeScript / Python)役割適した場面
tools / toolsセッションで利用可能なツールセットを制限モデルの能力範囲を狭める
allowedTools / allowed_tools許可ルールを追加低リスクツールの反復承認を不要にする
disallowedTools / disallowed_tools拒否ルールを追加高リスクツールを明示的に禁止
同じツールが allow と deny の両方にマッチする場合、deny が優先されます。これにより、より広い許可ルールによって禁止ルールがバイパスされることを防ぎます。 MCP ツールも完全なツール名でマッチします。例えば SDK MCP server 名が orders、ツール名が read_order の場合、完全なツール名は mcp__orders__read_order です。
query({
  prompt: 'Read order 1001.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: { orders: server },
    allowedTools: ['mcp__orders__read_order'],
  },
});

ランタイム承認:canUseTool

アプリケーションに「1 回だけ許可」「このセッションでは常に許可」「拒否」を表示する場合は、権限コールバックを使用します。企業のリスク管理サービスにコマンドの実行可否を問い合わせることもできます。呼び出しのタイミング、権限モードの影響、AskUserQuestion の処理は承認とユーザー入力を参照してください。
query({
  prompt: 'Create a changelog file for this release.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'default',
    async canUseTool(toolName, input, options) {
      showApprovalDialog({
        title: options.title ?? toolName,
        description: options.description,
        input,
      });

      const approved = await waitForUserApproval(options.signal);

      if (!approved) {
        return {
          behavior: 'deny',
          message: 'Rejected by user.',
          toolUseID: options.toolUseID,
        };
      }

      return {
        behavior: 'allow',
        updatedInput: input,
        toolUseID: options.toolUseID,
      };
    },
  },
});
コールバックのシグネチャ:
type CanUseTool = (
  toolName: string,
  input: Record<string, unknown>,
  options: {
    signal: AbortSignal;
    suggestions?: PermissionUpdate[];
    blockedPath?: string;
    decisionReason?: string;
    title?: string;
    displayName?: string;
    description?: string;
    toolUseID: string;
    agentID?: string;
  },
) => Promise<PermissionResult>;
主要フィールドの説明(TypeScript は第3引数 options 上、Python は context 上):
フィールド説明
ツール名完全ツール名。例:ReadBashmcp__orders__read_order
入力今回のツール呼び出しの元の引数
toolUseID / tool_use_id今回のツール呼び出し ID。TypeScript では承認結果の返却時に含めることを推奨
signal認可リクエストがキャンセルされたときに発火。UI やリモート承認は監視すべき
title / displayName / descriptionランタイム生成の人間可読テキスト。承認 UI にそのまま使える
suggestionsランタイムが提案する権限更新。「このセッションで常に許可」に使える
blockedPath / blocked_pathパス関連の認可シナリオにおける制限パス
decisionReason / decision_reasonランタイム提供の承認理由。表示や監査に使える
agentID / agent_idサブ Agent がツール呼び出しを開始した場合の Agent ID
allow を返すとツールの実行を継続します:
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
};
更新後の入力がツールが最終的に受け取る引数です。そのまま返しても、承認後に変更してもかまいません。テナント ID の追加、安全なディレクトリへのパス書き換え、許可されないフィールドの除去などです。 deny を返すとツールを拒否します:
return {
  behavior: 'deny',
  message: 'This command is not allowed in the current workspace.',
  toolUseID: options.toolUseID,
};
deny.message は必須です。拒否理由の一部として、モデル、ログ、ホストアプリの表示に使われます。SDK が CLI の認可リクエストを受け取ったのに権限コールバックが未設定の場合はエラーを返し、デフォルトで許可することはありません。 権限システムがツール呼び出しを直接拒否した場合、メッセージストリームに構造化された権限拒否メッセージが表示されることがあります:
type SDKPermissionDeniedMessage = {
  type: 'system';
  subtype: 'permission_denied';
  tool_name: string;
  tool_use_id?: string;
  message?: string;
  decision_reason?: string;
  decision_reason_type?: string;
};
この種のメッセージは dontAsk モード、自動拒否、ルール拒否などでよく現れます。ホストアプリはこれで UI 状態を更新したり監査ログを書いたりできます。

セッション内での権限更新:PermissionUpdate

PermissionUpdate は、承認後に現在のセッションの権限ルールを更新するためのものです。最も一般的なのは、ユーザーが承認 UI で「このセッションで常に許可」を選ぶ場面です。ランタイムが提示した suggestions をそのまま返すことも、自分で明示的なルールを構築することもできます。
async function canUseTool(toolName, input, options) {
  const decision = await showApprovalDialog({
    toolName,
    suggestions: options.suggestions,
  });

  if (decision === 'always-allow-this-session') {
    return {
      behavior: 'allow',
      updatedInput: input,
      toolUseID: options.toolUseID,
      updatedPermissions: options.suggestions,
    };
  }

  if (decision === 'allow-once') {
    return {
      behavior: 'allow',
      updatedInput: input,
      toolUseID: options.toolUseID,
    };
  }

  return {
    behavior: 'deny',
    message: 'Rejected by user.',
    toolUseID: options.toolUseID,
  };
}
ルールを直接構築することもできます:
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
  updatedPermissions: [
    {
      type: 'addRules',
      behavior: 'allow',
      destination: 'session',
      rules: [{ toolName: 'mcp__orders__read_order' }],
    },
  ],
};
サポートされる更新タイプ:
タイプ役割
addRulesallow、ask、deny ルールの追加
replaceRulesルールの置換
removeRulesルールの削除
setMode権限モードの切り替え
addDirectoriesアクセス許可ディレクトリの追加
removeDirectoriesディレクトリ承認の削除
動的な権限更新は現在のセッション(destination: 'session')に書き込むことを推奨します。session はこの query セッションの以降の権限チェックにのみ影響します。ローカル・プロジェクト・ユーザーレベルへの永続化が必要な場合は、単発の承認コールバック内の動的更新ではなく、settings の管理フローを優先してください。

追加ディレクトリへのアクセス

デフォルトでは、セッションは cwd を主作業ディレクトリとします。モデルが cwd 外のディレクトリを読み書きする必要がある場合は、明示的に追加ディレクトリを渡してください(TypeScript は additionalDirectories、Python は add_dirs)。
query({
  prompt: 'Inspect the app and the shared package.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/repo/app',
    additionalDirectories: ['/repo/packages/shared'],
  },
});
この設定は、セッションの主要作業ディレクトリが /repo/app であり、同時にモデルが /repo/packages/shared にアクセスすることを許可することを意味します。これは monorepo、クロスリポジトリデバッグ、共有ライブラリの調査などのシーンに適しています。 実行中に PermissionUpdate を通じてディレクトリ承認を調整することもできます:
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
  updatedPermissions: [
    {
      type: 'addDirectories',
      destination: 'session',
      directories: ['/repo/packages/shared'],
    },
  ],
};
ディレクトリ認可は権限境界の一部です。広範囲のディレクトリを汎用デフォルトにしないでください。タスクに応じて最小のディレクトリ集合を追加するのがより堅実です。

外部承認ツール:permissionPromptToolName

このオプション(TypeScript は permissionPromptToolName、Python は permission_prompt_tool_name)は、SDK ホストで権限コールバックを実装する代わりに、権限リクエストを実行環境の permission prompt tool に委ねます。既存の外部承認ツール、リモート実行環境、統一権限ゲートウェイがある場面に適しています。
query({
  prompt: 'Run the task.',
  options: {
    auth: accessTokenFromEnv(),
    permissionPromptToolName: 'mcp__permission_server__approve',
  },
});
使用時の注意点:
  • 現在の実行環境が認識できる prompt tool 名である必要があります。
  • 権限コールバック(canUseTool / can_use_tool)とは排他で、同時には渡せません。
  • SDK ホスト自身が承認を判断する場合は、権限コールバックを優先してください。
permission prompt tool は以下の入力を受け取ります:
type PermissionPromptToolInput = {
  tool_name: string;
  input: Record<string, unknown>;
  tool_use_id?: string;
};
権限結果を返す必要があります:
type PermissionPromptToolOutput =
  | {
      behavior: 'allow';
      updatedInput: Record<string, unknown>;
      updatedPermissions?: PermissionUpdate[];
      toolUseID?: string;
    }
  | {
      behavior: 'deny';
      message: string;
      interrupt?: boolean;
      toolUseID?: string;
    };
allow.updatedInput はツール実行時に使用される最終的な入力パラメータです。元の入力パラメータを保持する場合は、受け取った input をそのまま返す必要があります。deny.message は必須です。interrupt: true は拒否後に現在のエージェントフローを中断することを示します。

settings による権限ルールの提供

settings はセッション開始前に静的な権限設定を提供するのに適しています。「このプロジェクトはデフォルトで何を許可し、何を拒否し、どの追加ディレクトリがあるか」の表現には権限コールバックより向いています。
query({
  prompt: 'Inspect the project.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    settings: {
      permissions: {
        allow: ['Read', 'Grep'],
        deny: ['Bash'],
        ask: ['Write'],
        defaultMode: 'default',
        additionalDirectories: ['/path/to/shared-lib'],
      },
    },
  },
});
| フィールド | 型 | 任意 | 意味 |
フィールド説明
permissions.allow許可ルール
permissions.deny拒否ルール
permissions.ask常に確認ルール
permissions.defaultModeデフォルト権限モード
permissions.disableBypassPermissionsMode'disable' に設定すると権限チェックスキップモードを無効化
permissions.additionalDirectories追加アクセス可能ディレクトリ
アプリケーションが settings のデフォルト権限モードを読み取って適用する場合、高リスクモードの実行前に独自のプロダクトレベルの確認を行うことを推奨します。bypassPermissionsyolo のようなモードは、明確に信頼された環境でのみ使用すべきです。

hooks による高度なインターセプトと監査

Hooks は、既に SDK の hooks 体系を導入済みで、ツールのライフサイクル内でより細かい制御をしたい場面に適しています。権限コールバックと比べ、hooks は監査、アラート、統一インターセプト、拒否理由の記録といった横断的ロジックに向いています。
query({
  prompt: 'Inspect the repo.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    hooks: {
      PreToolUse: [
        {
          matcher: 'Bash',
          hooks: [
            async (input) => {
              return {
                hookSpecificOutput: {
                  hookEventName: 'PreToolUse',
                  permissionDecision: 'deny',
                  permissionDecisionReason: 'Shell commands are disabled here.',
                },
              };
            },
          ],
        },
      ],
    },
  },
});
権限関連の hook は主に3種類あります:
Hookトリガータイミング一般的な用途
PreToolUseツール呼び出し前事前の許可、拒否、確認要求、または後続フローへの委任
PermissionRequest権限リクエスト時通常の prompt 前に直接許可または拒否を返す
PermissionDenied権限拒否後監査、アラート、拒否理由の記録
PreToolUse は以下を返すことができます:
{
  hookSpecificOutput: {
    hookEventName: 'PreToolUse',
    permissionDecision: 'allow' | 'deny' | 'ask' | 'defer',
    permissionDecisionReason?: string,
    updatedInput?: Record<string, unknown>,
  },
}
PermissionRequest はツール承認に類似した権限結果を返すことができます:
{
  hookSpecificOutput: {
    hookEventName: 'PermissionRequest',
    decision: {
      behavior: 'deny',
      message: 'Denied by policy.',
    },
  },
}
PermissionDenied は通常、結果を観察するために使用し、ツールの通過は担当しません。入力には拒否されたツール名、ツール入力パラメータ、ツール呼び出し ID、拒否理由が含まれます。

MCP Tool Policy

権限ポリシーが本質的に特定の MCP server に属する場合、MCP server config で直接 tool レベルの permission policy を宣言することもできます。ポリシーがグローバルなツール許可/拒否リストに散らばらず、MCP server の設定に付随します。
query({
  prompt: 'Use repo tools.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: {
      repo_tools: {
        type: 'http',
        url: process.env.REPO_TOOLS_MCP_URL!,
        tools: [
          { name: 'search', permission_policy: 'always_allow' },
          { name: 'write_file', permission_policy: 'always_ask' },
          { name: 'delete_file', permission_policy: 'always_deny' },
        ],
      },
    },
  },
});
ポリシーの意味:
ポリシー動作
always_allowマッチするツールを直接許可
always_askマッチするツールは承認フローに入る
always_denyマッチするツールを直接拒否
name は MCP tool の元の名前でも完全なツール名でも指定できます(例: mcp__repo_tools__search)。実際のマッチング時、ランタイムはポリシー名を現在の MCP ツール呼び出しにマッピングします。
権限制御 - Qoder