UNPKG

jira-server-mcp

Version:

MCP (Model Context Protocol) para integração com Jira Server auto-hospedado. Uso principal via configuração MCP (mcp.json) para automações e integrações.

243 lines (219 loc) 5.75 kB
#!/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 fetch from 'node-fetch'; // Configuração do servidor const server = new Server( { name: 'jira-server-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Função para carregar a configuração function loadConfig() { try { // Se as variáveis de ambiente foram fornecidas if (process.env.JIRA_BASE_URL && process.env.JIRA_API_TOKEN) { return { baseUrl: process.env.JIRA_BASE_URL, token: process.env.JIRA_API_TOKEN }; } throw new Error('Configuração não encontrada. Defina JIRA_BASE_URL e JIRA_API_TOKEN'); } catch (error) { console.error('Erro ao carregar configuração:', error); throw error; } } // Configuração do Jira const config = loadConfig(); // Classe para interagir com a API do Jira class JiraAPI { constructor(baseUrl, token) { this.baseUrl = baseUrl; this.token = token; } async request(endpoint, options = {}) { const url = `${this.baseUrl}${endpoint}`; const headers = { 'Authorization': `Bearer ${this.token}`, 'Accept': 'application/json', 'Content-Type': 'application/json', ...options.headers }; try { const response = await fetch(url, { ...options, headers }); if (!response.ok) { const error = await response.text(); throw new Error(`Jira API error: ${response.status} - ${error}`); } return await response.json(); } catch (error) { console.error('Erro na requisição:', error); throw error; } } async getIssue(issueKey) { return this.request(`/rest/api/2/issue/${issueKey}`); } async searchIssues(jql) { return this.request('/rest/api/2/search', { method: 'POST', body: JSON.stringify({ jql, maxResults: 50 }) }); } async getIssueTransitions(issueKey) { return this.request(`/rest/api/2/issue/${issueKey}/transitions`); } async getMyself() { return this.request('/rest/api/2/myself'); } } // Inicializar API do Jira const jiraAPI = new JiraAPI(config.baseUrl, config.token); // Handler para listar ferramentas server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'get_issue', description: 'Buscar uma issue do Jira por chave', inputSchema: { type: 'object', properties: { issueKey: { type: 'string', description: 'Chave da issue (ex: CLI-123)', }, }, required: ['issueKey'], }, }, { name: 'search_issues', description: 'Buscar issues usando JQL (Jira Query Language)', inputSchema: { type: 'object', properties: { jql: { type: 'string', description: 'Query JQL para buscar issues', }, }, required: ['jql'], }, }, { name: 'get_transitions', description: 'Buscar transições disponíveis para uma issue', inputSchema: { type: 'object', properties: { issueKey: { type: 'string', description: 'Chave da issue (ex: CLI-123)', }, }, required: ['issueKey'], }, }, { name: 'test_connection', description: 'Testar a conexão com o Jira', inputSchema: { type: 'object', properties: {}, }, }, ], }; }); // Handler para executar ferramentas server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'get_issue': { const issue = await jiraAPI.getIssue(args.issueKey); return { content: [ { type: 'text', text: JSON.stringify(issue, null, 2), }, ], }; } case 'search_issues': { const results = await jiraAPI.searchIssues(args.jql); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } case 'get_transitions': { const transitions = await jiraAPI.getIssueTransitions(args.issueKey); return { content: [ { type: 'text', text: JSON.stringify(transitions, null, 2), }, ], }; } case 'test_connection': { const user = await jiraAPI.getMyself(); return { content: [ { type: 'text', text: `Conexão estabelecida com sucesso!\nUsuário: ${user.displayName} (${user.emailAddress})`, }, ], }; } default: throw new Error(`Ferramenta desconhecida: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Erro: ${error.message}`, }, ], isError: true, }; } }); // Conectar via stdio async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('Jira MCP Server iniciado via stdio'); } main().catch((error) => { console.error('Erro ao iniciar o servidor:', error); process.exit(1); });