Skip to main content
Glama
index.js6.84 kB
/** * Main entry point for the MCP Linear server using the official MCP SDK */ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import * as tools from './tools/mod.js'; import { getConfig } from './utils/config/mod.js'; import { createLogger, LogLevel } from './effects/logging/mod.js'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const logDir = path.resolve(__dirname, '../logs'); // Make sure log directory exists try { if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true }); } } catch (err) { // If we can't create logs directory, we'll fallback to noop logger } // Create a logger for stdio transport - logs to file instead of stdout/stderr const logFile = path.join(logDir, 'mcp-linear.log'); // Get log level from environment variable or use defaults const logLevelEnv = process.env.LOG_LEVEL?.toUpperCase(); let logLevel = LogLevel.INFO; // Default for production if (logLevelEnv) { // Allow setting log level through environment variable if (logLevelEnv === 'DEBUG') logLevel = LogLevel.DEBUG; if (logLevelEnv === 'INFO') logLevel = LogLevel.INFO; if (logLevelEnv === 'WARN') logLevel = LogLevel.WARN; if (logLevelEnv === 'ERROR') logLevel = LogLevel.ERROR; } else if (process.env.NODE_ENV === 'development') { // In development, default to DEBUG logLevel = LogLevel.DEBUG; } // Use stdio transport, so we need file logging const logger = createLogger({ useStdio: true, logFile, minLevel: logLevel, }); // Save the original console methods const originalConsole = { log: console.log, info: console.info, warn: console.warn, error: console.error, debug: console.debug, }; // Only output initial messages in development mode to avoid // polluting Claude desktop interface if (process.env.NODE_ENV === 'development') { originalConsole.log('Starting Linear MCP server...'); originalConsole.log('Redirecting logs to:', logFile); } // Override console methods to use our logger // This prevents logs from interfering with MCP protocol messages console.log = message => logger.info(message); console.info = message => logger.info(message); console.warn = message => logger.warn(message); console.error = message => logger.error(message); console.debug = message => logger.debug(message); /** * Initialize and run the MCP Linear server */ async function main() { logger.info('Initializing MCP Linear server'); // Define server info const serverInfo = { name: 'Linear', version: '0.1.0', description: 'Linear issue tracking integration', }; // Create MCP server using the SDK const server = new McpServer(serverInfo); try { // Load configuration const config = await getConfig(logger); // Import Linear effect const { createLinearClient } = await import('./effects/linear/index.js'); // Create context for tools const toolContext = { config, effects: { logger, linear: { createClient: apiKey => createLinearClient(apiKey), }, }, }; // Initialize tools with context const all_tools = [ new tools.ListIssues(toolContext), new tools.GetIssue(toolContext), new tools.ListMembers(toolContext), new tools.ListProjects(toolContext), new tools.GetProject(toolContext), new tools.ListTeams(toolContext), new tools.AddComment(toolContext), new tools.CreateIssue(toolContext), ]; // Register tools with the MCP server for (const tool of all_tools) { server.tool( tool.name, tool.description, tool.inputSchema.shape ?? {}, async args => { try { // Call our tool const result = await tool.call(args); // Return format expected by MCP SDK return { content: result.content, error: result.isError ? { message: result.content[0]?.text || 'An error occurred', } : undefined, }; } catch (error) { logger.error(`Error executing tool ${tool.name}: ${error.message}`); return { content: [{ type: 'text', text: `Error: ${error.message}` }], error: { message: error.message }, }; } } ); } // Log server information to the file logger.info('=== MCP Server Information ==='); logger.info(`Name: ${serverInfo.name}`); logger.info(`Version: ${serverInfo.version}`); logger.info('Tools available:'); // Log information about the available tools // Note: We're using all_tools directly instead of accessing private _registeredTools for (const tool of all_tools) { logger.info(` * ${tool.name}: ${tool.description}`); } // Only show verbose output in development mode if (process.env.NODE_ENV === 'development') { // Use original console to output visible information to terminal // before we start the transport originalConsole.log('\n=== MCP Server Information ==='); originalConsole.log('\nThe MCP server is running in stdio mode.'); originalConsole.log('To connect with the MCP Inspector, run:'); originalConsole.log('npx @modelcontextprotocol/inspector'); originalConsole.log( 'or visit: https://inspector.modelcontextprotocol.ai' ); originalConsole.log('\nServer info:'); originalConsole.log(`\n- Name: ${serverInfo.name}`); originalConsole.log(`- Version: ${serverInfo.version}`); originalConsole.log('- Tools available:'); // Log all registered tools for (const tool of all_tools) { originalConsole.log(` * ${tool.name}: ${tool.description}`); } originalConsole.log('\n==============================\n'); originalConsole.log( 'STDIO transport activated. All further logs redirected to:', logFile ); } // Create a stdio transport const transport = new StdioServerTransport(); // Connect the server to the transport logger.info('Starting STDIO transport'); await server.connect(transport); } catch (error) { logger.error(`Failed to start MCP server: ${error.message}`); // Use the original console to make sure the error is visible originalConsole.error('Failed to start MCP server:', error); process.exit(1); } } // Run the server main().catch(error => { logger.error(`Unhandled error: ${error.message}`); // Use the original console to make sure the error is visible originalConsole.error('Unhandled error:', error); process.exit(1); });

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/scoutos/mcp-linear'

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