Skip to main content
Glama
README.md
# Atlassian MCP Server

A Model Context Protocol (MCP) server for Atlassian products (Jira & Confluence), enabling AI assistants to interact with your Atlassian workspace.

## Features

### Jira
- ✅ Create issues with custom fields
- ✅ Update issue status, assignee, and fields
- ✅ Search issues with JQL
- ✅ Get issue details with comments
- ✅ Add comments to issues
- ✅ Transition issues between states

### Confluence
- ✅ Create pages with rich content
- ✅ Update page content
- ✅ Search pages
- ✅ Get page content and metadata

## Architecture

### How It Works

Your MCP server acts as a **bridge** between AI assistants and Jira's REST API:

```
┌──────────────────────────────────────────────┐
│  CURSOR IDE (the orchestrator)               │
│                                              │
│  1. User types: "Create a PH ticket"        │
│  2. Claude/GPT reads available MCP tools    │
│  3. AI decides to call: jira_create_issue   │
│  4. Extracts parameters from prompt         │
└────────────┬─────────────────────────────────┘
             │
             │ JSON-RPC via stdio (pipes)
             ↓
┌──────────────────────────────────────────────┐
│  YOUR MCP SERVER (Python subprocess)         │
│                                              │
│  Components:                                 │
│  ├─ Pydantic Settings (env vars)            │
│  ├─ Tool Registry (@server.list_tools)      │
│  │   • jira_create_issue                    │
│  │   • jira_update_issue                    │
│  │   • jira_search_issues                   │
│  │   • jira_get_issue                       │
│  │   • jira_add_comment                     │
│  │   • jira_transition_issue                │
│  ├─ Tool Router (@server.call_tool)         │
│  └─ JiraClient (async HTTP with auth)       │
└────────────┬─────────────────────────────────┘
             │
             │ HTTPS (Basic Auth with token)
             ↓
┌──────────────────────────────────────────────┐
│  JIRA REST API (Atlassian Cloud)             │
│  • POST /rest/api/3/issue                   │
│  • PUT /rest/api/3/issue/{key}              │
│  • GET /rest/api/3/search                   │
│  • etc.                                     │
└──────────────────────────────────────────────┘
```

### Key Concepts

#### 1. **MCP Server = Tool Provider**

Your server doesn't choose which tool to call - it just:
- **Advertises** available tools to the AI
- **Executes** tool calls when requested
- **Returns** results back to the AI

```python
# Tell AI what's available
@server.list_tools()
async def list_tools():
    return [Tool(name="jira_create_issue", ...)]

# Execute when AI calls it
@server.call_tool()
async def call_tool(name, arguments):
    if name == "jira_create_issue":
        return await jira_create_issue(...)
```

#### 2. **Communication via stdio (NOT HTTP)**

Unlike a web server, MCP servers communicate via **standard input/output**:

```bash
# Cursor launches your server as a subprocess
python -m atlassian_mcp_server

# Messages flow via pipes (stdin/stdout)
# No network ports, no HTTP, no sockets
```

This is configured in `~/.cursor/mcp_config.json`:
```json
{
  "mcpServers": {
    "atlassian": {
      "command": "python",
      "args": ["-m", "atlassian_mcp_server"],
      "env": {
        "ATLASSIAN_API_TOKEN": "your-token"
      }
    }
  }
}
```

#### 3. **AI Model Decides Tool Usage**

The AI (Claude/GPT) autonomously:
- Reads tool descriptions and schemas
- Picks the right tool for the user's request
- Extracts parameters from natural language
- Calls your tool with structured arguments

**You don't control:**
- ❌ Which AI model is used (Cursor chooses)
- ❌ When tools are called (AI decides)
- ❌ How parameters are extracted (AI does this)

**You do control:**
- ✅ What tools are available
- ✅ Tool descriptions and schemas
- ✅ How tools are implemented
- ✅ What happens when tools execute

#### 4. **Request Flow Example**

