jira-mcp

  • dist
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import fetch from 'node-fetch'; const SNYK_API_KEY = process.env.SNYK_API_KEY; if (!SNYK_API_KEY) { console.error("SNYK_API_KEY environment variable is not set"); process.exit(1); } // Schema definitions const ScanRepoSchema = z.object({ url: z.string().url().describe('Repository URL to scan'), branch: z.string().optional().describe('Branch to scan (optional)') }); const ScanProjectSchema = z.object({ projectId: z.string().describe('Snyk project ID to scan') }); const server = new Server({ name: 'snyk-mcp-server', version: '1.0.0' }, { capabilities: { tools: {} } }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "scan_repository", description: "Scan a repository for security vulnerabilities using Snyk", inputSchema: zodToJsonSchema(ScanRepoSchema) }, { name: "scan_project", description: "Scan an existing Snyk project", inputSchema: zodToJsonSchema(ScanProjectSchema) } ] }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { if (!request.params.arguments) { throw new Error("Arguments are required"); } switch (request.params.name) { case "scan_repository": { const args = ScanRepoSchema.parse(request.params.arguments); const response = await fetch('https://snyk.io/api/v1/test', { method: 'POST', headers: { 'Authorization': `token ${SNYK_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ target: { remoteUrl: args.url + (args.branch ? `/tree/${args.branch}` : '') } }) }); if (!response.ok) { throw new Error(`Snyk API error: ${response.statusText}`); } const result = await response.json(); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } case "scan_project": { const args = ScanProjectSchema.parse(request.params.arguments); const response = await fetch(`https://snyk.io/api/v1/project/${args.projectId}/issues`, { headers: { 'Authorization': `token ${SNYK_API_KEY}`, 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`Snyk API error: ${response.statusText}`); } const result = await response.json(); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } default: throw new Error(`Unknown tool: ${request.params.name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Invalid arguments: ${error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`); } throw error; } }); const transport = new StdioServerTransport(); server.connect(transport).catch((error) => { console.error("Fatal error:", error); process.exit(1); }); console.error('Snyk MCP Server running on stdio');