mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-12 18:22:48 +03:00
* feat: narrow mcp:connect scope + per-key HTTP tool-scope binding (#7895) Adds MCP_CONNECT_SCOPE ("mcp:connect"), a narrow additive API-key scope (kept out of MANAGEMENT_API_KEY_SCOPES, same precedent as SELF_USAGE_SCOPE) that authorizes ONLY the /api/mcp/ LOCAL_ONLY route-guard carve-out -- remote MCP-only callers no longer need broad manage/admin scope just to reach the transport routes. Scoped strictly to /api/mcp/; every other LOCAL_ONLY bypass prefix still requires hasManageScope() unchanged. Also resolves the caller's real api_keys.scopes over HTTP/SSE (httpAuthContext.ts::resolveMcpCallerAuthInfo) and passes it to the MCP SDK's transport.handleRequest(req, { authInfo }), so extra.authInfo.scopes reaching tool calls reflects the Bearer key's own scopes instead of the OMNIROUTE_MCP_SCOPES env fallback -- scopeEnforcement.ts already prioritized authInfo, it was simply unfed over HTTP. Does not flip the OMNIROUTE_MCP_ENFORCE_SCOPES default; stdio is unaffected (no per-caller identity, stays on the meta/env fallback chain). Closes #7895 * test(mcp): register mcp-connect-scope test in stryker tap.testFiles (#7895)
55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
/**
|
|
* Management API key scopes — the set of API key scopes that authorize a
|
|
* Bearer key on management routes (`/api/*` excluding `/api/v1/*` and the
|
|
* public allowlist).
|
|
*
|
|
* Single source of truth shared by:
|
|
* - `src/lib/api/requireManagementAuth.ts` (`hasManageScope`)
|
|
* - `src/shared/utils/apiAuth.ts` (`validateBearerApiKeyForManagement`)
|
|
*
|
|
* Keep both helpers in sync by importing `MANAGEMENT_API_KEY_SCOPES` from
|
|
* here — never re-declare the list inline.
|
|
*/
|
|
|
|
/** Canonical scope name granted to the default environment key. */
|
|
export const MANAGE_SCOPE = "manage";
|
|
|
|
/**
|
|
* Set of scopes that grant access to management API routes.
|
|
* `admin` is treated as a superset of `manage`.
|
|
*/
|
|
export const MANAGEMENT_API_KEY_SCOPES = new Set<string>(["manage", "admin"]);
|
|
|
|
/**
|
|
* Narrow, additive scope (#7895) that grants a non-loopback caller ONLY the
|
|
* `/api/mcp/` LOCAL_ONLY carve-out (see `LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES`
|
|
* in `src/server/authz/routeGuard.ts`) — it does NOT grant broader management
|
|
* API access. Deliberately kept OUT of `MANAGEMENT_API_KEY_SCOPES`, mirroring the
|
|
* existing narrow-additive-scope precedent (`SELF_USAGE_SCOPE`,
|
|
* `API_KEY_BYPASS_PROVIDER_QUOTA_SCOPE`). A key holding `manage`/`admin` still
|
|
* passes the carve-out unchanged; `mcp:connect` is an alternative, lower-privilege
|
|
* path for remote MCP-only callers.
|
|
*/
|
|
export const MCP_CONNECT_SCOPE = "mcp:connect";
|
|
|
|
/**
|
|
* Check whether any of the given scopes authorizes the `/api/mcp/` LOCAL_ONLY
|
|
* carve-out specifically — i.e. either a full management scope (`manage`/`admin`)
|
|
* or the narrow `mcp:connect` scope. Use this ONLY for the `/api/mcp/` bypass
|
|
* check; every other management route must keep using `hasManageScope`.
|
|
*/
|
|
export function hasMcpConnectOrManageScope(scopes: readonly string[] = []): boolean {
|
|
if (hasManageScope(scopes)) return true;
|
|
return scopes.includes(MCP_CONNECT_SCOPE);
|
|
}
|
|
|
|
/**
|
|
* Check whether any of the given scopes authorizes management API access.
|
|
*/
|
|
export function hasManageScope(scopes: readonly string[] = []): boolean {
|
|
for (const scope of scopes) {
|
|
if (MANAGEMENT_API_KEY_SCOPES.has(scope)) return true;
|
|
}
|
|
return false;
|
|
}
|