UNPKG

sourcegraph-mcp-server

Version:

A Model Context Protocol (MCP) server that connects AI assistants to Sourcegraph code search with natural language capabilities

98 lines (86 loc) 3.18 kB
import { Router, Request, Response } from 'express'; import { convertQueryToSourcegraphSyntax } from '../services/llm'; import { searchSourcegraph } from '../services/sourcegraph'; const router = Router(); /** * Helper function that either calls LLM or uses direct query. */ async function buildFinalQuery(naturalOrDirectQuery: string, isDirect: boolean, defaultType: string): Promise<string> { let sgQuery = ''; if (isDirect) { // We assume the user has provided a valid Sourcegraph query sgQuery = naturalOrDirectQuery.trim(); } else { // Convert from natural language -> Sourcegraph syntax sgQuery = await convertQueryToSourcegraphSyntax(naturalOrDirectQuery); } // If the query does not contain type:, append it // e.g. "repo:myorg/myrepo functionName" // We'll assume `defaultType` is something like 'file', 'commit', 'diff' if (!/\btype:\w+/.test(sgQuery)) { sgQuery += ` type:${defaultType}`; } // Ensure we get all results if (!/\bcount:/.test(sgQuery)) { sgQuery += ' count:all'; } return sgQuery.trim(); } /** * POST /search/code * Body: { query: string, directQuery?: boolean } */ router.post('/code', async (req: Request, res: Response) => { try { const { query, directQuery = false } = req.body; if (!query) { return res.status(400).json({ error: 'Missing query field in request body' }); } // Build or convert query for searching code (type:file) const finalQuery = await buildFinalQuery(query, directQuery, 'file'); const results = await searchSourcegraph(finalQuery); return res.json({ finalQuery, results }); } catch (err: any) { console.error('Error in /search/code:', err); return res.status(500).json({ error: err.message }); } }); /** * POST /search/commits * Body: { query: string, directQuery?: boolean } */ router.post('/commits', async (req: Request, res: Response) => { try { const { query, directQuery = false } = req.body; if (!query) { return res.status(400).json({ error: 'Missing query field in request body' }); } // Build or convert query for searching commits (type:commit) const finalQuery = await buildFinalQuery(query, directQuery, 'commit'); const results = await searchSourcegraph(finalQuery); return res.json({ finalQuery, results }); } catch (err: any) { console.error('Error in /search/commits:', err); return res.status(500).json({ error: err.message }); } }); /** * POST /search/diffs * Body: { query: string, directQuery?: boolean } */ router.post('/diffs', async (req: Request, res: Response) => { try { const { query, directQuery = false } = req.body; if (!query) { return res.status(400).json({ error: 'Missing query field in request body' }); } // Build or convert query for searching diffs (type:diff) const finalQuery = await buildFinalQuery(query, directQuery, 'diff'); const results = await searchSourcegraph(finalQuery); return res.json({ finalQuery, results }); } catch (err: any) { console.error('Error in /search/diffs:', err); return res.status(500).json({ error: err.message }); } }); export default router;