From 2b3f2c8eb6e9250c949e5ddae8677a318f0796ba Mon Sep 17 00:00:00 2001 From: Jan Leon Date: Mon, 29 Jun 2026 15:31:27 +0200 Subject: [PATCH] chore: remove unused MCP scope helper exports (#5336) Verified dead-code removal: typecheck:core clean + affected unit tests + check-fabricated-docs gate green. All 'external references' were false positives (negative-assertion guards / doc comments). Integrated into release/v3.8.41. Thanks @JxnLexn! --- docs/architecture/AUTHZ_GUIDE.md | 4 +- src/shared/constants/mcpScopes.ts | 63 -------------------------- tests/unit/mcp-pool-tools-3368.test.ts | 21 +++++---- 3 files changed, 15 insertions(+), 73 deletions(-) diff --git a/docs/architecture/AUTHZ_GUIDE.md b/docs/architecture/AUTHZ_GUIDE.md index 3944c007e4..4f10555901 100644 --- a/docs/architecture/AUTHZ_GUIDE.md +++ b/docs/architecture/AUTHZ_GUIDE.md @@ -163,7 +163,9 @@ write:resilience, pricing:write, read:cache, write:cache, read:compression, write:compression, read:proxies ``` -Preset bundles (`MCP_SCOPE_PRESETS`): `readonly`, `full`, `monitor`, `agent`. Use `hasRequiredScopes(granted, toolName)` and `getMissingScopes()` for enforcement inside MCP handlers. +Scope enforcement in `open-sse/mcp-server/server.ts` passes each tool's scope list into +`evaluateToolScopes()` after `resolveCallerScopeContext()` resolves scopes from MCP auth info, +request metadata, or `OMNIROUTE_MCP_SCOPES`. ## Auth Required Toggle diff --git a/src/shared/constants/mcpScopes.ts b/src/shared/constants/mcpScopes.ts index 80f987c648..62bda5a99c 100644 --- a/src/shared/constants/mcpScopes.ts +++ b/src/shared/constants/mcpScopes.ts @@ -76,66 +76,3 @@ export const MCP_TOOL_SCOPES: Record = { // Stealth browser pool observability (#3368 PR7) omniroute_browser_pool_status: ["read:health"], } as const; - -// ============ Scope Groups ============ - -/** Preset scope bundles for common use cases */ -export const MCP_SCOPE_PRESETS = { - /** Read-only access to all health, combo, quota, and usage data */ - readonly: [ - "read:health", - "read:combos", - "read:quota", - "read:usage", - "read:models", - "read:cache", - "read:compression", - ] as const satisfies readonly McpScope[], - - /** Full access including writes and execution */ - full: [...MCP_SCOPE_LIST] as McpScope[], - - /** Monitoring only — health and metrics */ - monitor: [ - "read:health", - "read:quota", - "read:usage", - "read:cache", - "read:compression", - ] as const satisfies readonly McpScope[], - - /** Agent — can execute completions and read state */ - agent: [ - "read:health", - "read:combos", - "read:quota", - "read:usage", - "read:models", - "read:cache", - "read:compression", - "execute:completions", - "execute:search", - ] as const satisfies readonly McpScope[], -} as const; - -// ============ Helpers ============ - -/** - * Check if a set of granted scopes satisfies the required scopes for a tool. - */ -export function hasRequiredScopes(grantedScopes: readonly string[], toolName: string): boolean { - const required = MCP_TOOL_SCOPES[toolName]; - if (!required) return false; - const granted = new Set(grantedScopes); - return required.every((scope) => granted.has(scope)); -} - -/** - * Get the list of missing scopes for a tool given granted scopes. - */ -export function getMissingScopes(grantedScopes: readonly string[], toolName: string): string[] { - const required = MCP_TOOL_SCOPES[toolName]; - if (!required) return []; - const granted = new Set(grantedScopes); - return required.filter((scope) => !granted.has(scope)); -} diff --git a/tests/unit/mcp-pool-tools-3368.test.ts b/tests/unit/mcp-pool-tools-3368.test.ts index 5994cab3aa..13a3f720c7 100644 --- a/tests/unit/mcp-pool-tools-3368.test.ts +++ b/tests/unit/mcp-pool-tools-3368.test.ts @@ -17,9 +17,8 @@ const { handlePoolWarm, handleBrowserPoolStatus, } = await import("../../open-sse/mcp-server/tools/poolTools.ts"); -const { MCP_TOOL_SCOPES, MCP_SCOPE_LIST } = await import( - "../../src/shared/constants/mcpScopes.ts" -); +const mcpScopesModule = await import("../../src/shared/constants/mcpScopes.ts"); +const { MCP_TOOL_SCOPES, MCP_SCOPE_LIST } = mcpScopesModule; const POOL_TOOL_NAMES = [ "omniroute_pool_status", @@ -107,6 +106,12 @@ test("read tools require read:health; lifecycle tools require write:resilience", assert.deepEqual(tools.omniroute_pool_warm.scopes, ["write:resilience"]); }); +test("MCP scope constants public surface excludes unused helper bundles", () => { + assert.equal("MCP_SCOPE_PRESETS" in mcpScopesModule, false); + assert.equal("hasRequiredScopes" in mcpScopesModule, false); + assert.equal("getMissingScopes" in mcpScopesModule, false); +}); + // ── Live handler behavior (against the in-memory PoolRegistry) ───────────── // No pools are created here, so the registry stays empty: status returns the // all-pools aggregate shape and per-provider tools return a clear error. @@ -155,9 +160,8 @@ test("handlePoolReset reports reset:false for an unknown provider", async () => // ── #3368 PR7 — browser pool observability ──────────────────────────────── test("handleBrowserPoolStatus returns status + cumulative metrics shape", async () => { - const { __resetBrowserPoolMetricsForTest } = await import( - "../../open-sse/services/browserPool.ts" - ); + const { __resetBrowserPoolMetricsForTest } = + await import("../../open-sse/services/browserPool.ts"); __resetBrowserPoolMetricsForTest(); const result = (await handleBrowserPoolStatus()) as { @@ -184,9 +188,8 @@ test("handleBrowserPoolStatus returns status + cumulative metrics shape", async }); test("shutdownPool increments the shutdowns counter and records the reason", async () => { - const { shutdownPool, getBrowserPoolMetrics, __resetBrowserPoolMetricsForTest } = await import( - "../../open-sse/services/browserPool.ts" - ); + const { shutdownPool, getBrowserPoolMetrics, __resetBrowserPoolMetricsForTest } = + await import("../../open-sse/services/browserPool.ts"); __resetBrowserPoolMetricsForTest(); await shutdownPool("unit-test-reason");