Claude Code has first-class MCP support in both the terminal and the VS Code extension, and the config is shared between them once you register the server at the right scope. This topic walks through the actual claude mcp add invocation, the JSON it produces, and the prompt patterns that get reliable results out of Jira's tool set rather than vague, unusable JQL.
Installing and Connecting Jira MCP to Claude Code
The fastest path is claude mcp add with a local stdio server running mcp-atlassian via uvx (no local install needed if you have uv):
claude mcp add jira \
--env JIRA_URL=https://your-domain.atlassian.net \
--env JIRA_USERNAME=you@company.com \
--env JIRA_API_TOKEN=$JIRA_API_TOKEN \
--env JIRA_PROJECTS_FILTER=PROJ \
-- uvx mcp-atlassian
Prefer Docker if you don't want uv on the host, or you're standardizing across a team with different local setups:
claude mcp add jira \
--env JIRA_URL=https://your-domain.atlassian.net \
--env JIRA_USERNAME=you@company.com \
--env JIRA_API_TOKEN=$JIRA_API_TOKEN \
-- docker run -i --rm \
-e JIRA_URL -e JIRA_USERNAME -e JIRA_API_TOKEN \
ghcr.io/sooperset/mcp-atlassian:latest
This writes to ~/.claude.json (user scope) by default. For a team project, add it at project scope instead so it's checked into .mcp.json and everyone on the repo gets the same server on git pull:
claude mcp add jira --scope project \
--env JIRA_URL=https://your-domain.atlassian.net \
-- uvx mcp-atlassian
The resulting .mcp.json looks like this — note the credential is referenced, not hardcoded:
{
"mcpServers": {
"jira": {
"command": "uvx",
"args": ["mcp-atlassian"],
"env": {
"JIRA_URL": "https://your-domain.atlassian.net",
"JIRA_USERNAME": "you@company.com",
"JIRA_API_TOKEN": "${JIRA_API_TOKEN}",
"JIRA_PROJECTS_FILTER": "PROJ"
}
}
}
}
Claude Code expands ${JIRA_API_TOKEN} from your shell environment at launch, so .mcp.json itself stays safe to commit. Verify the connection with:
claude mcp list
You should see jira: connected. If it says failed, run claude mcp get jira for the raw stderr — nine times out of ten it's a bad token or a typo in JIRA_URL missing https://.
Tips
- Use--scope projectfor anything a team shares,--scope local(the default outside a project) for personal experimentation — mixing them up is the most common cause of "it works on my machine."
- Runclaude mcp get jiraimmediately after adding — catching a bad token at setup time is much faster than debugging a confusing tool-call failure five prompts later.
- If your org uses scoped API tokens, confirm the token hasread:jira-workandwrite:jira-work— a token scoped only to Confluence will connect but every Jira tool call will 403.
Querying and Updating Jira Issues from the Claude Code Terminal
Once connected, you can drive Jira entirely through natural language, but the quality of the result tracks directly with how much structure you put in the prompt. Vague prompts get vague JQL.
claude "Find all open bugs in PROJ tagged 'regression' assigned to me, \
sorted by priority, and summarize each in one line"
Under the hood, that becomes something close to:
project = PROJ AND issuetype = Bug AND labels = regression
AND assignee = currentUser() AND status != Done
ORDER BY priority DESC
For scripted, non-interactive use (CI hooks, cron jobs), use -p (print mode) with --output-format json so you can parse the result programmatically:
claude -p "List all issues in the current sprint for board 42 that have no assignee" \
--output-format json > unassigned.json
Updating issues works the same way, but always ask the agent to show you the plan before it executes a write — Claude Code will surface the tool call it's about to make, and you can approve or deny per-call unless you've pre-approved the tool:
claude "Transition PROJ-451 to 'In Review' and add a comment: \
'Fix verified in staging, PR #882 merged'"
Watch for the permission prompt — by default, Claude Code asks before invoking jira_transition_issue and jira_add_comment the first time in a session. You can pre-approve specific tools for a trusted, scoped server:
claude mcp add jira --scope project \
--env JIRA_URL=https://your-domain.atlassian.net \
-- uvx mcp-atlassian
{
"permissions": {
"allow": [
"mcp__jira__jira_get_issue",
"mcp__jira__jira_search",
"mcp__jira__jira_get_sprint_issues"
]
}
}
Note that this allowlist only covers read tools — leave writes (jira_transition_issue, jira_update_issue, jira_add_comment) requiring manual approval unless you're running in a controlled CI context with READ_ONLY_MODE unset intentionally and a narrow ENABLED_TOOLS list.
Tips
- Pre-approve read-only Jira tools in.claude/settings.jsonto cut down on approval fatigue, but leave writes as manual-approval — the two-second pause has caught real mistakes in practice.
- Use--output-format jsonwith-pwhenever you're piping Claude Code's output into another script; the plain-text format is for humans and its structure isn't stable across versions.
- If a query returns nothing and you expect results, ask the agent to print the raw JQL it ran —JIRA_PROJECTS_FILTERscoping silently excludes projects outside the allowlist, which looks identical to "no matching issues."
Jira MCP in the Claude Code VS Code Extension
The VS Code extension reads the same .mcp.json (project scope) and ~/.claude.json (user scope) as the CLI — there's no separate config to maintain. Open the Claude Code panel in VS Code, and any server already connected via the CLI shows up automatically in the MCP status indicator at the bottom of the chat panel.
Where the extension earns its keep over the raw terminal is context linking: you can highlight a block of code, right-click into the Claude Code panel, and ask it to cross-reference against a Jira issue without leaving the editor.
[with app/services/payment.py:142-168 selected]
"This function is throwing the NullPointerException described in PROJ-892.
Read the issue, confirm this is the same code path, and draft a fix."
The extension also renders Jira issue links (PROJ-892) as clickable text in its output when it recognizes the pattern, which is a small thing but saves a context switch to the browser during a debugging session.
One friction point worth knowing about: the VS Code extension's approval dialogs render slightly differently than the terminal's — tool call arguments can get truncated in the panel view for large JQL strings or long issue descriptions. If you need to inspect the exact JQL being sent, drop back to the terminal (claude in the integrated terminal) for that one call, then continue in the extension.
Tips
- Keep the terminal and the VS Code extension pointed at the same project-scoped.mcp.json— don't maintain a separate user-scope Jira server for the extension, or you'll end up debugging two different token configurations.
- Use inline code selection plus a Jira issue key in the same prompt when you want the agent to connect a bug report to a specific code path — it's more reliable than asking it to search the codebase blind.
- When a tool call's arguments look truncated in the VS Code panel, re-run the same prompt in the terminal to see the full JQL or payload before trusting the result.
Prompting Patterns for Effective Jira Ticket Management
The single biggest lever on output quality is giving the agent explicit JQL scaffolding instead of asking it to invent queries from scratch. Compare:
Weak: "What's going on with the backend team's work?"
Better: "Run this JQL and summarize the results grouped by status:
project = PROJ AND component = Backend AND sprint in openSprints()"
For recurring reports, keep a small library of named JQL snippets in a project file (.claude/jira-queries.md) and reference them by name in prompts:
## Stale bugs
project = PROJ AND issuetype = Bug AND status = "To Do"
AND created <= -14d ORDER BY created ASC
## Unassigned sprint work
project = PROJ AND sprint in openSprints() AND assignee is EMPTY
## My review queue
project = PROJ AND status = "In Review" AND reviewer = currentUser()
claude "Using the 'Stale bugs' query from .claude/jira-queries.md, \
list each issue with its age in days and suggest which ones to close as won't-fix"
For issue creation, front-load the template rather than letting the model guess your team's conventions:
"Create a bug in PROJ using this template, filling in details from the
stack trace I'm about to paste:
Summary: [component] - [one-line symptom]
Description:
## Steps to Reproduce
## Expected Behavior
## Actual Behavior
## Stack Trace
Priority: infer from exception type (NPE/500 = High, cosmetic = Low)
Labels: auto-triaged"
This pattern — template plus explicit inference rule — consistently outperforms open-ended "file a bug for this" prompts, because it removes the ambiguity that causes inconsistent priority or missing sections across tickets filed over time.
Tips
- Maintain a shared.claude/jira-queries.md(or equivalent) with named JQL snippets — it turns "what's the query for X" into a one-line reference and keeps report formats consistent across the team.
- Give explicit inference rules ("NPE/500 = High priority") when asking the agent to fill in judgment-call fields — it produces far more consistent tickets than leaving the mapping implicit.
- Ask for the JQL or payload back in the response before a write executes, especially forjira_create_issueandjira_batch_create_issues— reviewing the draft costs seconds and catches template drift early.
Tips
Claude Code's Jira integration is at its best when you treat JQL as a first-class artifact you write and review, not a black box the model improvises each time — the CLI and VS Code extension share config, so get the setup right once and both surfaces benefit.
Tips
- Validate the MCP connection withclaude mcp get jiraright after setup — most integration problems are credential or scope issues caught in seconds at this step.
- Keep write-tool approvals manual in interactive sessions; only pre-approve reads.
- Build a reusable JQL snippet library early — it pays for itself the first time two people on the team need the same "stale bugs" report.