```
User: "Create a high-priority PH task for adding WO_JOB_MGMT_URL to DevInt"

    ↓ (AI processes prompt)

AI Decision:
{
  "tool": "jira_create_issue",
  "arguments": {
    "project_key": "PH",
    "summary": "Add WO_JOB_MGMT_URL to DevInt",
    "issue_type": "Task",
    "priority": "High",
    "description": "Add WO_JOB_MGMT_URL=http://10.51.50.91:8001 to DevInt .env"
  }
}

    ↓ (MCP sends JSON-RPC message via stdio)

Your Server Receives:
- name: "jira_create_issue"
- arguments: {...}

    ↓ (Routes to Python function)

jira_create_issue() executes:
1. Validates arguments
2. Builds Jira API payload
3. Makes HTTPS POST to Jira
4. Returns formatted result

    ↓ (Result flows back via stdio)

AI formats response:
"✅ Created issue PH-2738: Add WO_JOB_MGMT_URL to DevInt
📋 https://picarro.atlassian.net/browse/PH-2738"
```

### Component Details

#### **Pydantic Settings** (`config.py`)
- Loads credentials from environment variables
- Type-safe configuration management
- Validation on startup

#### **JiraClient** (`jira_client.py`)
- Async HTTP client with `httpx`
- Basic Auth with API token
- Rate limiting (10 req/sec)
- Error handling and retries

#### **Tool Registry** (`server.py`)
- Declares tools with JSON schemas
- Defines required/optional parameters
- Provides descriptions for AI

#### **Tool Router** (`server.py`)
- Receives tool calls from AI
- Dispatches to correct Python function
- Returns results in AI-friendly format

#### **Tool Implementations** (`tools.py`)
- Python async functions
- Make authenticated API calls
- Return JSON strings

### Why This Architecture?

**Separation of Concerns:**
- AI handles natural language understanding
- Your server handles API integration
- Jira handles data storage

**Security:**
- Credentials in environment variables
- No secrets in code or version control
- API token scoped to your permissions

**Extensibility:**
- Add new tools = add Python functions
- No changes to protocol or communication
- AI automatically discovers new tools

**Performance:**
- Async I/O for concurrent requests
- Rate limiting prevents API abuse
- Lightweight subprocess (not a web server)

**Portability:**
- Works with any MCP-compatible client
- Docker containerized for consistency
- Environment-based configuration

## Installation

```bash
# Clone the repository
git clone <your-repo>
cd atlassian-mcp-server

# Create virtual environment
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -e .
```

## Configuration

Create a `.env` file or set environment variables:

```bash
# Required
ATLASSIAN_CLOUD_ID=your-domain.atlassian.net
ATLASSIAN_EMAIL=your-email@company.com
ATLASSIAN_API_TOKEN=your-api-token

# Optional
JIRA_DEFAULT_PROJECT=PH  # Default project key
MCP_LOG_LEVEL=INFO
```

### Getting Your API Token

