Skip to main content
Glama
jira-client.ts•6.74 kB
import axios, { AxiosInstance } from "axios"; export interface JiraConfig { host: string; email: string; apiToken: string; } export interface JiraIssue { key: string; fields: { summary: string; description?: any; status: { name: string; }; assignee?: { displayName: string; emailAddress: string; }; reporter?: { displayName: string; emailAddress: string; }; priority?: { name: string; }; issuetype: { name: string; }; project: { key: string; name: string; }; created: string; updated: string; [key: string]: any; }; } export interface JiraProject { id: string; key: string; name: string; projectTypeKey: string; style?: string; } export interface JiraTransition { id: string; name: string; to: { name: string; id: string; }; } export interface JiraBoard { id: number; name: string; type: string; location?: { projectKey: string; projectName: string; }; } export class JiraClient { private client: AxiosInstance; private config: JiraConfig; constructor(config: JiraConfig) { this.config = config; // Remove any trailing slashes from host const host = config.host.replace(/\/+$/, ""); // Check if host already includes protocol const baseURL = host.startsWith("http://") || host.startsWith("https://") ? `${host}/rest/api/3` : `https://${host}/rest/api/3`; this.client = axios.create({ baseURL, auth: { username: config.email, password: config.apiToken, }, headers: { Accept: "application/json", "Content-Type": "application/json", }, }); } async searchIssues( jql: string, maxResults: number = 50, startAt: number = 0 ): Promise<{ issues: JiraIssue[]; total: number }> { const response = await this.client.post("/search", { jql, maxResults, startAt, fields: [ "summary", "status", "assignee", "reporter", "priority", "issuetype", "project", "created", "updated", "description", ], }); return { issues: response.data.issues, total: response.data.total, }; } async getIssue(issueKey: string): Promise<JiraIssue> { const response = await this.client.get(`/issue/${issueKey}`); return response.data; } async createIssue( projectKey: string, summary: string, issueType: string, description?: string, additionalFields?: any ): Promise<JiraIssue> { const issueData: any = { fields: { project: { key: projectKey }, summary, issuetype: { name: issueType }, ...additionalFields, }, }; if (description) { issueData.fields.description = { type: "doc", version: 1, content: [ { type: "paragraph", content: [ { type: "text", text: description, }, ], }, ], }; } const response = await this.client.post("/issue", issueData); return await this.getIssue(response.data.key); } async updateIssue(issueKey: string, fields: any): Promise<void> { await this.client.put(`/issue/${issueKey}`, { fields, }); } async addComment(issueKey: string, comment: string): Promise<any> { const response = await this.client.post(`/issue/${issueKey}/comment`, { body: { type: "doc", version: 1, content: [ { type: "paragraph", content: [ { type: "text", text: comment, }, ], }, ], }, }); return response.data; } async getTransitions(issueKey: string): Promise<JiraTransition[]> { const response = await this.client.get(`/issue/${issueKey}/transitions`); return response.data.transitions; } async transitionIssue(issueKey: string, transitionId: string): Promise<void> { await this.client.post(`/issue/${issueKey}/transitions`, { transition: { id: transitionId, }, }); } async assignIssue(issueKey: string, accountId: string | null): Promise<void> { await this.client.put(`/issue/${issueKey}/assignee`, { accountId, }); } async getProjects(): Promise<JiraProject[]> { const response = await this.client.get("/project"); return response.data; } async getUsers(query: string): Promise<any[]> { const response = await this.client.get("/user/search", { params: { query }, }); return response.data; } async getIssueComments(issueKey: string): Promise<any[]> { const response = await this.client.get(`/issue/${issueKey}/comment`); return response.data.comments; } async getBoards( startAt: number = 0, maxResults: number = 50 ): Promise<{ boards: JiraBoard[]; total: number }> { // Use the agile API endpoint for boards const host = this.config.host.replace(/\/+$/, ""); const agileBaseURL = host.startsWith("http://") || host.startsWith("https://") ? `${host}/rest/agile/1.0` : `https://${host}/rest/agile/1.0`; const response = await axios.get(`${agileBaseURL}/board`, { params: { startAt, maxResults }, auth: { username: this.config.email, password: this.config.apiToken, }, headers: { Accept: "application/json", "Content-Type": "application/json", }, }); return { boards: response.data.values || [], total: response.data.total || 0, }; } async getBoardIssues( boardId: number, startAt: number = 0, maxResults: number = 50, jql?: string ): Promise<{ issues: JiraIssue[]; total: number }> { // Use the agile API endpoint for board issues const host = this.config.host.replace(/\/+$/, ""); const agileBaseURL = host.startsWith("http://") || host.startsWith("https://") ? `${host}/rest/agile/1.0` : `https://${host}/rest/agile/1.0`; const params: any = { startAt, maxResults }; if (jql) { params.jql = jql; } const response = await axios.get(`${agileBaseURL}/board/${boardId}/issue`, { params, auth: { username: this.config.email, password: this.config.apiToken, }, headers: { Accept: "application/json", "Content-Type": "application/json", }, }); return { issues: response.data.issues || [], total: response.data.total || 0, }; } }

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/garimiddisuman/jira-mcp'

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