Skip to main content
Glama

Atlassian Read-only

Read-only Jira and Confluence toolkit for AI agents — no write operations are possible.

License: Internal Node ≥ 20

📋 Table of Contents


Related MCP server: MCP Atlassian Server

Features

Capability

Jira

Confluence

Read a single issue/page

✅ get-issue

✅ get-page

Search with query language

✅ JQL

✅ CQL

Projections (JMESPath subset)

✅

✅

Any allowlisted read endpoint

✅ get

✅ get

Response size limits

✅

✅

Secret redaction

✅

✅

HTML→Markdown conversion

—

✅ optional dependency

Read-only by construction — only GET, allowlisted paths, no POST/PUT/PATCH/DELETE.


Three Ways to Use

Method

Best for

Setup

Agent Skill

Casual queries via Claude/Copilot

npx skills add ... then npm run setup

MCP Server

Persistent tool integration in VS Code, CLI, Claude Code

Config file

Direct Script

Scripts, CI, token-efficient calls

node atlassian.mjs ...


Quick Start

1. Install the skill

npx skills add AlexSchaap-TMMC/atlassian-readonly --skill atlassian-readonly

The --skill argument is required because the GitHub repository may contain multiple skills (multiple directories under skills/). This flag tells the installer which skill directory to install. Without it, the installer wouldn't know which of potentially many skills to use.

2. Run setup

cd ~/.agents/skills/atlassian-readonly
npm run setup

That single command stores your credentials in the OS credential store (Windows Credential Manager, macOS Keychain, or Linux Secret Service; falling back to ~/.config token files where none exists), enables the corporate certificate store if it detects TLS inspection, and verifies both tokens against the live API. Nothing is installed first: the scripts use Node built-ins only, so the skill works straight after step 1. Non-interactive:

npm run setup -- "you@example.com" "<jira-token>" "<confluence-token>"

Token creation and scope requirements are in skills/references/setup.md; the same file covers rotation, headless/WSL setups, and troubleshooting.

3. Ask your agent

Read HEC-123 and summarize its acceptance criteria.
Search Jira for open bugs assigned to me.
Search Confluence for pages about Kafka retry handling.

💡 Finding space keys: When searching Confluence, use the space key (not display name). Run node ./skills/atlassian.mjs confluence search --cql 'title ~ "project-name"' first to discover the correct space key from results.


Direct Script Execution

For fast, token-efficient access, run the bundled script directly:

💡 Corporate networks: Prepend NODE_OPTIONS="--use-system-ca" for Zscaler/corporate TLS.

# Read a Jira issue
node ./skills/atlassian.mjs jira get-issue --issue-key HEC-123

# Search Jira with JQL
node ./skills/atlassian.mjs jira search-issues --jql 'project=HEC AND status="To Do"' --limit 10

# Read a Confluence page
node ./skills/atlassian.mjs confluence get-page --page-id 123456789

# Search Confluence with CQL
node ./skills/atlassian.mjs confluence search --cql 'title ~ "Kafka"' --limit 10

For an "open" filter use status, not statusCategory: statusCategory=Open returns 0 issues on this tenant. See troubleshooting.

Projections

Reduce response size with --projection (a JMESPath subset, no dependency needed):

node ./skills/atlassian.mjs jira search-issues \
  --jql 'project=HEC' \
  --projection 'issues[*].{key: key, summary: fields.summary, status: fields.status.name}'

node ./skills/atlassian.mjs confluence get-page \
  --page-id 123 \
  --projection 'title,body[storage].value'

JMESPath object shorthand {key, summary} is invalid — object entries need explicit name: expression pairs, and nested fields must use their full path. Supported syntax is a.b.c, [0], [-1], ["key"], [*], {k: expr}, |, @ and length(); filters, slices and other functions are rejected with an explicit error.

Any Other Read Endpoint

Use get for allowlisted GET paths the named commands do not cover:

node ./skills/atlassian.mjs jira get \
  --path '/rest/api/3/issue/HEC-123/changelog' --projection 'values[*].id'

