better-jira-mcp
# better-jira-mcp
A thin MCP pass-through to the Jira and Confluence Cloud REST APIs. Built because `mcp-atlassian` mangles Jira descriptions: it regex-converts markdown into Jira *wiki markup* and posts that through REST v2, so `aws_vpc_endpoint` becomes `aws*vpc*endpoint`, `{id}` and `a + b` get eaten as macros, and `**bold**` comes back escaped.
This server instead parses markdown with a real CommonMark parser (`markdown-it-py`), emits [ADF](https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/) directly, and talks to Jira REST v3 and Confluence REST v2 (`atlas_doc_format`), which both speak ADF natively. One converter, no server-side re-interpretation, so bodies round-trip. Every write returns the object re-read so the agent verifies what landed.
## Tools
| Tool | Description |
|------|-------------|
| `atlassian_request` | Raw `method + path + body` pass-through to any endpoint (`/rest/api/3/...`, `/rest/agile/1.0/...`, `/wiki/api/v2/...`). The escape hatch. |
| **Jira** | |
| `jira_get_issue` | Issue with description (and optionally comments) as markdown |
| `jira_search_issues` | JQL search via `/rest/api/3/search/jql` |
| `jira_create_issue` | Markdown description → ADF; component names must match exactly or the call fails; returns the created issue re-read |
| `jira_update_issue` | Same, for updates. Refuses `status` (use a transition) |
| `jira_add_comment` | Markdown comment → ADF |
| `jira_get_transitions` / `jira_transition_issue` | Workflow moves. No inline comment parameter, on purpose |
| `jira_list_components` | Component names and ids for a project |
| `jira_find_user` | Look up accountIds by name or email, for assignee/reporter fields |
| **Confluence** | |
| `confluence_search` | CQL search |
| `confluence_get_page` | Page by id, or space key + title; body (and optionally footer comments) as markdown |
| `confluence_get_page_children` | Direct children of a page |
| `confluence_create_page` | Markdown → ADF page under a space (optionally under a parent) |
| `confluence_update_page` | Replace body and/or title; handles the version bump |
| `confluence_add_page_comment` | Markdown footer comment |
Tool names are prefixed so they don't collide with other MCP servers (GitHub's `search_issues`, for example).
Quirks from the team guide this addresses directly:
- **Lossy markdown / paired `_` / `{}` / paired `+`** – gone; text is text in ADF.
- **Long descriptions break on create** – gone; the body is JSON, no newline escaping.
- **Components fail open** – names are resolved to ids against the project and unknown names are rejected with a "did you mean" hint.
- **Transition comments can be public** – transitions don't accept a comment.
- **Read back what you wrote** – done automatically.
Jira's own behaviour (Team field wants a bare UUID, resolution is one-way, status only moves by transition) is documented in the tool descriptions rather than papered over.
## Installation
No clone needed — `uvx` can run it straight from GitHub:
```bash
uvx --from git+https://github.com/aviddiviner/better-jira-mcp better-jira-mcp
```
Or, for local development:
```bash
git clone https://github.com/aviddiviner/better-jira-mcp
cd better-jira-mcp
uv sync
```
You'll need an [Atlassian API token](https://id.atlassian.com/manage-profile/security/api-tokens). One token covers Jira and Confluence on the same site.
## Zed MCP configuration
Add to `settings.json` under `"context_servers"`. Same env var names as `mcp-atlassian`, so you can copy them across; no separate Confluence variables are needed:
```json
{
"context_servers": {
"better-jira": {
"enabled": true,
"command": "uvx",
"args": ["--from", "git+https://github.com/aviddiviner/better-jira-mcp", "better-jira-mcp"],
"env": {
"JIRA_URL": "https://your.atlassian.net",
"JIRA_USERNAME": "you@example.com",
"JIRA_API_TOKEN": "<token>"
}
}
}
}
```
If you cloned it instead, use `"command": "uv"` with `"args": ["run", "--project", "/path/to/better-jira-mcp", "better-jira-mcp"]`.
## Tests
```bash
uv run pytest
```
TDQS
Scored across 16 tools
Every typed tool is scoped to a specific Jira or Confluence resource and action (get, search, create, update, transition, comment). The raw atlassian_request tool is explicitly framed as a fallback, so there is little realistic confusion between tools.
Most tools follow a clear domain_verb_noun pattern (jira_get_issue, confluence_create_page, jira_transition_issue). Minor deviations exist: confluence_search omits the object noun, and atlassian_request breaks the domain prefix convention, but these are understandable exceptions.
16 tools is slightly above the typical sweet spot, but the scope covers two substantial Atlassian products (Jira and Confluence), and each tool has a distinct role. The count feels justified rather than bloated.
The set covers core Jira issue workflows (search, get, create, update, transition, comment) and Confluence page workflows (search, get, create, update, comment). Some operations like deletes or attachments are absent, but the raw atlassian_request tool provides an escape hatch for edge cases.