diff --git a/packages/types/src/mode.ts b/packages/types/src/mode.ts index d4cb347189..28c5b45927 100644 --- a/packages/types/src/mode.ts +++ b/packages/types/src/mode.ts @@ -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(), diff --git a/src/core/prompts/sections/mcp-servers.ts b/src/core/prompts/sections/mcp-servers.ts index f5eb4d90f2..62b3a5f6d6 100644 --- a/src/core/prompts/sections/mcp-servers.ts +++ b/src/core/prompts/sections/mcp-servers.ts @@ -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 diff --git a/webview-ui/src/components/modes/McpSelector.tsx b/webview-ui/src/components/modes/McpSelector.tsx index 4baa3012fd..50ce0a1f74 100644 --- a/webview-ui/src/components/modes/McpSelector.tsx +++ b/webview-ui/src/components/modes/McpSelector.tsx @@ -206,44 +206,51 @@ const McpSelector: React.FC = ({ )} - {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) => ( - { - 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"> -
- { - e.stopPropagation() - const isIncluded = mcpIncludedList.includes(server.name) - if (isIncluded) { - setMcpIncludedList( - mcpIncludedList.filter((n) => n !== server.name), - ) - } else { - setMcpIncludedList([...mcpIncludedList, server.name]) - } - }} - /> - {server.name} -
-
- ))} + return uniqueMcpServers + .filter( + (server) => + !searchValue || + server.name.toLowerCase().includes(searchValue.toLowerCase()), + ) + .map((server) => ( + { + 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"> +
+ { + e.stopPropagation() + const isIncluded = mcpIncludedList.includes(server.name) + if (isIncluded) { + setMcpIncludedList( + mcpIncludedList.filter((n) => n !== server.name), + ) + } else { + setMcpIncludedList([...mcpIncludedList, server.name]) + } + }} + /> + {server.name} +
+
+ )) + })()}