node ./skills/atlassian.mjs confluence get \
  --path '/wiki/api/v2/pages' --query 'limit=5&sort=-created-date' --projection 'results[*].{t: title}'

Validate Tokens

Check tokens before API calls to avoid wasted requests:

node ./skills/atlassian.mjs test jira   # exit 0 = valid, exit 1 = invalid
node ./skills/atlassian.mjs test confluence

MCP Server

The bundled server exposes four tools via stdio:

Tool ID

Description

jira_get_issue

Read a single Jira issue

jira_search_issues

Search Jira with JQL

confluence_get_page

Read a Confluence page

confluence_search

Search Confluence with CQL

GitHub Copilot in VS Code

Run MCP: Open User Configuration from the Command Palette, then add:

{
  "servers": {
    "atlassian-readonly": {
      "type": "stdio",
      "command": "node",
      "args": ["./skills/server.mjs"],
      "env": {
        "ATLASSIAN_USER_EMAIL": "your.email@example.com",
        "NODE_OPTIONS": "--use-system-ca"
      }
    }
  }
}

Reload VS Code, open Copilot Chat, select Configure Tools, and enable the four Atlassian tools.

GitHub Copilot CLI

copilot mcp add atlassian-readonly \
  --env ATLASSIAN_USER_EMAIL="your.atlassian.email@example.com" \
  --env NODE_OPTIONS="--use-system-ca" \
  -- node ./skills/server.mjs

Claude Code

Edit ~/.claude/mcp.json:

{
  "servers": {
    "atlassian-readonly": {
      "command": "node",
      "args": ["./skills/server.mjs"],
      "env": {
        "ATLASSIAN_USER_EMAIL": "your.email@example.com",
        "NODE_OPTIONS": "--use-system-ca"
      }
    }
  }
}

Manual mcp.json

cp ./skills/references/mcp.json atlassian-readonly-mcp.json

Then update args to the absolute path of skills/server.mjs and set ATLASSIAN_USER_EMAIL. Load it into your client as mcpServers — the file holds one server object, not the whole mcpServers map.


Create API Tokens

Open Atlassian API tokens and create two separate tokens (Jira and Confluence cannot share one).

Jira token

read:jira-work

This classic scope alone is verified for issue retrieval and JQL search. Atlassian rejects granular Jira scopes with 401 Unauthorized; scope does not match.

Confluence token

read:page:confluence
read:content-details:confluence
search:confluence

These granular scopes are verified for CQL search and full page retrieval.

⚠️ Scopes are fixed at creation time. Copy each token immediately — the dialog won't show it again. Never place tokens in source files, config, shell history, issues, or chat.


Store & Rotate Credentials

npm run setup stores credentials for you. To rotate or remove them afterwards:

npm run configure -- jira        # replace
npm run configure -- confluence  # replace
npm run configure -- jira delete # remove
npm run configure -- confluence delete

Tokens are saved in your OS credential store (Windows Credential Manager, macOS Keychain, or Linux Secret Service), falling back to ~/.config/atlassian-<product>-token with mode 0600 where no credential store is reachable.

⚠️ Local deletion does not revoke the token at Atlassian. Revoke it separately from Atlassian's token management page.


Troubleshooting

See skills/references/setup.md for the full list, including why a valid token can be reported as invalid and how to confirm which credential source each product resolves from.

Corporate certificates (Zscaler, etc.)

TLS inspection re-signs HTTPS traffic with a corporate CA. npm run setup detects this and records it in the git-ignored config.json; force it with npm run setup -- --system-ca. Alternatively set NODE_OPTIONS=--use-system-ca (supported Node.js versions).

Or export the non-expired corporate CA as Base-64 PEM and set NODE_EXTRA_CA_CERTS to its path. Never disable TLS verification.

WSL

WSL uses a separate Linux trust store. Export the corporate root and intermediate certificates from Windows, save as .crt, then:

sudo cp *.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

Restart WSL before retrying HTTPS clients.


WSL & Headless Systems

npm run setup writes ~/.config/atlassian-<product>-token files (mode 0600) when no device credential store is reachable — no manual steps needed. To place them by hand:

