@@ -6,12 +6,12 @@ import {
66 ApiConfiguration ,
77 createApiClient ,
88 BaseToolExecutor ,
9- CliContextProvider ,
109 MessageParser ,
1110 AVAILABLE_TOOLS ,
1211 ToolResponse ,
1312 ApiClient
1413} from './lib' ;
14+ import { McpClient } from './lib/mcp/McpClient' ;
1515import { Anthropic } from '@anthropic-ai/sdk' ;
1616
1717function formatToolResponse ( response : ToolResponse ) : string {
@@ -54,10 +54,12 @@ class CliToolExecutor extends BaseToolExecutor {
5454
5555async function main ( ) {
5656 const args = process . argv . slice ( 2 ) ;
57- const task = args [ 0 ] ;
57+ const toolsFlag = args . includes ( '--tools' ) ;
58+ const debugFlag = args . includes ( '--debug' ) ;
59+ const task = args . find ( arg => ! [ '--tools' , '--debug' ] . includes ( arg ) ) ;
5860
5961 if ( ! task ) {
60- console . error ( 'Usage: cline "My Task" [--tools]' ) ;
62+ console . error ( 'Usage: cline "My Task" [--tools] [--debug] ' ) ;
6163 process . exit ( 1 ) ;
6264 }
6365
@@ -75,12 +77,66 @@ async function main() {
7577
7678 const cwd = process . cwd ( ) ;
7779 const toolExecutor = new CliToolExecutor ( cwd ) ;
78- const contextProvider = new CliContextProvider ( cwd ) ;
7980 const messageParser = new MessageParser ( AVAILABLE_TOOLS ) ;
8081 const apiClient = createApiClient ( apiConfiguration ) ;
82+ const mcpClient = new McpClient ( ) ;
83+
84+ // Initialize MCP client early if --tools flag is present
85+ if ( toolsFlag ) {
86+ console . log ( 'Loading available tools...' ) ;
87+ try {
88+ await mcpClient . initializeServers ( ) ;
89+ // Get built-in tools documentation
90+ const toolDocs = AVAILABLE_TOOLS . map ( tool => {
91+ const params = Object . entries ( tool . parameters )
92+ . map ( ( [ name , param ] ) => '- ' + name + ': (' + ( param . required ? 'required' : 'optional' ) + ') ' + param . description )
93+ . join ( '\n' ) ;
94+ return '## ' + tool . name + '\nDescription: ' + tool . description + '\nParameters:\n' + params ;
95+ } ) . join ( '\n\n' ) ;
96+
97+ // Get MCP server tools
98+ const mcpTools = [ ] ;
99+ mcpTools . push ( '\nMCP SERVERS\n' ) ;
100+ mcpTools . push ( '\nThe Model Context Protocol (MCP) enables communication between the system and locally running MCP servers that provide additional tools and resources to extend your capabilities.\n' ) ;
101+ mcpTools . push ( '\n# Connected MCP Servers\n' ) ;
102+ mcpTools . push ( '\nWhen a server is connected, you can use the server\'s tools via the `use_mcp_tool` tool, and access the server\'s resources via the `access_mcp_resource` tool.\n' ) ;
103+
104+ // Get list of available servers
105+ const availableServers = mcpClient . getAvailableServers ( ) ;
106+
107+ mcpTools . push ( `\nCurrently connected servers: ${ availableServers . join ( ', ' ) || 'None' } \n` ) ;
108+ mcpTools . push ( '\nExample usage:\n' ) ;
109+ mcpTools . push ( '```xml' ) ;
110+ mcpTools . push ( '<use_mcp_tool>' ) ;
111+ mcpTools . push ( '<server_name>mcp-rand</server_name>' ) ;
112+ mcpTools . push ( '<tool_name>generate_uuid</tool_name>' ) ;
113+ mcpTools . push ( '<arguments>' ) ;
114+ mcpTools . push ( '{}' ) ;
115+ mcpTools . push ( '</arguments>' ) ;
116+ mcpTools . push ( '</use_mcp_tool>' ) ;
117+ mcpTools . push ( '```\n' ) ;
118+
119+ const serverTools = await mcpClient . getServerTools ( ) ;
120+ if ( serverTools . length > 0 ) {
121+ mcpTools . push ( ...serverTools ) ;
122+ } else {
123+ mcpTools . push ( '\n(No MCP servers currently connected)' ) ;
124+ }
125+
126+ console . log ( '\nAVAILABLE TOOLS\n' ) ;
127+ console . log ( toolDocs ) ;
128+ console . log ( mcpTools . filter ( Boolean ) . join ( '' ) ) ;
129+ process . exit ( 0 ) ;
130+ } catch ( error ) {
131+ console . error ( 'Error loading tools:' , error ) ;
132+ process . exit ( 1 ) ;
133+ }
134+ }
81135
82136 try {
83- await initiateTaskLoop ( task , toolExecutor , contextProvider , messageParser , apiClient ) ;
137+ // Initialize MCP servers before starting the task loop
138+ await mcpClient . initializeServers ( ) ;
139+ await initiateTaskLoop ( task , toolExecutor , messageParser , apiClient , mcpClient , debugFlag ) ;
84140 } catch ( error ) {
85141 console . error ( 'Error:' , error . message ) ;
86142 process . exit ( 1 ) ;
@@ -90,22 +146,65 @@ async function main() {
90146async function initiateTaskLoop (
91147 task : string ,
92148 toolExecutor : CliToolExecutor ,
93- contextProvider : CliContextProvider ,
94149 messageParser : MessageParser ,
95- apiClient : ApiClient
150+ apiClient : ApiClient ,
151+ mcpClient : McpClient ,
152+ debugFlag : boolean
96153) {
97154 let history : Anthropic . MessageParam [ ] = [ ] ;
98155 let includeFileDetails = true ;
99156
100157 while ( true ) {
101- const envDetails = await contextProvider . getEnvironmentDetails ( includeFileDetails ) ;
158+ const envDetails = `Current Working Directory: ${ process . cwd ( ) } ` ;
159+
160+ // Get built-in tools documentation
102161 const toolDocs = AVAILABLE_TOOLS . map ( tool => {
103162 const params = Object . entries ( tool . parameters )
104163 . map ( ( [ name , param ] ) => '- ' + name + ': (' + ( param . required ? 'required' : 'optional' ) + ') ' + param . description )
105164 . join ( '\n' ) ;
106165 return '## ' + tool . name + '\nDescription: ' + tool . description + '\nParameters:\n' + params ;
107166 } ) . join ( '\n\n' ) ;
108167
168+ // Get MCP server tools
169+ const mcpTools = [ ] ;
170+ mcpTools . push ( '\nMCP SERVERS\n' ) ;
171+ mcpTools . push ( '\nThe Model Context Protocol (MCP) enables communication between the system and locally running MCP servers that provide additional tools and resources to extend your capabilities.\n' ) ;
172+ mcpTools . push ( '\n# Connected MCP Servers\n' ) ;
173+ mcpTools . push ( '\nWhen a server is connected, you can use the server\'s tools via the `use_mcp_tool` tool, and access the server\'s resources via the `access_mcp_resource` tool.\n' ) ;
174+
175+ // Get list of available servers
176+ const availableServers = mcpClient . getAvailableServers ( ) ;
177+
178+ mcpTools . push ( `\nCurrently connected servers: ${ availableServers . join ( ', ' ) || 'None' } \n` ) ;
179+ mcpTools . push ( '\nExample usage:\n' ) ;
180+ mcpTools . push ( '```xml' ) ;
181+ mcpTools . push ( '<use_mcp_tool>' ) ;
182+ mcpTools . push ( '<server_name>mcp-rand</server_name>' ) ;
183+ mcpTools . push ( '<tool_name>generate_uuid</tool_name>' ) ;
184+ mcpTools . push ( '<arguments>' ) ;
185+ mcpTools . push ( '{}' ) ;
186+ mcpTools . push ( '</arguments>' ) ;
187+ mcpTools . push ( '</use_mcp_tool>' ) ;
188+ mcpTools . push ( '```\n' ) ;
189+
190+ const serverTools = await mcpClient . getServerTools ( ) ;
191+ if ( serverTools . length > 0 ) {
192+ mcpTools . push ( ...serverTools ) ;
193+ } else {
194+ mcpTools . push ( '\n(No MCP servers currently connected)' ) ;
195+ }
196+
197+ // Get the last tool result if any
198+ const lastMessage = history . length >= 2 ? history [ history . length - 1 ] : null ;
199+ let previousResult : string | null = null ;
200+
201+ if ( lastMessage && typeof lastMessage . content === 'string' ) {
202+ const content = lastMessage . content ;
203+ if ( content . startsWith ( '[' ) && content . includes ( '] Result: ' ) ) {
204+ previousResult = content . substring ( content . indexOf ( '] Result: ' ) + 9 ) ;
205+ }
206+ }
207+
109208 const systemPromptParts = [
110209 'You are Cline, a highly skilled software engineer.' ,
111210 '' ,
@@ -115,16 +214,24 @@ async function initiateTaskLoop(
115214 '' ,
116215 toolDocs ,
117216 '' ,
217+ ...mcpTools . filter ( Boolean ) ,
218+ '' ,
118219 'RULES' ,
119220 '' ,
120- '1. Use one tool at a time ' ,
221+ '1. YOU MUST use exactly one tool in each response. If this is the final response, you must use the `attempt_completion` tool. ' ,
121222 '2. Wait for tool execution results before proceeding' ,
122223 '3. Handle errors appropriately' ,
123224 '4. Document your changes' ,
124225 '' ,
125226 'TASK' ,
126227 '' ,
127- task
228+ task ,
229+ '' ,
230+ ...( previousResult ? [
231+ 'PREVIOUS RESULT' ,
232+ '' ,
233+ previousResult
234+ ] : [ ] )
128235 ] ;
129236
130237 const systemPrompt = systemPromptParts . join ( '\n' ) ;
@@ -141,7 +248,11 @@ async function initiateTaskLoop(
141248 let didAlreadyUseTool = false ;
142249 let assistantMessage = '' ;
143250
144- console . log ( chalk . yellow ( `[DEBUG] System prompt:\n${ systemPrompt } ` ) ) ;
251+ if ( debugFlag ) {
252+ console . log ( chalk . yellow ( `[DEBUG] System prompt:\n${ systemPrompt } ` ) ) ;
253+ }
254+
255+ console . log ( chalk . gray ( 'Thinking...' ) ) ;
145256 for await ( const chunk of apiClient . createMessage ( systemPrompt , history ) ) {
146257 if ( chunk . type === 'text' && chunk . text ) {
147258 assistantMessage += chunk . text ;
@@ -163,44 +274,89 @@ async function initiateTaskLoop(
163274 let result : ToolResponse = '' ;
164275
165276 switch ( toolUse . name ) {
166- case 'write_to_file' :
277+ case 'write_to_file' : {
167278 [ error , result ] = await toolExecutor . writeFile (
168279 toolUse . params . path ,
169280 toolUse . params . content ,
170281 parseInt ( toolUse . params . line_count )
171282 ) ;
172283 break ;
173- case 'read_file' :
284+ }
285+ case 'read_file' : {
174286 [ error , result ] = await toolExecutor . readFile ( toolUse . params . path ) ;
175287 break ;
176- case 'list_files' :
288+ }
289+ case 'list_files' : {
290+ const recursive = toolUse . params . recursive === 'true' ;
177291 [ error , result ] = await toolExecutor . listFiles (
178292 toolUse . params . path ,
179- toolUse . params . recursive === 'true'
293+ recursive
180294 ) ;
181295 break ;
182- case 'search_files' :
296+ }
297+ case 'search_files' : {
183298 [ error , result ] = await toolExecutor . searchFiles (
184299 toolUse . params . path ,
185300 toolUse . params . regex ,
186301 toolUse . params . file_pattern
187302 ) ;
188303 break ;
189- case 'execute_command' :
304+ }
305+ case 'execute_command' : {
190306 [ error , result ] = await toolExecutor . executeCommand ( toolUse . params . command ) ;
191307 break ;
192- case 'attempt_completion' :
308+ }
309+ case 'attempt_completion' : {
193310 console . log ( chalk . green ( toolUse . params . result ) ) ;
194311 if ( toolUse . params . command ) {
195312 [ error , result ] = await toolExecutor . executeCommand ( toolUse . params . command ) ;
196313 }
197- return ;
198- case 'list_code_definition_names' :
314+ // Add result to history before returning
315+ if ( result ) {
316+ history . push (
317+ { role : 'assistant' , content : assistantMessage } ,
318+ { role : 'user' , content : `[${ toolUse . name } ] Result: ${ formatToolResponse ( result ) } ` }
319+ ) ;
320+ }
321+ process . exit ( 0 ) ;
322+ }
323+ case 'list_code_definition_names' : {
199324 [ error , result ] = await toolExecutor . listCodeDefinitions ( toolUse . params . path ) ;
200325 break ;
201- default :
326+ }
327+ case 'use_mcp_tool' : {
328+ try {
329+ const mcpResult = await mcpClient . callTool (
330+ toolUse . params . server_name ,
331+ toolUse . params . tool_name ,
332+ JSON . parse ( toolUse . params . arguments || '{}' )
333+ ) ;
334+ error = mcpResult . isError === true ;
335+ result = mcpResult . content . map ( item => item . text ) . join ( '\n' ) ;
336+ } catch ( err ) {
337+ error = true ;
338+ result = `Error executing MCP tool: ${ err . message } ` ;
339+ }
340+ break ;
341+ }
342+ case 'access_mcp_resource' : {
343+ try {
344+ const mcpResult = await mcpClient . readResource (
345+ toolUse . params . server_name ,
346+ toolUse . params . uri
347+ ) ;
348+ error = false ;
349+ result = mcpResult . contents . map ( item => item . text ) . join ( '\n' ) ;
350+ } catch ( err ) {
351+ error = true ;
352+ result = `Error accessing MCP resource: ${ err . message } ` ;
353+ }
354+ break ;
355+ }
356+ default : {
202357 error = true ;
203358 result = `Unknown tool: ${ toolUse . name } ` ;
359+ }
204360 }
205361
206362 // Mark that we've used a tool and add the result to history
@@ -210,7 +366,9 @@ async function initiateTaskLoop(
210366 { role : 'user' , content : `[${ toolUse . name } ] Result: ${ formatToolResponse ( result ) } ` }
211367 ) ;
212368 // Log full response in yellow for debugging
213- console . log ( chalk . yellow ( `[DEBUG] Full response:\n${ assistantMessage } ` ) ) ;
369+ if ( debugFlag ) {
370+ console . log ( chalk . yellow ( `[DEBUG] Full response:\n${ assistantMessage } ` ) ) ;
371+ }
214372 continue ;
215373 }
216374 }
@@ -222,13 +380,16 @@ async function initiateTaskLoop(
222380 { role : 'user' , content : 'You responded with only text but have not called attempt_completion yet. Please either use a tool to proceed with the task or call attempt_completion if the task is complete.' }
223381 ) ;
224382 // Log full response in yellow for debugging
225- console . log ( chalk . yellow ( `[DEBUG] Full response:\n${ assistantMessage } ` ) ) ;
383+ if ( debugFlag ) {
384+ console . log ( chalk . yellow ( `[DEBUG] Full response:\n${ assistantMessage } ` ) ) ;
385+ }
226386 }
227387
228388 // Only include file details in first iteration
229389 includeFileDetails = false ;
230390 }
231391}
392+
232393main ( ) . catch ( error => {
233394 console . error ( 'Fatal error:' , error ) ;
234395 process . exit ( 1 ) ;
0 commit comments