Skip to main content
Glama

mcptix

by ownlytics
index.ts5.96 kB
/** * McpTix - A reusable ticket tracking system with MCP and API server capabilities * Main entry point for the package */ import { ApiServer } from './api/server'; import { McpTixConfig, mergeConfig, validateConfig } from './config'; import { TicketQueries } from './db/queries'; import { clearDatabase } from './db/schema'; import { DatabaseService } from './db/service'; import { McpTixServer } from './mcp/server'; import { Logger } from './utils/logger'; // Export all types and configuration for users export * from './types'; export * from './config'; /** * Main class for McpTix * Provides a unified interface for managing the McpTix system */ export class McpTix { private static isShuttingDown = false; private config: McpTixConfig; private dbService: DatabaseService; private db: any; private ticketQueries: TicketQueries; private apiServer?: ApiServer; private mcpServer?: McpTixServer; /** * Create a new McpTix instance * @param userConfig Configuration options */ constructor(userConfig: Partial<McpTixConfig> = {}) { // Merge and validate configuration this.config = mergeConfig(userConfig); validateConfig(this.config); // Initialize database using the singleton service this.dbService = DatabaseService.getInstance(); this.db = this.dbService.initialize(this.config, this.config.clearDataOnInit); Logger.info('McpTix', `Database initialized at absolute path: ${this.db.name}`); this.ticketQueries = new TicketQueries(this.db); // Set up cleanup on process exit process.on('SIGINT', this.shutdown.bind(this)); process.on('SIGTERM', this.shutdown.bind(this)); } /** * Start the McpTix servers * @returns A promise that resolves to the McpTix instance */ async start(): Promise<McpTix> { try { // Start API server if enabled if (this.config.apiEnabled) { this.apiServer = new ApiServer(this.ticketQueries); await this.apiServer.start(this.config.apiPort, this.config.apiHost); } // Start MCP server if enabled if (this.config.mcpEnabled) { this.mcpServer = new McpTixServer(this.ticketQueries, this.config); await this.mcpServer.run(); } return this; } catch (error) { // Clean up on error await this.shutdown(); throw error; } } /** * Gracefully shut down McpTix * @returns A promise that resolves when shutdown is complete */ async shutdown(): Promise<void> { // Prevent duplicate shutdown messages if (McpTix.isShuttingDown) { return Promise.resolve(); } McpTix.isShuttingDown = true; Logger.info('McpTix', 'Gracefully shutting down...'); try { // Stop MCP server if running if (this.mcpServer) { await this.mcpServer.close(); this.mcpServer = undefined; } // Stop API server if running if (this.apiServer) { await this.apiServer.stop(); this.apiServer = undefined; } // Close database connection if (this.db) { this.dbService.close(); this.db = null; } Logger.success('McpTix', 'Shut down successfully'); } catch (error) { Logger.error('McpTix', 'Error during shutdown', error); throw error; } } /** * Clear all data from the database * @returns A promise that resolves when the data is cleared */ async clearData(): Promise<void> { try { if (this.db) { clearDatabase(this.db); } return Promise.resolve(); } catch (error) { return Promise.reject(error); } } /** * Get the ticket queries instance for programmatic access * @returns The TicketQueries instance */ getTicketQueries(): TicketQueries { return this.ticketQueries; } } /** * Factory function for creating a McpTix instance * @param config Configuration options * @returns A new McpTix instance */ export function createMcpTix(config?: Partial<McpTixConfig>): McpTix { return new McpTix(config); } // If this file is run directly, start the servers based on command line arguments const isDirectlyExecuted = process.argv.length > 1 && process.argv[1] === __filename; if (isDirectlyExecuted) { const args = process.argv.slice(2); const runApi = args.includes('--api'); const runMcp = args.includes('--mcp'); // Check for development mode and database path const isDevMode = process.env.MCPTIX_DEV_MODE === 'true'; // Parse command line arguments let dbPath: string | undefined; let apiPort: number | undefined; let apiHost: string | undefined; for (const arg of args) { if (arg.startsWith('--db-path=')) { dbPath = arg.split('=')[1]; } else if (arg.startsWith('--port=')) { apiPort = parseInt(arg.split('=')[1], 10); } else if (arg.startsWith('--host=')) { apiHost = arg.split('=')[1]; } } // Default to API only if no specific flags are provided const config: Partial<McpTixConfig> = { apiEnabled: runApi || !runMcp, // Enable API if --api flag is present or --mcp is not present mcpEnabled: runMcp, // Enable MCP only if --mcp flag is present }; // Apply command line configuration if (dbPath) { config.dbPath = dbPath; } if (apiPort) { config.apiPort = apiPort; } if (apiHost) { config.apiHost = apiHost; } // If in development mode, set log level to debug if (isDevMode) { config.logLevel = 'debug'; } Logger.info( 'McpTix', `Starting with configuration: - API server: ${config.apiEnabled ? 'enabled' : 'disabled'} - MCP server: ${config.mcpEnabled ? 'enabled' : 'disabled'} - Database: ${config.dbPath || 'default'} - API port: ${config.apiPort || 'default'} - API host: ${config.apiHost || 'default'}`, ); const mcpTix = createMcpTix(config); mcpTix.start().catch(error => { Logger.error('McpTix', 'Failed to start', error); process.exit(1); }); }

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/ownlytics/mcptix'

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