All skills
jeffallan avatar

/atlassian-mcp

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,124

Integrates with Atlassian products to manage project tracking and documentation via MCP protocol. Use when querying Jira issues with JQL filters, creating and updating tickets with custom fields, searching or editing Confluence pages with CQL, managing sprints and backlogs, setting up MCP server authentication, syncing documentation, or debugging Atlassian API integrations.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/atlassian-mcp

This session only. Nothing lands on disk.

referencesjira-queries.md

≈3.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Jira Queries and Operations


JQL Fundamentals

Basic Query Structure

field OPERATOR value [AND|OR field OPERATOR value]

Common Operators

Operator Description Example
= Exact match project = "PROJ"
!= Not equal status != Done
~ Contains (text search) summary ~ "login bug"
!~ Does not contain description !~ "test"
>, <, >=, <= Comparison created >= -7d
IN Multiple values status IN (Open, "In Progress")
NOT IN Exclude values assignee NOT IN (john, jane)
IS Null check assignee IS EMPTY
IS NOT Not null resolution IS NOT EMPTY
WAS Historical state status WAS "In Progress"
CHANGED Field changed status CHANGED FROM Open

Field Reference

Standard Fields:

project = PROJ
issuetype = Bug
status = "In Progress"
priority = High
assignee = currentUser()
reporter = "john.doe"
resolution = Unresolved
labels = backend
component = "API"
fixVersion = "2.0"
affectsVersion = "1.5"

Date Fields:

created >= -30d                    -- Last 30 days
updated >= "2024-01-01"           -- Since specific date
due <= endOfWeek()                 -- Due this week
resolved >= startOfMonth()         -- Resolved this month

Text Search:

summary ~ "authentication"         -- Summary contains
description ~ "error AND login"    -- Description search
text ~ "payment failed"            -- All text fields
comment ~ "blocked"                -- Comment contains

Essential JQL Patterns

Sprint and Backlog Queries

-- Current sprint issues
sprint in openSprints() AND project = PROJ

-- Backlog items
sprint IS EMPTY AND resolution IS EMPTY AND project = PROJ

-- Sprint completion
sprint = "Sprint 23" AND status = Done

-- Spillover from last sprint
sprint in closedSprints() AND resolution IS EMPTY

-- Ready for sprint planning
status = "Ready for Dev" AND sprint IS EMPTY

Bug Tracking

-- Open bugs by priority
issuetype = Bug AND resolution IS EMPTY ORDER BY priority DESC

-- Critical production bugs
issuetype = Bug AND priority IN (Highest, High)
  AND labels = production AND resolution IS EMPTY

-- Bugs created this week
issuetype = Bug AND created >= startOfWeek()

-- Bugs without reproduction steps
issuetype = Bug AND "Reproduction Steps" IS EMPTY
  AND resolution IS EMPTY

-- Regression bugs
issuetype = Bug AND labels = regression AND fixVersion = "2.0"

Team Workload

-- My open issues
assignee = currentUser() AND resolution IS EMPTY

-- Unassigned high priority
assignee IS EMPTY AND priority IN (Highest, High)
  AND resolution IS EMPTY

-- Team member workload
assignee = "jane.smith" AND sprint in openSprints()

-- Blocked issues
status = Blocked OR labels = blocked

-- Stale issues (no update in 14 days)
updated <= -14d AND resolution IS EMPTY

Release Management

-- Release candidates
fixVersion = "2.0" AND status = "Ready for Release"

-- Missing fix version
resolution = Done AND fixVersion IS EMPTY AND updated >= -30d

-- Release blockers
fixVersion = "2.0" AND priority = Blocker AND resolution IS EMPTY

-- Changelog items
fixVersion = "2.0" AND resolution = Done ORDER BY issuetype

MCP Tool Calls

Searching Issues

// Basic JQL search
const searchResult = await client.callTool({
  name: "jira_search",
  arguments: {
    jql: "project = PROJ AND sprint in openSprints()",
    max_results: 50,
    fields: ["summary", "status", "assignee", "priority"]
  }
});

// Parse response
const issues = JSON.parse(searchResult.content[0].text);
for (const issue of issues.issues) {
  console.log(`${issue.key}: ${issue.fields.summary}`);
}

Getting Issue Details

// Get single issue with all fields
const issue = await client.callTool({
  name: "jira_get_issue",
  arguments: {
    issue_key: "PROJ-123",
    expand: ["changelog", "comments", "transitions"]
  }
});

// Get issue with specific fields
const issuePartial = await client.callTool({
  name: "jira_get_issue",
  arguments: {
    issue_key: "PROJ-123",
    fields: ["summary", "description", "customfield_10001"]
  }
});

Creating Issues

