Skip to main content
Glama
smithery.ts11.9 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { TestRailMCPTools } from './tools/testrail-tools'; import { TestRailMCPTool } from './types'; import { z } from 'zod'; /** * Configuration schema for TestRail MCP Server * This is used by Smithery to generate configuration forms for users */ export const configSchema = z.object({ baseUrl: z.string().describe('TestRail instance URL (e.g., https://yourcompany.testrail.io)'), username: z.string().describe('TestRail username (email address)'), apiKey: z.string().describe('TestRail API key'), defaultProjectId: z.number().default(1).describe('Default project ID'), defaultSuiteId: z.number().default(1).describe('Default suite ID'), rateLimitRequestsPerMinute: z.number().default(60).describe('Rate limit requests per minute'), cacheTtl: z.number().default(300).describe('Cache TTL in seconds'), timeout: z.number().default(30000).describe('Request timeout in milliseconds'), }); /** * Create TestRail MCP Server instance * Required by Smithery TypeScript deployment */ export default function createServer({ config }: { config: z.infer<typeof configSchema> }) { const server = new Server( { name: 'testrail-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); const tools = new TestRailMCPTools(); // Initialize with user configuration if (config) { // Set environment variables from config for the tools to use process.env.TESTRAIL_BASE_URL = config.baseUrl; process.env.TESTRAIL_USERNAME = config.username; process.env.TESTRAIL_API_KEY = config.apiKey; process.env.DEFAULT_PROJECT_ID = config.defaultProjectId?.toString(); process.env.DEFAULT_SUITE_ID = config.defaultSuiteId?.toString(); process.env.RATE_LIMIT_REQUESTS_PER_MINUTE = config.rateLimitRequestsPerMinute?.toString(); process.env.CACHE_TTL = config.cacheTtl?.toString(); } // Define all available TestRail MCP tools const getToolDefinitions = (): TestRailMCPTool[] => { return [ // Connection & Authentication Tools { name: 'connect_testrail', description: 'Connect to TestRail instance with credentials', inputSchema: { type: 'object', properties: { baseUrl: { type: 'string', description: 'TestRail instance URL (e.g., https://yourcompany.testrail.io)', }, username: { type: 'string', description: 'TestRail username (email address)', }, apiKey: { type: 'string', description: 'TestRail API key', }, timeout: { type: 'number', description: 'Request timeout in milliseconds (default: 30000)', }, }, required: ['baseUrl', 'username', 'apiKey'], }, }, { name: 'test_connection', description: 'Test TestRail connection and validate credentials', inputSchema: { type: 'object', properties: {}, }, }, // Project Management Tools { name: 'get_projects', description: 'Get all TestRail projects', inputSchema: { type: 'object', properties: { isCompleted: { type: 'boolean', description: 'Filter by completion status', }, }, }, }, { name: 'get_project', description: 'Get specific TestRail project by ID', inputSchema: { type: 'object', properties: { projectId: { type: 'number', description: 'Project ID', }, }, required: ['projectId'], }, }, { name: 'create_project', description: 'Create new TestRail project', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Project name', }, announcement: { type: 'string', description: 'Project announcement', }, showAnnouncement: { type: 'boolean', description: 'Show announcement to users', }, suiteMode: { type: 'number', description: 'Suite mode (1=single, 2=single+baselines, 3=multiple)', }, }, required: ['name'], }, }, // Test Case Management Tools { name: 'get_cases', description: 'Get test cases for a project/suite', inputSchema: { type: 'object', properties: { projectId: { type: 'number', description: 'Project ID', }, suiteId: { type: 'number', description: 'Suite ID', }, sectionId: { type: 'number', description: 'Section ID (optional)', }, }, required: ['projectId'], }, }, { name: 'create_case', description: 'Create new test case', inputSchema: { type: 'object', properties: { sectionId: { type: 'number', description: 'Section ID', }, title: { type: 'string', description: 'Test case title', }, typeId: { type: 'number', description: 'Test case type ID', }, priorityId: { type: 'number', description: 'Priority ID', }, estimate: { type: 'string', description: 'Time estimate', }, milestone_id: { type: 'number', description: 'Milestone ID', }, refs: { type: 'string', description: 'References (requirements)', }, }, required: ['sectionId', 'title'], }, }, // Test Run Management Tools { name: 'get_runs', description: 'Get test runs for a project', inputSchema: { type: 'object', properties: { projectId: { type: 'number', description: 'Project ID', }, createdAfter: { type: 'number', description: 'Created after timestamp', }, createdBefore: { type: 'number', description: 'Created before timestamp', }, createdBy: { type: 'array', items: { type: 'number' }, description: 'Created by user IDs', }, isCompleted: { type: 'boolean', description: 'Filter by completion status', }, limit: { type: 'number', description: 'Limit results', }, offset: { type: 'number', description: 'Offset for pagination', }, }, required: ['projectId'], }, }, { name: 'create_run', description: 'Create new test run', inputSchema: { type: 'object', properties: { projectId: { type: 'number', description: 'Project ID', }, name: { type: 'string', description: 'Test run name', }, description: { type: 'string', description: 'Test run description', }, suiteId: { type: 'number', description: 'Suite ID', }, milestoneId: { type: 'number', description: 'Milestone ID', }, assignedtoId: { type: 'number', description: 'Assigned user ID', }, caseIds: { type: 'array', items: { type: 'number' }, description: 'Test case IDs to include', }, }, required: ['projectId', 'name'], }, }, // Reporting Tools { name: 'generate_project_dashboard', description: 'Generate comprehensive project dashboard with metrics and analytics', inputSchema: { type: 'object', properties: { projectId: { type: 'number', description: 'Project ID', }, timeframe: { type: 'string', enum: ['7d', '30d', '90d', 'all'], description: 'Time frame for analytics', }, includeCharts: { type: 'boolean', description: 'Include chart data', }, }, required: ['projectId'], }, }, ]; }; // Setup tool handlers server.setRequestHandler(ListToolsRequestSchema, async () => { const toolDefinitions = getToolDefinitions(); return { tools: toolDefinitions.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const toolDefinitions = getToolDefinitions(); const tool = toolDefinitions.find((t) => t.name === name); if (!tool) { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } // Route to appropriate tool method let result; switch (name) { // Connection & Authentication case 'connect_testrail': result = await tools.connectTestRail(args as any); break; case 'test_connection': result = await tools.testConnection(); break; // Project Management case 'get_projects': result = await tools.getProjects(args as any); break; case 'get_project': result = await tools.getProject(args as any); break; case 'create_project': result = await tools.createProject(args as any); break; // Test Case Management case 'get_cases': result = await tools.getCases(args as any); break; case 'create_case': result = await tools.createCase(args as any); break; // Test Run Management case 'get_runs': result = await tools.getRuns(args as any); break; case 'create_run': result = await tools.createRun(args as any); break; // Reporting case 'generate_project_dashboard': result = await tools.generateProjectDashboard(args as any); break; default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } // Return the result from the tool method return result; } catch (error) { console.error(`Error executing tool ${name}:`, error); if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}` ); } }); // Return the server instance as required by Smithery return server; }

Latest Blog Posts

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/samuelvinay91/testrail-mcp'

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