feat: mcp resources (#6542)

This commit is contained in:
Paolo Ricciuti
2026-01-04 16:12:54 +01:00
committed by GitHub
parent e00621cb17
commit 21dc3c24d9
9 changed files with 329 additions and 4 deletions

View File

@@ -117,7 +117,15 @@ export namespace MessageV2 {
ref: "SymbolSource",
})
export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource]).meta({
export const ResourceSource = FilePartSourceBase.extend({
type: z.literal("resource"),
clientName: z.string(),
uri: z.string(),
}).meta({
ref: "ResourceSource",
})
export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource, ResourceSource]).meta({
ref: "FilePartSource",
})

View File

@@ -811,6 +811,78 @@ export namespace SessionPrompt {
const parts = await Promise.all(
input.parts.map(async (part): Promise<MessageV2.Part[]> => {
if (part.type === "file") {
// before checking the protocol we check if this is an mcp resource because it needs special handling
if (part.source?.type === "resource") {
const { clientName, uri } = part.source
log.info("mcp resource", { clientName, uri, mime: part.mime })
const pieces: MessageV2.Part[] = [
{
id: Identifier.ascending("part"),
messageID: info.id,
sessionID: input.sessionID,
type: "text",
synthetic: true,
text: `Reading MCP resource: ${part.filename} (${uri})`,
},
]
try {
const resourceContent = await MCP.readResource(clientName, uri)
if (!resourceContent) {
throw new Error(`Resource not found: ${clientName}/${uri}`)
}
// Handle different content types
const contents = Array.isArray(resourceContent.contents)
? resourceContent.contents
: [resourceContent.contents]
for (const content of contents) {
if ("text" in content && content.text) {
pieces.push({
id: Identifier.ascending("part"),
messageID: info.id,
sessionID: input.sessionID,
type: "text",
synthetic: true,
text: content.text as string,
})
} else if ("blob" in content && content.blob) {
// Handle binary content if needed
const mimeType = "mimeType" in content ? content.mimeType : part.mime
pieces.push({
id: Identifier.ascending("part"),
messageID: info.id,
sessionID: input.sessionID,
type: "text",
synthetic: true,
text: `[Binary content: ${mimeType}]`,
})
}
}
pieces.push({
...part,
id: part.id ?? Identifier.ascending("part"),
messageID: info.id,
sessionID: input.sessionID,
})
} catch (error: unknown) {
log.error("failed to read MCP resource", { error, clientName, uri })
const message = error instanceof Error ? error.message : String(error)
pieces.push({
id: Identifier.ascending("part"),
messageID: info.id,
sessionID: input.sessionID,
type: "text",
synthetic: true,
text: `Failed to read MCP resource ${part.filename}: ${message}`,
})
}
return pieces
}
const url = new URL(part.url)
switch (url.protocol) {
case "data:":