Skip to main content
Glama

greptile-mcp

index.ts13.1 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { GreptileClient } from './clients/greptile.js'; import type { QueryMessage, StreamingChunk } from './types/index.js'; import { generateSessionId, createErrorResponse } from './utils/index.js'; // Configuration schema for Smithery - this will auto-generate the session config UI export const configSchema = z.object({ // Required API credentials with graceful defaults for development greptileApiKey: z .string() .default('') .describe( 'Your Greptile API key from app.greptile.com/settings/api (required for functionality)' ), githubToken: z .string() .default('') .describe( 'GitHub personal access token with repo permissions (required for repository access)' ), // Optional service configuration greptileBaseUrl: z .string() .url('Must be a valid URL') .default('https://api.greptile.com/v2') .describe('Greptile API base URL (leave default unless using custom instance)'), // Transport and networking settings transport: z .enum(['stdio', 'sse']) .default('stdio') .describe('MCP transport method (stdio for Claude Desktop, sse for web interfaces)'), host: z .string() .ip({ version: 'v4' }) .default('0.0.0.0') .describe( 'Host binding for SSE transport (0.0.0.0 for all interfaces, 127.0.0.1 for localhost only)' ), port: z .number() .int() .min(1024, 'Port must be above 1024') .max(65535, 'Port must be below 65536') .default(8080) .describe('Port for SSE transport (1024-65535, default 8080)'), }); // Export the config type for external use export type IndexConfig = z.infer<typeof configSchema>; type Config = z.infer<typeof configSchema>; // Required: Export default createServer function for Smithery export default function createServer({ config }: { config: Config }) { const server = new McpServer({ name: 'greptile-mcp-server', version: '3.0.4', description: 'AI-powered code search and querying with Greptile API', }); // Initialize Greptile client with user-provided configuration const greptileClient = new GreptileClient({ apiKey: config.greptileApiKey, githubToken: config.githubToken, baseUrl: config.greptileBaseUrl, }); // Register greptile_help tool server.registerTool( 'greptile_help', { title: 'Greptile Help', description: 'Get comprehensive help and usage examples for all Greptile MCP tools', inputSchema: {}, }, async () => { const helpContent = `# 🚀 Greptile MCP Server - Comprehensive Guide ## Overview The Greptile MCP Server provides AI-powered code search and querying capabilities through the Model Context Protocol (MCP). It integrates with the Greptile API to index repositories and answer natural language questions about codebases. ## Available Tools ### 1. \`greptile_help\` Get this comprehensive help documentation. ### 2. \`index_repository\` Index a repository to make it searchable for future queries. **Parameters:** - \`remote\`: "github" or "gitlab" - \`repository\`: Repository in "owner/repo" format - \`branch\`: Branch to index - \`reload\`: Force reprocessing (optional, default: true) - \`notify\`: Email notification (optional, default: false) ### 3. \`query_repository\` Query repositories using natural language to get detailed answers with code references. **Parameters:** - \`query\`: Natural language question - \`repositories\`: Array of repository objects - \`session_id\`: For conversation continuity (auto-generated if not provided) - \`stream\`: Enable streaming response (optional, default: false) - \`genius\`: Enhanced capabilities (optional, default: true) ### 4. \`get_repository_info\` Get information about an indexed repository. **Parameters:** - \`remote\`: Repository host - \`repository\`: Repository identifier - \`branch\`: Branch name ## Best Practices ### Repository Workflow 1. **Index** repositories first using \`index_repository\` 2. **Verify** indexing status with \`get_repository_info\` 3. **Query** using natural language with \`query_repository\` ### Session Management - Use consistent \`session_id\` across related queries for better context - Session continuity improves answer quality over multiple interactions For more information, visit: https://docs.greptile.com`; return { content: [{ type: 'text', text: helpContent }], }; } ); // Register index_repository tool server.registerTool( 'index_repository', { title: 'Index Repository', description: 'Index a repository to make it searchable for future queries', inputSchema: { remote: z.enum(['github', 'gitlab']).describe('Repository host (github or gitlab)'), repository: z.string().describe('Repository in owner/repo format'), branch: z.string().describe('Branch to index'), reload: z .boolean() .default(true) .describe('Force reprocessing of previously indexed repository'), notify: z .boolean() .default(false) .describe('Send email notification when indexing completes'), }, }, async ({ remote, repository, branch, reload, notify }) => { try { const result = await greptileClient.indexRepository( remote, repository, branch, reload, notify ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text', text: createErrorResponse(`Failed to index repository: ${errorMessage}`), }, ], }; } } ); // Register query_repository tool server.registerTool( 'query_repository', { title: 'Query Repository', description: 'Query repositories using natural language to get detailed answers with code references', inputSchema: { query: z.string().describe('Natural language query about the codebase'), repositories: z .array( z.object({ remote: z.enum(['github', 'gitlab']), repository: z.string(), branch: z.string(), }) ) .default([]) .describe('List of repositories to query'), session_id: z .string() .optional() .describe('Session ID for conversation continuity (auto-generated if not provided)'), stream: z.boolean().default(false).describe('Enable streaming response'), genius: z.boolean().default(true).describe('Use enhanced query capabilities'), timeout: z.number().default(60000).describe('Request timeout in milliseconds'), previous_messages: z .array( z.object({ role: z.enum(['user', 'assistant']), content: z.string(), }) ) .default([]) .describe('Previous conversation messages for context'), }, }, async ({ query, repositories, session_id, stream, genius, timeout, previous_messages }) => { try { // Generate session ID if not provided const sessionId = session_id || generateSessionId(); // Prepare messages array const messages: QueryMessage[] = [ ...previous_messages, { role: 'user' as const, content: query }, ]; if (stream) { // Handle streaming response const streamResults: string[] = []; const streamingResponse = await greptileClient.queryRepositories( messages, repositories, sessionId, true, genius, timeout ); for await (const chunk of streamingResponse as AsyncIterable<StreamingChunk>) { if (chunk.type === 'text' && chunk.content) { streamResults.push(chunk.content); } } return { content: [ { type: 'text', text: JSON.stringify( { message: streamResults.join(''), session_id: sessionId, streamed: true, }, null, 2 ), }, ], }; } else { // Handle regular response const result = await greptileClient.queryRepositories( messages, repositories, sessionId, false, genius, timeout ); return { content: [ { type: 'text', text: JSON.stringify({ ...result, session_id: sessionId }, null, 2), }, ], }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text', text: createErrorResponse(`Failed to query repository: ${errorMessage}`), }, ], }; } } ); // Register get_repository_info tool server.registerTool( 'get_repository_info', { title: 'Get Repository Info', description: 'Get information about an indexed repository including status and metadata', inputSchema: { remote: z.enum(['github', 'gitlab']).describe('Repository host'), repository: z.string().describe('Repository in owner/repo format'), branch: z.string().describe('Branch that was indexed'), }, }, async ({ remote, repository, branch }) => { try { const result = await greptileClient.getRepositoryInfo(remote, repository, branch); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text', text: createErrorResponse(`Failed to get repository info: ${errorMessage}`), }, ], }; } } ); // Register resources server.registerResource( 'greptile-help', 'greptile://help', { title: 'Greptile MCP Help', description: 'Comprehensive documentation for all Greptile MCP features', mimeType: 'text/markdown', }, async uri => { const helpContent = `# Greptile MCP Server Resources\n\nThis resource provides comprehensive documentation for all Greptile MCP features.`; return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text: helpContent }], }; } ); server.registerResource( 'greptile-config', 'greptile://config', { title: 'Current Configuration', description: 'Current server configuration and settings', mimeType: 'application/json', }, async uri => { return { contents: [ { uri: uri.href, mimeType: 'application/json', text: JSON.stringify(config, null, 2), }, ], }; } ); // Register prompts server.registerPrompt( 'codebase_exploration', { title: 'Codebase Exploration', description: 'Start exploring a codebase with guided questions', argsSchema: { repository: z.string().describe('Repository to explore (owner/repo)'), focus_area: z .string() .optional() .describe('Specific area to focus on (architecture, authentication, etc.)'), }, }, ({ repository, focus_area }) => { const basePrompt = `Let's explore the ${repository} codebase systematically.`; let promptText = basePrompt; if (focus_area) { promptText += ` I'm particularly interested in understanding the ${focus_area} aspects. Please start by indexing the repository, then provide an overview of how ${focus_area} is implemented.`; } else { promptText += ` Please start by indexing the repository, then provide a comprehensive overview of the codebase architecture.`; } return { description: 'Guided codebase exploration prompt', messages: [ { role: 'user' as const, content: { type: 'text', text: promptText, }, }, ], }; } ); return server.server; } // Also export the legacy exports for backward compatibility export { GreptileMCPServer } from './server.js'; export { GreptileClient } from './clients/greptile.js'; export * from './types/index.js'; export * from './utils/index.js';

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sosacrazy126/greptile-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server