mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-13 09:16:04 +00:00
fix(mcp): read stdio args from form state in testMcp to avoid stale closure
The MCP detail page invokes testMcp() through an imperative handle (formRef.current.testMcp()). The handle closure is only refreshed when [mcpTesting] changes, so testMcp read a stale snapshot of the stdioArgs/ extraArgs React state — on the detail page that snapshot is the empty initial [], so stdio 'args' were dropped entirely. The sandbox then launched 'uvx' with no package, which exits 2 and surfaces only an opaque 'Connection closed' with no detail. Read command/args/env via form.getValues() (kept in sync on every edit and on load) instead of the captured state, matching how 'command' was already read. Fixes stdio MCP test failing with empty args on the detail page.
This commit is contained in:
@@ -450,6 +450,9 @@ const MCPForm = forwardRef<MCPFormHandle, MCPFormProps>(function MCPForm(
|
||||
testMcp: () => testMcp(),
|
||||
isTesting: mcpTesting,
|
||||
}),
|
||||
// testMcp now reads everything via form.getValues(), so it does not need
|
||||
// the latest stdioArgs/extraArgs closure — but keep mcpTesting so the
|
||||
// exposed isTesting flag stays accurate.
|
||||
[mcpTesting],
|
||||
);
|
||||
|
||||
@@ -680,6 +683,17 @@ const MCPForm = forwardRef<MCPFormHandle, MCPFormProps>(function MCPForm(
|
||||
|
||||
try {
|
||||
const mode = form.getValues('mode');
|
||||
// Read every field via form.getValues() rather than the captured
|
||||
// `stdioArgs` / `extraArgs` state. testMcp() is invoked through an
|
||||
// imperative handle (formRef.current.testMcp()) whose closure is only
|
||||
// refreshed when [mcpTesting] changes, so reading the React state here
|
||||
// would use a stale snapshot — on the detail page that snapshot is the
|
||||
// empty initial [], which dropped stdio args entirely and launched
|
||||
// `uvx` with no package (exit 2 / "Connection closed", no detail).
|
||||
// The form values are kept in sync on every edit and on load, so they
|
||||
// are always current.
|
||||
const formExtraArgs = form.getValues('extra_args') ?? [];
|
||||
const formStdioArgs = form.getValues('args') ?? [];
|
||||
let extraArgsData:
|
||||
| MCPServerExtraArgsSSE
|
||||
| MCPServerExtraArgsHttp
|
||||
@@ -690,7 +704,7 @@ const MCPForm = forwardRef<MCPFormHandle, MCPFormProps>(function MCPForm(
|
||||
url: form.getValues('url')!,
|
||||
timeout: form.getValues('timeout'),
|
||||
headers: Object.fromEntries(
|
||||
extraArgs.map((arg) => [arg.key, arg.value]),
|
||||
formExtraArgs.map((arg) => [arg.key, arg.value]),
|
||||
),
|
||||
ssereadtimeout: form.getValues('ssereadtimeout'),
|
||||
};
|
||||
@@ -699,14 +713,16 @@ const MCPForm = forwardRef<MCPFormHandle, MCPFormProps>(function MCPForm(
|
||||
url: form.getValues('url')!,
|
||||
timeout: form.getValues('timeout'),
|
||||
headers: Object.fromEntries(
|
||||
extraArgs.map((arg) => [arg.key, arg.value]),
|
||||
formExtraArgs.map((arg) => [arg.key, arg.value]),
|
||||
),
|
||||
};
|
||||
} else {
|
||||
extraArgsData = {
|
||||
command: form.getValues('command')!,
|
||||
args: stdioArgs.map((arg) => arg.value),
|
||||
env: Object.fromEntries(extraArgs.map((arg) => [arg.key, arg.value])),
|
||||
args: formStdioArgs.map((arg) => arg.value),
|
||||
env: Object.fromEntries(
|
||||
formExtraArgs.map((arg) => [arg.key, arg.value]),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user