Skip to content

Commit 8f9fa6e

Browse files
committed
simplify mcp loading
1 parent 70fdb6e commit 8f9fa6e

6 files changed

Lines changed: 49 additions & 95 deletions

File tree

packages/app/src/components/dialog-select-mcp.tsx

Lines changed: 7 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import { useMutation } from "@tanstack/solid-query"
2-
import { Component, createEffect, createMemo, on, Show } from "solid-js"
3-
import { createStore } from "solid-js/store"
1+
import { useMutation, useQueryClient } from "@tanstack/solid-query"
2+
import { Component, createMemo, Show } from "solid-js"
43
import { useSync } from "@/context/sync"
54
import { useSDK } from "@/context/sdk"
65
import { Dialog } from "@opencode-ai/ui/dialog"
76
import { List } from "@opencode-ai/ui/list"
87
import { Switch } from "@opencode-ai/ui/switch"
9-
import { showToast } from "@opencode-ai/ui/toast"
108
import { useLanguage } from "@/context/language"
9+
import { loadMcpQuery } from "@/context/global-sync"
1110

1211
const statusLabels = {
1312
connected: "mcp.status.connected",
@@ -20,48 +19,7 @@ export const DialogSelectMcp: Component = () => {
2019
const sync = useSync()
2120
const sdk = useSDK()
2221
const language = useLanguage()
23-
const [state, setState] = createStore({
24-
done: false,
25-
loading: false,
26-
})
27-
28-
createEffect(
29-
on(
30-
() => sync.data.mcp_ready,
31-
(ready, prev) => {
32-
if (!ready && prev) setState("done", false)
33-
},
34-
{ defer: true },
35-
),
36-
)
37-
38-
createEffect(() => {
39-
if (state.done || state.loading) return
40-
if (sync.data.mcp_ready) {
41-
setState("done", true)
42-
return
43-
}
44-
45-
setState("loading", true)
46-
void sdk.client.mcp
47-
.status()
48-
.then((result) => {
49-
sync.set("mcp", result.data ?? {})
50-
// sync.set("mcp_ready", true)
51-
setState("done", true)
52-
})
53-
.catch((err) => {
54-
setState("done", true)
55-
showToast({
56-
variant: "error",
57-
title: language.t("common.requestFailed"),
58-
description: err instanceof Error ? err.message : String(err),
59-
})
60-
})
61-
.finally(() => {
62-
setState("loading", false)
63-
})
64-
})
22+
const queryClient = useQueryClient()
6523

6624
const items = createMemo(() =>
6725
Object.entries(sync.data.mcp ?? {})
@@ -71,16 +29,10 @@ export const DialogSelectMcp: Component = () => {
7129

7230
const toggle = useMutation(() => ({
7331
mutationFn: async (name: string) => {
74-
const status = sync.data.mcp[name]
75-
if (status?.status === "connected") {
76-
await sdk.client.mcp.disconnect({ name })
77-
} else {
78-
await sdk.client.mcp.connect({ name })
79-
}
80-
81-
const result = await sdk.client.mcp.status()
82-
if (result.data) sync.set("mcp", result.data)
32+
if (sync.data.mcp[name]?.status === "connected") await sdk.client.mcp.disconnect({ name })
33+
else await sdk.client.mcp.connect({ name })
8334
},
35+
onSuccess: () => queryClient.refetchQueries({ queryKey: loadMcpQuery(sync.directory).queryKey }),
8436
}))
8537

8638
const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length)

packages/app/src/components/status-popover-body.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog"
33
import { Icon } from "@opencode-ai/ui/icon"
44
import { Switch } from "@opencode-ai/ui/switch"
55
import { Tabs } from "@opencode-ai/ui/tabs"
6-
import { useMutation } from "@tanstack/solid-query"
6+
import { useMutation, useQueryClient } from "@tanstack/solid-query"
77
import { showToast } from "@opencode-ai/ui/toast"
88
import { useNavigate } from "@solidjs/router"
99
import { type Accessor, createEffect, createMemo, For, type JSXElement, onCleanup, Show } from "solid-js"
@@ -15,6 +15,7 @@ import { useSDK } from "@/context/sdk"
1515
import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
1616
import { useSync } from "@/context/sync"
1717
import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health"
18+
import { loadMcpQuery } from "@/context/global-sync"
1819

1920
const pollMs = 10_000
2021

@@ -137,14 +138,14 @@ const useMcpToggleMutation = () => {
137138
const sync = useSync()
138139
const sdk = useSDK()
139140
const language = useLanguage()
141+
const queryClient = useQueryClient()
140142

141143
return useMutation(() => ({
142144
mutationFn: async (name: string) => {
143145
const status = sync.data.mcp[name]
144146
await (status?.status === "connected" ? sdk.client.mcp.disconnect({ name }) : sdk.client.mcp.connect({ name }))
145-
const result = await sdk.client.mcp.status()
146-
if (result.data) sync.set("mcp", result.data)
147147
},
148+
onSuccess: () => queryClient.refetchQueries({ queryKey: loadMcpQuery(sync.directory).queryKey }),
148149
onError: (err) => {
149150
showToast({
150151
variant: "error",

packages/app/src/context/global-sync.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type {
1010
import { showToast } from "@opencode-ai/ui/toast"
1111
import { getFilename } from "@opencode-ai/shared/util/path"
1212
import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
13-
import { createStore, produce, reconcile, unwrap } from "solid-js/store"
13+
import { createStore, produce, reconcile } from "solid-js/store"
1414
import { useLanguage } from "@/context/language"
1515
import { Persist, persisted } from "@/utils/persist"
1616
import type { InitError } from "../pages/error"
@@ -61,7 +61,7 @@ export const loadMcpQuery = (directory: string, sdk?: OpencodeClient) =>
6161
export const loadLspQuery = (directory: string, sdk?: OpencodeClient) =>
6262
queryOptions({
6363
queryKey: [directory, "lsp"],
64-
queryFn: sdk ? () => sdk.lsp.status().then((r) => r.data ?? {}) : skipToken,
64+
queryFn: sdk ? () => sdk.lsp.status().then((r) => r.data ?? []) : skipToken,
6565
})
6666

6767
function createGlobalSync() {
@@ -203,6 +203,17 @@ function createGlobalSync() {
203203
// bootstrapInstance,
204204
// })
205205

206+
const sdkFor = (directory: string) => {
207+
const cached = sdkCache.get(directory)
208+
if (cached) return cached
209+
const sdk = globalSDK.createClient({
210+
directory,
211+
throwOnError: true,
212+
})
213+
sdkCache.set(directory, sdk)
214+
return sdk
215+
}
216+
206217
const children = createChildStoreManager({
207218
owner,
208219
isBooting: (directory) => booting.has(directory),
@@ -218,19 +229,9 @@ function createGlobalSync() {
218229
clearSessionPrefetchDirectory(directory)
219230
},
220231
translate: language.t,
232+
getSdk: sdkFor,
221233
})
222234

223-
const sdkFor = (directory: string) => {
224-
const cached = sdkCache.get(directory)
225-
if (cached) return cached
226-
const sdk = globalSDK.createClient({
227-
directory,
228-
throwOnError: true,
229-
})
230-
sdkCache.set(directory, sdk)
231-
return sdk
232-
}
233-
234235
async function loadSessions(directory: string) {
235236
const pending = sessionLoads.get(directory)
236237
if (pending) return pending
@@ -381,9 +382,7 @@ function createGlobalSync() {
381382
setSessionTodo,
382383
vcsCache: children.vcsCache.get(directory),
383384
loadLsp: () => {
384-
void queryClient.fetchQuery(loadLspQuery(directory, sdkFor(directory))).then((data) => {
385-
setStore("lsp", data ?? [])
386-
})
385+
void queryClient.fetchQuery(loadLspQuery(directory, sdkFor(directory)))
387386
},
388387
})
389388
})

packages/app/src/context/global-sync/bootstrap.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,6 @@ export async function bootstrapDirectory(input: {
265265
if (Object.keys(input.store.config).length === 0 && Object.keys(input.global.config).length > 0) {
266266
input.setStore("config", input.global.config)
267267
}
268-
input.setStore("mcp", {})
269-
input.setStore("lsp", [])
270268
if (loading) input.setStore("status", "partial")
271269

272270
const rev = (providerRev.get(input.directory) ?? 0) + 1
@@ -354,18 +352,14 @@ export async function bootstrapDirectory(input: {
354352
() => Promise.resolve(input.loadSessions(input.directory)),
355353
() => input.queryClient.fetchQuery(loadMcpQuery(input.directory, input.sdk)),
356354
() =>
357-
input.queryClient.ensureQueryData(
358-
loadProvidersQuery(input.directory, input.sdk),
359-
// .catch((err) => {
360-
// if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
361-
// const project = getFilename(input.directory)
362-
// showToast({
363-
// variant: "error",
364-
// title: input.translate("toast.project.reloadFailed.title", { project }),
365-
// description: formatServerError(err, input.translate),
366-
// })
367-
// })
368-
),
355+
input.queryClient.fetchQuery(loadProvidersQuery(input.directory, input.sdk)).catch((err) => {
356+
const project = getFilename(input.directory)
357+
showToast({
358+
variant: "error",
359+
title: input.translate("toast.project.reloadFailed.title", { project }),
360+
description: formatServerError(err, input.translate),
361+
})
362+
}),
369363
].filter(Boolean) as (() => Promise<any>)[]
370364

371365
await waitForPaint()

packages/app/src/context/global-sync/child-store.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ describe("createChildStoreManager", () => {
2222
onBootstrap() {},
2323
onDispose() {},
2424
translate: (key) => key,
25+
getSdk: () => null!,
2526
})
2627

2728
Array.from({ length: 30 }, (_, index) => `/pinned-${index}`).forEach((directory) => {

packages/app/src/context/global-sync/child-store.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createRoot, getOwner, onCleanup, runWithOwner, type Owner } from "solid-js"
22
import { createStore, type SetStoreFunction, type Store } from "solid-js/store"
33
import { Persist, persisted } from "@/utils/persist"
4-
import type { VcsInfo } from "@opencode-ai/sdk/v2/client"
4+
import type { OpencodeClient, VcsInfo } from "@opencode-ai/sdk/v2/client"
55
import {
66
DIR_IDLE_TTL_MS,
77
MAX_DIR_STORES,
@@ -25,6 +25,7 @@ export function createChildStoreManager(input: {
2525
onBootstrap: (directory: string) => void
2626
onDispose: (directory: string) => void
2727
translate: (key: string, vars?: Record<string, string | number>) => string
28+
getSdk: (directory: string) => OpencodeClient
2829
}) {
2930
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
3031
const vcsCache = new Map<string, VcsCache>()
@@ -157,15 +158,17 @@ export function createChildStoreManager(input: {
157158

158159
const init = () =>
159160
createRoot((dispose) => {
161+
const sdk = input.getSdk(directory)
162+
160163
const initialMeta = meta[0].value
161164
const initialIcon = icon[0].value
162165

163166
const [pathQuery, mcpQuery, lspQuery, providerQuery] = useQueries(() => ({
164167
queries: [
165-
loadPathQuery(directory),
166-
loadMcpQuery(directory),
167-
loadLspQuery(directory),
168-
loadProvidersQuery(directory),
168+
loadPathQuery(directory, sdk),
169+
loadMcpQuery(directory, sdk),
170+
loadLspQuery(directory, sdk),
171+
loadProvidersQuery(directory, sdk),
169172
],
170173
}))
171174

@@ -196,11 +199,15 @@ export function createChildStoreManager(input: {
196199
get mcp_ready() {
197200
return mcpQuery.isLoading
198201
},
199-
mcp: {},
202+
get mcp() {
203+
return mcpQuery.isLoading ? {} : (mcpQuery.data ?? {})
204+
},
200205
get lsp_ready() {
201206
return lspQuery.isLoading
202207
},
203-
lsp: [],
208+
get lsp() {
209+
return lspQuery.isLoading ? [] : (lspQuery.data ?? [])
210+
},
204211
vcs: vcsStore.value,
205212
limit: 5,
206213
message: {},

0 commit comments

Comments
 (0)