// Create a bug
const newBug = await client.callTool({
  name: "jira_create_issue",
  arguments: {
    project_key: "PROJ",
    issue_type: "Bug",
    summary: "Login fails with SSO enabled",
    description: {
      type: "doc",
      version: 1,
      content: [
        {
          type: "paragraph",
          content: [{ type: "text", text: "Users cannot log in when SSO is enabled." }]
        },
        {
          type: "heading",
          attrs: { level: 3 },
          content: [{ type: "text", text: "Steps to Reproduce" }]
        },
        {
          type: "orderedList",
          content: [
            { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "Enable SSO in settings" }] }] },
            { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "Log out" }] }] },
            { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "Attempt to log in via SSO" }] }] }
          ]
        }
      ]
    },
    priority: "High",
    labels: ["sso", "authentication", "production"],
    components: ["Authentication"],
    assignee: "jane.smith"
  }
});

console.log(`Created: ${newBug.content[0].text}`); // PROJ-456

Updating Issues

// Update issue fields
await client.callTool({
  name: "jira_update_issue",
  arguments: {
    issue_key: "PROJ-123",
    fields: {
      summary: "Updated summary",
      priority: { name: "Highest" },
      labels: ["urgent", "production"]
    }
  }
});

// Add comment
await client.callTool({
  name: "jira_add_comment",
  arguments: {
    issue_key: "PROJ-123",
    body: "Investigating this issue. Initial analysis suggests a race condition."
  }
});

// Transition issue
await client.callTool({
  name: "jira_transition_issue",
  arguments: {
    issue_key: "PROJ-123",
    transition: "In Progress"
  }
});

Sprint Operations

// Get active sprints
const sprints = await client.callTool({
  name: "jira_get_sprints",
  arguments: {
    board_id: 42,
    state: "active"
  }
});

// Move issue to sprint
await client.callTool({
  name: "jira_move_to_sprint",
  arguments: {
    sprint_id: 123,
    issue_keys: ["PROJ-100", "PROJ-101", "PROJ-102"]
  }
});

// Get sprint report
const report = await client.callTool({
  name: "jira_get_sprint_report",
  arguments: {
    board_id: 42,
    sprint_id: 123
  }
});

Issue Linking

Use jira_create_issue_link to create dependency relationships between issues.

The parameter names are counterintuitive. The naming reflects Jira's internal "inward/outward" link direction, not natural English. Verify every link call against the table below.

Parameter Semantics for "Blocks" Links
Parameter Role Meaning
inward_issue_key Blocker This issue blocks the other
outward_issue_key Blocked This issue is blocked by the other

Memory aid: inward_issue_key = the issue receiving the inward description ("is blocked by") — but it is the blocker. Think: "the inward key is where the arrow points FROM."

Single Blocks Link
// Make AUTH-1 block AUTH-2
// AUTH-1 will show: "blocks AUTH-2"
// AUTH-2 will show: "is blocked by AUTH-1"
await client.callTool({
  name: "jira_create_issue_link",
  arguments: {
    link_type: "Blocks",
    inward_issue_key: "AUTH-1",   // blocker
    outward_issue_key: "AUTH-2"   // blocked
  }
});
Linking a Dependency Chain

When creating a chain A → B → C (A blocks B, B blocks C):

const chain = [
  { blocker: "AUTH-1", blocked: "AUTH-2" },
  { blocker: "AUTH-2", blocked: "AUTH-3" },
  { blocker: "AUTH-3", blocked: "AUTH-4" }
];

for (const dep of chain) {
  await client.callTool({
    name: "jira_create_issue_link",
    arguments: {
      link_type: "Blocks",
      inward_issue_key: dep.blocker,
      outward_issue_key: dep.blocked
    }
  });

  // Respect rate limits between link operations
  await delay(100);
}
Other Link Types

The same inward/outward pattern applies to all link types:

Link Type inward_issue_key shows outward_issue_key shows
Blocks "blocks [outward]" "is blocked by [inward]"
Duplicate "duplicates [outward]" "is duplicated by [inward]"
Relates "relates to [outward]" "relates to [inward]"
// Mark PROJ-10 as a duplicate of PROJ-5
await client.callTool({
  name: "jira_create_issue_link",
  arguments: {
    link_type: "Duplicate",
    inward_issue_key: "PROJ-10",   // the duplicate
    outward_issue_key: "PROJ-5"    // the original
  }
});
Anti-Pattern: Reversed Parameters
// WRONG — This makes AUTH-2 block AUTH-1 (backwards!)
await client.callTool({
  name: "jira_create_issue_link",
  arguments: {
    link_type: "Blocks",
    inward_issue_key: "AUTH-2",   // accidentally made AUTH-2 the blocker
    outward_issue_key: "AUTH-1"   // accidentally made AUTH-1 the blocked
  }
});

Always verify: after creating a link, the blocker (inward_issue_key) should display "blocks [outward]" in its Jira issue view.

Pagination Handling

