fix(tui): refresh MCP status for active location (#36882)

This commit is contained in:
Aiden Cline 2026-07-14 10:49:56 -05:00 committed by GitHub
commit a6b5cf94b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 3 deletions

View file

@ -841,7 +841,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
// Authenticating an MCP integration reconnects its server, which emits mcp.status.changed,
// so the mcp list refreshes here rather than off integration.updated.
case "mcp.status.changed":
if (bootstrapping) break
void result.location.mcp.server.refresh(event.location)
break
case "mcp.resources.changed":
@ -1044,7 +1043,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.mcp?.server
},
async refresh(ref?: LocationRef) {
const result = await client.api.mcp.list({ location: locationQuery(ref) })
const result = await client.api.mcp.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, {
...store.location[key],
@ -1057,7 +1056,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.mcp?.resource
},
async refresh(ref?: LocationRef) {
const result = await client.api.mcp.resource.catalog({ location: locationQuery(ref) })
const result = await client.api.mcp.resource.catalog({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, {
...store.location[key],

View file

@ -42,6 +42,90 @@ function durable(sessionID: string, seq = 0, version = 1) {
return { aggregateID: sessionID, seq, version }
}
test("bootstraps MCP data for the TUI location", async () => {
const events = createEventStream()
const requests: URL[] = []
const calls = createFetch((url) => {
if (url.pathname === "/api/mcp" || url.pathname === "/api/mcp/resource") requests.push(url)
return undefined
}, events)
const app = await testRender(() => (
<TestTuiContexts>
<ClientProvider api={createApi(calls.fetch)}>
<ProjectProvider>
<DataProvider>
<box />
</DataProvider>
</ProjectProvider>
</ClientProvider>
</TestTuiContexts>
))
try {
await wait(() => requests.length === 2)
expect(requests.map((url) => url.searchParams.get("location[directory]"))).toEqual([
process.cwd(),
process.cwd(),
])
} finally {
app.renderer.destroy()
}
})
test("refreshes MCP status when a connection settles during bootstrap", async () => {
const events = createEventStream()
let mcpRequests = 0
let resolveModels!: (response: Response) => void
const calls = createFetch((url) => {
if (url.pathname === "/api/mcp") {
mcpRequests++
return json({
location: { directory, project: { id: "proj_test", directory } },
data: [{ name: "context7", status: { status: mcpRequests === 1 ? "pending" : "connected" } }],
})
}
if (url.pathname === "/api/model")
return new Promise<Response>((resolve) => {
resolveModels = resolve
})
return undefined
}, events)
let data!: ReturnType<typeof useData>
function Probe() {
data = useData()
return <box />
}
const app = await testRender(() => (
<TestTuiContexts>
<ClientProvider api={createApi(calls.fetch)}>
<ProjectProvider>
<DataProvider>
<Probe />
</DataProvider>
</ProjectProvider>
</ClientProvider>
</TestTuiContexts>
))
try {
await wait(() => data.location.mcp.server.list()?.[0]?.status.status === "pending")
emitEvent(events, {
id: "evt_mcp_connected",
created: 1,
type: "mcp.status.changed",
data: { server: "context7" },
})
await wait(() => data.location.mcp.server.list()?.[0]?.status.status === "connected")
expect(mcpRequests).toBe(2)
resolveModels(json({ location: { directory, project: { id: "proj_test", directory } }, data: [] }))
} finally {
app.renderer.destroy()
}
})
test("refreshes resources into reactive getters", async () => {
const events = createEventStream()
const location = {