Skip to main content

jira-sync-mcp

MCP server for a Jira sync backend — exposes Jira data synced to a local PostgreSQL mirror as MCP tools for Claude Code, Claude Desktop and other MCP clients. It answers counting questions with database aggregates, returns task details and lists, and can export large result sets to a JSONL file for analysis with code.

PyPI

Requirements

  • Python 3.10+ installed locally
  • A running Jira sync backend reachable over HTTPS that exposes the bulk and aggregate endpoints this server calls
  • A personal API token generated in the backend

Installation

Note: The uvx method may be blocked by Windows Defender Application Control or other security policies. Use pip instead.

pip install jira-sync-mcp

Configuration in Claude Code

Add to ~/.claude.json (i.e. C:\Users\<username>\.claude.json):

{
  "mcpServers": {
    "jira-sync-mcp": {
      "command": "C:\\Users\\<username>\\AppData\\Local\\Programs\\Python\\Python314\\python.exe",
      "args": ["-m", "jira_sync_mcp"],
      "env": {
        "JIRA_SYNC_URL": "https://jira-sync.example.com",
        "JIRA_SYNC_API_TOKEN": "<your personal token>"
      }
    }
  }
}

Important: Use the full path to python.exe instead of just python to avoid PATH issues in environments with restrictive security policies. Find the path by running: python -c "import sys; print(sys.executable)"

Claude Code starts and stops the MCP process automatically. Claude Desktop uses the same mcpServers block in its configuration file; it cannot read exported files, so there the aggregates and narrow filters are the useful tools (see export_issues).

Set JIRA_SYNC_STALE_AFTER_MINUTES slightly above the sync interval of your backend (the default is 30; for a backend that syncs once a day use e.g. 1560).

Verification