mkdir -p ~/.config
install -m 600 /dev/null ~/.config/atlassian-user-email
install -m 600 /dev/null ~/.config/atlassian-jira-token
install -m 600 /dev/null ~/.config/atlassian-confluence-token
printf '%s' "your.email@example.com" > ~/.config/atlassian-user-email
read -rsp "Jira API token: " token; echo
printf '%s' "$token" > ~/.config/atlassian-jira-token
read -rsp "Confluence API token: " token; echo
printf '%s' "$token" > ~/.config/atlassian-confluence-token
unset token

Or set environment variables:

export ATLASSIAN_USER_EMAIL_FILE=~/.config/atlassian-user-email
export ATLASSIAN_JIRA_TOKEN_FILE=~/.config/atlassian-jira-token
export ATLASSIAN_CONFLUENCE_TOKEN_FILE=~/.config/atlassian-confluence-token

ATLASSIAN_<PRODUCT>_API_TOKEN is read at a higher priority than the credential store, which is what you want in CI. Keep it process-scoped and never persist it in desktop configuration.


Repository Layout

skills/
  SKILL.md            agent-facing instructions (kept short)
  references/setup.md detailed setup and troubleshooting
  setup.mjs           one-command setup + verification
  atlassian.mjs       CLI and the read-only operations
  jmespath.mjs        projection evaluator (no dependencies)
  server.mjs          MCP stdio server (needs npm install)
  credentials.mjs     credential resolution + config.json TLS
  wincred.mjs         Windows Credential Manager reads, no dependencies
  configure.mjs       interactive rotate/remove
  save-keyring-tokens.mjs
  scripts/check-tokens.sh  credential-store-free validator (curl)
  scripts/run.sh           TLS wrapper for atlassian.mjs
  scripts/unpin-tokens.sh  drop token-file pins from config.json
test/                 node:test suites
DEPENDENCIES.md       why the core has zero dependencies, and how to keep it that way

npm run check syntax-checks every entry point; npm test runs the unit tests; npm run setup -- --check verifies live credentials without changing anything.


Security

Defense in depth

┌─────────────────────────────────────────────────────┐
│              YOUR REQUEST                            │
└──────────────┬──────────────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────────────┐
│  Layer 2: Implementation Enforcement                 │
│  • GET only, paths restricted to an allowlist        │
│  • No custom host or method                          │
│  • Response size-limited, secrets redacted           │
└──────────────┬──────────────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────────────┐
│  Layer 1: Token Scopes                               │
│  • Jira: read:jira-work                            │
│  • Confluence: read:page, read:content-details,     │
│    search:confluence                                 │
│  • Atlassian rejects any write attempt               │
└─────────────────────────────────────────────────────┘

Key guarantees:

  • No writes possible — neither Atlassian nor this code allows write operations.

  • Allowlisted paths — --path accepts only /rest/api/3/... and /wiki/... GETs.

  • Bounded responses — size limits prevent excessive data exfiltration.

  • Secret redaction — common credential patterns are masked in output.

  • Visibility inherited — the runtime can only read content the token account can already access.

⚠️ Supplying a broader token weakens the token layer but does not enable write operations in this code.

See SECURITY.md for vulnerability reporting guidelines.


License

⚠️ Internal Use Only — This software was developed on Toyota hardware during Toyota work hours. It is intended for use by Toyota employees only.

TODO: Confirm the correct license and copyright holder with Toyota's internal IP/Legal team. The current LICENSE file may need updating.

See LICENSE

Available Tools

4 tools
confluence_get_pageA

Read a Confluence page by ID and convert storage HTML to Markdown. This server has no write operations.

