jira-mcp
by LesterAJohn
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`.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues