show connected mcp servers

This commit is contained in:
axb 2025-07-08 01:21:48 +08:00 committed by Daniel Riccio
parent d474779023
commit 1aa827450c
No known key found for this signature in database
GPG key ID: FFD5FD825F8E8209
3 changed files with 99 additions and 82 deletions

View file

@ -28,18 +28,7 @@ export const groupOptionsSchema = z.object({
description: z.string().optional(),
mcp: z
.object({
included: z.array(
z.union([
z.string(),
z.record(
z.string(),
z.object({
allowedTools: z.array(z.string()).optional(), // not used yet
disallowedTools: z.array(z.string()).optional(), // not used yet
}),
),
]),
),
included: z.array(z.string()),
description: z.string().optional(),
})
.optional(),

View file

@ -71,42 +71,63 @@ export async function getMcpServersSection(
const filteredServers = memoizeFilteredServers(mcpHub, mcpIncludedList)
const connectedServers =
filteredServers.length > 0
? `${filteredServers
.map((server) => {
const tools = server.tools
let connectedServers: string
if (filteredServers.length > 0) {
connectedServers = `${filteredServers
.map((server) => {
const tools = server.tools
?.filter((tool) => tool.enabledForPrompt !== false)
?.map((tool) => {
const schemaStr = tool.inputSchema
? ` Input Schema:
${JSON.stringify(tool.inputSchema, null, 2).split("\n").join("\n ")}`
: ""
?.map((tool) => {
const schemaStr = tool.inputSchema
? ` Input Schema:
${JSON.stringify(tool.inputSchema, null, 2).split("\n").join("\n ")}`
: ""
return `- ${tool.name}: ${tool.description}\n${schemaStr}`
})
.join("\n\n")
const templates = server.resourceTemplates
?.map((template) => `- ${template.uriTemplate} (${template.name}): ${template.description}`)
.join("\n")
const resources = server.resources
?.map((resource) => `- ${resource.uri} (${resource.name}): ${resource.description}`)
.join("\n")
const config = JSON.parse(server.config)
return (
`## ${server.name}${config.command ? ` (\`${config.command}${config.args && Array.isArray(config.args) ? ` ${config.args.join(" ")}` : ""}\`)` : ""}` +
(server.instructions ? `\n\n### Instructions\n${server.instructions}` : "") +
(tools ? `\n\n### Available Tools\n${tools}` : "") +
(templates ? `\n\n### Resource Templates\n${templates}` : "") +
(resources ? `\n\n### Direct Resources\n${resources}` : "")
)
return `- ${tool.name}: ${tool.description}\n${schemaStr}`
})
.join("\n\n")}`
: "(No MCP servers currently connected)"
.join("\n\n")
const templates = server.resourceTemplates
?.map((template) => `- ${template.uriTemplate} (${template.name}): ${template.description}`)
.join("\n")
const resources = server.resources
?.map((resource) => `- ${resource.uri} (${resource.name}): ${resource.description}`)
.join("\n")
const config = JSON.parse(server.config)
return (
`## ${server.name}${config.command ? ` (\`${config.command}${config.args && Array.isArray(config.args) ? ` ${config.args.join(" ")}` : ""}\`)` : ""}` +
(server.instructions ? `\n\n### Instructions\n${server.instructions}` : "") +
(tools ? `\n\n### Available Tools\n${tools}` : "") +
(templates ? `\n\n### Resource Templates\n${templates}` : "") +
(resources ? `\n\n### Direct Resources\n${resources}` : "")
)
})
.join("\n\n")}`
} else if (mcpIncludedList && mcpIncludedList.length > 0) {
const allServers = mcpHub.getAllServers()
const disconnectedServers = mcpIncludedList
.map((name) => {
const server = allServers.find((s) => s.name === name)
if (server && server.status !== "connected") {
return `- ${server.name} (${server.status})`
}
if (!server) {
return `- ${name} (not found)`
}
return null
})
.filter(Boolean)
.join("\n")
connectedServers = `(Configured MCP servers are not currently connected)${
disconnectedServers ? `\n\nConfigured but disconnected servers:\n${disconnectedServers}` : ""
}`
} else {
connectedServers = "(No MCP servers currently connected)"
}
const baseSection = `MCP SERVERS

View file

@ -206,44 +206,51 @@ const McpSelector: React.FC<McpSelectorProps> = ({
)}
</CommandEmpty>
<CommandGroup>
{mcpServers
.filter(
(server) =>
!searchValue ||
server.name.toLowerCase().includes(searchValue.toLowerCase()),
{(() => {
const uniqueMcpServers = Array.from(
new Map(mcpServers.map((server) => [server.name, server])).values(),
)
.map((server) => (
<CommandItem
key={`included-${server.name}`}
value={`included-${server.name}`}
onSelect={() => {
const isIncluded = mcpIncludedList.includes(server.name)
if (isIncluded) {
setMcpIncludedList(mcpIncludedList.filter((n) => n !== server.name))
} else {
setMcpIncludedList([...mcpIncludedList, server.name])
}
}}
className="flex items-center px-2 py-1">
<div className="flex items-center flex-1 gap-2">
<VSCodeCheckbox
checked={mcpIncludedList.includes(server.name)}
onClick={(e) => {
e.stopPropagation()
const isIncluded = mcpIncludedList.includes(server.name)
if (isIncluded) {
setMcpIncludedList(
mcpIncludedList.filter((n) => n !== server.name),
)
} else {
setMcpIncludedList([...mcpIncludedList, server.name])
}
}}
/>
<span>{server.name}</span>
</div>
</CommandItem>
))}
return uniqueMcpServers
.filter(
(server) =>
!searchValue ||
server.name.toLowerCase().includes(searchValue.toLowerCase()),
)
.map((server) => (
<CommandItem
key={`included-${server.name}`}
value={`included-${server.name}`}
onSelect={() => {
const isIncluded = mcpIncludedList.includes(server.name)
if (isIncluded) {
setMcpIncludedList(
mcpIncludedList.filter((n) => n !== server.name),
)
} else {
setMcpIncludedList([...mcpIncludedList, server.name])
}
}}
className="flex items-center px-2 py-1">
<div className="flex items-center flex-1 gap-2">
<VSCodeCheckbox
checked={mcpIncludedList.includes(server.name)}
onClick={(e) => {
e.stopPropagation()
const isIncluded = mcpIncludedList.includes(server.name)
if (isIncluded) {
setMcpIncludedList(
mcpIncludedList.filter((n) => n !== server.name),
)
} else {
setMcpIncludedList([...mcpIncludedList, server.name])
}
}}
/>
<span>{server.name}</span>
</div>
</CommandItem>
))
})()}
</CommandGroup>
</CommandList>
</div>