NameRequiredDescriptionDefault
page_idYes
projectionNoOptional JMESPath projection to reduce returned fields.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavioral burden. It discloses the conversion behavior (storage HTML to Markdown) and states the server has no write operations, which is helpful. However, it does not mention error handling, response format, or any limits, leaving gaps for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The main purpose is front-loaded, and the read-only clarification is concise and useful. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool with only two parameters and no output schema, the description covers the core purpose and behavioral nuance. It does not explain return structure or error scenarios, but these are less critical given the tool's simplicity. Overall, it is sufficiently complete for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: projection has a description, but page_id does not. The description does not compensate for the missing page_id semantics beyond reiterating 'by ID'. It adds nothing about projection beyond the schema, so minimal value is provided for parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb ('Read') and a specific resource ('Confluence page by ID'), plus a distinctive detail (conversion to Markdown). This distinguishes it from sibling tools like confluence_search and jira_get_issue without needing to inspect the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies usage when a page ID is known, but it does not explicitly contrast with confluence_search or state when NOT to use this tool. The read-only note provides general context, but no alternative routing guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jira_get_issueA

Read one Jira issue. This server has no write operations.

NameRequiredDescriptionDefault
issue_keyYes
projectionNoOptional JMESPath projection to reduce returned fields.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral disclosure burden. It does mention the read-only nature and that the server has no write operations, which is useful context. However, it does not describe error behavior, response format, or what happens when the issue does not exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences, both earning their place. It front-loads the core action and adds the server-wide write constraint without any redundant phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool, the inputs and general action are covered, but the absence of an output schema means the return value is only implied. The description does not clarify what fields are returned or how to interpret the response, leaving a moderate gap for the agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides a pattern for issue_key and a description for projection, but the tool description itself adds no parameter-level explanation. With schema coverage at 50%, the description does not compensate for the undocumented issue_key semantics, though the parameter name is fairly self-explanatory.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('read') and resource ('one Jira issue'), making the tool's purpose unmistakable. It is clearly differentiated from sibling search and Confluence tools by focusing on a single issue retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when a specific issue key is available, but it does not explicitly mention jira_search_issues as the alternative for query-based retrieval. There is no warning against using it for searches or a clear when-not-to-use statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jira_search_issuesB

Search Jira with JQL. Results and fields are bounded; this server has no write operations.

NameRequiredDescriptionDefault
jqlYes
limitNo
projectionNoOptional JMESPath projection to reduce returned fields.

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral disclosure burden. It adds two useful traits: 'Results and fields are bounded' and 'this server has no write operations', which are not present in the schema. However, it omits details like pagination, ordering, rate limits, or error behavior, so transparency is partial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, tight sentence that front-loads the core action and immediately adds a scope limitation. No filler words or redundant repetition of the tool name. Every phrase contributes meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given three parameters, no output schema, and no annotations, the description is not sufficient. It does not describe what a search result looks like, how to construct a valid JQL query, or the effect of 'limit' and 'projection'. The bounded/no-write note is useful but only addresses safety, not invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only 33% of the parameters have schema descriptions (projection). The description clarifies that 'jql' is the Jira Query Language string, but it does not explain the 'limit' parameter or add syntax/format details. Since schema coverage is low, the description should compensate more but does not for two of the three parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('Search') and resource ('Jira'), and correctly implies searching issues via the tool name and JQL mention. It distinguishes from jira_get_issue (which fetches a single issue) and confluence_search (different product), though it does not explicitly say 'issues' or contrast these siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives. The description does not mention jira_get_issue, confluence_search, or any condition that would select one over the other. The only usage hint is 'Search Jira with JQL', which is implied functionality rather than a directive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedconfluence_get_page
    • First observedconfluence_search
    • First observedjira_get_issue
    • First observedjira_search_issues

TDQS

A3.8/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: get versus search for both Jira and Confluence. There is no overlap or ambiguity between any pair, enabling precise tool selection.

Naming Consistency5/5

All tool names follow a consistent product_action pattern with snake_case (e.g., jira_get_issue, confluence_search). The naming is uniform and predictable.

Tool Count5/5

With 4 tools covering two products (Jira and Confluence) each having a get and search operation, the count is well-scoped for a read-only server. No tool feels redundant or missing.

Completeness4/5

The read-only surface provides essential get and search for both products. Minor gaps exist such as bulk fetch or additional metadata endpoints, but core querying needs are well covered.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers