Jira MCP (Model Context Protocol) server built with FastMCP for Jira Cloud API v3
Project description
Jira MCP Server
A comprehensive MCP (Model Context Protocol) server for Jira Cloud integration, built with FastMCP v3. Provides 8 focused tools for complete Jira issue and project management, with automatic ADF formatting, multi-tenant HTTP support, and interactive Elicitation for guided issue creation.
Version 3.1.0 — Single-server FastMCP v3 rewrite with multi-tenant support, Elicitation, resource templates, and 118 tests. Published on PyPI.
Features
- 8 Focused Tools for complete Jira issue and project management
- Interactive Elicitation —
issue_createandissue_deleteinteractively request missing or confirmatory input - Streamable-HTTP + Stdio Transport — run as an HTTP server or stdio for Claude Desktop
- Multi-Tenant HTTP — different clients can connect with different Jira credentials per request
- Smart Field Normalization — case-insensitive types/priorities, display-name assignee resolution, component name-to-ID lookup
- Automatic ADF Formatting — plain text and Markdown auto-converted to Atlassian Document Format
- Transition Resolution — use transition names ("In Progress") instead of numeric IDs
- JQL Search with verbosity control (
ids/summary/full) - Jira Cloud API v3 compatibility
- Docker Support with hot-reload development mode
- 118 Tests — unit tests and FastMCP Client integration tests
Installation
Prerequisites
- Python 3.10+
- Jira Cloud account with an API token (create one here)
Install from PyPI (Recommended)
The package is published to PyPI. Choose any Python package manager:
uvx (Run Without Installing)
The fastest way to try it — runs in an ephemeral environment with no permanent install:
uvx atlassian-jira-mcp-server
uv tool (Persistent Install)
Installs the CLI commands (jira-mcp-server, jira-mcp-http) in an isolated environment:
uv tool install atlassian-jira-mcp-server
pipx (Isolated Install)
Same concept as uv tool but using pipx:
pipx install atlassian-jira-mcp-server
pip (Virtual Environment)
pip install atlassian-jira-mcp-server
After any of the above, two CLI commands are available:
| Command | Transport | Use Case |
|---|---|---|
jira-mcp-server |
stdio | Claude Desktop, Claude Code (stdio), any MCP client |
jira-mcp-http |
streamable-http | Multi-tenant HTTP deployment, remote access |
MCP Client Configuration
Claude Desktop (stdio via PyPI)
Add to claude_desktop_config.json:
{
"mcpServers": {
"jira": {
"command": "jira-mcp-server",
"env": {
"JIRA_BASE_URL": "https://your-domain.atlassian.net",
"JIRA_USERNAME": "your-email@domain.com",
"JIRA_API_TOKEN": "your-api-token",
"JIRA_DEFAULT_PROJECT": "PROJ"
}
}
}
}
Claude Desktop (stdio via uvx — no install needed)
{
"mcpServers": {
"jira": {
"command": "uvx",
"args": ["atlassian-jira-mcp-server"],
"env": {
"JIRA_BASE_URL": "https://your-domain.atlassian.net",
"JIRA_USERNAME": "your-email@domain.com",
"JIRA_API_TOKEN": "your-api-token",
"JIRA_DEFAULT_PROJECT": "PROJ"
}
}
}
}
Claude Code (stdio)
claude mcp add jira -- jira-mcp-server
Or with uvx (no install):
claude mcp add jira -- uvx atlassian-jira-mcp-server
Then set environment variables in your shell or .env file.
Claude Code / Any HTTP Client
Start the HTTP server first:
jira-mcp-http
# or: uvx --from atlassian-jira-mcp-server jira-mcp-http
Then configure the client:
{
"mcpServers": {
"jira": {
"url": "http://localhost:8000/mcp",
"headers": {
"X-Jira-Base-Url": "https://your-domain.atlassian.net",
"X-Jira-Username": "your-email@domain.com",
"X-Jira-Api-Token": "your-api-token"
}
}
}
}
Install from Source (Development)
git clone https://github.com/your-username/atlassian-jira-mcp-server
cd atlassian-jira-mcp-server
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install with dev dependencies
pip install -e ".[dev]"
Or install directly as a uv tool from source:
git clone https://github.com/your-username/atlassian-jira-mcp-server
cd atlassian-jira-mcp-server
uv tool install . --force --reinstall
Docker (HTTP Transport)
git clone https://github.com/your-username/atlassian-jira-mcp-server
cd atlassian-jira-mcp-server
# Create a .env file with your credentials (see Configuration section)
cp .env.example .env # edit with your values
# Build and start the server
docker-compose up -d
The server will be available at http://localhost:8000/mcp.
For multi-tenant mode, leave Jira credentials out of .env and provide them via headers or query params on each request instead.
Configuration
Environment Variables
Create a .env file in the project root:
# Jira credentials (required for single-tenant / env-based config)
JIRA_BASE_URL=https://your-domain.atlassian.net
JIRA_USERNAME=your-email@domain.com
JIRA_API_TOKEN=your-api-token
JIRA_DEFAULT_PROJECT=PROJ # Optional default project key
# HTTP server settings (HTTP transport only)
FASTMCP_HOST=0.0.0.0 # Default: 0.0.0.0
FASTMCP_PORT=8000 # Default: 8000
# Optional bearer-token authentication for the MCP endpoint
MCP_AUTH_TOKEN=your-secure-bearer-token
Multi-Source Credential Resolution (HTTP Transport)
For HTTP deployments, credentials are resolved per request using the following priority (highest to lowest):
- Query parameters —
?jira_base_url=...&jira_username=...&jira_api_token=... Authorization: Basicheader — standard HTTP Basic Auth (username:api_token base64-encoded)X-Jira-*headers —X-Jira-Base-Url,X-Jira-Username,X-Jira-Api-Token,X-Jira-Default-Project- Environment variables — fallback for single-tenant / Docker deployments
This allows a single HTTP server instance to serve multiple Jira tenants simultaneously.
Example: Query Parameter Auth
curl "http://localhost:8000/mcp?jira_base_url=https://your-domain.atlassian.net&jira_username=user@example.com&jira_api_token=your-token"
Example: Basic Auth Header
curl -H "Authorization: Basic $(echo -n 'user@example.com:api-token' | base64)" \
http://localhost:8000/mcp
Example: X-Jira-* Headers
curl -H "X-Jira-Base-Url: https://your-domain.atlassian.net" \
-H "X-Jira-Username: your-email@domain.com" \
-H "X-Jira-Api-Token: your-api-token" \
http://localhost:8000/mcp
Usage
Running the Server
HTTP Transport
# With Docker (recommended)
docker-compose up -d
# Manually via Python entry point
python -c "from server import run_http; run_http()"
# Or via the installed CLI command
jira-mcp-http
Stdio Transport (Claude Desktop)
# Via installed CLI command
jira-mcp-server
# Or directly
python server.py
Connecting with MCP Clients
See the MCP Client Configuration section under Installation above for Claude Desktop, Claude Code, and HTTP client setup.
For multi-tenant HTTP deployments, configure clients to include credentials per request via headers or query params. The server resolves credentials fresh per request so different clients can target different Jira instances.
Available Tools
Issue Operations
issue_get — Get a single issue
issue_get(
issue_key="PROJ-123",
verbosity="full", # "ids" | "summary" | "full" (default: "full")
include_transitions=True,
include_comments=True,
)
Verbosity levels:
ids— issue key only (minimal tokens)summary— key fields: summary, status, assignee, priority, datesfull— complete details including description, comments, transitions
issue_search — Search with JQL
issue_search(
jql="project = PROJ AND status = 'In Progress'",
verbosity="summary", # default: "summary"
max_results=50,
)
Common JQL patterns:
# My open issues
issue_search(jql="assignee = currentUser() AND statusCategory != Done")
# High priority bugs
issue_search(jql="priority = High AND issuetype = Bug")
# Sprint backlog
issue_search(jql="sprint in openSprints() AND project = PROJ")
issue_create — Create a new issue
Supports interactive Elicitation for missing required fields (project_key, issue_type, summary).
issue_create(
project_key="PROJ",
issue_type="Story", # case-insensitive; "story", "bug", "task" all work
summary="Implement login feature",
description="## Overview\nDetailed description with **markdown** support",
priority="high", # aliases: "high"→"High", "critical"→"Highest"
assignee="John Smith", # display name, email, or account ID
components=["frontend"], # component names auto-resolved to IDs
labels=["backend", "auth"],
auto_normalize=True, # default; normalizes all field values
)
issue_update — Update fields, transition status, and add comments (unified)
# Update fields
issue_update(issue_key="PROJ-123", priority="High", labels=["backend"])
# Transition status (by name or ID)
issue_update(issue_key="PROJ-123", transition="In Progress")
# Add a comment
issue_update(issue_key="PROJ-123", comment="Review complete")
# Combined: transition + assign + comment in one call
issue_update(
issue_key="PROJ-123",
transition="In Progress",
assignee="dev@example.com",
comment="Starting work on this",
)
issue_delete — Delete an issue
Uses Elicitation to confirm before deleting.
issue_delete(issue_key="PROJ-123", delete_subtasks=False)
issue_comment — Add a comment
issue_comment(
issue_key="PROJ-123",
body="Looks good to me — merging.",
mentions=["user@example.com"], # optional @mentions
)
Project Operations
project_get — Get project details
project_get(
project_key="PROJ",
verbosity="summary",
include_components=True,
include_versions=True,
)
Validation
issue_validate_fields — Validate and normalize fields before creation
Use this to preview normalization and catch errors before calling issue_create:
result = issue_validate_fields(
project_key="PROJ",
issue_type="bug",
priority="high",
assignee="John",
components=["frontend"],
)
# result["valid"] == True/False
# result["normalized"] == normalized field values
# result["errors"] == list of field errors with suggestions
Resource Endpoints
Resource Templates (Parameterized)
Read any Jira entity by URI — MCP clients discover these via list_resource_templates():
| URI Template | Description |
|---|---|
issue://{issue_key} |
Get any issue by key (e.g., issue://PROJ-123) |
project://{project_key} |
Get any project by key (e.g., project://PROJ) |
Static Resources
Access workspace data through fixed MCP resource URIs:
| URI | Description |
|---|---|
current-user://info |
Current authenticated Jira user |
current-user://issues |
Issues assigned to the current user |
workspace://users |
Active users in the workspace |
workspace://projects |
Accessible Jira projects |
workspace://recent-issues |
Issues updated in the last 7 days |
workspace://verbose-metadata |
Combined metadata: priorities and statuses |
workspace://issue-creation-metadata |
Issue types per project + priorities + assignees |
adf-examples:// |
ADF formatting examples and reference |
ADF (Atlassian Document Format) Support
The server automatically converts plain text and Markdown to ADF format — no manual formatting required.
# Plain text
description = "Simple text description"
# Markdown (headings, bold, lists, code blocks, links all supported)
description = """
## Overview
This issue implements **important** features.
### Acceptance Criteria
- First criterion
- Second criterion
```python
def example():
return "code block"
"""
## Architecture
Version 3.0.0 uses a single FastMCP instance with direct tool/resource/prompt registration:
atlassian-jira-mcp-server/ ├── server.py # Single FastMCP server entry point ├── src/ │ ├── client/ │ │ ├── jira.py # JiraClient — per-request HTTP client │ │ ├── config.py # TenantConfig — multi-source credential resolution │ │ └── errors.py # Typed error classes (PermanentError, etc.) │ ├── tools/ │ │ ├── issue.py # issue_get, issue_search, issue_create, issue_update, │ │ │ # issue_delete, issue_comment │ │ ├── project.py # project_get │ │ ├── validation.py # issue_validate_fields │ │ └── helpers.py # Shared utilities (get_jira_client, elicit_or_error) │ ├── resources/ │ │ ├── static.py # ADF examples resource │ │ └── workspace.py # Dynamic workspace/user/project resources │ ├── prompts/ │ │ └── workflows.py # Workflow guidance prompts │ ├── middleware/ │ │ ├── auth.py # BearerAuthMiddleware — MCP endpoint token validation │ │ └── tenant.py # TenantMiddleware — per-request credential resolution │ └── utilities/ │ ├── adf.py # Markdown→ADF conversion │ ├── resolvers.py # Component/transition name→ID resolution with caching │ └── formatting.py # Issue/project response formatting + verbosity ├── tests/ # 118 tests (unit + FastMCP Client integration) ├── Dockerfile ├── docker-compose.yml ├── pyproject.toml └── requirements.txt
### Key Design Patterns
1. **Single-Server Architecture** — no mounted sub-servers; tools, resources, and prompts register directly on one `FastMCP` instance
2. **Middleware Stack** — `BearerAuthMiddleware` (endpoint auth) → `TenantMiddleware` (per-request credential injection)
3. **Per-Request JiraClient** — no global HTTP client; each tool call gets a fresh `JiraClient` scoped to the request's `TenantConfig`
4. **Multi-Tenant by Default** — HTTP mode supports any number of Jira tenants with zero configuration changes
5. **Elicitation** — `issue_create` and `issue_delete` use FastMCP v3's `ctx.elicit()` for interactive guidance
## Development
### Running Tests
```bash
# Run full test suite
pytest tests/ -v
# Run a specific test file
pytest tests/test_integration.py -v
# With venv
.venv/bin/pytest tests/ -v
The test suite includes:
- Unit tests for individual functions (
test_client.py,test_config.py,test_errors.py,test_tools_*.py, etc.) - FastMCP Client integration tests (
test_integration.py) — exercise the full MCP stack in-memory using FastMCP'sClientwithout a running server - Middleware tests (
test_middleware.py) — validate auth and tenant credential resolution
After Code Changes
# Reinstall uv tool
uv tool uninstall atlassian-jira-mcp-server && uv tool install . --reinstall
# Rebuild Docker image
docker-compose down && docker-compose build && docker-compose up -d
Verifying Imports
python -c "from src.tools import register_tools; print('OK')"
python -c "from server import create_server; print('OK')"
Adding New Tools
- Implement in
src/tools/(e.g.,src/tools/issue.py):
@mcp.tool
async def issue_new_operation(ctx: Context, issue_key: str) -> dict:
"""Tool description shown to the LLM."""
async with await get_jira_client(ctx) as client:
result = await client.request("GET", f"issue/{issue_key}/subtasks")
return result
- Register in
src/tools/__init__.py:
from src.tools import new_module
new_module.register(mcp)
Error Handling
The server distinguishes temporary from permanent errors:
| Error Type | Retry? | Example |
|---|---|---|
| Connection error | Yes | "Connection Error: Unable to connect..." |
| Timeout | Yes | "Timeout Error: Request timed out..." |
| Session error | Yes | "No valid session ID provided" |
| Permission error (403) | No | "Permission Error (HTTP 403): ..." |
| Validation error (400) | No | "Jira API Error: field 'x' is required" |
| Not found (404) | No | Project or issue does not exist |
Troubleshooting
"externally-managed-environment" Error (pip)
Use uv tool install (Method 2) or a virtual environment (Method 3) instead of a system pip install.
Python Not Found with pyenv
# Set a global Python version
pyenv global 3.12.11
# Or use python3 explicitly
python3 -m venv .venv
Authentication Failures
- Verify
JIRA_BASE_URLincludeshttps://and no trailing slash - Confirm the API token belongs to the same email as
JIRA_USERNAME - Check that the token has not expired in Atlassian account settings
Permission Errors (HTTP 403)
- Confirm the Jira user has Browse Project and the relevant Create/Edit/Delete permissions
- Check that the issue type is available in the target project
Contributing
Contributions are welcome. Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality (
pytest tests/ -vmust pass) - Submit a pull request
License
MIT License — see LICENSE file for details.
Support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file atlassian_jira_mcp_server-3.1.0.tar.gz.
File metadata
- Download URL: atlassian_jira_mcp_server-3.1.0.tar.gz
- Upload date:
- Size: 50.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
37770ade721d45cee01e1b4621c2fee5febf1146d73aa1e5452d8499e0380d46
|
|
| MD5 |
f740d9c7042e9ae2a54614689ce6eca6
|
|
| BLAKE2b-256 |
a7d1c7344d8175c1a21c9cc354db8f3cda4a16cc5eafd884be3def1d2565ac64
|
Provenance
The following attestation bundles were made for atlassian_jira_mcp_server-3.1.0.tar.gz:
Publisher:
publish.yml on jasonpaulso/jira-openapi-generated
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
atlassian_jira_mcp_server-3.1.0.tar.gz -
Subject digest:
37770ade721d45cee01e1b4621c2fee5febf1146d73aa1e5452d8499e0380d46 - Sigstore transparency entry: 1165177952
- Sigstore integration time:
-
Permalink:
jasonpaulso/jira-openapi-generated@91852d2fcb0b1add331bcc68b5afeedc0b31eec5 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/jasonpaulso
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91852d2fcb0b1add331bcc68b5afeedc0b31eec5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file atlassian_jira_mcp_server-3.1.0-py3-none-any.whl.
File metadata
- Download URL: atlassian_jira_mcp_server-3.1.0-py3-none-any.whl
- Upload date:
- Size: 45.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
456eb4bf20b9f1e704e388917ee3a59c35d189fdef51abe363db01af2163ef59
|
|
| MD5 |
fc3cbaeacb0c946bf567ef3d7fdd8524
|
|
| BLAKE2b-256 |
4f72dae8151792a7537bf238c097a822139d8e51f8b2f98a111ff3abc1bd4809
|
Provenance
The following attestation bundles were made for atlassian_jira_mcp_server-3.1.0-py3-none-any.whl:
Publisher:
publish.yml on jasonpaulso/jira-openapi-generated
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
atlassian_jira_mcp_server-3.1.0-py3-none-any.whl -
Subject digest:
456eb4bf20b9f1e704e388917ee3a59c35d189fdef51abe363db01af2163ef59 - Sigstore transparency entry: 1165178002
- Sigstore integration time:
-
Permalink:
jasonpaulso/jira-openapi-generated@91852d2fcb0b1add331bcc68b5afeedc0b31eec5 -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/jasonpaulso
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91852d2fcb0b1add331bcc68b5afeedc0b31eec5 -
Trigger Event:
push
-
Statement type: