Atlassian MCP Server
Search Jira and Confluence directly from your IDE — no browser needed.
Status: 416 tests passing | Hexagonal Architecture (DDD) | Jira v3 + Confluence v2
What Does This Do?
Talk to your AI assistant and get Atlassian data:
You: "What tickets are assigned to me?"
AI: Shows your Jira tickets
You: "Find our deployment documentation"
AI: Shows Confluence pages about deployment
Works with Cursor, Claude Code, or any MCP-compatible client.
Quick Start
1. Get Atlassian OAuth Credentials
- Go to https://developer.atlassian.com/console/myapps/
- Click Create > OAuth 2.0 integration
- Name it:
MCP Server - Callback URL:
http://localhost:8084/auth/callback - Add permissions:
- Jira:
read:jira-work,read:jira-user - Confluence:
read:confluence-content.all,search:confluence,read:confluence-space.summary
- Jira:
- Copy your Client ID and Client Secret
2. Configure
cp env.example .env
Edit .env:
ATLASSIAN_SITE=yourcompany.atlassian.net # no https://
OAUTH_CLIENT_ID=your_client_id
OAUTH_CLIENT_SECRET=your_client_secret
# Generate these:
TOKEN_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
REDIS_PASSWORD=$(node -e "console.log(require('crypto').randomBytes(16).toString('hex'))")
3. Start
docker-compose up -d
4. Authenticate
open http://localhost:8084/auth/login
Click "Accept" when Atlassian asks for permission.
5. Connect Your IDE
Cursor — edit ~/.cursor/mcp.json:
{
"mcpServers": {
"atlassian": {
"url": "http://localhost:8084/mcp",
"type": "http"
}
}
}
Claude Code — edit ~/.claude/claude_desktop_config.json:
{
"mcpServers": {
"atlassian": {
"url": "http://localhost:8084/mcp"
}
}
}
Restart your IDE after adding the config.
6. Test It
- "What Jira tickets are assigned to me?"
- "Find deployment documentation in Confluence"
- "Show me ticket ENG-123"
Available Tools
| Tool | Description |
|---|---|
search_jira | Search Jira with JQL filters |
get_jira_ticket | Get full ticket details |
list_my_tickets | List your assigned tickets |
search_confluence | Search Confluence with CQL |
get_confluence_page | Get full page content |
Architecture
MCP Protocol (HTTP)
IDE / AI Client ──────────── http://localhost:8084/mcp
│
┌─────────────────────────────────────┼─────────────────────────────┐
│ Atlassian MCP Server │ │
│ │ │
│ ┌──────────────┐ ┌───────────────┼────────────┐ │
│ │ Domain │ │ Application │ │ │
│ │ │ │ ▼ │ │
│ │ Models │◄──│ Use Cases (5) │ │
│ │ Services │ │ Ports (interfaces) │ │
│ │ Value Objects│ │ DTOs (Zod validated) │ │
│ └──────────────┘ └──────────────┬─────────────┘ │
│ │ │
│ ┌─────────────────────────────────┼────────────────────────────┐ │
│ │ Infrastructure │ │ │
│ │ ▼ │ │
│ │ Adapters: JiraRestAdapter, ConfluenceRestAdapter │ │
│ │ Auth: OAuthAdapter, RedisTokenAdapter │ │
│ │ Cache: RedisCacheAdapter │ │
│ │ MCP: McpToolRouter, toolDefinitions │ │
│ │ Server: Express routes, middleware │ │
│ └──────┬──────────────┬───────────────────┬────────────────────┘ │
└─────────┼──────────────┼───────────────────┼──────────────────────┘
│ │ │
┌────────▼────────┐ ┌──▼────────────┐ ┌────▼──────┐
│ Jira REST API │ │ Confluence │ │ Redis │
│ v3 (search/JQL) │ │ v1 (search) │ │ Cache + │
│ │ │ v2 (pages) │ │ Tokens │
└─────────────────┘ └───────────────┘ └───────────┘
Key design decisions:
- Hexagonal / DDD — Domain has zero infrastructure imports. Application layer defines port interfaces. Infrastructure implements adapters.
- Strangler Fig migration — Confluence v1
/content/{id}migrated to v2/pages/{id}. v1 search (/content/search) stays (not deprecated). - ESLint enforced layer boundaries —
import-x/no-restricted-pathsprevents domain from importing infrastructure. - Composition Root — All wiring in
compositionRoot.ts. Use cases receive ports via constructor injection.
Project Structure
src/
domain/ # Models, value objects, domain services (zero deps)
application/ # Use cases, ports (interfaces), DTOs
infrastructure/ # Adapters (Atlassian, auth, cache, MCP, logging)
server/ # Express routes, middleware, MCP setup
services/ # REST clients, OAuth, token storage, cache
common/ # Config, logger, shared errors
compositionRoot.ts
index.ts
tests/ # Mirrors src/ structure, 416 tests
Development
Run Without Docker
npm install
npm run build
npm run dev # development mode with auto-reload
npm start # production build
Tests
npm test # Run all 416 tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage report
Code Quality
npm run lint # ESLint with DDD boundary checks
npm run typecheck # TypeScript strict mode
npm run validate # All checks (lint + typecheck + test)
Configuration
Required (.env)
ATLASSIAN_SITE=yourcompany.atlassian.net # no https://
OAUTH_CLIENT_ID=your_client_id
OAUTH_CLIENT_SECRET=your_client_secret
TOKEN_ENCRYPTION_KEY=<64-char hex string> # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
REDIS_PASSWORD=<random string> # node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
Optional
PORT=8084 # Server port
LOG_LEVEL=info # error | warn | info | debug
CACHE_TTL=3600 # Cache TTL in seconds (default: 1 hour)
ENABLE_CACHE=true # Redis caching
Docker Commands
docker-compose up -d # Start all services
docker-compose stop # Stop
docker-compose logs -f atlassian-mcp # View logs
docker-compose build && docker-compose up -d # Rebuild after code changes
Security
- OAuth 2.1 tokens encrypted at rest via
TOKEN_ENCRYPTION_KEY - Automatic token refresh on expiry
- Redis authenticated with
REDIS_PASSWORD(--requirepass) - Ports bound to
127.0.0.1only (localhost) - Non-root container user (
atlassian:1001) - Multi-stage Docker build (no build tools in production image)
- No
curlin production image (healthcheck uses Node.js nativefetch) .dockerignoreexcludes.env,.git,node_modules- All Atlassian permissions respected (read-only scopes)
- Never commit
.envto git
Troubleshooting
"Not authenticated" — Visit http://localhost:8084/auth/login and re-authorize.
Tools don't appear in IDE — Fully quit and restart your IDE (not just reload).
Server not starting — Check docker-compose logs -f atlassian-mcp and verify .env is configured.
Health check — Visit http://localhost:8084/health or http://localhost:8084/ready.