1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
2. Click "Create API token"
3. Give it a name (e.g., "MCP Server")
4. Copy the token immediately (you won't see it again)

## Usage

### With Cursor

Add to your Cursor MCP settings (`~/.cursor/mcp_config.json`):

```json
{
  "mcpServers": {
    "atlassian": {
      "command": "/path/to/venv/bin/python",
      "args": ["-m", "atlassian_mcp_server"],
      "env": {
        "ATLASSIAN_CLOUD_ID": "your-domain.atlassian.net",
        "ATLASSIAN_EMAIL": "your-email@company.com",
        "ATLASSIAN_API_TOKEN": "your-token"
      }
    }
  }
}
```

### Standalone Testing

```bash
# Run in development mode
python -m atlassian_mcp_server

# Test with MCP inspector
npx @modelcontextprotocol/inspector python -m atlassian_mcp_server
```

## Available Tools

### Jira Tools

#### `jira_create_issue`
Create a new Jira issue.

**Parameters:**
- `project_key` (required): Project key (e.g., "PH", "CDP")
- `summary` (required): Issue title
- `issue_type` (required): Issue type (Task, Bug, Story, etc.)
- `description` (optional): Issue description (Atlassian Document Format)
- `priority` (optional): Priority name (High, Medium, Low)
- `assignee_email` (optional): Assignee email address
- `labels` (optional): Array of label strings

**Example:**
```python
{
  "project_key": "PH",
  "summary": "Add WO_JOB_MGMT_URL to DevInt",
  "issue_type": "Task",
  "description": "Enable processing_status updates...",
  "priority": "High",
  "labels": ["sre", "devint"]
}
```

#### `jira_update_issue`
Update an existing Jira issue.

**Parameters:**
- `issue_key` (required): Issue key (e.g., "PH-2301")
- `summary` (optional): New title
- `description` (optional): New description
- `assignee_email` (optional): New assignee
- `priority` (optional): New priority
- `status` (optional): New status (triggers transition)

#### `jira_search_issues`
Search for issues using JQL.

**Parameters:**
- `jql` (required): Jira Query Language string
- `max_results` (optional): Max results (default: 50)

**Example:**
```python
{
  "jql": "project = PH AND status = 'In Progress' AND assignee = currentUser()",
  "max_results": 20
}
```

#### `jira_get_issue`
Get detailed information about an issue.

**Parameters:**
- `issue_key` (required): Issue key (e.g., "PH-2301")
- `include_comments` (optional): Include comments (default: true)

#### `jira_add_comment`
Add a comment to an issue.

**Parameters:**
- `issue_key` (required): Issue key
- `comment` (required): Comment text (markdown supported)

#### `jira_transition_issue`
Transition an issue to a new status.

**Parameters:**
- `issue_key` (required): Issue key
- `transition_name` (required): Target status name

### Confluence Tools

#### `confluence_create_page`
Create a new Confluence page.

**Parameters:**
- `space_key` (required): Space key
- `title` (required): Page title
- `content` (required): Page content (Atlassian Document Format)
- `parent_page_id` (optional): Parent page ID

#### `confluence_update_page`
Update an existing Confluence page.

**Parameters:**
- `page_id` (required): Page ID
- `title` (optional): New title
- `content` (optional): New content
- `version` (required): Current page version (for optimistic locking)

#### `confluence_search_pages`
Search for Confluence pages.

**Parameters:**
- `query` (required): Search query (CQL)
- `max_results` (optional): Max results (default: 25)

#### `confluence_get_page`
Get a Confluence page's content and metadata.

**Parameters:**
- `page_id` (required): Page ID

## Development

```bash
# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/

# Type checking
mypy src/

# Linting
ruff check src/

# Format code
black src/
```

## Error Handling

The server implements comprehensive error handling:

- **Authentication errors**: Clear messages when credentials are invalid
- **Rate limiting**: Automatic backoff and retry with exponential delay
- **Network errors**: Graceful degradation with informative error messages
- **Validation errors**: Parameter validation before API calls

## Rate Limiting

The server respects Atlassian's rate limits:
- Jira Cloud: 10 requests/second per user
- Confluence Cloud: 5 requests/second per user

Automatic throttling and retry logic is implemented.

## Security

- ✅ API tokens stored in environment variables (never in code)
- ✅ Secure communication over HTTPS only
- ✅ Token validation on startup
- ✅ Input sanitization to prevent injection attacks
- ✅ No logging of sensitive data

## Resume Highlights

**Key Technical Skills Demonstrated:**
- Model Context Protocol (MCP) implementation
- REST API integration (Atlassian Cloud APIs)
- Authentication & authorization (API tokens, OAuth)
- Async I/O with Python's asyncio
- Error handling & resilience patterns
- Rate limiting & throttling
- Type safety with Python type hints
- Test-driven development
- Documentation & API design

**Technologies:**
- Python 3.11+
- MCP SDK (@modelcontextprotocol/sdk)
- Atlassian REST APIs (Jira, Confluence)
- JSON-RPC 2.0
- HTTP/REST
- Environment-based configuration

## License

MIT

## Author

Ajay Jain

## Contributing

Contributions welcome! Please open an issue or PR.

## Roadmap

- [ ] OAuth 2.0 support (in addition to API tokens)
- [ ] Jira Service Management integration
- [ ] Bitbucket integration
- [ ] Webhook support for real-time updates
- [ ] Caching for frequently accessed data
- [ ] Bulk operations support
- [ ] Advanced JQL query builder