fix(mcp): reorder enforceScopes guard before MCP_TOOL_MAP lookup, add scopes to all dynamic tool definitions - #2958
Conversation
…to all dynamic tool definitions - Move !enforceScopes guard before MCP_TOOL_MAP lookup in evaluateToolScopes() - Add inlineScopes parameter for dynamic tool scope resolution - Add scopes to all 33 dynamic tool definitions across 5 tool files - Wire toolDef.scopes through withScopeEnforcement in server.ts - Preserves existing behavior: tool_definition_missing returned when enforceScopes=true and no scopes found anywhere
There was a problem hiding this comment.
Code Review
This pull request refactors the MCP server's scope enforcement mechanism to support inline scope definitions across various tools, including compression, gamification, memory, plugin, and skill tools. It updates the scope evaluation logic to accept an optional inlineScopes parameter. A critical issue was identified in the scope evaluation logic where tools that explicitly require no scopes (an empty scopes array) are incorrectly blocked and flagged as having a missing tool definition. A code suggestion was provided to resolve this by checking if the tool scopes are undefined instead of checking if the required scopes array is empty.
| const toolScopes = inlineScopes ?? MCP_TOOL_MAP[toolName]?.scopes; | ||
| const required = Array.isArray(toolScopes) ? Array.from(toolScopes) : []; | ||
|
|
||
| if (required.length === 0) { | ||
| return { | ||
| allowed: false, | ||
| required: [], | ||
| provided: Array.from(callerScopes), | ||
| provided, | ||
| missing: [], | ||
| reason: "tool_definition_missing", | ||
| }; | ||
| } |
There was a problem hiding this comment.
The current implementation treats any tool with an empty scopes list (required.length === 0) as having a missing tool definition, returning allowed: false with reason: "tool_definition_missing". This blocks any tool that explicitly requires no scopes (e.g., scopes: []).
Instead, we should check if toolScopes is undefined to determine if the tool definition is missing. If toolScopes is defined (even if it is an empty array), and no scopes are required, the tool should be allowed.
| const toolScopes = inlineScopes ?? MCP_TOOL_MAP[toolName]?.scopes; | |
| const required = Array.isArray(toolScopes) ? Array.from(toolScopes) : []; | |
| if (required.length === 0) { | |
| return { | |
| allowed: false, | |
| required: [], | |
| provided: Array.from(callerScopes), | |
| provided, | |
| missing: [], | |
| reason: "tool_definition_missing", | |
| }; | |
| } | |
| const toolScopes = inlineScopes ?? MCP_TOOL_MAP[toolName]?.scopes; | |
| if (toolScopes === undefined) { | |
| return { | |
| allowed: false, | |
| required: [], | |
| provided, | |
| missing: [], | |
| reason: "tool_definition_missing", | |
| }; | |
| } | |
| const required = Array.isArray(toolScopes) ? Array.from(toolScopes) : []; |
PR Reviewer Guide 🔍
|
Code Review SummaryStatus: No Issues Found | Recommendation: Merge The PR implements a critical fix for MCP scope enforcement on dynamic tools. The changes are well-structured:
The existing comment on line 122 of scopeEnforcement.ts appears incomplete/corrupted and does not match any visible issue in the current code. The logic at line 114 ( Files Reviewed (6 files)
Reviewed by laguna-m.1-20260312:free · 786,427 tokens |
|
Thank you for your contribution! This PR has been reviewed and integrated into the upcoming |
…add contributor hall Audited all 687 commits / 60 release/v3.8.8 PRs since v3.8.7 against the CHANGELOG: - Added 5 missing Fixed entries: #3052 (heap-pressure auto-calibration), #3051/#3048 (proxy fail-closed + registry assignments, @terence71-glitch), #3049/#3046 (session-pool fingerprint rotation + claude-web cf_clearance, @oyi77). - Credited previously-uncredited contributors: @branben (#2958 scope fix, #2959 Notion context source) and @JxnLexn (per-API-key stream default mode). - Added an Added entry for the per-API-key stream default mode feature. - Added the "🏆 Contributors" hall (24 contributors), matching the v3.8.6 format. Maintainer fix-PRs (#2966–#3030) are intentionally referenced by their original issue numbers in the body rather than the fix-PR number; @diegosouzapw is in the hall.
…s + add contributor hall Consolidate the split [Unreleased]/[3.8.11] sections into one, add entries for every merged contributor PR that was missing credit (#3170/#3171/#3172 @pizzav-xyz, #3185/#3195 @zhiru, #3188 @xz-dev, #3189/#3203/#3204/#3241 @wilsonicdev, #3191 @bypanghu, #3206 @juandisay, #3217 @oyi77, #3226 @miracuves, #3187/#3200 maintainer), drop stale v3.8.8 leftovers (#2958/#2959 already shipped) and 3 empty v3.8.10 stub headers.
…s + add contributor hall Consolidate the split [Unreleased]/[3.8.11] sections into one, add entries for every merged contributor PR that was missing credit (diegosouzapw#3170/diegosouzapw#3171/diegosouzapw#3172 @pizzav-xyz, diegosouzapw#3185/diegosouzapw#3195 @zhiru, diegosouzapw#3188 @xz-dev, diegosouzapw#3189/diegosouzapw#3203/diegosouzapw#3204/diegosouzapw#3241 @wilsonicdev, diegosouzapw#3191 @bypanghu, diegosouzapw#3206 @juandisay, diegosouzapw#3217 @oyi77, diegosouzapw#3226 @miracuves, diegosouzapw#3187/diegosouzapw#3200 maintainer), drop stale v3.8.8 leftovers (diegosouzapw#2958/diegosouzapw#2959 already shipped) and 3 empty v3.8.10 stub headers.
…add contributor hall Audited all 687 commits / 60 release/v3.8.8 PRs since v3.8.7 against the CHANGELOG: - Added 5 missing Fixed entries: diegosouzapw#3052 (heap-pressure auto-calibration), diegosouzapw#3051/diegosouzapw#3048 (proxy fail-closed + registry assignments, @terence71-glitch), diegosouzapw#3049/diegosouzapw#3046 (session-pool fingerprint rotation + claude-web cf_clearance, @oyi77). - Credited previously-uncredited contributors: @branben (diegosouzapw#2958 scope fix, diegosouzapw#2959 Notion context source) and @JxnLexn (per-API-key stream default mode). - Added an Added entry for the per-API-key stream default mode feature. - Added the "🏆 Contributors" hall (24 contributors), matching the v3.8.6 format. Maintainer fix-PRs (diegosouzapw#2966–diegosouzapw#3030) are intentionally referenced by their original issue numbers in the body rather than the fix-PR number; @diegosouzapw is in the hall.
… scopes to all dynamic tool definitions (diegosouzapw#2958) Integrated into release/v3.8.8
…s + add contributor hall Consolidate the split [Unreleased]/[3.8.11] sections into one, add entries for every merged contributor PR that was missing credit (diegosouzapw#3170/diegosouzapw#3171/diegosouzapw#3172 @pizzav-xyz, diegosouzapw#3185/diegosouzapw#3195 @zhiru, diegosouzapw#3188 @xz-dev, diegosouzapw#3189/diegosouzapw#3203/diegosouzapw#3204/diegosouzapw#3241 @wilsonicdev, diegosouzapw#3191 @bypanghu, diegosouzapw#3206 @juandisay, diegosouzapw#3217 @oyi77, diegosouzapw#3226 @miracuves, diegosouzapw#3187/diegosouzapw#3200 maintainer), drop stale v3.8.8 leftovers (diegosouzapw#2958/diegosouzapw#2959 already shipped) and 3 empty v3.8.10 stub headers.
…add contributor hall Audited all 687 commits / 60 release/v3.8.8 PRs since v3.8.7 against the CHANGELOG: - Added 5 missing Fixed entries: diegosouzapw#3052 (heap-pressure auto-calibration), diegosouzapw#3051/diegosouzapw#3048 (proxy fail-closed + registry assignments, @terence71-glitch), diegosouzapw#3049/diegosouzapw#3046 (session-pool fingerprint rotation + claude-web cf_clearance, @oyi77). - Credited previously-uncredited contributors: @branben (diegosouzapw#2958 scope fix, diegosouzapw#2959 Notion context source) and @JxnLexn (per-API-key stream default mode). - Added an Added entry for the per-API-key stream default mode feature. - Added the "🏆 Contributors" hall (24 contributors), matching the v3.8.6 format. Maintainer fix-PRs (diegosouzapw#2966–diegosouzapw#3030) are intentionally referenced by their original issue numbers in the body rather than the fix-PR number; @diegosouzapw is in the hall.
… scopes to all dynamic tool definitions (diegosouzapw#2958) Integrated into release/v3.8.8
…s + add contributor hall Consolidate the split [Unreleased]/[3.8.11] sections into one, add entries for every merged contributor PR that was missing credit (diegosouzapw#3170/diegosouzapw#3171/diegosouzapw#3172 @pizzav-xyz, diegosouzapw#3185/diegosouzapw#3195 @zhiru, diegosouzapw#3188 @xz-dev, diegosouzapw#3189/diegosouzapw#3203/diegosouzapw#3204/diegosouzapw#3241 @wilsonicdev, diegosouzapw#3191 @bypanghu, diegosouzapw#3206 @juandisay, diegosouzapw#3217 @oyi77, diegosouzapw#3226 @miracuves, diegosouzapw#3187/diegosouzapw#3200 maintainer), drop stale v3.8.8 leftovers (diegosouzapw#2958/diegosouzapw#2959 already shipped) and 3 empty v3.8.10 stub headers.
…add contributor hall Audited all 687 commits / 60 release/v3.8.8 PRs since v3.8.7 against the CHANGELOG: - Added 5 missing Fixed entries: diegosouzapw#3052 (heap-pressure auto-calibration), diegosouzapw#3051/diegosouzapw#3048 (proxy fail-closed + registry assignments, @terence71-glitch), diegosouzapw#3049/diegosouzapw#3046 (session-pool fingerprint rotation + claude-web cf_clearance, @oyi77). - Credited previously-uncredited contributors: @branben (diegosouzapw#2958 scope fix, diegosouzapw#2959 Notion context source) and @JxnLexn (per-API-key stream default mode). - Added an Added entry for the per-API-key stream default mode feature. - Added the "🏆 Contributors" hall (24 contributors), matching the v3.8.6 format. Maintainer fix-PRs (diegosouzapw#2966–diegosouzapw#3030) are intentionally referenced by their original issue numbers in the body rather than the fix-PR number; @diegosouzapw is in the hall.
… scopes to all dynamic tool definitions (diegosouzapw#2958) Integrated into release/v3.8.8
…s + add contributor hall Consolidate the split [Unreleased]/[3.8.11] sections into one, add entries for every merged contributor PR that was missing credit (diegosouzapw#3170/diegosouzapw#3171/diegosouzapw#3172 @pizzav-xyz, diegosouzapw#3185/diegosouzapw#3195 @zhiru, diegosouzapw#3188 @xz-dev, diegosouzapw#3189/diegosouzapw#3203/diegosouzapw#3204/diegosouzapw#3241 @wilsonicdev, diegosouzapw#3191 @bypanghu, diegosouzapw#3206 @juandisay, diegosouzapw#3217 @oyi77, diegosouzapw#3226 @miracuves, diegosouzapw#3187/diegosouzapw#3200 maintainer), drop stale v3.8.8 leftovers (diegosouzapw#2958/diegosouzapw#2959 already shipped) and 3 empty v3.8.10 stub headers.
Summary
Fixes scope enforcement for dynamic MCP tool groups (memory, skills, plugins, compression, gamification). The
evaluateToolScopes()guard was checkingMCP_TOOL_MAPbefore checking dynamic inline scopes, causing dynamic tools to always fail scope checks.Changes
evaluateToolScopes(): inline scopes checked first,MCP_TOOL_MAPfallback only when no inline scopes providedwithScopeEnforcement()now accepts optionaltoolScopesparameter; all dynamic tool groups pass their declared scopesscopesfield to all dynamic tool definitionsTesting
7 scope-enforcement tests pass.