UNPKG

@sourcebot/mcp

Version:

[![Sourcebot](https://img.shields.io/badge/Website-sourcebot.dev-blue)](https://sourcebot.dev) [![GitHub](https://img.shields.io/badge/GitHub-sourcebot--dev%2Fsourcebot-green?logo=github)](https://github.com/sourcebot-dev/sourcebot) [![Docs](https://img.s

142 lines 5.56 kB
import { env } from './env.js'; import { listReposResponseSchema, searchResponseSchema, fileSourceResponseSchema, listCommitsResponseSchema, askCodebaseResponseSchema, listLanguageModelsResponseSchema, listTreeApiResponseSchema } from './schemas.js'; import { isServiceError, ServiceErrorException } from './utils.js'; const parseResponse = async (response, schema) => { const text = await response.text(); let json; try { json = JSON.parse(text); } catch { throw new Error(`Invalid JSON response: ${text}`); } // Check if the response is already a service error from the API if (isServiceError(json)) { throw new ServiceErrorException(json); } const parsed = schema.safeParse(json); if (!parsed.success) { throw new Error(`Failed to parse response: ${parsed.error.message}`); } return parsed.data; }; export const search = async (request) => { const response = await fetch(`${env.SOURCEBOT_HOST}/api/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, body: JSON.stringify(request) }); return parseResponse(response, searchResponseSchema); }; export const listRepos = async (queryParams = {}) => { const url = new URL(`${env.SOURCEBOT_HOST}/api/repos`); for (const [key, value] of Object.entries(queryParams)) { if (value) { url.searchParams.set(key, value.toString()); } } const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, }); const repos = await parseResponse(response, listReposResponseSchema); const totalCount = parseInt(response.headers.get('X-Total-Count') ?? '0', 10); return { repos, totalCount }; }; export const getFileSource = async (request) => { const url = new URL(`${env.SOURCEBOT_HOST}/api/source`); for (const [key, value] of Object.entries(request)) { if (value) { url.searchParams.set(key, value.toString()); } } const response = await fetch(url, { method: 'GET', headers: { 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, }); return parseResponse(response, fileSourceResponseSchema); }; export const listCommits = async (queryParams) => { const url = new URL(`${env.SOURCEBOT_HOST}/api/commits`); for (const [key, value] of Object.entries(queryParams)) { if (value) { url.searchParams.set(key, value.toString()); } } const response = await fetch(url, { method: 'GET', headers: { 'X-Org-Domain': '~', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, }); const commits = await parseResponse(response, listCommitsResponseSchema); const totalCount = parseInt(response.headers.get('X-Total-Count') ?? '0', 10); return { commits, totalCount }; }; /** * Fetches a repository tree (or subtree union) from the Sourcebot tree API. * * @param request - Repository name, revision, and path selectors for the tree query * @returns A tree response rooted at `tree` containing nested `tree`/`blob` nodes */ export const listTree = async (request) => { const response = await fetch(`${env.SOURCEBOT_HOST}/api/tree`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, body: JSON.stringify(request), }); return parseResponse(response, listTreeApiResponseSchema); }; /** * Asks a natural language question about the codebase using the Sourcebot AI agent. * This is a blocking call that runs the full agent loop and returns when complete. * * @param request - The question and optional repo filters * @returns The agent's answer, chat URL, sources, and metadata */ export const askCodebase = async (request) => { const response = await fetch(`${env.SOURCEBOT_HOST}/api/chat/blocking`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, body: JSON.stringify(request), }); return parseResponse(response, askCodebaseResponseSchema); }; /** * Lists the available language models configured on the Sourcebot instance. * * @returns Array of language model info objects */ export const listLanguageModels = async () => { const response = await fetch(`${env.SOURCEBOT_HOST}/api/models`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'X-Sourcebot-Client-Source': 'mcp', ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) }, }); return parseResponse(response, listLanguageModelsResponseSchema); }; //# sourceMappingURL=client.js.map