async function getAllIssues(jql: string): Promise<Issue[]> {
  const allIssues: Issue[] = [];
  let startAt = 0;
  const maxResults = 100;

  while (true) {
    const result = await client.callTool({
      name: "jira_search",
      arguments: {
        jql,
        start_at: startAt,
        max_results: maxResults,
        fields: ["summary", "status", "assignee"]
      }
    });

    const response = JSON.parse(result.content[0].text);
    allIssues.push(...response.issues);

    if (startAt + response.issues.length >= response.total) {
      break;
    }

    startAt += maxResults;
  }

  return allIssues;
}

Bulk Operations

// Bulk update with JQL
async function bulkUpdateLabels(jql: string, addLabels: string[]) {
  const issues = await getAllIssues(jql);

  for (const issue of issues) {
    const existingLabels = issue.fields.labels || [];
    await client.callTool({
      name: "jira_update_issue",
      arguments: {
        issue_key: issue.key,
        fields: {
          labels: [...new Set([...existingLabels, ...addLabels])]
        }
      }
    });

    // Respect rate limits
    await delay(100);
  }
}

// Usage
await bulkUpdateLabels(
  'project = PROJ AND sprint in openSprints() AND labels = backend',
  ['q4-priority', 'needs-review']
);

Error Handling

async function safeJiraCall<T>(
  operation: () => Promise<T>,
  retries = 3
): Promise<T> {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      return await operation();
    } catch (error: any) {
      const status = error.response?.status;

      // Don't retry client errors (except rate limits)
      if (status >= 400 && status < 500 && status !== 429) {
        throw error;
      }

      // Rate limited - wait and retry
      if (status === 429) {
        const retryAfter = parseInt(error.response?.headers?.['retry-after'] || '60');
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await delay(retryAfter * 1000);
        continue;
      }

      // Server error - exponential backoff
      if (attempt < retries) {
        const backoff = Math.pow(2, attempt) * 1000;
        console.log(`Attempt ${attempt} failed. Retrying in ${backoff}ms...`);
        await delay(backoff);
      } else {
        throw error;
      }
    }
  }
  throw new Error('Unexpected end of retry loop');
}

Common Anti-Patterns

Avoid:

-- Too broad (slow, may timeout)
project IS NOT EMPTY

-- Missing quotes for multi-word values
status = In Progress  -- WRONG
status = "In Progress"  -- CORRECT

-- Case sensitivity issues
assignee = John  -- May fail
assignee = "john.doe@company.com"  -- CORRECT

-- Inefficient ordering
ORDER BY created  -- Missing direction
ORDER BY created DESC  -- CORRECT

Related References

  • common-workflows.md - End-to-end workflow patterns
  • authentication-patterns.md - Credential setup for API calls
  • confluence-operations.md - Linking Jira issues to Confluence pages

Source: SKILL.md on GitHub

2 alerts16d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    This skill provides developer guidance for integrating Atlassian products with the Model Context Protocol (MCP). While the content is primarily educational, automated scanners have flagged the documentation URL and the skill's main entry point. The skill also recommends the use of community-maintained packages from non-trusted sources and provides workflows vulnerable to indirect prompt injection.

  • Socket16d

    1 alert: gptAnomaly

  • Snyk16d

    Risk: MEDIUM · 1 issue

  • Runlayer6mo

    4/6 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "platform",
  "triggers": "Jira, Confluence, Atlassian, MCP, tickets, issues, wiki, JQL, CQL, sprint, backlog, project management",
  "role": "expert",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "mcp-developer, api-designer, security-reviewer"
}
  • MCP
  • jira
  • confluence
  • atlassian
  • jql
  • cql
  • project-management
  • api-integration
  • authentication

README badge

README badge for jeffallan/claude-skills/atlassian-mcp

Integrates Claude with Jira and Confluence via MCP protocol to query issues with JQL, create and update tickets, search pages with CQL, and manage sprints and backlogs. Handles OAuth and API token authentication, pagination, rate limits, and permission validation for Atlassian cloud and self-hosted instances.

Generated from the current SKILL.md.

Does this skill work with self-hosted Jira and Confluence instances?
Yes. The skill supports official cloud, open-source, and self-hosted MCP servers. You configure the server URL and authentication method (OAuth 2.0, API tokens, or PAT) in the MCP configuration.
What authentication methods are supported?
The skill supports OAuth 2.0, API tokens, and personal access tokens (PAT). Credentials must be loaded from environment variables or a secrets manager, never hardcoded.
Can I automate sprint and backlog management with this skill?
Yes. The skill covers JQL queries for sprints and backlogs, issue linking, and bulk operations. It includes patterns for sprint workflows, issue triage, and board updates with required permission validation.
How do I avoid hitting Atlassian API rate limits?
The skill requires implementing exponential backoff, pagination (50-100 items per page), and monitoring rate limit headers from Atlassian APIs. Always probe with `maxResults=1` before executing large queries.
Does this skill handle Confluence page creation and editing?
Yes. The skill covers CQL search syntax, page creation, space management, and comments. Reference documentation includes Confluence-specific operations and workflow examples.

Generated from the current SKILL.md. These answers refresh after source changes.