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.
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
uvxmethod may be blocked by Windows Defender Application Control or other security policies. Usepipinstead.
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.exeinstead of justpythonto 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.
get_filter_values(kind, field, project_id, search)
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_issuesto 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: useget_issues(ids=["PROJ-1"])(addincludefor comments, worklogs, links, changelog).search_issuesnow takes typed filter arguments, the defaultpage_sizeis 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 withfields.get_projectsreturnsitemswithage_minutesandstale;get_sync_statusreturns{page, page_size, total, items}with fieldsprojectanderror.JIRA_SYNC_URLis now required (0.1.x defaulted tohttp://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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.