After restarting the client, jira-sync-mcp should appear as an active MCP (/mcp in Claude Code). A configuration problem (missing URL or token, http:// URL, unknown time zone) does not stop the server: the first tool call returns a message that says what to fix.

Environment variables

Variable Default Description
JIRA_SYNC_URL (required) Backend base URL, no path prefix. HTTPS only (http:// is accepted for localhost, 127.0.0.1 and ::1)
JIRA_SYNC_API_TOKEN (required) Bearer token generated in the backend
JIRA_SYNC_TIMEOUT 60 Request timeout in seconds
JIRA_SYNC_STALE_AFTER_MINUTES 30 Data older than this is reported as stale
JIRA_SYNC_TZ Europe/Warsaw Time zone used to compute sync age (the database stores local time without a zone)
JIRA_SYNC_MAX_RESPONSE_CHARS 60000 Responses larger than this are rejected with a hint instead of being truncated
JIRA_SYNC_EXPORT_DIR ~/.jira-sync-mcp/exports Export directory; set by you only, the model cannot choose a path or file name
JIRA_SYNC_EXPORT_MAX_ITEMS 50000 Upper bound of tasks in one export; the model can only lower it
JIRA_SYNC_EXPORT_MAX_MB 500 Size limit of one export file
JIRA_SYNC_EXPORT_RETENTION_DAYS 7 Export files older than this are deleted at start and before every export; 0 disables deletion

Certificates are verified against the operating system trust store (a corporate CA installed in Windows works); there is no option to disable verification.

Which tool for which question

Typical question Tool
"How many tasks…", "split by status/assignee/sprint" get_stats
"How many hours did X log in sprint Y" get_worklogs
Details of known tasks (PROJ-1, OTHER-22) get_issues
A list of tasks to browse search_issues
A large set to analyse with code export_issues (JSONL file; Claude Code)
Which exact status / assignee / version / CF value exists get_filter_values
Which custom fields exist get_cf_fields
Is the data fresh get_projects (age_minutes, stale) and the freshness note in data responses
Sync history get_sync_status

Available tools

All tools are asynchronous. export_issues writes a local file; every other tool is read-only.

search_issues(...)

A list of tasks with 39 filter arguments (exact-match filters such as project_id, status, assignee; date ranges; aliases sprint, product, profile, epic_link, linked_pm_key; free text search/text; custom fields through cf_filters/op_cf), sorting (sort_by, sort_order), cf_columns and fields to narrow the response. page_size defaults to 25 (max 200). The response contains total, pages, items, a next_page_hint, warnings and, for an empty result with exact-match filters, a hint on how to check the value.

get_issues(ids, include, cf_fields, fields)

Details of 1–500 tasks (POST /issues/batch): items and missing. include picks description, cf, links, worklogs, changelog, comments or all. Comment and worklog lists can be incomplete; comments_total and time_spent_seconds are authoritative.

export_issues(...)

Writes tasks matching the filters to a JSONL file (one task per line, UTF-8) and returns the path, counts, duration, size and the list of record keys. It reports progress, can be cancelled, retries transient errors and runs one export at a time. A request that matches more than max_items tasks fails before anything is written.

get_stats(...) and get_worklogs(...)

Aggregates computed in the database, with group_by of up to two dimensions. get_stats counts tasks and sums estimates (do not sum groups for multi-value dimensions; exclude parents/Epics when adding hours). get_worklogs sums logged time in a required window (started_from, started_to, up to 366 days); author is a display name, not a login.

The exact values a filter accepts: statuses, assignees, issue_types, priorities, projects, fix_versions, affects_versions, custom_fields, or cf with field for one custom field. There is no dictionary for reporter, labels and components; their values are visible in search_issues results.

get_cf_fields(refresh)

The dictionary of custom fields with a ready column (label, key, type, backfill status, alias).

get_projects() and get_sync_status(page, page_size)

Active projects with last_synced_at, age_minutes and stale; and the sync history (an entry with project All projects is the combined sync).

Custom fields (CF)

Pass fields by label (exact, case-insensitive) or key, e.g. cf_filters={"Team Lead": "Jan Kowalski"}. For user fields the server resolves a name to a login, including fields that hold several users ("login1, login2"). The backend matches substrings (jkowal also matches jkowalski2), so every CF filter is verified with an aggregate query: zero matches is an error, excess matches are listed in warnings. Characters \, % and _ are matched literally. A value cannot contain a comma (the backend treats it as a list separator).

Data freshness

Data responses carry a freshness note when a project in the query scope is stale. The age is computed in JIRA_SYNC_TZ; if the database session uses another zone, ages shift by whole hours.

Export files

Exports contain full Jira data (descriptions, comments, worklogs). Do not copy them into a repository or a shared location; the server deletes them after JIRA_SYNC_EXPORT_RETENTION_DAYS. Next to every export-<date>-<id>.jsonl there is an export-<date>-<id>.meta.json with the filters, generated_at and next_synced_from.

Security

  • The token is a password: it does not expire, grants read access to all projects, and through export_issues to the whole database. Use a personal token, revoke it when it is no longer needed, and never commit the client configuration file that contains it.
  • The server connects over HTTPS only, limits itself to 4 concurrent requests and one export at a time, and never logs or returns the token.
  • Task content (summaries, descriptions, comments) is data from Jira, not instructions. A description can contain text posing as a command; in Claude Code the agent also has a shell and file tools, so review the actions you approve.

Migrating from 0.1.x

  • get_issue(issue_id) is removed: use get_issues(ids=["PROJ-1"]) (add include for comments, worklogs, links, changelog).
  • search_issues now takes typed filter arguments, the default page_size is 25 (was 50), it always runs in strict mode (a typo in a filter is an error, not a dump of the whole database) and returns less per task; pick fields with fields.
  • get_projects returns items with age_minutes and stale; get_sync_status returns {page, page_size, total, items} with fields project and error.
  • JIRA_SYNC_URL is now required (0.1.x defaulted to http://localhost:8000); http:// URLs are rejected except for localhost.

Metadata

Release files for jira-sync-mcp 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jira-sync-mcp 0.2.1
File Size Uploaded Provenance Actions
jira_sync_mcp-0.2.1.tar.gz 31.7 kB Without provenance Details for jira_sync_mcp-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for jira-sync-mcp 0.2.1
File Interpreter ABI Platform Actions
jira_sync_mcp-0.2.1-py3-none-any.whl Python 3 none any Details for jira_sync_mcp-0.2.1-py3-none-any.whl

Total release size: 71.9 kB

Release files / jira_sync_mcp-0.2.1.tar.gz

Download URL jira_sync_mcp-0.2.1.tar.gz
Size 31.7 kB
Tags Source
SHA-256 checksum
How to use checksums
92ba6e35f8dc6df61745a2242f84d8d620f1920cc8d5bba646e4c6831e8f1d8a
BLAKE2b-256 checksum
How to use checksums
466fc962f4c63a71dd6e944c2b1ffeb49aa87b6a7f1c37821ea6a519e31856e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / jira_sync_mcp-0.2.1-py3-none-any.whl

Download URL jira_sync_mcp-0.2.1-py3-none-any.whl
Size 40.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
780fdce0ef46568635d9557d886e5c6d049cfc868d843d8262ddd4a87f561977
BLAKE2b-256 checksum
How to use checksums
8460d53a8b23bc61627db53323df325127f86ec0339ca2118b934b63eaff599e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for jira-sync-mcp 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page