Skip to main content
Glama
webhook.ts1.9 kB
import { Request, Response, NextFunction } from 'express'; import crypto from 'crypto'; import { SSEManager } from '../services/sse-manager'; import { LinearService } from '../services/linear-service'; import { McpNotification } from '../types/mcp'; import { ApiError } from '../middleware/error-handler'; import { metrics } from '../utils/metrics'; import { logger } from '../utils/logger'; export function createWebhookHandler(sseManager: SSEManager, _linearService: LinearService) { return async (req: Request, res: Response, next: NextFunction) => { try { const signature = req.headers['linear-signature'] as string; const webhookSecret = process.env.WEBHOOK_SECRET; if (webhookSecret && signature) { const payload = JSON.stringify(req.body); const expectedSignature = crypto .createHmac('sha256', webhookSecret) .update(payload) .digest('hex'); if (signature !== expectedSignature) { throw new ApiError(401, 'Invalid webhook signature'); } } const { action, type, data, updatedFrom } = req.body; logger.info({ action, type, dataId: data?.id }, 'Webhook received'); const notification: McpNotification = { type: 'mcp.notification', method: 'linear.webhook', params: { entityType: type.toLowerCase() as any, entityId: data?.id || 'unknown', action: action.toLowerCase() as any, data: { ...data, updatedFrom, }, timestamp: new Date().toISOString(), }, }; sseManager.broadcast(notification); metrics.webhookEvents.inc({ entity_type: notification.params.entityType, action: notification.params.action }); res.status(200).json({ received: true }); } catch (error) { next(error); } }; }

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

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