The DB migration sets search_tools DEFAULT ARRAY['*'], but the auth check
and listing filter treated "*" as a literal name, causing 401s and empty
list responses for all callers with the default permission.
- Add wildcard handling in _can_object_call_search_tools
- Add _normalize_search_tools_wildcard to convert ["*"] → None (no restriction)
- Move get_allowed_search_tool_names from endpoints.py to auth_checks.py
to eliminate cross-router import between search_tool_management and endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add type casts for TypedDict .get() calls and rename loop variable to
avoid type shadowing between config and DB search tool iterations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add search_tools permission support across the UI (key create/edit, team create,
object permissions view) with breaking-change alerts for the new least-privilege
default. Modernize the Search Tools page with AntD Tabs, a Test playground tab,
and ProviderLogo integration. Migrate TeamDropdown to self-fetching infinite
scroll pattern using useInfiniteTeams hook. Scope search tools visibility for
internal users based on their team memberships.
Backend: Add search_tools field to Prisma schema (all copies), Pydantic models
(ObjectPermissionBase + ObjectPermissionTable), and allowed routes for virtual
keys. Add permission filtering to /search_tools/list endpoint. Include
object_permission in team list v2 queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests using MagicMock for MCPServerTable were missing the new team_id
field, causing Pydantic validation errors. Updated auth failure test
to expect 400 (team_id required) instead of 403 since non-admin users
now must provide team_id before permission checks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Internal users can now see the create modal (with a team selection
prompt). Updated the test from asserting the modal is hidden to
asserting the team selection prompt is shown.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove assertions for alias text (column was removed)
- Disambiguate "Team" filter label from "Team (Owner)" column header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dashboard layout was using Sidebar2, which routed all entries to
path-based URLs like /ui/keys — but only api-reference has been migrated.
Switch back to the old leftnav so unmigrated pages navigate to the legacy
root page (?page=X) and migrated pages use path routing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add TeamDropdown as first field in create MCP server form
- For internal users, hide form fields until team is selected
- Fix useMCPServerHealth to append new servers to cache on recheck
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed low-value columns (Alias, Auth Type, Updated) to reduce
horizontal overflow. Added explicit size hints to remaining columns.
DataTable now applies column sizes to header and body cells.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added team_id to the MCPServer model class, build_mcp_server_from_table,
and _build_mcp_server_table so team_id flows from DB → registry →
list endpoint responses.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The early return on missing auth params blocked the entire page from
rendering. The hooks already guard on accessToken being available, and
DataTable shows its own loading state via isLoading prop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows the owning team alias resolved from team_id. Global servers
(team_id=null) display "Global". Header includes info icon explaining
that only servers from teams with mcp:read permission are visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The list endpoint returns an empty list (not 403) when a user has no
MCP servers available. For internal users, show a message suggesting
they may need mcp:read permission or team MCP server assignments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace "Missing required authentication parameters" with a loading
state. When the MCP servers fetch fails (e.g. 403), show a clear
error message with steps on how to get mcp:read permission.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a proxy admin deleted an MCP server, team_id was None so
remove_mcp_server_from_team was skipped, leaving stale server IDs
in the team's ObjectPermissionTable. Now fetches the server's
team_id before deletion to ensure cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_invalidate_team_cache only cleared the team object cache but not the
ObjectPermissionTable cache. After add_mcp_server_to_team, the team
was re-fetched from DB but its object_permission was served from stale
cache, causing newly created servers to not appear in the list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move team_id clear-to-null and ObjectPermissionTable sync before
registry reload so the cache reflects the new ownership state.
Also update the response object when clearing team_id to null.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make search_tools String[]? (nullable) in all 3 schema.prisma files
so Prisma preserves NULL from DB instead of coercing to []
- Remove get_permitted_search_tool_names (dead code — never called
from any production path) and its tests
- Add -> bool return type annotation to _can_object_call_search_tools
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Revert MCP management endpoint changes: team-scoped CRUD depends on
check_member_permission, add_mcp_server_to_team, remove_mcp_server_from_team
which exist only in the base branch, not main. Importing them crashes
all MCP endpoints on main.
- Revert ObjectPermissionTable default changes for pre-existing fields
(mcp_servers, mcp_access_groups, vector_stores, agents, agent_access_groups)
back to [] to avoid backwards-incompatible behavior change. Only
search_tools (new field) uses None default.
- Restore vector store access check: [] = allow all (existing behavior)
- Restore vector store test assertion
- Revert common_utils.py inline import changes (infrastructure not in scope)
- Add ValueError fallback to get_search_tool_access_error_type_for_object
for unrecognized object_type values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migration: remove DEFAULT ARRAY[]::TEXT[] so existing rows get NULL
(NULL = all access) instead of [] (no access)
- Schema: remove @default([]) for search_tools in all 3 schema.prisma files
- Use cached get_object_permission instead of raw DB queries in
search_tool_access_check and _get_allowed_search_tool_names
- Reject requests with missing search_tool_name (400) instead of
silently bypassing access control
- Fix vector store test: [] now correctly denies access (not allows)
- Update search_tool_access_check tests to mock get_object_permission
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change all ObjectPermissionTable array field defaults from [] to None
(None = all access / no restriction, [] = no access)
- Update vector store access check: [] now denies access instead of allowing all
- Add team-scoped MCP server management (create/update/delete) with
granular permissions (mcp:create, mcp:update, mcp:delete)
- Auto-assign created servers to team's ObjectPermissionTable
- Auto-remove deleted servers from team's ObjectPermissionTable
- Fix unreachable special MCP server name guard in add_mcp_server
- Fix server_id validation ordering in edit_mcp_server
- Fix description typo on PUT /server endpoint
- Move inline imports to module level in common_utils.py (CLAUDE.md)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix double error handling in getTeamPermissionsCall: return empty data
on HTTP error instead of calling handleError + throwing, preventing
duplicate error notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix double error handling in getTeamPermissionsCall: return empty data
on HTTP error instead of calling handleError + throwing, preventing
duplicate error notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix unknown permissions duplication: seed selected state with only known
permissions so existingUnknown and selected are disjoint on save
- Disable Add MCP Server button for non-admins without a team selected,
show tooltip explaining they need to select a team first
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Separate save failure from refresh failure: close drawer after successful
save even if teamInfoCall refresh fails
- Preserve unknown permissions not in availablePermissions when saving,
preventing silent drops of permissions from newer backend versions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Type onUpdate as () => Promise<void> and await it before closing drawer
- Replace accessToken! assertion with explicit null guard
- Gate fetchAvailableTeamMemberPermissions behind canEditTeam check
- Pass team_id for admins too when a team is selected in the filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add UI support for the MCP team management permissions introduced in PR #24266.
- Add MemberPermissionsDrawer component (Ant Design Drawer) for managing
per-member MCP permissions (mcp:read, mcp:create, mcp:update, mcp:delete)
- Add permissions button to team member table actions column
- Fetch available permissions from GET /team/available_permissions
- Pass extra_permissions in team member update API calls
- Allow all users to create MCP servers directly (backend enforces permissions)
- Pass team_id when non-admin users create MCP servers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move callbacks outside try/catch so only mutation errors are caught,
not errors from onVersionCreated/onVersionStatusUpdated callbacks
- Replace policyName! non-null assertion with DISABLED_POLICY_KEY
sentinel to avoid undefined in cache keys when query is disabled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add PolicyVersionsData type for select output; specify TData generic
so consumers get Policy[] (not Policy[] | undefined) for versions
- Remove empty-string queryKey fallback — use policyName! since
enabled:false prevents fetch when policyName is null
- Add cache invalidation tests for both mutation hooks
- Add explanatory comment for ?? [] fallback in component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make PolicyVersionsResponse.versions optional (Policy[] | undefined)
to match real API shape — select fallback handles normalization
- Add policyName guard to useUpdatePolicyVersionStatus mutationFn
to fail loudly instead of silently skipping cache invalidation
- Add test for null policyName in updateStatus mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>