fix: double-add race, conditional bulk query, narrow DELETE_RE, hoist search input

This commit is contained in:
Ishaan Jaffer 2026-03-11 20:24:41 -07:00
parent 5010b2b0cd
commit 9e767ce77f
4 changed files with 29 additions and 35 deletions

View file

@ -369,11 +369,6 @@ if MCP_AVAILABLE:
list_tools_result = []
error_message = None
# Bulk-fetch all OAuth credentials for this user in a single DB query
# so per-server calls below can use a dict lookup (O(1)) instead of
# issuing one DB query per server (N+1 pattern).
bulk_oauth_headers = await _get_bulk_user_oauth_headers(user_api_key_dict)
# If server_id is specified, only query that specific server
if server_id:
# Resolve a server name to its UUID if needed (MCPConnectPicker passes
@ -422,7 +417,8 @@ if MCP_AVAILABLE:
server_auth_header = _get_server_auth_header(
server, mcp_server_auth_headers, mcp_auth_header
)
user_oauth_extra_headers = bulk_oauth_headers.get(server.server_id)
# Single-server request: targeted lookup is more efficient than a bulk fetch.
user_oauth_extra_headers = await _get_user_oauth_extra_headers(server, user_api_key_dict)
try:
list_tools_result = await _get_tools_for_single_server(
@ -464,7 +460,10 @@ if MCP_AVAILABLE:
},
)
# Query all servers the user has access to
# Query all servers the user has access to.
# Bulk-fetch OAuth creds once so each per-server call below can
# do an O(1) dict lookup instead of N individual DB queries.
bulk_oauth_headers = await _get_bulk_user_oauth_headers(user_api_key_dict)
errors = []
for allowed_server_id in allowed_server_ids:
server = global_mcp_server_manager.get_mcp_server_by_id(

View file

@ -193,7 +193,11 @@ const MCPAppsPanel: React.FC<Props> = ({ accessToken, selectedServers, onChange
message.warning(`Could not load tools for ${serverName}`);
return;
}
onChange([...selectedServers, serverName]);
// Use the ref so we read the most up-to-date list; guard against duplicates
// that the oauthConnected effect may have already added while we awaited.
if (!selectedServersRef.current.includes(serverName)) {
onChange([...selectedServersRef.current, serverName]);
}
} catch {
message.warning(`Could not load tools for ${serverName}`);
} finally {

View file

@ -451,39 +451,30 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
</Text>
</div>
{/* Search box shared by both views */}
<Input
placeholder="Search tools by name or description..."
prefix={<SearchOutlined className="text-gray-400" />}
value={toolSearchTerm}
onChange={(e) => setToolSearchTerm(e.target.value)}
allowClear
className="rounded-lg"
size="large"
/>
{/* CRUD grouped view */}
{viewMode === "crud" && (
<>
<Input
placeholder="Search tools by name or description..."
prefix={<SearchOutlined className="text-gray-400" />}
value={toolSearchTerm}
onChange={(e) => setToolSearchTerm(e.target.value)}
allowClear
className="rounded-lg"
size="large"
/>
<McpCrudPermissionPanel
tools={tools}
searchFilter={toolSearchTerm}
value={allowedTools}
onChange={(allowed) => onAllowedToolsChange(allowed)}
/>
</>
<McpCrudPermissionPanel
tools={tools}
searchFilter={toolSearchTerm}
value={allowedTools}
onChange={(allowed) => onAllowedToolsChange(allowed)}
/>
)}
{/* Flat list view */}
{viewMode === "flat" && (
<>
<Input
placeholder="Search tools by name or description..."
prefix={<SearchOutlined className="text-gray-400" />}
value={toolSearchTerm}
onChange={(e) => setToolSearchTerm(e.target.value)}
allowClear
className="rounded-lg"
size="large"
/>
{filteredTools.length === 0 ? (
<div className="text-center py-6 text-gray-400 border rounded-lg border-dashed">
<SearchOutlined className="text-2xl mb-2" />

View file

@ -1,6 +1,6 @@
export type CrudOp = "read" | "create" | "update" | "delete" | "unknown";
const DELETE_RE = /\b(delete|remove|destroy|purge|drop|clear|erase|unlink|disconnect)\b/i;
const DELETE_RE = /\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i;
const CREATE_RE = /\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i;
const UPDATE_RE = /\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i;
const READ_RE = /\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;