feat: mcp prompts as slash commands (alternative) (#5767)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
Paolo Ricciuti
2025-12-31 07:51:25 +01:00
committed by GitHub
parent 977c9a3e2c
commit 57a2b5f444
4 changed files with 135 additions and 7 deletions

View File

@@ -132,6 +132,9 @@ export namespace MCP {
type TransportWithAuth = StreamableHTTPClientTransport | SSEClientTransport
const pendingOAuthTransports = new Map<string, TransportWithAuth>()
// Prompt cache types
type PromptInfo = Awaited<ReturnType<MCPClient["listPrompts"]>>["prompts"][number]
const state = Instance.state(
async () => {
const cfg = await Config.get()
@@ -176,6 +179,29 @@ export namespace MCP {
},
)
// Helper function to fetch prompts for a specific client
async function fetchPromptsForClient(clientName: string, client: Client) {
const prompts = await client.listPrompts().catch((e) => {
log.error("failed to get prompts", { clientName, error: e.message })
return undefined
})
if (!prompts) {
return
}
const commands: Record<string, PromptInfo & { client: string }> = {}
for (const prompt of prompts.prompts) {
const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_")
const sanitizedPromptName = prompt.name.replace(/[^a-zA-Z0-9_-]/g, "_")
const key = sanitizedClientName + ":" + sanitizedPromptName + " (MCP)"
commands[key] = { ...prompt, client: clientName }
}
return commands
}
export async function add(name: string, mcp: Config.Mcp) {
const s = await state()
const result = await create(name, mcp)
@@ -492,6 +518,55 @@ export namespace MCP {
return result
}
export async function prompts() {
const s = await state()
const clientsSnapshot = await clients()
const prompts = Object.fromEntries<PromptInfo & { client: string }>(
(
await Promise.all(
Object.entries(clientsSnapshot).map(async ([clientName, client]) => {
if (s.status[clientName]?.status !== "connected") {
return []
}
return Object.entries((await fetchPromptsForClient(clientName, client)) ?? {})
}),
)
).flat(),
)
return prompts
}
export async function getPrompt(clientName: string, name: string, args?: Record<string, string>) {
const clientsSnapshot = await clients()
const client = clientsSnapshot[clientName]
if (!client) {
log.warn("client not found for prompt", {
clientName,
})
return undefined
}
const result = await client
.getPrompt({
name: name,
arguments: args,
})
.catch((e) => {
log.error("failed to get prompt from MCP server", {
clientName,
promptName: name,
error: e.message,
})
return undefined
})
return result
}
/**
* Start OAuth authentication flow for an MCP server.
* Returns the authorization URL that should be opened in a browser.