UNPKG

sourcegraph-mcp-server

Version:

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

192 lines (191 loc) 5.9 kB
"use strict"; /** * Natural language processing for search queries */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.naturalLanguageSearch = void 0; const axios_1 = __importDefault(require("axios")); const formatter_1 = require("../utils/formatter"); /** * Executes a search based on a natural language query */ async function naturalLanguageSearch(naturalQuery, sourcegraphConfig) { try { // Extract structured query parameters from natural language using LLM const { type = 'file', query, author, after, repos = [], originalQuery } = await (0, formatter_1.analyzeQuery)(naturalQuery); // For clarity in logs, show the transformation console.log(`Natural query: "${naturalQuery}" → Sourcegraph: "${query}" (type: ${type})`); // Base search query let searchQuery = query; // Add type filter searchQuery += ` type:${type}`; // Add author filter for commit and diff searches if (author && (type === 'commit' || type === 'diff')) { searchQuery += ` author:${author}`; } // Add date filter if (after && (type === 'commit' || type === 'diff')) { searchQuery += ` after:${after}`; } // Add repository filters if (repos.length > 0) { const repoFilters = repos.map(repo => { // If it looks like a GitHub repo (contains a slash), format accordingly if (repo.includes('/')) { return `repo:^github\\.com/${repo}$`; } // Otherwise use as-is return `repo:${repo}`; }); searchQuery += ` ${repoFilters.join(' ')}`; } // Add result count limit searchQuery += ' count:20'; // Select the appropriate GraphQL query based on search type let graphqlQuery; if (type === 'file') { graphqlQuery = getFileSearchQuery(); } else if (type === 'commit') { graphqlQuery = getCommitSearchQuery(); } else if (type === 'diff') { graphqlQuery = getDiffSearchQuery(); } else { throw new Error(`Unsupported search type: ${type}`); } // Headers for Sourcegraph API const headers = { 'Authorization': `token ${sourcegraphConfig.token}`, 'Content-Type': 'application/json' }; // Make the request to Sourcegraph API const response = await axios_1.default.post(`${sourcegraphConfig.url}/.api/graphql`, { query: graphqlQuery, variables: { query: searchQuery } }, { headers }); // Check for API errors if (response.data.errors) { return { content: [{ type: "text", text: `Sourcegraph API Error: ${JSON.stringify(response.data.errors)}` }], isError: true }; } // Prepare results for formatting const results = response.data.data.search.results; // Generate a natural language response const naturalResponse = (0, formatter_1.formatSearchResults)(results, { query, type }); return { content: [{ type: "text", text: naturalResponse }] }; } catch (error) { return { content: [{ type: "text", text: `Error processing natural language search: ${error.message || 'Unknown error'}` }], isError: true }; } } exports.naturalLanguageSearch = naturalLanguageSearch; // GraphQL query for file search function getFileSearchQuery() { return ` query FileSearch($query: String!) { search(query: $query, version: V3) { results { matchCount results { __typename ... on FileMatch { repository { name } file { path } lineMatches { lineNumber preview } } } } } } `; } // GraphQL query for commit search function getCommitSearchQuery() { return ` query CommitSearch($query: String!) { search(query: $query, version: V3) { results { matchCount results { __typename ... on CommitSearchResult { commit { oid message author { person { name email } date } repository { name } } } } } } } `; } // GraphQL query for diff search function getDiffSearchQuery() { return ` query DiffSearch($query: String!) { search(query: $query, version: V3) { results { matchCount results { __typename ... on CommitSearchResult { commit { oid message author { person { name email } date } repository { name } } diff { fileDiffs { oldPath newPath hunks { body oldRange { start, lines } newRange { start, lines } } } } } } } } } `; }