2025-11-10 21:39:40 +00:00
import z from "zod"
import { Tool } from "./tool"
import DESCRIPTION from "./codesearch.txt"
2026-02-03 23:51:26 +00:00
import { abortAfterAny } from "../util/abort"
2025-11-10 21:39:40 +00:00
const API_CONFIG = {
BASE_URL : "https://mcp.exa.ai" ,
ENDPOINTS : {
CONTEXT : "/mcp" ,
} ,
} as const
interface McpCodeRequest {
jsonrpc : string
id : number
method : string
params : {
name : string
arguments : {
query : string
tokensNum : number
}
}
}
interface McpCodeResponse {
jsonrpc : string
result : {
content : Array < {
type : string
text : string
} >
}
}
export const CodeSearchTool = Tool . define ( "codesearch" , {
description : DESCRIPTION ,
parameters : z.object ( {
query : z
. string ( )
. describe (
"Search query to find relevant context for APIs, Libraries, and SDKs. For example, 'React useState hook examples', 'Python pandas dataframe filtering', 'Express.js middleware', 'Next js partial prerendering configuration'" ,
) ,
tokensNum : z
. number ( )
. min ( 1000 )
. max ( 50000 )
. default ( 5000 )
. describe (
"Number of tokens to return (1000-50000). Default is 5000 tokens. Adjust this value based on how much context you need - use lower values for focused queries and higher values for comprehensive documentation." ,
) ,
} ) ,
async execute ( params , ctx ) {
2026-01-01 22:54:11 +00:00
await ctx . ask ( {
permission : "codesearch" ,
patterns : [ params . query ] ,
always : [ "*" ] ,
metadata : {
query : params.query ,
tokensNum : params.tokensNum ,
} ,
} )
2025-11-10 21:39:40 +00:00
const codeRequest : McpCodeRequest = {
jsonrpc : "2.0" ,
id : 1 ,
method : "tools/call" ,
params : {
name : "get_code_context_exa" ,
arguments : {
query : params.query ,
tokensNum : params.tokensNum || 5000 ,
} ,
} ,
}
2026-02-03 23:51:26 +00:00
const { signal , clearTimeout } = abortAfterAny ( 30000 , ctx . abort )
2025-11-10 21:39:40 +00:00
try {
const headers : Record < string , string > = {
accept : "application/json, text/event-stream" ,
"content-type" : "application/json" ,
}
const response = await fetch ( ` ${ API_CONFIG . BASE_URL } ${ API_CONFIG . ENDPOINTS . CONTEXT } ` , {
method : "POST" ,
headers ,
body : JSON.stringify ( codeRequest ) ,
2026-02-03 23:51:26 +00:00
signal ,
2025-11-10 21:39:40 +00:00
} )
2026-02-03 23:51:26 +00:00
clearTimeout ( )
2025-11-10 21:39:40 +00:00
if ( ! response . ok ) {
const errorText = await response . text ( )
throw new Error ( ` Code search error ( ${ response . status } ): ${ errorText } ` )
}
const responseText = await response . text ( )
// Parse SSE response
const lines = responseText . split ( "\n" )
for ( const line of lines ) {
if ( line . startsWith ( "data: " ) ) {
const data : McpCodeResponse = JSON . parse ( line . substring ( 6 ) )
if ( data . result && data . result . content && data . result . content . length > 0 ) {
return {
output : data.result.content [ 0 ] . text ,
title : ` Code search: ${ params . query } ` ,
metadata : { } ,
}
}
}
}
return {
output :
"No code snippets or documentation found. Please try a different query, be more specific about the library or programming concept, or check the spelling of framework names." ,
title : ` Code search: ${ params . query } ` ,
metadata : { } ,
}
} catch ( error ) {
2026-02-03 23:51:26 +00:00
clearTimeout ( )
2025-11-10 21:39:40 +00:00
if ( error instanceof Error && error . name === "AbortError" ) {
throw new Error ( "Code search request timed out" )
}
throw error
}
} ,
} )