fix(config): align MCP discovery semantics and MCP server editor behavior
This commit is contained in:
parent
d7f77e7744
commit
c1442a9b42
3 changed files with 79 additions and 14 deletions
|
|
@ -43,6 +43,21 @@ import { Button } from "@/components/ui/button"
|
|||
import { showSaveSuccessOrRestartToast } from "@/lib/restart-required"
|
||||
import { refreshGatewayState } from "@/store/gateway"
|
||||
|
||||
function buildStringMapMergePatch(
|
||||
next: Record<string, string>,
|
||||
previous: Record<string, string>,
|
||||
): Record<string, string | null> {
|
||||
const patch: Record<string, string | null> = { ...next }
|
||||
|
||||
for (const key of Object.keys(previous)) {
|
||||
if (!(key in next)) {
|
||||
patch[key] = null
|
||||
}
|
||||
}
|
||||
|
||||
return patch
|
||||
}
|
||||
|
||||
export function ConfigPage() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
|
|
@ -279,13 +294,13 @@ export function ConfigPage() {
|
|||
form.mcpDiscoveryTTL,
|
||||
"MCP discovery ttl",
|
||||
{
|
||||
min: 0,
|
||||
min: 1,
|
||||
},
|
||||
)
|
||||
mcpDiscoveryPatch.max_search_results = parseIntField(
|
||||
form.mcpDiscoveryMaxSearchResults,
|
||||
"MCP discovery max search results",
|
||||
{ min: 0 },
|
||||
{ min: 1 },
|
||||
)
|
||||
}
|
||||
const execConfigPatch: Record<string, unknown> = {
|
||||
|
|
@ -335,8 +350,19 @@ export function ConfigPage() {
|
|||
.filter((name) => !currentServerNames.has(name))
|
||||
.map((name) => [name, null] as const)
|
||||
|
||||
const baselineServersByName = new Map(
|
||||
baseline.mcpServers
|
||||
.map((server) => ({
|
||||
...server,
|
||||
name: server.name.trim(),
|
||||
}))
|
||||
.filter((server) => server.name !== "")
|
||||
.map((server) => [server.name, server] as const),
|
||||
)
|
||||
|
||||
const upsertServerEntries = normalizedServers.map((server) => {
|
||||
const deferredPatch = { deferred: server.deferredOverride }
|
||||
const baselineServer = baselineServersByName.get(server.name)
|
||||
|
||||
if (server.type !== "stdio") {
|
||||
if (server.url === "") {
|
||||
|
|
@ -364,9 +390,17 @@ export function ConfigPage() {
|
|||
enabled: server.enabled,
|
||||
type: server.type,
|
||||
url: server.url,
|
||||
headers: parseJSONObjectField(
|
||||
server.headersText,
|
||||
`MCP server ${server.name} headers`,
|
||||
headers: buildStringMapMergePatch(
|
||||
parseJSONObjectField(
|
||||
server.headersText,
|
||||
`MCP server ${server.name} headers`,
|
||||
),
|
||||
baselineServer
|
||||
? parseJSONObjectField(
|
||||
baselineServer.headersText,
|
||||
`Saved MCP server ${server.name} headers`,
|
||||
)
|
||||
: {},
|
||||
),
|
||||
command: null,
|
||||
args: null,
|
||||
|
|
@ -388,9 +422,17 @@ export function ConfigPage() {
|
|||
type: "stdio",
|
||||
command: server.command,
|
||||
args: parseMultilineList(server.argsText),
|
||||
env: parseJSONObjectField(
|
||||
server.envText,
|
||||
`MCP server ${server.name} env`,
|
||||
env: buildStringMapMergePatch(
|
||||
parseJSONObjectField(
|
||||
server.envText,
|
||||
`MCP server ${server.name} env`,
|
||||
),
|
||||
baselineServer
|
||||
? parseJSONObjectField(
|
||||
baselineServer.envText,
|
||||
`Saved MCP server ${server.name} env`,
|
||||
)
|
||||
: {},
|
||||
),
|
||||
env_file: server.envFile === "" ? null : server.envFile,
|
||||
url: null,
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ export function MCPSection({
|
|||
>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
min={1}
|
||||
value={form.mcpDiscoveryTTL}
|
||||
onChange={(e) =>
|
||||
onFieldChange("mcpDiscoveryTTL", e.target.value)
|
||||
|
|
@ -294,7 +294,7 @@ export function MCPSection({
|
|||
>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
min={1}
|
||||
value={form.mcpDiscoveryMaxSearchResults}
|
||||
onChange={(e) =>
|
||||
onFieldChange(
|
||||
|
|
@ -366,6 +366,7 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_name_placeholder",
|
||||
)}
|
||||
aria-label={t("pages.config.mcp_server_name_placeholder")}
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(server.id, "name", e.target.value)
|
||||
}
|
||||
|
|
@ -381,7 +382,9 @@ export function MCPSection({
|
|||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger
|
||||
aria-label={t("pages.config.mcp_server_discovery_mode")}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -416,7 +419,9 @@ export function MCPSection({
|
|||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger
|
||||
aria-label={t("pages.config.mcp_server_discovery_mode")}
|
||||
>
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"pages.config.mcp_server_discovery_mode",
|
||||
|
|
@ -444,6 +449,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_url_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_url_placeholder",
|
||||
)}
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(server.id, "url", e.target.value)
|
||||
}
|
||||
|
|
@ -453,6 +461,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_headers_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_headers_placeholder",
|
||||
)}
|
||||
className="min-h-[88px] font-mono text-xs"
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(
|
||||
|
|
@ -470,6 +481,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_command_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_command_placeholder",
|
||||
)}
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(
|
||||
server.id,
|
||||
|
|
@ -483,6 +497,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_env_file_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_env_file_placeholder",
|
||||
)}
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(
|
||||
server.id,
|
||||
|
|
@ -496,6 +513,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_args_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_args_placeholder",
|
||||
)}
|
||||
className="min-h-[88px] font-mono text-xs"
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(
|
||||
|
|
@ -510,6 +530,9 @@ export function MCPSection({
|
|||
placeholder={t(
|
||||
"pages.config.mcp_server_env_placeholder",
|
||||
)}
|
||||
aria-label={t(
|
||||
"pages.config.mcp_server_env_placeholder",
|
||||
)}
|
||||
className="min-h-[88px] font-mono text-xs"
|
||||
onChange={(e) =>
|
||||
onServerFieldChange(
|
||||
|
|
|
|||
|
|
@ -706,8 +706,8 @@
|
|||
"mcp_enabled_hint": "Turn MCP server integration on or off.",
|
||||
"mcp_discovery_enabled": "Enable MCP Discovery",
|
||||
"mcp_discovery_enabled_hint": "Allow MCP discovery tools to search registered MCP servers.",
|
||||
"mcp_discovery_ttl": "Discovery Cache TTL (minutes)",
|
||||
"mcp_discovery_ttl_hint": "How long MCP discovery results stay cached.",
|
||||
"mcp_discovery_ttl": "Discovered tool unlock TTL",
|
||||
"mcp_discovery_ttl_hint": "How many tool-execution TTL ticks discovered tools remain available after search.",
|
||||
"mcp_discovery_max_results": "Discovery Max Results",
|
||||
"mcp_discovery_max_results_hint": "Maximum MCP discovery matches returned per query.",
|
||||
"mcp_discovery_use_bm25": "Use BM25 Ranking",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue