Skip to main content
Glama
README.md
# jira-mcp

Jira Cloud MCP server built from the skeleton architecture, with Jira-first tools and full REST coverage through a generic Jira API request tool.

## What this solution provides

- Jira-focused MCP tools for common workflows:
  - profile lookup (`jira_get_myself`)
  - project discovery (`jira_list_projects`, `jira_get_project`)
  - issue search and retrieval (`jira_search_issues`, `jira_get_issue`)
  - issue mutation (`jira_create_issue`, `jira_edit_issue`, `jira_transition_issue`, `jira_add_comment`)
- Full Jira REST v3 coverage via:
  - `jira_api_request` (generic method/path/query/body)
  - `jira_operation_request` (operation-key based request for documented high-value endpoints)
- Workflow and schema discovery helper:
  - `jira_query_suggestion_schema_discovery` (task-based tool recommendations with per-tool input schema and examples)
- Existing hardened HTTP transport and auth controls from the skeleton:
  - bearer token gate on `/mcp`
  - request limits and rate limits
  - IP/origin allow-lists
  - optional Vault-backed token verification path

## Jira API sources used

- Jira docs landing page: https://confluence.atlassian.com/jira
- Jira Cloud REST API v3 intro: https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/
- Jira Cloud REST API groups (issues/projects/search/users), plus operation references from Atlassian documentation.

## Architecture

- `src/index.js`: stdio MCP entrypoint
- `src/http/index.js`: HTTP MCP entrypoint
- `src/http/server.js`: streamable HTTP transport with auth/rate-limit/access logs
- `src/mcp/server.js`: Jira tool registration and auth wrapper
- `src/services/targetService.js`: Jira service client (`JiraServiceClient`) and operation catalog
- `src/config/env.js`: environment parsing and validation

## Tool catalog

### Shared behavior for all tools

- Transport and credentials selection:
  - All Jira calls use environment-backed client settings: `JIRA_BASE_URL`, `JIRA_AUTH_MODE`, auth credentials, `JIRA_TIMEOUT_MS`, and `JIRA_API_PREFIX`.
  - `jira_scope_info` and `jira_connection_info` expose app/user scope metadata derived from `APP_NAME` and `MCP_CONFIG_DEFAULT_USER_ID`.
- Mutating authorization gate:
  - If `MCP_ADMIN_AUTH_KEY` is set, mutating operations require a matching `authorizationKey` argument.
- Response envelope (all tools):
  - Success shape:
    ```json
    {
      "content": [{ "type": "text", "text": "{\"ok\":true,\"status\":200,\"data\":{...}}" }]
    }
    ```
  - Error shape:
    ```json
    {
      "content": [{ "type": "text", "text": "{\"ok\":false,\"status\":<code>,\"error\":\"message\"}" }],
      "isError": true
    }
    ```
- Common failure conditions:
  - Jira authentication failures (401/403).
  - Missing or invalid required parameters (schema validation or path params).
  - Jira endpoint not found (404) or unsupported operation key (400).
  - Request timeout at `JIRA_TIMEOUT_MS`.

### Read-only tools

#### jira_connection_info

- Use when: verifying MCP/Jira runtime wiring and auth-mode configuration before any Jira operation.
- Do not use when: you need Jira data payloads (issues/projects) rather than configuration metadata.
- Risk class: read-only, low risk.
- Permissions and prerequisites: no Jira mutation permission needed; Jira credentials may be absent.
- Environment selection behavior: returns server identity, `adminAuthConfigured`, scope model, and Jira client config from env.
- Parameters: none.
- Expected `data` shape:
  - `server`: `{ name, version, adminAuthConfigured, scopeModel }`
  - `jira`: `{ baseUrl, apiPrefix, timeoutMs, authMode, bearerTokenConfigured, basicUsernameConfigured, basicPasswordConfigured }`
- Recommended tools:
  - Prerequisite: none.
  - Follow-up: `jira_health_check`, `jira_get_myself`.
- Example:
  ```json
  { "name": "jira_connection_info", "arguments": {} }
  ```

#### jira_scope_info

- Use when: resolving app/user scoping for Vault token index and Postgres config rows.
- Do not use when: you only need Jira API objects.
- Risk class: read-only, low risk.
- Permissions and prerequisites: no Jira permission required.
- Environment selection behavior: uses `APP_NAME` and supplied `userId` or `MCP_CONFIG_DEFAULT_USER_ID`.
- Parameters:
  - `userId?`: non-empty string.
- Expected `data` shape:
  - `{ appName, userId, userIdPathSegment, postgres: {...}, vault: {...} }`
- Common failures:
  - Invalid empty `userId`.
- Recommended tools:
  - Prerequisite: none.
  - Follow-up: `jira_connection_info`.
- Example:
  ```json
  { "name": "jira_scope_info", "arguments": { "userId": "alice" } }
  ```

#### jira_list_operations

- Use when: discovering supported operation keys for `jira_operation_request`.
- Do not use when: you already know exact path/method and prefer `jira_api_request`.
- Risk class: read-only, low risk.
- Permissions and prerequisites: no mutation permission required.
- Environment selection behavior: independent of Jira auth success; lists locally registered catalog.
- Parameters:
  - `group?`: non-empty string; exact group match (case-insensitive).
  - `method?`: non-empty string; normalized to uppercase.
  - `keyContains?`: non-empty substring match.
- Expected `data` shape:
  - `{ groups: string[], operations: [{ key, method, path, group, description }] }`
- Recommended tools:
  - Prerequisite: `jira_connection_info`.
  - Follow-up: `jira_operation_request`.
- Example:
  ```json
  {
    "name": "jira_list_operations",
    "arguments": { "group": "issues", "method": "get", "keyContains": "issue" }
  }
  ```

#### jira_query_suggestion_schema_discovery

- Use when: you want guidance on which MCP tools to call and in what sequence for a Jira task.
- Do not use when: you already know the exact tool and request shape you need.
- Risk class: read-only, low risk.
- Permissions and prerequisites: none.
- Environment selection behavior: returns recommendations and tool metadata; does not call Jira.
- Parameters:
  - `task?`: non-empty free-text task description.
  - `includeSchemas?`: boolean (default `true`).
  - `includeExamples?`: boolean (default `true`).
  - `includeMutating?`: boolean (default `true`) to include write-capable tools.
- Expected `data` shape:
  - `recommendations`: ordered tool sequences with intent-specific reasoning.
  - `tools`: per-tool metadata, mutability, schema hints, and examples.
  - `notes.mutatingAuthorization`: admin-key behavior summary for mutating calls.
- Recommended tools:
  - Prerequisite: none.
  - Follow-up: suggested tool sequence from the response.
- Example:
  ```json
  {
    "name": "jira_query_suggestion_schema_discovery",
    "arguments": {
      "task": "create issue and move it to done",
      "includeMutating": true
    }
  }
  ```

#### jira_health_check

- Use when: validating live Jira connectivity and credentials quickly.
- Do not use when: you need full profile details with specific field selection.
- Risk class: read-only, low risk.
- Permissions and prerequisites: requires Jira auth that can access `/myself`.
- Environment selection behavior: executes `GET /myself` through configured Jira client.
- Parameters: none.
- Expected `data` shape:
  - Jira HTTP response envelope: `{ method, path, url, status, contentType, data }`.
- Common failures:
  - Invalid Jira base URL.
  - Token/user lacks access.
  - Timeout/network failures.
- Recommended tools:
  - Prerequisite: `jira_connection_info`.
  - Follow-up: `jira_get_myself`.
- Example:
  ```json
  { "name": "jira_health_check", "arguments": {} }
  ```

#### jira_get_myself

- Use when: retrieving the current Jira principal profile.
- Do not use when: checking generic connectivity only (`jira_health_check` is lighter intent-wise).
- Risk class: read-only, low risk.
- Permissions and prerequisites: authenticated Jira identity with `/myself` access.
- Environment selection behavior: resolved through active env-based Jira auth mode.
- Parameters: none.
- Expected `data` shape:
  - Jira HTTP response envelope with profile payload in `data`.
- Recommended tools:
  - Prerequisite: `jira_health_check`.
  - Follow-up: `jira_list_projects`, `jira_search_issues`.
- Example:
  ```json
  { "name": "jira_get_myself", "arguments": {} }
  ```

#### jira_list_projects

- Use when: searching/browsing projects with pagination.
- Do not use when: you already know one project key/id (`jira_get_project`).
- Risk class: read-only, low risk.
- Permissions and prerequisites: Jira project browse permission.
- Environment selection behavior: maps to `GET /project/search` with query params.
- Parameters:
  - `startAt?`: integer, `>= 0`.
  - `maxResults?`: integer, `>= 1`.
  - `query?`: string.
  - `keys?`: array of non-empty strings.
  - `orderBy?`: string.
- Expected `data` shape:
  - Jira HTTP response envelope with page payload (`values`, pagination metadata).
- Common failures:
  - Invalid numeric bounds.
  - Unauthorized project visibility.
- Recommended tools:
  - Prerequisite: `jira_get_myself`.
  - Follow-up: `jira_get_project`, `jira_search_issues`.
- Example:
  ```json
  {
    "name": "jira_list_projects",
    "arguments": { "startAt": 0, "maxResults": 25, "query": "platform", "orderBy": "name" }
  }
  ```

#### jira_get_project

- Use when: retrieving one project by key or id.
- Do not use when: you need cross-project discovery (`jira_list_projects`).
- Risk class: read-only, low risk.
- Permissions and prerequisites: Jira access to target project.
- Environment selection behavior: calls `GET /project/{projectIdOrKey}`.
- Parameters:
  - `projectIdOrKey`: non-empty string (required).
  - `expand?`: string.
- Expected `data` shape:
  - Jira HTTP response envelope with project object.
- Common failures:
  - Missing `projectIdOrKey`.
  - Unknown project key/id (404).
- Recommended tools:
  - Prerequisite: `jira_list_projects`.
  - Follow-up: `jira_search_issues`.
- Example:
  ```json
  { "name": "jira_get_project", "arguments": { "projectIdOrKey": "ENG" } }
  ```

#### jira_search_issues

- Use when: executing JQL search with field selection and pagination token support.
- Do not use when: retrieving a single known issue key (`jira_get_issue`).
- Risk class: read-only from business perspective, medium risk operationally (expensive queries).
- Permissions and prerequisites: Jira browse access for target projects/issues.
- Environment selection behavior: maps to `POST /search/jql` with body.
- Parameters:
  - `jql`: non-empty string (required).
  - `maxResults?`: integer, `>= 1`.
  - `nextPageToken?`: string.
  - `fields?`: array of non-empty strings.
  - `expand?`: array of non-empty strings.
  - `reconcileIssues?`: array of integers.
  - `failFast?`: boolean.
- Expected `data` shape:
  - Jira HTTP response envelope with search results (`issues`, paging metadata, optional token).
- Common failures:
  - Invalid JQL syntax.
  - Excessive payloads/permissions constraints.
- Recommended tools:
  - Prerequisite: `jira_get_myself`.
  - Follow-up: `jira_get_issue`, `jira_transition_issue`.
- Example:
  ```json
  {
    "name": "jira_search_issues",
    "arguments": {
      "jql": "project = ENG ORDER BY updated DESC",
      "maxResults": 20,
      "fields": ["summary", "status", "assignee"]
    }
  }
  ```

#### jira_get_issue

- Use when: fetching one issue by key/id with optional field restriction.
- Do not use when: querying broad sets (`jira_search_issues`).
- Risk class: read-only, low risk.
- Permissions and prerequisites: Jira issue browse permission.
- Environment selection behavior: calls `GET /issue/{issueIdOrKey}`.
- Parameters:
  - `issueIdOrKey`: non-empty string (required).
  - `fields?`: array of non-empty strings.
  - `expand?`: string.
  - `updateHistory?`: boolean.
- Expected `data` shape:
  - Jira HTTP response envelope with issue object.
- Common failures:
  - Unknown issue key/id.
  - Field visibility restrictions.
- Recommended tools:
  - Prerequisite: `jira_search_issues`.
  - Follow-up: `jira_edit_issue`, `jira_add_comment`, `jira_transition_issue`.
- Example:
  ```json
  {
    "name": "jira_get_issue",
    "arguments": { "issueIdOrKey": "ENG-123", "fields": ["summary", "status"] }
  }
  ```

### Mutating tools

> Safety warning: these operations can create or modify Jira data. Prefer calling read-only discovery tools first, validate issue/project identifiers, and use least-privilege credentials.

#### jira_create_issue

- Use when: creating a new issue with Jira field payload.
- Do not use when: unsure about required field schema for the issue type/project.
- Risk class: mutating, high risk.
- Permissions and prerequisites:
  - Jira create-issue permission in target project.
  - `authorizationKey` required when `MCP_ADMIN_AUTH_KEY` is configured.
- Environment selection behavior: calls `POST /issue` under configured `JIRA_API_PREFIX`.
- Parameters:
  - `fields`: object (required).
  - `update?`: object.
  - `properties?`: array.
  - `transition?`: object.
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope with created issue identifiers.
- Common failures:
  - Missing required Jira fields.
  - Unauthorized mutation key.
- Recommended tools:
  - Prerequisite: `jira_get_project`, `jira_list_operations`.
  - Follow-up: `jira_get_issue`, `jira_add_comment`.
- Example:
  ```json
  {
    "name": "jira_create_issue",
    "arguments": {
      "fields": {
        "project": { "key": "ENG" },
        "issuetype": { "name": "Task" },
        "summary": "Investigate webhook retry behavior"
      },
      "authorizationKey": "<admin-key-if-required>"
    }
  }
  ```

#### jira_edit_issue

- Use when: updating issue fields or applying Jira update operations.
- Do not use when: uncertain about field editability or transition requirements.
- Risk class: mutating, high risk.
- Permissions and prerequisites:
  - Jira edit-issue permission.
  - `authorizationKey` gate when configured.
- Environment selection behavior: calls `PUT /issue/{issueIdOrKey}`.
- Parameters:
  - `issueIdOrKey`: non-empty string (required).
  - `body`: object (required).
  - `query?`: object.
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope (often 204/no content).
- Common failures:
  - Invalid field updates.
  - Unauthorized mutation key.
- Recommended tools:
  - Prerequisite: `jira_get_issue`.
  - Follow-up: `jira_get_issue`.
- Example:
  ```json
  {
    "name": "jira_edit_issue",
    "arguments": {
      "issueIdOrKey": "ENG-123",
      "body": { "fields": { "summary": "Updated summary" } },
      "authorizationKey": "<admin-key-if-required>"
    }
  }
  ```

#### jira_transition_issue

- Use when: moving an issue to a new workflow state.
- Do not use when: transition id has not been validated for this issue.
- Risk class: mutating, high risk.
- Permissions and prerequisites:
  - Jira transition permission and valid transition id.
  - `authorizationKey` gate when configured.
- Environment selection behavior: calls `POST /issue/{issueIdOrKey}/transitions`.
- Parameters:
  - `issueIdOrKey`: non-empty string (required).
  - `transitionId`: positive integer or non-empty string (required).
  - `fields?`: object.
  - `update?`: object.
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope (often 204/no content).
- Common failures:
  - Invalid transition id for current issue state.
  - Unauthorized mutation key.
- Recommended tools:
  - Prerequisite: `jira_get_issue`, `jira_operation_request` with transition-list operation.
  - Follow-up: `jira_get_issue`.
- Example:
  ```json
  {
    "name": "jira_transition_issue",
    "arguments": {
      "issueIdOrKey": "ENG-123",
      "transitionId": "31",
      "authorizationKey": "<admin-key-if-required>"
    }
  }
  ```

#### jira_add_comment

- Use when: posting discussion/worklog context to an issue.
- Do not use when: you need structured field updates instead of comment text/body.
- Risk class: mutating, medium risk.
- Permissions and prerequisites:
  - Jira comment permission on target issue.
  - `authorizationKey` gate when configured.
- Environment selection behavior: calls `POST /issue/{issueIdOrKey}/comment`.
- Parameters:
  - `issueIdOrKey`: non-empty string (required).
  - `body`: any JSON value accepted by Jira comment API (required).
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope with created comment data.
- Common failures:
  - Malformed comment body schema.
  - Unauthorized mutation key.
- Recommended tools:
  - Prerequisite: `jira_get_issue`.
  - Follow-up: `jira_get_issue`.
- Example:
  ```json
  {
    "name": "jira_add_comment",
    "arguments": {
      "issueIdOrKey": "ENG-123",
      "body": {
        "type": "doc",
        "version": 1,
        "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Investigating now." }] }]
      },
      "authorizationKey": "<admin-key-if-required>"
    }
  }
  ```

#### jira_operation_request

- Use when: executing a known, documented operation key from server catalog.
- Do not use when: operation key is unknown or you need arbitrary Jira endpoints (`jira_api_request`).
- Risk class: mixed; read-only or mutating depending on operation method.
- Permissions and prerequisites:
  - `operationKey` must exist in `jira_list_operations` output.
  - `authorizationKey` required if resolved method is mutating.
- Environment selection behavior:
  - Resolves path template params and executes against configured Jira client.
  - Uses operation-specific method/path from server catalog.
- Parameters:
  - `operationKey`: non-empty string (required).
  - `pathParams?`: object with primitive values (`string|number|boolean`).
  - `query?`: object with `string|number|boolean|string[]` values.
  - `body?`: any JSON value.
  - `headers?`: object of string headers.
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope.
- Common failures:
  - Unknown `operationKey` (400).
  - Missing required path template value.
  - Unauthorized mutation key for mutating methods.
- Safety warnings:
  - Validate the method returned by `jira_list_operations` before executing.
  - Treat mutating keys (`POST/PUT/PATCH/DELETE`) as destructive.
- Recommended tools:
  - Prerequisite: `jira_list_operations`.
  - Follow-up: read tool matching affected resource (`jira_get_issue`, `jira_get_project`).
- Example:
  ```json
  {
    "name": "jira_operation_request",
    "arguments": {
      "operationKey": "issueGet",
      "pathParams": { "issueIdOrKey": "ENG-123" }
    }
  }
  ```

#### jira_api_request

- Use when: you need full Jira REST coverage beyond first-class wrappers.
- Do not use when: a dedicated strongly-typed tool already exists (prefer safer wrappers first).
- Risk class: mixed; potentially high risk for mutating methods.
- Permissions and prerequisites:
  - Valid Jira endpoint path and schema knowledge required.
  - `authorizationKey` required when `method` is `POST|PUT|PATCH|DELETE` and admin key is configured.
- Environment selection behavior:
  - `method` normalized to uppercase.
  - `path` normalized to leading slash and resolved under `JIRA_API_PREFIX` unless already `/rest/api/...`.
- Parameters:
  - `method`: non-empty string (required).
  - `path`: non-empty string (required).
  - `query?`: object with `string|number|boolean|string[]` values.
  - `body?`: any JSON value.
  - `headers?`: object of string headers.
  - `authorizationKey?`: non-empty string.
- Expected `data` shape:
  - Jira HTTP response envelope.
- Common failures:
  - Invalid HTTP method/path.
  - Jira validation errors for body/query.
  - Unauthorized mutation key.
- Safety warnings:
  - This tool can call destructive endpoints (for example delete issue).
  - Confirm endpoint semantics in Atlassian docs before executing mutating methods.
- Recommended tools:
  - Prerequisite: `jira_connection_info`, `jira_list_operations`.
  - Follow-up: resource-specific read tool for verification.
- Example:
  ```json
  {
    "name": "jira_api_request",
    "arguments": {
      "method": "GET",
      "path": "/issue/ENG-123",
      "query": { "fields": ["summary", "status"] }
    }
  }
  ```

## Registering the MCP server

### VS Code / local stdio

```json
{
  "mcpServers": {
    "jira-mcp": {
      "command": "npm",
      "args": ["run", "start:stdio"],
      "cwd": "/Users/lesterjohn/Documents/GitHub/jira-mcp"
    }
  }
}
```

### HTTP transport

Run:

```bash
npm run start:http
```

Default URLs:

- MCP: `http://127.0.0.1:3000/mcp`
- Health: `http://127.0.0.1:3000/healthz`

## Environment variables

### Core

- `APP_NAME` (default `jira`)
- `MCP_SERVER_NAME` (default `jira-mcp`)
- `MCP_SERVER_VERSION`
- `MCP_ADMIN_AUTH_KEY`
- `MCP_TRANSPORT_MODE` (`stdio`, `http`, `both`)

### Jira service integration

- `JIRA_BASE_URL` (e.g. `https://your-domain.atlassian.net`)
- `JIRA_TIMEOUT_MS`
- `JIRA_AUTH_MODE` (`none`, `bearer`, `basic`)
- `JIRA_BEARER_TOKEN`
- `JIRA_BASIC_USERNAME`
- `JIRA_BASIC_PASSWORD` (use Jira API token for basic auth)
- `JIRA_API_PREFIX` (default `/rest/api/3`)

### HTTP transport gate

- `MCP_HTTP_HOST`, `MCP_HTTP_PORT`, `MCP_HTTP_PATH`, `MCP_HTTP_HEALTH_PATH`
- `MCP_HTTP_AUTH_MODE` (`token`)
- `MCP_HTTP_AUTH_TOKENS`
- `MCP_HTTP_ALLOWED_ORIGINS`
- `MCP_HTTP_ALLOWED_IPS`
- `MCP_HTTP_MAX_BODY_BYTES`
- `MCP_HTTP_RATE_LIMIT_WINDOW_MS`
- `MCP_HTTP_RATE_LIMIT_MAX_REQUESTS`

### Postgres / Vault support (retained from skeleton)

- `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`
- `VAULT_ADDR`, `VAULT_TOKEN`

## Quick start

1. Install dependencies: `npm install`
2. Copy `.env.example` to `.env`
3. Fill in Jira credentials (`JIRA_BASE_URL`, auth variables)
4. Start server:
   - stdio: `npm run start:stdio`
   - HTTP: `npm run start:http`
5. Run tests: `npm test`

## External Services Mode

This repository keeps the skeleton's app-only mode for external infrastructure, including `docker-compose.external.yml`.

Use this mode when Vault and Postgres are managed outside this repository.

Required environment variables include:

- `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`
- `VAULT_ADDR`, `VAULT_TOKEN`

Run:

```bash
docker compose -f docker-compose.external.yml up -d
```

## Notes on "full coverage"

Jira REST v3 has a very large endpoint surface. This solution provides practical full coverage by combining:

- high-value first-class tools for common Jira workflows
- operation-key execution for curated documented endpoints
- unrestricted Jira REST pass-through via `jira_api_request`

That means any Jira REST path documented by Atlassian can be called through MCP without waiting for a dedicated wrapper tool.

## License

This project is licensed under the MIT License. See `LICENSE`.