Skip to content

feat(nodes): add tool_jira — JQL search, issue read, create, comment and transition as agent tools #2799

Open

Description

@mithileshgau

Problem Statement

Pipelines and agents have no way to read or write Jira: a triage agent that lists the open P1s for a component, a standup pipeline that summarizes what changed since yesterday, a support agent that files a bug from a conversation, or a release-notes pipeline that reads the issues in a fix version. Jira Cloud exposes all of this over a documented REST API, and there is no Atlassian code anywhere in the repo. tool_http_request can reach the API today, but every pipeline would have to hand-roll basic auth, Atlassian Document Format bodies and the new search pagination. Jira is on RocketRide's GTM list.

Proposed Solution

Add a tool_jira agent-tool node (classType tool, register filter, lanes: {}), mirroring nodes/src/nodes/tool_notion/ (REST client module with no engine imports, API-token auth, the {success, error} result envelope, offline unit tests with faked HTTP).

API basis (Jira Cloud REST API v3, https://developer.atlassian.com/cloud/jira/platform/rest/v3/):

  • Base URL: https://<site>.atlassian.net/rest/api/3
  • Auth: HTTP basic with email:api_token (an unscoped token from https://id.atlassian.com/manage-profile/security/api-tokens). Scoped tokens must go through the https://api.atlassian.com/ex/jira/{cloudId} gateway; out of scope for v1.
  • Search: POST /search/jql (a GET form takes the same parameters) with jql, fields, maxResults (default 50) and nextPageToken. The old /search endpoint is marked deprecated and being removed (CHANGE-2046); Atlassian's KB says it has already been removed from Jira Cloud. The new endpoint returns only issue ids unless fields is passed, returns no total, pages with nextPageToken (tokens expire after 7 days) and sets isLast on the final page.
  • Issues: GET /issue/{key}?fields=..., POST /issue, PUT /issue/{key}
  • Comments: POST /issue/{key}/comment with an ADF body
  • Transitions: GET /issue/{key}/transitions, POST /issue/{key}/transitions with {"transition": {"id": "..."}}
  • Projects: GET /project/search; connection check: GET /myself
  • Text bodies (issue description, comments) are Atlassian Document Format (ADF) in v3. The minimal document is {"type": "doc", "version": 1, "content": [{"type": "paragraph", "content": [{"type": "text", "text": "..."}]}]}. The client needs a small text-to-ADF converter (paragraphs, bullet lists, code blocks) and an ADF-to-text flattener, the way notion_client.py flattens block trees.
  • Rate limits: API-token traffic is governed by Atlassian's burst limits (100 requests per second for GET and POST, 50 for PUT and DELETE, and 20 writes per 2 seconds on one issue); the points-based hourly quota announced for March 2, 2026 applies to Forge, Connect and OAuth apps. A 429 carries Retry-After, and Atlassian says to retry only idempotent calls that carry it.

Suggested tool operations (exposed to agents):

Must-have:

  1. jira_check_connection — GET /myself; returns {ok, account_id, display_name, site}
  2. jira_search — jql (required), max_results (1-100, default from config), next_page_token; returns issues[{key, summary, status, type, assignee, priority, updated, url}] and next_page_token. The client always sends fields for this shape, since the endpoint otherwise returns ids only.
  3. jira_issue_get — key, include_comments (default false), max_comments (default 20); returns {key, summary, status, type, assignee, reporter, priority, labels, fix_versions, created, updated, description_text, comments[{author, created, body_text}], url}
  4. jira_projects_list — returns projects[{key, name, type}], filtered by the allowlist
  5. jira_issue_create — project, issue_type, summary (required); description, labels, priority, assignee_account_id; returns {key, url} (write)
  6. jira_comment_add — key, body (plain text or a markdown subset); returns {comment_id, url} (write)

Stretch:

  1. jira_transitions_list — key; returns transitions[{id, name, to_status}]
  2. jira_issue_transition — key, transition (name or id; a name is resolved through the list); returns {key, status} (write)
  3. jira_issue_update — key; any of summary, labels, priority, assignee_account_id; returns {key, updated_fields} (write)

Config schema (in services.json, field keys tool_jira.*):

  • siteUrl (string, required): https://<site>.atlassian.net, validated as https
  • email (string, required)
  • apiToken (secret, ApiKeyWidget, required)
  • readOnly (boolean, default true): blocks every write tool, the pattern tool_n8n and tool_git use
  • projects (string, default ""): comma-separated project keys the node may touch; empty means all. Use a string, not an array: array-typed params reach Python nodes as JSON text inside a one-element list.
  • maxResults (integer, default 25, clamped to 1-100)
  • createdLabel (string, default ""): a label added to every issue the node creates, for auditability

Env fallback (config wins): ROCKETRIDE_JIRA_SITE_URL, ROCKETRIDE_JIRA_EMAIL, ROCKETRIDE_JIRA_API_TOKEN. Use the ROCKETRIDE_ prefix; the test framework maps only those.

Guardrails:

  • readOnly defaults to true; write tools refuse with a message that names the config field.
  • Project allowlist on search: split off a trailing ORDER BY clause, wrap the rest as project in (<allowlist>) AND (<jql>), then re-append the ORDER BY. No existing tool node has a project allowlist, so this is a new pattern; keep it in the client module with its own tests.
  • Project allowlist on key-based calls: fetch the issue and check fields.project.key before acting. Do not trust the key prefix: an issue moved between projects still resolves under its old key.
  • max_results is capped at 100 in the node regardless of the API maximum; description and comment bodies are capped at 32 KB.
  • No delete, bulk, user-admin, permission or attachment tools.

Error handling: the client raises JiraAPIError(status, messages) and the _run() envelope turns it into {success: false, error}. A 400 on bad JQL returns Jira's errorMessages verbatim so the agent can fix its query. 401 and 403 name the token and project permissions. 404 says the issue was not found or is not visible to this account. 429 honours Retry-After; reads retry up to twice, writes never retry. Reads retry once on 5xx.

Implementation notes:

  • Files: __init__.py, IGlobal.py, IInstance.py, jira_client.py (auth, request, retry, ADF helpers, JQL wrapping), services.json, jira.svg, requirements.txt (requests>=2.34.2; no Jira SDK, the community jira library adds nothing a 300-line client does not), README.md with the generated-params marker pair (params regenerate from services.json via nodes:docs-generate, which runs on develop after merge).
  • Also touch: the credentials stub in packages/ai/src/ai/modules/mcp/credentials.json (./builder nodes:credentials-generate; CI's shell-contract job checks it), an _LLM_MOCK_CREDENTIALS entry in nodes/test/framework/pipeline.py for the services.json smoke test, and a CHANGELOG.md line.
  • The Confluence tool node (separate issue) reuses the basic-auth, retry and ADF helpers. Decide at design review whether they move to a shared module under packages/ai/src/ai/common/ or stay duplicated (about 100 lines); do not import one node from the other.
  • Unit tests: follow nodes/test/tool_notion/test_notion.py (engine stubs, faked requests): paging, fields always sent, ADF round-trips, JQL wrapping with and without ORDER BY, project checks on moved issues, read-only refusals, error mapping, 429 handling. Target 60+ tests.
  • Live test: nodes/test/tool_jira/test_jira_live.py, skipped unless ROCKETRIDE_JIRA_* are set, against a free Atlassian site seeded with one project. Run it at least once before review and record the run in the PR.
  • Test ladder: uvx ruff@0.16.5 check and format --check, ./builder nodes:test --pytest-pattern=jira, python3 scripts/validate-node-readme.py nodes/src/nodes/tool_jira (Python 3.10+).
  • Ship with capabilities: ["invoke", "experimental"] until the live run passes, then drop experimental.

Acceptance criteria:

  • All six must-have tools work against a live Jira Cloud site, recorded in the PR (tool, input, result)
  • jira_search pages past 100 issues with next_page_token and never returns an id-only issue
  • With projects set, a search for another project returns nothing and jira_issue_get on a key from another project is refused, including a key that was moved
  • With readOnly=true (the default) every write tool refuses
  • A comment created from markdown with a bullet list and a code block renders correctly in Jira
  • Bad JQL, bad token, unknown key and 429 each produce a {success: false, error} result
  • README passes validate-node-readme.py; "As a tool" table matches the exposed functions exactly
  • ruff clean, credentials stub present, CHANGELOG line added, CI OK green

Size estimate: about 1,100 lines of node code (client 350, IInstance 450, services.json 120, README 100) plus 700 lines of tests; 12 to 18 person-days.

Open questions:

  • Atlassian's pages do not state whether the Free plan allows REST API tokens; third-party sources say it does. A 15-minute check (free site, token, GET /myself) settles it before anyone starts.
  • Atlassian's create-issue examples use numeric project.id and issuetype.id. project.key and issuetype.name are in wide use but not shown officially; if the live test rejects them, resolve ids through GET /project/{key}, which lists the project's issueTypes.
  • Scoped API tokens and OAuth 2.0 (3LO) are deferred; say so in the README.

Alternatives Considered

  • tool_http_request per pipeline: works, but every pipeline author re-learns basic auth, ADF and search/jql paging, and nothing is discoverable in the canvas.
  • Atlassian's hosted MCP server through tool_mcp_client: fine for an interactive session, but it needs a browser OAuth login per user, which a scheduled pipeline cannot do, and it offers no read-only mode or project scoping.
  • The community jira Python library (3.10.5, BSD): mature, but it pulls in its own dependency set for about six calls, and its error types would need wrapping anyway.

Affected Modules

  • server (C++ engine)
  • client-typescript
  • client-python
  • client-mcp
  • nodes (pipeline)
  • ai
  • vscode

Good community/hackathon candidate (see epic #1522; part of the GTM node integrations epic, #2798). Template node: tool_notion.

Activity

  1. github-actions commented on Oct 23, 2026

    @github-actions
    Contributor
    🤖 Internal: Discord sync marker

    Auto-managed by the Discord notification workflow. Stores the linked Discord message ID and forum thread ID. Do not edit or delete.

  2. added
    featureNew feature or enhancement
    pythonPull requests that update python code
    help wantedExtra attention is needed
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature or enhancementhelp wantedExtra attention is neededmodule:nodesPython pipeline nodespythonPull requests that update python code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions