Skip to content

Commit 1aa8274

Browse files
qdaxbdaniel-lxs
authored andcommitted
show connected mcp servers
1 parent d474779 commit 1aa8274

File tree

3 files changed

+100
-83
lines changed

3 files changed

+100
-83
lines changed

packages/types/src/mode.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,7 @@ export const groupOptionsSchema = z.object({
2828
description: z.string().optional(),
2929
mcp: z
3030
.object({
31-
included: z.array(
32-
z.union([
33-
z.string(),
34-
z.record(
35-
z.string(),
36-
z.object({
37-
allowedTools: z.array(z.string()).optional(), // not used yet
38-
disallowedTools: z.array(z.string()).optional(), // not used yet
39-
}),
40-
),
41-
]),
42-
),
31+
included: z.array(z.string()),
4332
description: z.string().optional(),
4433
})
4534
.optional(),

src/core/prompts/sections/mcp-servers.ts

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,42 +71,63 @@ export async function getMcpServersSection(
7171

7272
const filteredServers = memoizeFilteredServers(mcpHub, mcpIncludedList)
7373

74-
const connectedServers =
75-
filteredServers.length > 0
76-
? `${filteredServers
77-
.map((server) => {
78-
const tools = server.tools
74+
let connectedServers: string
75+
76+
if (filteredServers.length > 0) {
77+
connectedServers = `${filteredServers
78+
.map((server) => {
79+
const tools = server.tools
7980
?.filter((tool) => tool.enabledForPrompt !== false)
80-
?.map((tool) => {
81-
const schemaStr = tool.inputSchema
82-
? ` Input Schema:
83-
${JSON.stringify(tool.inputSchema, null, 2).split("\n").join("\n ")}`
84-
: ""
85-
86-
return `- ${tool.name}: ${tool.description}\n${schemaStr}`
87-
})
88-
.join("\n\n")
89-
90-
const templates = server.resourceTemplates
91-
?.map((template) => `- ${template.uriTemplate} (${template.name}): ${template.description}`)
92-
.join("\n")
93-
94-
const resources = server.resources
95-
?.map((resource) => `- ${resource.uri} (${resource.name}): ${resource.description}`)
96-
.join("\n")
97-
98-
const config = JSON.parse(server.config)
99-
100-
return (
101-
`## ${server.name}${config.command ? ` (\`${config.command}${config.args && Array.isArray(config.args) ? ` ${config.args.join(" ")}` : ""}\`)` : ""}` +
102-
(server.instructions ? `\n\n### Instructions\n${server.instructions}` : "") +
103-
(tools ? `\n\n### Available Tools\n${tools}` : "") +
104-
(templates ? `\n\n### Resource Templates\n${templates}` : "") +
105-
(resources ? `\n\n### Direct Resources\n${resources}` : "")
106-
)
81+
?.map((tool) => {
82+
const schemaStr = tool.inputSchema
83+
? ` Input Schema:
84+
${JSON.stringify(tool.inputSchema, null, 2).split("\n").join("\n ")}`
85+
: ""
86+
87+
return `- ${tool.name}: ${tool.description}\n${schemaStr}`
10788
})
108-
.join("\n\n")}`
109-
: "(No MCP servers currently connected)"
89+
.join("\n\n")
90+
91+
const templates = server.resourceTemplates
92+
?.map((template) => `- ${template.uriTemplate} (${template.name}): ${template.description}`)
93+
.join("\n")
94+
95+
const resources = server.resources
96+
?.map((resource) => `- ${resource.uri} (${resource.name}): ${resource.description}`)
97+
.join("\n")
98+
99+
const config = JSON.parse(server.config)
100+
101+
return (
102+
`## ${server.name}${config.command ? ` (\`${config.command}${config.args && Array.isArray(config.args) ? ` ${config.args.join(" ")}` : ""}\`)` : ""}` +
103+
(server.instructions ? `\n\n### Instructions\n${server.instructions}` : "") +
104+
(tools ? `\n\n### Available Tools\n${tools}` : "") +
105+
(templates ? `\n\n### Resource Templates\n${templates}` : "") +
106+
(resources ? `\n\n### Direct Resources\n${resources}` : "")
107+
)
108+
})
109+
.join("\n\n")}`
110+
} else if (mcpIncludedList && mcpIncludedList.length > 0) {
111+
const allServers = mcpHub.getAllServers()
112+
const disconnectedServers = mcpIncludedList
113+
.map((name) => {
114+
const server = allServers.find((s) => s.name === name)
115+
if (server && server.status !== "connected") {
116+
return `- ${server.name} (${server.status})`
117+
}
118+
if (!server) {
119+
return `- ${name} (not found)`
120+
}
121+
return null
122+
})
123+
.filter(Boolean)
124+
.join("\n")
125+
connectedServers = `(Configured MCP servers are not currently connected)${
126+
disconnectedServers ? `\n\nConfigured but disconnected servers:\n${disconnectedServers}` : ""
127+
}`
128+
} else {
129+
connectedServers = "(No MCP servers currently connected)"
130+
}
110131

111132
const baseSection = `MCP SERVERS
112133

webview-ui/src/components/modes/McpSelector.tsx

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -206,44 +206,51 @@ const McpSelector: React.FC<McpSelectorProps> = ({
206206
)}
207207
</CommandEmpty>
208208
<CommandGroup>
209-
{mcpServers
210-
.filter(
211-
(server) =>
212-
!searchValue ||
213-
server.name.toLowerCase().includes(searchValue.toLowerCase()),
209+
{(() => {
210+
const uniqueMcpServers = Array.from(
211+
new Map(mcpServers.map((server) => [server.name, server])).values(),
214212
)
215-
.map((server) => (
216-
<CommandItem
217-
key={`included-${server.name}`}
218-
value={`included-${server.name}`}
219-
onSelect={() => {
220-
const isIncluded = mcpIncludedList.includes(server.name)
221-
if (isIncluded) {
222-
setMcpIncludedList(mcpIncludedList.filter((n) => n !== server.name))
223-
} else {
224-
setMcpIncludedList([...mcpIncludedList, server.name])
225-
}
226-
}}
227-
className="flex items-center px-2 py-1">
228-
<div className="flex items-center flex-1 gap-2">
229-
<VSCodeCheckbox
230-
checked={mcpIncludedList.includes(server.name)}
231-
onClick={(e) => {
232-
e.stopPropagation()
233-
const isIncluded = mcpIncludedList.includes(server.name)
234-
if (isIncluded) {
235-
setMcpIncludedList(
236-
mcpIncludedList.filter((n) => n !== server.name),
237-
)
238-
} else {
239-
setMcpIncludedList([...mcpIncludedList, server.name])
240-
}
241-
}}
242-
/>
243-
<span>{server.name}</span>
244-
</div>
245-
</CommandItem>
246-
))}
213+
return uniqueMcpServers
214+
.filter(
215+
(server) =>
216+
!searchValue ||
217+
server.name.toLowerCase().includes(searchValue.toLowerCase()),
218+
)
219+
.map((server) => (
220+
<CommandItem
221+
key={`included-${server.name}`}
222+
value={`included-${server.name}`}
223+
onSelect={() => {
224+
const isIncluded = mcpIncludedList.includes(server.name)
225+
if (isIncluded) {
226+
setMcpIncludedList(
227+
mcpIncludedList.filter((n) => n !== server.name),
228+
)
229+
} else {
230+
setMcpIncludedList([...mcpIncludedList, server.name])
231+
}
232+
}}
233+
className="flex items-center px-2 py-1">
234+
<div className="flex items-center flex-1 gap-2">
235+
<VSCodeCheckbox
236+
checked={mcpIncludedList.includes(server.name)}
237+
onClick={(e) => {
238+
e.stopPropagation()
239+
const isIncluded = mcpIncludedList.includes(server.name)
240+
if (isIncluded) {
241+
setMcpIncludedList(
242+
mcpIncludedList.filter((n) => n !== server.name),
243+
)
244+
} else {
245+
setMcpIncludedList([...mcpIncludedList, server.name])
246+
}
247+
}}
248+
/>
249+
<span>{server.name}</span>
250+
</div>
251+
</CommandItem>
252+
))
253+
})()}
247254
</CommandGroup>
248255
</CommandList>
249256
</div>

0 commit comments

Comments
 (0)