# Jira Writer

> Deliberate, confirmed writes to Jira via the jira-sandbox MCP server — create issues, comment, update fields, transition status, epics, sprints, story points. Use whenever the user explicitly asks to change Jira ("create a ticket", "comment on PROJ-123", "move it to Done"). Every write gets a preview + explicit confirmation first. For lookups, status questions, or reports use jira-reader — never use this just to read.

- Skill: `artsmc-claude-dev-agents/jira-writer` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add artsmc-claude-dev-agents/jira-writer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/artsmc-claude-dev-agents/jira-writer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: artsmc (https://skillmd.com/u/artsmc-claude-dev-agents)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/artsmc-claude-dev-agents/jira-writer

---


# Jira Writer

Make changes to Jira through the `jira-sandbox` MCP server — carefully. Jira is an
org-wide system of record: a stray comment, transition, or ticket is visible to the
whole team and noisy to undo. So every write here follows the same discipline:
**read → preview → confirm → write → verify**.

## The write tools (use no others for mutation)

| Tool | Mutates | Required params |
|------|---------|-----------------|
| `create_jira_issue` | New issue | `project_key`, `summary`, `description` (+ optional `issue_type`, `epic_key`) |
| `add_jira_comment` | Comment | `issue_key`, `comment` |
| `update_jira_issue` | Issue fields | `issue_key`, `fields` (object of field → new value) |
| `transition_jira_issue` | Status | `issue_key`, `transition_id` (an ID, not a name — see below) |
| `link_issues_to_epic` | Epic membership | `epic_key`, `issue_keys` |
| `add_issues_to_sprint` | Sprint membership | `sprint_id`, `issue_keys` |
| `set_story_points` | Estimate | `issue_key`, `story_points` |

All are `mcp__jira-sandbox__<tool>`. Same connectivity rules as jira-reader: VPN-only
(connection failures mean VPN is off), and tools load via ToolSearch if not yet in session.

## The procedure

**1. Read first.** Before any write, fetch current state with the read tools
(`get_jira_issue`, `get_jira_transitions`, `get_sprints`, `search_jira_issues`).
This catches the cases that burn people: the issue is already in the target status,
the "new" ticket already exists as a duplicate, the sprint is closed, the epic key is
actually a story. For creates, search for likely duplicates first
(`project = X AND text ~ "..." AND resolution = Unresolved`).

**2. Preview.** Show the user exactly what will change, before changing it:
target issue key (with current state), the operation, and the full new content
(complete comment text, all fields and values, transition from → to). For multi-issue
operations, list every affected key.

**3. Confirm.** Wait for an explicit yes on that specific preview. Don't treat the
original request as pre-approval — the request told you *what* they want; the
confirmation approves *how it landed in the preview*. Exception: if the user has
already given the exact final content and target in their message ("comment exactly
this on PROJ-42: ...") and the read in step 1 surfaced no surprises, one combined
"here's what I'm about to post — posting unless you stop me" is too weak; still ask.
If you cannot get a confirmation (non-interactive run), stop at the preview and
report that the write is staged awaiting approval — never write unconfirmed.

**4. Write.** One tool call per confirmed operation. For transitions: call
`get_jira_transitions` for the issue, match the user's intent ("done", "start it",
"send back") to a transition by name, and pass that transition's **id**. If no
transition matches, show the available ones and ask — don't force the closest guess.

**5. Verify.** Re-read the issue (`get_jira_issue`) and confirm the change actually
landed — status really changed, field really updated. Two server quirks (verified live
2026-06-10): `get_jira_issue` does NOT render comments, so to prove a comment landed,
search `issue = KEY AND comment ~ "distinctive phrase"` instead. And all writes are
attributed to the shared service account (not the requesting user) — for comments,
prefix with who it's actually from when authorship matters. Report expected vs actual.
If a write is rejected (permission error), report that faithfully, give the user the
paste-ready content to apply manually, and don't retry through other routes.

## Scope limits

- Despite the "sandbox" in its ALB name, this MCP fronts the org's **live** Atlassian
  Data Center Jira (`atlassian-dc.example.com`) — the same instance the team works in
  daily, across all projects (PROJ, TEAM, etc.). Writes are real and team-visible.
  There is no lowered-stakes safety net; the confirmation discipline below is the only one.
- No bulk writes without an explicit list confirmation: "transition all of these" gets
  a preview enumerating every key, not a count.
- Nothing here deletes (the server exposes no delete tools). If asked to delete,
  say it isn't possible via this connection.
- Reading is jira-reader's job. If a request is purely a question, hand off — don't
  load up write tools to answer a read.

