Skip to content

Commit ba0d081

Browse files
committed
Fixes #4900: MCP Tool reminders enforce the wrong syntax
- Modified formatResponse.noToolsUsed() and formatResponse.missingToolParameterError() to accept optional hasMcpTools parameter - Added getToolUseInstructionsReminder() function that provides correct syntax based on tool type - When MCP tools are available, shows proper use_mcp_tool format instead of generic XML format - Added hasMcpToolsAvailable() method to Task class to detect when MCP servers with tools are connected - Updated all call sites to pass MCP tool availability information - Maintains backward compatibility with legacy toolUseInstructionsReminder constant This prevents the infinite loop where AI tries wrong MCP syntax and gets corrected with wrong format.
1 parent 2e2f83b commit ba0d081

File tree

2 files changed

+73
-12
lines changed

2 files changed

+73
-12
lines changed

src/core/prompts/responses.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ export const formatResponse = {
1818
rooIgnoreError: (path: string) =>
1919
`Access to ${path} is blocked by the .rooignore file settings. You must try to continue in the task without using this file, or ask the user to update the .rooignore file.`,
2020

21-
noToolsUsed: () =>
21+
noToolsUsed: (hasMcpTools?: boolean) =>
2222
`[ERROR] You did not use a tool in your previous response! Please retry with a tool use.
2323
24-
${toolUseInstructionsReminder}
24+
${getToolUseInstructionsReminder(hasMcpTools)}
2525
2626
# Next Steps
2727
28-
If you have completed the user's task, use the attempt_completion tool.
29-
If you require additional information from the user, use the ask_followup_question tool.
30-
Otherwise, if you have not completed the task and do not need additional information, then proceed with the next step of the task.
28+
If you have completed the user's task, use the attempt_completion tool.
29+
If you require additional information from the user, use the ask_followup_question tool.
30+
Otherwise, if you have not completed the task and do not need additional information, then proceed with the next step of the task.
3131
(This is an automated message, so do not respond to it conversationally.)`,
3232

3333
tooManyMistakes: (feedback?: string) =>
3434
`You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<feedback>\n${feedback}\n</feedback>`,
3535

36-
missingToolParameterError: (paramName: string) =>
37-
`Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${toolUseInstructionsReminder}`,
36+
missingToolParameterError: (paramName: string, hasMcpTools?: boolean) =>
37+
`Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${getToolUseInstructionsReminder(hasMcpTools)}`,
3838

3939
lineCountTruncationError: (actualLineCount: number, isNewFile: boolean, diffStrategyEnabled: boolean = false) => {
4040
const truncationMessage = `Note: Your response may have been truncated because it exceeded your output limit. You wrote ${actualLineCount} lines of content, but the line_count parameter was either missing or not included in your response.`
@@ -66,7 +66,7 @@ Otherwise, if you have not completed the task and do not need additional informa
6666
`RECOMMENDED APPROACH:\n` +
6767
`${existingFileApproaches.join("\n")}\n`
6868

69-
return `${isNewFile ? newFileGuidance : existingFileGuidance}\n${toolUseInstructionsReminder}`
69+
return `${isNewFile ? newFileGuidance : existingFileGuidance}\n${getToolUseInstructionsReminder()}`
7070
},
7171

7272
invalidMcpToolArgumentError: (serverName: string, toolName: string) =>
@@ -190,7 +190,34 @@ const formatImagesIntoBlocks = (images?: string[]): Anthropic.ImageBlockParam[]
190190
: []
191191
}
192192

193-
const toolUseInstructionsReminder = `# Reminder: Instructions for Tool Use
193+
const getToolUseInstructionsReminder = (hasMcpTools?: boolean) => {
194+
if (hasMcpTools) {
195+
return `# Reminder: Instructions for MCP Tool Use
196+
197+
MCP tools must be called using the use_mcp_tool format:
198+
199+
<use_mcp_tool>
200+
<server_name>server name here</server_name>
201+
<tool_name>tool name here</tool_name>
202+
<arguments>
203+
{
204+
"param1": "value1",
205+
"param2": "value2"
206+
}
207+
</arguments>
208+
</use_mcp_tool>
209+
210+
For regular tools, use the standard XML format:
211+
212+
<actual_tool_name>
213+
<parameter1_name>value1</parameter1_name>
214+
<parameter2_name>value2</parameter2_name>
215+
...
216+
</actual_tool_name>
217+
218+
Always use the correct format for the type of tool you are calling.`
219+
} else {
220+
return `# Reminder: Instructions for Tool Use
194221
195222
Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
196223
@@ -209,3 +236,8 @@ I have completed the task...
209236
</attempt_completion>
210237
211238
Always use the actual tool name as the XML tag name for proper parsing and execution.`
239+
}
240+
}
241+
242+
// Legacy constant for backward compatibility
243+
const toolUseInstructionsReminder = getToolUseInstructionsReminder()

src/core/task/Task.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,8 @@ export class Task extends EventEmitter<ClineEvents> {
709709
relPath ? ` for '${relPath.toPosix()}'` : ""
710710
} without value for required parameter '${paramName}'. Retrying...`,
711711
)
712-
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName))
712+
const hasMcpTools = await this.hasMcpToolsAvailable()
713+
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName, hasMcpTools))
713714
}
714715

715716
// Start / Abort / Resume
@@ -1128,7 +1129,8 @@ export class Task extends EventEmitter<ClineEvents> {
11281129
// the user hits max requests and denies resetting the count.
11291130
break
11301131
} else {
1131-
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed() }]
1132+
const hasMcpTools = await this.hasMcpToolsAvailable()
1133+
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed(hasMcpTools) }]
11321134
this.consecutiveMistakeCount++
11331135
}
11341136
}
@@ -1517,7 +1519,8 @@ export class Task extends EventEmitter<ClineEvents> {
15171519
const didToolUse = this.assistantMessageContent.some((block) => block.type === "tool_use")
15181520

15191521
if (!didToolUse) {
1520-
this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed() })
1522+
const hasMcpTools = await this.hasMcpToolsAvailable()
1523+
this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed(hasMcpTools) })
15211524
this.consecutiveMistakeCount++
15221525
}
15231526

@@ -1622,6 +1625,32 @@ export class Task extends EventEmitter<ClineEvents> {
16221625
})()
16231626
}
16241627

1628+
private async hasMcpToolsAvailable(): Promise<boolean> {
1629+
try {
1630+
const { mcpEnabled } = (await this.providerRef.deref()?.getState()) ?? {}
1631+
if (!(mcpEnabled ?? true)) {
1632+
return false
1633+
}
1634+
1635+
const provider = this.providerRef.deref()
1636+
if (!provider) {
1637+
return false
1638+
}
1639+
1640+
const mcpHub = await McpServerManager.getInstance(provider.context, provider)
1641+
if (!mcpHub) {
1642+
return false
1643+
}
1644+
1645+
// Check if there are any connected MCP servers with tools
1646+
const servers = mcpHub.getServers()
1647+
return servers.some((server) => server.tools && server.tools.length > 0)
1648+
} catch (error) {
1649+
console.error("Error checking MCP tools availability:", error)
1650+
return false
1651+
}
1652+
}
1653+
16251654
public async *attemptApiRequest(retryAttempt: number = 0): ApiStream {
16261655
const state = await this.providerRef.deref()?.getState()
16271656
const {

0 commit comments

Comments
 (0)