Motivation
I'm a huge fan of Cursor IDE and use it daily for all my development work. As someone who spends a lot of time in both Cursor and Jira, I wanted to build deeper integration between the two tools. Building an MCP server seemed like the perfect way to accomplish this while also getting more practice with the MCP protocol. This project lets me leverage Cursor's AI capabilities to interact with Jira data directly from my editor.
Implementation
Let's walk through building a production-ready MCP server for Jira integration step by step.
Project Structure
First, create a new project with this structure:
mcp-server/
├── package.json
├── tsconfig.json
├── src/
│ ├── main.ts
│ ├── server.ts
│ ├── types.ts
│ └── config.ts
Install Dependencies
Add the required dependencies to package.json:
{
"name": "jira-mcp-server",
"version": "1.0.0",
"dependencies": {
"@cursor/mcp-server": "^1.0.0",
"axios": "^1.6.2",
"zod": "^3.22.4",
"dotenv": "^16.3.1"
},
"devDependencies": {
"typescript": "^5.3.3",
"@types/node": "^20.10.4"
}
}
Environment Configuration
Create a config.ts file to handle environment variables:
import { z } from 'zod';
import dotenv from 'dotenv';
dotenv.config();
const envSchema = z.object({
JIRA_HOST: z.string(),
JIRA_EMAIL: z.string().email(),
JIRA_API_TOKEN: z.string()
});
export const config = envSchema.parse(process.env);
Create Jira Client
In server.ts, set up an axios client with authentication:
import axios from 'axios';
import { config } from './config';
const jiraClient = axios.create({
baseURL: `https://${config.JIRA_HOST}/rest/api/3`,
auth: {
username: config.JIRA_EMAIL,
password: config.JIRA_API_TOKEN
},
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
Initialize MCP Server
Create the MCP server instance:
import { McpServer } from '@cursor/mcp-server';
const server = new McpServer();
server.setInfo({
name: 'jira-mcp',
version: '1.0.0',
description: 'Jira integration for Cursor IDE'
});
Add Tool Example
Let's implement a tool to search for issues:
const searchIssuesSchema = z.object({
jql: z.string(),
maxResults: z.number().optional().default(10)
});
server.tool({
name: 'searchIssues',
description: 'Search for Jira issues using JQL',
parameters: searchIssuesSchema,
handler: async ({ jql, maxResults }) => {
const response = await jiraClient.get('/search', {
params: { jql, maxResults }
});
return response.data.issues.map(issue => ({
key: issue.key,
summary: issue.fields.summary,
status: issue.fields.status.name
}));
}
});
Create Entry Point
In main.ts, add the server startup code:
import { server } from './server';
async function main() {
await server.listen(3000);
console.log('Jira MCP server running on port 3000');
}
main().catch(console.error);
Usage
Here's how to set up and use the Jira MCP server with Cursor IDE.
Global Installation
Install the package globally:
npm install -g jira-mcp-server
Configure Cursor Integration
Add this entry to your ~/.cursor/mcp.json:
{
"servers": {
"jira": {
"command": "jira-mcp-server",
"env": {
"JIRA_HOST": "your-domain.atlassian.net",
"JIRA_EMAIL": "your-email@company.com",
"JIRA_API_TOKEN": "your-api-token"
}
}
}
}
Example Prompts
Here are some example prompts and their responses:
- Search for high-priority bugs:
> Find all high priority bugs assigned to me in Jira
Using searchIssues tool to query Jira...
Found 3 matching issues:
- PROJ-123: Authentication fails on mobile devices
- PROJ-456: Database connection timeout
- PROJ-789: Memory leak in processing service
- Create a new issue:
> Create a Jira bug for the login page crash
Using createIssue tool...
Created issue PROJ-234: "Login page crashes on form submission"
Status: Open
Priority: High
- Update issue status:
> Move PROJ-123 to In Progress
Using transitionIssue tool...
Updated PROJ-123 status from "Open" to "In Progress"
Notified watchers of the change
How It Works
Here's the flow of how the Jira MCP server integrates with Cursor:
Rendering diagram...