@@ -87,6 +87,7 @@ async function callMCPSearch(query: string): Promise<SearchResult[]> {
8787 let errorData = "" ;
8888 let hasReceivedResponse = false ;
8989 let responseTimeout : NodeJS . Timeout ;
90+ let isInitialized = false ;
9091
9192 // Set a timeout for the MCP response
9293 responseTimeout = setTimeout ( ( ) => {
@@ -100,36 +101,98 @@ async function callMCPSearch(query: string): Promise<SearchResult[]> {
100101 const output = data . toString ( ) ;
101102 responseData += output ;
102103
103- // Check if we have a complete JSON-RPC response
104+ // Process line-delimited JSON-RPC messages
104105 const lines = responseData . split ( "\n" ) ;
106+ responseData = lines . pop ( ) || "" ; // Keep incomplete line for next data event
107+
105108 for ( const line of lines ) {
106- if (
107- line . trim ( ) &&
108- line . includes ( '"jsonrpc":"2.0"' ) &&
109- line . includes ( '"id":1' )
110- ) {
111- hasReceivedResponse = true ;
112- clearTimeout ( responseTimeout ) ;
113-
114- // Process the response immediately
115- try {
116- const results = parseMCPResponse ( line ) ;
117- mcpProcess . kill ( ) ; // Clean up the process
118- resolve ( results ) ;
119- return ;
120- } catch ( error ) {
121- console . error ( "Parse error:" , error ) ;
109+ if ( ! line . trim ( ) ) continue ;
110+
111+ try {
112+ const message = JSON . parse ( line ) ;
113+
114+ // Handle initialize response
115+ if ( message . id === 1 && message . result && ! isInitialized ) {
116+ console . log ( "MCP server initialized" ) ;
117+ isInitialized = true ;
118+
119+ // Send initialized notification
120+ const initializedNotification = {
121+ jsonrpc : "2.0" ,
122+ method : "notifications/initialized" ,
123+ params : { } ,
124+ } ;
125+ mcpProcess . stdin . write (
126+ JSON . stringify ( initializedNotification ) + "\n"
127+ ) ;
128+
129+ // Now send the actual search request
130+ const searchRequest = {
131+ jsonrpc : "2.0" ,
132+ id : 2 ,
133+ method : "tools/call" ,
134+ params : {
135+ name : "search" ,
136+ arguments : {
137+ query : query ,
138+ fields : [
139+ "title" ,
140+ "url" ,
141+ "repository" ,
142+ "created_at" ,
143+ "author" ,
144+ "type" ,
145+ "state" ,
146+ ] ,
147+ } ,
148+ } ,
149+ } ;
150+ mcpProcess . stdin . write ( JSON . stringify ( searchRequest ) + "\n" ) ;
151+ continue ;
152+ }
153+
154+ // Handle search response
155+ if ( message . id === 2 && message . result ) {
156+ hasReceivedResponse = true ;
157+ clearTimeout ( responseTimeout ) ;
158+
159+ try {
160+ const results = parseMCPResponse ( line ) ;
161+ mcpProcess . kill ( ) ; // Clean up the process
162+ resolve ( results ) ;
163+ return ;
164+ } catch ( error ) {
165+ console . error ( "Parse error:" , error ) ;
166+ mcpProcess . kill ( ) ;
167+ reject (
168+ new Error ( `Failed to parse MCP response: ${ error . message } ` )
169+ ) ;
170+ return ;
171+ }
172+ }
173+
174+ // Handle errors
175+ if ( message . error ) {
176+ console . error ( "MCP returned error:" , message . error ) ;
122177 mcpProcess . kill ( ) ;
123- reject ( new Error ( `Failed to parse MCP response: ${ error . message } ` ) ) ;
178+ reject (
179+ new Error (
180+ `MCP error: ${ message . error . message || "Unknown error" } `
181+ )
182+ ) ;
124183 return ;
125184 }
185+ } catch ( parseError ) {
186+ // Ignore parse errors for incomplete messages
187+ console . log ( "Skipping unparseable message:" , line ) ;
126188 }
127189 }
128190 } ) ;
129191
130192 mcpProcess . stderr . on ( "data" , ( data ) => {
131193 const error = data . toString ( ) ;
132194 errorData += error ;
195+ console . error ( "MCP stderr:" , error ) ;
133196 } ) ;
134197
135198 mcpProcess . on ( "error" , ( error ) => {
@@ -145,32 +208,23 @@ async function callMCPSearch(query: string): Promise<SearchResult[]> {
145208 }
146209 } ) ;
147210
148- // Send the search request via JSON-RPC
149- const searchRequest = {
211+ // Start the MCP handshake with initialize request
212+ const initializeRequest = {
150213 jsonrpc : "2.0" ,
151214 id : 1 ,
152- method : "tools/call " ,
215+ method : "initialize " ,
153216 params : {
154- name : "search" ,
155- arguments : {
156- query : query ,
157- fields : [
158- "title" ,
159- "url" ,
160- "repository" ,
161- "created_at" ,
162- "author" ,
163- "type" ,
164- "state" ,
165- ] ,
217+ protocolVersion : "2025-06-18" ,
218+ clientInfo : {
219+ name : "raycast-github-brain" ,
220+ version : "1.0.0" ,
166221 } ,
222+ capabilities : { } ,
167223 } ,
168224 } ;
169225
170226 try {
171- mcpProcess . stdin . write ( JSON . stringify ( searchRequest ) + "\n" ) ;
172- // Don't end stdin immediately - let the process handle the response first
173- // The stdin will be closed when we kill the process after getting the response
227+ mcpProcess . stdin . write ( JSON . stringify ( initializeRequest ) + "\n" ) ;
174228 } catch ( error ) {
175229 console . error ( "Error writing to MCP stdin:" , error ) ;
176230 clearTimeout ( responseTimeout ) ;
0 commit comments