From a6b5cf94b0aba9e75b5c90630ff86f673bd3bff8 Mon Sep 17 00:00:00 2001
From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Date: Tue, 14 Jul 2026 10:49:56 -0500
Subject: [PATCH] fix(tui): refresh MCP status for active location (#36882)
---
packages/tui/src/context/data.tsx | 5 +-
packages/tui/test/cli/tui/data.test.tsx | 84 +++++++++++++++++++++++++
2 files changed, 86 insertions(+), 3 deletions(-)
diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx
index 114da13a1f..0399a56aa5 100644
--- a/packages/tui/src/context/data.tsx
+++ b/packages/tui/src/context/data.tsx
@@ -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],
diff --git a/packages/tui/test/cli/tui/data.test.tsx b/packages/tui/test/cli/tui/data.test.tsx
index 2671ba1e22..7b2f4d54b3 100644
--- a/packages/tui/test/cli/tui/data.test.tsx
+++ b/packages/tui/test/cli/tui/data.test.tsx
@@ -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(() => (
+
+
+
+
+
+
+
+
+
+ ))
+
+ 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((resolve) => {
+ resolveModels = resolve
+ })
+ return undefined
+ }, events)
+ let data!: ReturnType
+
+ function Probe() {
+ data = useData()
+ return
+ }
+
+ const app = await testRender(() => (
+
+
+
+
+
+
+
+
+
+ ))
+
+ 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 = {