JIRA MCP Server
A production-ready Model Context Protocol (MCP) server for JIRA integration. This server enables AI assistants to query JIRA issues and perform searches using natural language.
🎯 What This Demonstrates
MCP Concepts
- Tool Registration: Using
@mcp.tooldecorator - Async Operations: Asynchronous tool functions
- Tool Documentation: Proper descriptions and type hints
- Server Lifecycle: Managing MCP sessions with FastAPI
- HTTP Streaming: Stateless HTTP-based MCP communication
Integration Patterns
- API Wrapper Design: Clean separation between MCP layer and API layer
- Error Handling: Robust error handling for API failures
- Configuration: Environment-based configuration
- Formatting: LLM-friendly Markdown output
- Authentication: Bearer token authentication
🚀 Quick Start
Prerequisites
- Python 3.11 or higher
- JIRA instance (Atlassian Cloud or self-hosted)
- JIRA API token with appropriate permissions
Installation
-
Navigate to this directory:
cd 20_mcp/04-implementations/02-jira-server -
Install dependencies:
# Using uv (recommended) uv venv uv sync # Or using pip python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate pip install -r requirements.txt -
Configure environment:
cp .env.example .env nano .env
Configuration
Create a .env file with your JIRA details:
# JIRA Configuration
JIRA_API_TOKEN=your_api_token_here
JIRA_BASE_URL=https://your-company.atlassian.net
# Optional: Custom SSL Certificate Path
# JIRA_CERT_PATH=/path/to/ca-bundle.crt
# Optional: Server Port
PORT=8000
Getting Your JIRA API Token
For Atlassian Cloud:
- Log in to https://id.atlassian.com
- Go to Security → API tokens
- Click Create API token
- Copy the token and add to
.env
For Self-Hosted JIRA:
- Log in to your JIRA instance
- Go to Profile → Personal Access Tokens
- Create a new token with appropriate scopes
- Copy the token and add to
.env
Running the Server
# Method 1: Using Python
python server.py
# Method 2: Using uvicorn directly
uvicorn server:app --host 0.0.0.0 --port 8000
# Method 3: Using uv
uv run server.py
Server will be available at:
- MCP Endpoint: http://localhost:8000/jira
- API Docs: http://localhost:8000/docs
📖 Usage
Available Tools
1. Get JIRA Issue
Fetch detailed information about a specific JIRA issue.
Example:
# Single issue
get_jira_issue("PROJECT-123")
# Multiple issues (comma-separated)
get_jira_issue("PROJECT-123,PROJECT-456")
Returns:
### Issue PROJECT-123: Fix login bug
**Status:** Open
#### Description:
Users cannot log in after password reset. Error occurs on login page...
2. Search JIRA Issues
Search for issues using JQL (JIRA Query Language).
Example JQL Queries:
# Open issues in a project
project = MYPROJECT AND status = Open
# High priority bugs assigned to you
assignee = currentUser() AND priority = High AND type = Bug
# Recently created issues
created >= -7d
# Search by text
summary ~ "performance" OR description ~ "performance"
# Complex query
project = MYPROJECT AND status IN (Open, "In Progress") AND assignee = currentUser() ORDER BY priority DESC
Example:
search_jira_issue("project = MYPROJECT AND status = Open")
Returns:
### Issue PROJECT-123: Fix login bug
**Status:** Open
#### Description:
Users cannot log in...
### Issue PROJECT-456: Update API documentation
**Status:** Open
#### Description:
API docs need updating...
🔌 Integration with AI Assistants
VS Code with GitHub Copilot
Add to your VS Code settings.json:
{
"mcp.servers": {
"jira": {
"command": "python",
"args": ["/path/to/20_mcp/04-implementations/02-jira-server/server.py"],
"env": {
"JIRA_API_TOKEN": "${env:JIRA_API_TOKEN}",
"JIRA_BASE_URL": "https://your-company.atlassian.net"
}
}
}
}
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"jira": {
"command": "python",
"args": ["/path/to/20_mcp/04-implementations/02-jira-server/server.py"],
"env": {
"JIRA_API_TOKEN": "your_token_here",
"JIRA_BASE_URL": "https://your-company.atlassian.net"
}
}
}
}
Using with MCP Client
from mcp.client import Client
async with Client("http://localhost:8000/jira") as client:
# Get issue details
result = await client.call_tool("get_jira_issue", {"issue_key": "PROJECT-123"})
print(result)
# Search issues
result = await client.call_tool(
"search_jira_issue",
{"query": "project = MYPROJECT AND status = Open"}
)
print(result)
🐳 Docker Deployment
FROM python:3.11-slim
WORKDIR /app
COPY pyproject.toml ./
RUN pip install uv && uv sync
COPY . .
CMD ["python", "server.py"]
Build and run:
docker build -t jira-mcp .
docker run -p 8000:8000 --env-file .env jira-mcp
🔒 Security Considerations
Authentication
- ✅ Uses Bearer token authentication (secure)
- ✅ Tokens stored in environment variables (not in code)
- ✅ Supports custom SSL certificates for enterprise
- ⚠️ Ensure
.envis in.gitignore
Best Practices
- Use read-only JIRA tokens when possible
- Implement rate limiting for production
- Add request validation and sanitization
- Use HTTPS in production
- Implement proper logging (avoid logging tokens)
📚 JQL Reference
Common Operators
=: Equals!=: Not equals~: Contains text>,<,>=,<=: ComparisonIN: Match any of a listAND,OR: Logical operators
Common Fields
project: Project keystatus: Issue statusassignee: Assigned userpriority: Issue prioritytype: Issue type (Bug, Story, etc.)created,updated: Datessummary,description: Text fields
Special Functions
currentUser(): Current logged-in user-7d: Relative dates (7 days ago)ORDER BY: Sort results
Full JQL Documentation:
🧪 Testing
# Run tests
pytest
# With coverage
pytest --cov=. --cov-report=html
# Test individual tool
python -c "
from jiraAPI import JIRA
print(JIRA.get_jira_issue('PROJECT-123'))
"
🔧 Customization
Adding More Tools
@mcp.tool(description="Create a new JIRA issue")
async def create_jira_issue(
project: str,
summary: str,
description: str,
issue_type: str = "Task"
) -> str:
"""Create a new JIRA issue"""
# Implementation here
pass
Adding Resources
@mcp.resource("jira://projects")
async def list_projects() -> str:
"""List all available JIRA projects"""
# Implementation here
pass
Adding Prompts
@mcp.prompt()
async def analyze_sprint() -> str:
"""Generate a sprint analysis prompt"""
return "Analyze the current sprint and provide insights..."
📊 Architecture
┌─────────────────┐
│ AI Assistant │ (Claude, GPT, Copilot)
└────────┬────────┘
│ MCP Protocol
┌────────▼────────┐
│ FastAPI Server │ (server.py)
└────────┬────────┘
│
┌────────▼────────┐
│ jiraMCP.py │ (MCP Tools)
└────────┬────────┘
│
┌────────▼────────┐
│ jiraAPI.py │ (JIRA API Wrapper)
└────────┬────────┘
│ HTTPS
┌────────▼────────┐
│ JIRA Server │ (Atlassian Cloud / Self-Hosted)
└─────────────────┘
🐛 Troubleshooting
"Authentication failed"
- Verify JIRA_API_TOKEN is correct
- Check token hasn't expired
- Ensure token has appropriate permissions
"SSL Certificate verify failed"
- For self-hosted JIRA with custom certs, set JIRA_CERT_PATH
- For Atlassian Cloud, ensure JIRA_CERT_PATH is not set or set to
None
"Issue not found"
- Verify issue key format (e.g., "PROJECT-123")
- Check you have permission to view the issue
- Ensure project key is correct
"JQL query failed"
- Validate JQL syntax at: https://your-jira-instance/secure/IssueNavigator.jspa
- Check field names are correct
- Ensure you have permission for the queried projects
📝 License
MIT License - Feel free to use in your projects
🤝 Contributing
This is an educational example. Feel free to:
- Extend with more JIRA operations
- Add better error handling
- Implement caching
- Add rate limiting
- Improve documentation
📚 Related Documentation
- MCP Protocol Documentation
- JIRA REST API Reference
- JQL Documentation
- FastAPI Documentation
- FastMCP Documentation
Part of the MCP Learning Guide: Main Repository