mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-08 03:07:53 +00:00
Move use_mcp_tool and access_mcp_resource to tool files (#2101)
This commit is contained in:
parent
937b1f3c90
commit
9b0790fce7
3 changed files with 190 additions and 162 deletions
|
|
@ -93,6 +93,8 @@ import { listCodeDefinitionNamesTool } from "./tools/listCodeDefinitionNamesTool
|
|||
import { searchFilesTool } from "./tools/searchFilesTool"
|
||||
import { browserActionTool } from "./tools/browserActionTool"
|
||||
import { executeCommandTool } from "./tools/executeCommandTool"
|
||||
import { useMcpToolTool } from "./tools/useMcpToolTool"
|
||||
import { accessMcpResourceTool } from "./tools/accessMcpResourceTool"
|
||||
|
||||
export type ToolResponse = string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam>
|
||||
type UserContent = Array<Anthropic.Messages.ContentBlockParam>
|
||||
|
|
@ -1630,170 +1632,19 @@ export class Cline extends EventEmitter<ClineEvents> {
|
|||
break
|
||||
}
|
||||
case "use_mcp_tool": {
|
||||
const server_name: string | undefined = block.params.server_name
|
||||
const tool_name: string | undefined = block.params.tool_name
|
||||
const mcp_arguments: string | undefined = block.params.arguments
|
||||
try {
|
||||
if (block.partial) {
|
||||
const partialMessage = JSON.stringify({
|
||||
type: "use_mcp_tool",
|
||||
serverName: removeClosingTag("server_name", server_name),
|
||||
toolName: removeClosingTag("tool_name", tool_name),
|
||||
arguments: removeClosingTag("arguments", mcp_arguments),
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||
break
|
||||
} else {
|
||||
if (!server_name) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(
|
||||
await this.sayAndCreateMissingParamError("use_mcp_tool", "server_name"),
|
||||
)
|
||||
break
|
||||
}
|
||||
if (!tool_name) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(
|
||||
await this.sayAndCreateMissingParamError("use_mcp_tool", "tool_name"),
|
||||
)
|
||||
break
|
||||
}
|
||||
// arguments are optional, but if they are provided they must be valid JSON
|
||||
// if (!mcp_arguments) {
|
||||
// this.consecutiveMistakeCount++
|
||||
// pushToolResult(await this.sayAndCreateMissingParamError("use_mcp_tool", "arguments"))
|
||||
// break
|
||||
// }
|
||||
let parsedArguments: Record<string, unknown> | undefined
|
||||
if (mcp_arguments) {
|
||||
try {
|
||||
parsedArguments = JSON.parse(mcp_arguments)
|
||||
} catch (error) {
|
||||
this.consecutiveMistakeCount++
|
||||
await this.say(
|
||||
"error",
|
||||
`Roo tried to use ${tool_name} with an invalid JSON argument. Retrying...`,
|
||||
)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
formatResponse.invalidMcpToolArgumentError(server_name, tool_name),
|
||||
),
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.consecutiveMistakeCount = 0
|
||||
const completeMessage = JSON.stringify({
|
||||
type: "use_mcp_tool",
|
||||
serverName: server_name,
|
||||
toolName: tool_name,
|
||||
arguments: mcp_arguments,
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
const didApprove = await askApproval("use_mcp_server", completeMessage)
|
||||
if (!didApprove) {
|
||||
break
|
||||
}
|
||||
// now execute the tool
|
||||
await this.say("mcp_server_request_started") // same as browser_action_result
|
||||
const toolResult = await this.providerRef
|
||||
.deref()
|
||||
?.getMcpHub()
|
||||
?.callTool(server_name, tool_name, parsedArguments)
|
||||
|
||||
// TODO: add progress indicator and ability to parse images and non-text responses
|
||||
const toolResultPretty =
|
||||
(toolResult?.isError ? "Error:\n" : "") +
|
||||
toolResult?.content
|
||||
.map((item) => {
|
||||
if (item.type === "text") {
|
||||
return item.text
|
||||
}
|
||||
if (item.type === "resource") {
|
||||
const { blob, ...rest } = item.resource
|
||||
return JSON.stringify(rest, null, 2)
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n\n") || "(No response)"
|
||||
await this.say("mcp_server_response", toolResultPretty)
|
||||
pushToolResult(formatResponse.toolResult(toolResultPretty))
|
||||
break
|
||||
}
|
||||
} catch (error) {
|
||||
await handleError("executing MCP tool", error)
|
||||
break
|
||||
}
|
||||
await useMcpToolTool(this, block, askApproval, handleError, pushToolResult, removeClosingTag)
|
||||
break
|
||||
}
|
||||
case "access_mcp_resource": {
|
||||
const server_name: string | undefined = block.params.server_name
|
||||
const uri: string | undefined = block.params.uri
|
||||
try {
|
||||
if (block.partial) {
|
||||
const partialMessage = JSON.stringify({
|
||||
type: "access_mcp_resource",
|
||||
serverName: removeClosingTag("server_name", server_name),
|
||||
uri: removeClosingTag("uri", uri),
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||
break
|
||||
} else {
|
||||
if (!server_name) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(
|
||||
await this.sayAndCreateMissingParamError("access_mcp_resource", "server_name"),
|
||||
)
|
||||
break
|
||||
}
|
||||
if (!uri) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(
|
||||
await this.sayAndCreateMissingParamError("access_mcp_resource", "uri"),
|
||||
)
|
||||
break
|
||||
}
|
||||
this.consecutiveMistakeCount = 0
|
||||
const completeMessage = JSON.stringify({
|
||||
type: "access_mcp_resource",
|
||||
serverName: server_name,
|
||||
uri,
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
const didApprove = await askApproval("use_mcp_server", completeMessage)
|
||||
if (!didApprove) {
|
||||
break
|
||||
}
|
||||
// now execute the tool
|
||||
await this.say("mcp_server_request_started")
|
||||
const resourceResult = await this.providerRef
|
||||
.deref()
|
||||
?.getMcpHub()
|
||||
?.readResource(server_name, uri)
|
||||
const resourceResultPretty =
|
||||
resourceResult?.contents
|
||||
.map((item) => {
|
||||
if (item.text) {
|
||||
return item.text
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n\n") || "(Empty response)"
|
||||
|
||||
// handle images (image must contain mimetype and blob)
|
||||
let images: string[] = []
|
||||
resourceResult?.contents.forEach((item) => {
|
||||
if (item.mimeType?.startsWith("image") && item.blob) {
|
||||
images.push(item.blob)
|
||||
}
|
||||
})
|
||||
await this.say("mcp_server_response", resourceResultPretty, images)
|
||||
pushToolResult(formatResponse.toolResult(resourceResultPretty, images))
|
||||
break
|
||||
}
|
||||
} catch (error) {
|
||||
await handleError("accessing MCP resource", error)
|
||||
break
|
||||
}
|
||||
await accessMcpResourceTool(
|
||||
this,
|
||||
block,
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
removeClosingTag,
|
||||
)
|
||||
break
|
||||
}
|
||||
case "ask_followup_question": {
|
||||
const question: string | undefined = block.params.question
|
||||
|
|
|
|||
77
src/core/tools/accessMcpResourceTool.ts
Normal file
77
src/core/tools/accessMcpResourceTool.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
|
||||
import { RemoveClosingTag } from "./types"
|
||||
import { ToolUse } from "../assistant-message"
|
||||
import { AskApproval, HandleError, PushToolResult } from "./types"
|
||||
import { Cline } from "../Cline"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
export async function accessMcpResourceTool(
|
||||
cline: Cline,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
pushToolResult: PushToolResult,
|
||||
removeClosingTag: RemoveClosingTag,
|
||||
) {
|
||||
const server_name: string | undefined = block.params.server_name
|
||||
const uri: string | undefined = block.params.uri
|
||||
try {
|
||||
if (block.partial) {
|
||||
const partialMessage = JSON.stringify({
|
||||
type: "access_mcp_resource",
|
||||
serverName: removeClosingTag("server_name", server_name),
|
||||
uri: removeClosingTag("uri", uri),
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
await cline.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||
return
|
||||
} else {
|
||||
if (!server_name) {
|
||||
cline.consecutiveMistakeCount++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("access_mcp_resource", "server_name"))
|
||||
return
|
||||
}
|
||||
if (!uri) {
|
||||
cline.consecutiveMistakeCount++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("access_mcp_resource", "uri"))
|
||||
return
|
||||
}
|
||||
cline.consecutiveMistakeCount = 0
|
||||
const completeMessage = JSON.stringify({
|
||||
type: "access_mcp_resource",
|
||||
serverName: server_name,
|
||||
uri,
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
const didApprove = await askApproval("use_mcp_server", completeMessage)
|
||||
if (!didApprove) {
|
||||
return
|
||||
}
|
||||
// now execute the tool
|
||||
await cline.say("mcp_server_request_started")
|
||||
const resourceResult = await cline.providerRef.deref()?.getMcpHub()?.readResource(server_name, uri)
|
||||
const resourceResultPretty =
|
||||
resourceResult?.contents
|
||||
.map((item) => {
|
||||
if (item.text) {
|
||||
return item.text
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n\n") || "(Empty response)"
|
||||
|
||||
// handle images (image must contain mimetype and blob)
|
||||
let images: string[] = []
|
||||
resourceResult?.contents.forEach((item) => {
|
||||
if (item.mimeType?.startsWith("image") && item.blob) {
|
||||
images.push(item.blob)
|
||||
}
|
||||
})
|
||||
await cline.say("mcp_server_response", resourceResultPretty, images)
|
||||
pushToolResult(formatResponse.toolResult(resourceResultPretty, images))
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
await handleError("accessing MCP resource", error)
|
||||
return
|
||||
}
|
||||
}
|
||||
100
src/core/tools/useMcpToolTool.ts
Normal file
100
src/core/tools/useMcpToolTool.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import { Cline } from "../Cline"
|
||||
import { ToolUse } from "../assistant-message"
|
||||
import { AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "./types"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
|
||||
|
||||
export async function useMcpToolTool(
|
||||
cline: Cline,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
pushToolResult: PushToolResult,
|
||||
removeClosingTag: RemoveClosingTag,
|
||||
) {
|
||||
const server_name: string | undefined = block.params.server_name
|
||||
const tool_name: string | undefined = block.params.tool_name
|
||||
const mcp_arguments: string | undefined = block.params.arguments
|
||||
try {
|
||||
if (block.partial) {
|
||||
const partialMessage = JSON.stringify({
|
||||
type: "use_mcp_tool",
|
||||
serverName: removeClosingTag("server_name", server_name),
|
||||
toolName: removeClosingTag("tool_name", tool_name),
|
||||
arguments: removeClosingTag("arguments", mcp_arguments),
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
await cline.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||
return
|
||||
} else {
|
||||
if (!server_name) {
|
||||
cline.consecutiveMistakeCount++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("use_mcp_tool", "server_name"))
|
||||
return
|
||||
}
|
||||
if (!tool_name) {
|
||||
cline.consecutiveMistakeCount++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("use_mcp_tool", "tool_name"))
|
||||
return
|
||||
}
|
||||
// arguments are optional, but if they are provided they must be valid JSON
|
||||
// if (!mcp_arguments) {
|
||||
// cline.consecutiveMistakeCount++
|
||||
// pushToolResult(await cline.sayAndCreateMissingParamError("use_mcp_tool", "arguments"))
|
||||
// return
|
||||
// }
|
||||
let parsedArguments: Record<string, unknown> | undefined
|
||||
if (mcp_arguments) {
|
||||
try {
|
||||
parsedArguments = JSON.parse(mcp_arguments)
|
||||
} catch (error) {
|
||||
cline.consecutiveMistakeCount++
|
||||
await cline.say("error", `Roo tried to use ${tool_name} with an invalid JSON argument. Retrying...`)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(formatResponse.invalidMcpToolArgumentError(server_name, tool_name)),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
cline.consecutiveMistakeCount = 0
|
||||
const completeMessage = JSON.stringify({
|
||||
type: "use_mcp_tool",
|
||||
serverName: server_name,
|
||||
toolName: tool_name,
|
||||
arguments: mcp_arguments,
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
const didApprove = await askApproval("use_mcp_server", completeMessage)
|
||||
if (!didApprove) {
|
||||
return
|
||||
}
|
||||
// now execute the tool
|
||||
await cline.say("mcp_server_request_started") // same as browser_action_result
|
||||
const toolResult = await cline.providerRef
|
||||
.deref()
|
||||
?.getMcpHub()
|
||||
?.callTool(server_name, tool_name, parsedArguments)
|
||||
|
||||
// TODO: add progress indicator and ability to parse images and non-text responses
|
||||
const toolResultPretty =
|
||||
(toolResult?.isError ? "Error:\n" : "") +
|
||||
toolResult?.content
|
||||
.map((item) => {
|
||||
if (item.type === "text") {
|
||||
return item.text
|
||||
}
|
||||
if (item.type === "resource") {
|
||||
const { blob, ...rest } = item.resource
|
||||
return JSON.stringify(rest, null, 2)
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n\n") || "(No response)"
|
||||
await cline.say("mcp_server_response", toolResultPretty)
|
||||
pushToolResult(formatResponse.toolResult(toolResultPretty))
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
await handleError("executing MCP tool", error)
|
||||
return
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue