jiradatacenter-mcp
MCP server for Jira Data Center / Server (self-hosted Jira, REST API v2)— exposes core work-item project-management operations (platform + Agile)as MCP tools.
MSPbots Connector
The MCP Gateway built for MSPs: visible, controlled, and your data stays where it belongs.
MSPbots Connector gives your AI clients one MCP URL to reach your entire MSP stack (RMM, PSA, documentation, security, finance), and gives you control over who can call which tool and a record of everything that was called.
Hosted service: connect.mspbots.ai · Free to use.
Why Connector

| Visible | Every tool call is logged: who, which vendor, when. Usage dashboard, CSV export, SIEM streaming. |
| Controlled | Role-based, per-tool allowlist. Deny by default. |
| Protected | Credentials encrypted per record. AI clients never see your vendor passwords or tokens. |
| MSP-native | Built for the MSP stack only: RMM, PSA, documentation, security, finance. |
Quick start
- Sign up at connect.mspbots.ai.
- Connect your vendors. Pick from 150+ connectors and authorize each one on the vendor's own page, or bring your own API keys. No extra vendor accounts needed.
- Set access. Create roles and decide which tools each role may call. Nothing is allowed until you allow it.
- Add your MCP URL to your AI client. Copy the URL from your Connector dashboard into Claude, ChatGPT, Cursor, VS Code, Gemini, Codex, or any MCP-capable client.
- Ask your AI to do real work, and watch every call appear in the audit log.
Features
Unified gateway
- One MCP URL for all your AI clients
- 150+ connectors across the MSP stack
- Custom MCP servers supported, free
- Authorization happens on each vendor's own page; the AI never sees passwords or tokens
- Bring your own credentials: use the vendor API keys you already have
- Multiple accounts per app; connect once, reuse across AI clients
- Tool search: finds the right action for the task
- One sign-in; vendor credentials are injected behind the scenes and OAuth tokens refresh automatically
Visibility
- Audit log for every tool call (who, which vendor, when)
- Usage dashboard: call volume, top vendors, error rate, per-user activity
- Export audit logs to CSV, or stream to Loki, Graylog, or LogScale (SIEM)
- Optional recording of tool arguments and result summaries (off by default, enabled per organization)
Control
- Per-role, per-tool allowlist, deny by default
- owner / admin / member roles
- SCIM provisioning with Entra ID, Okta, JumpCloud, and Google Workspace
Security
- Credentials encrypted one record at a time (AES-256-GCM, per-record key)
- AI clients authenticate with OAuth 2.1 + PKCE
- Vendor responses are scanned for prompt-injection patterns and returned as structured data. This is one layer of defense, not a guarantee against every attack.
- Static egress IP for customer firewall and API allowlisting
Pricing
Free.
Links: connect.mspbots.ai · mspbots.ai
Overview
- Stateless HTTP service. No credentials are ever persisted — each requestsupplies its own site URL and Basic Auth credentials via headers, usedonly for the lifetime of that single request.
- Supports concurrent requests; per-request credential isolation is donevia Python
contextvars, not a global/shared client instance. - Entry points:
POST /mcp(MCP protocol) andGET /health(health check). - Default port:
8080(configurable viaMCP_HTTP_PORT).
Scope
15 tools, trimmed down from a prior 29-tool build (2026-08-07). The15 kept tools focus on core issue/search/project/user/agile-sprintoperations — full issue CRUD + comments + sub-tasks, JQL search, projectlookups, user lookups, and read-only agile board/sprint operations.Dropped in this trim: the niche metadata-lookup categories(issuetype, priority, jql autocomplete, customfields) and theless-common bulk/sync-oriented tools (version project-versionmanagement, worklog sync-since-timestamp endpoints), plus 2 of the 5agile tools (jira_agile_get_board, jira_agile_get_sprint — single-entity lookups that overlapped with the kept list-oriented board/sprinttools).
| Category | Kept tools | Notes |
|---|---|---|
| issue | get/create/edit/delete issue, get/add comment, get sub-tasks (7) | kept as-is |
| search | search via JQL (1) | kept as-is |
| project | get all projects, get project (2) | kept as-is |
| user | get user, find users (2) | kept as-is |
| agile | get all boards, get all sprints for board, get issues for sprint (3) | kept 3 of 5; dropped get_board and get_sprint |
Everything else — customfields, issuetype, jql, priority,version, worklog (6 whole modules), plus jira_agile_get_board andjira_agile_get_sprint from agile.py — was removed from this build.
The original 214-tool full-WADL build was trimmed to 29 tools on2026-08-04. MSPbots' own stored integration config for this vendor is apre-generic-framework (legacy) integration — its 17 configured endpointentries return an entirely empty apiConfig (real endpoint logic lives inbackend Java code, not the generic config API), so there's no per-endpointmethod/path to reverse-engineer directly. The 17 endpoint names were usedas the category guide instead (Issue Search, Worklog, subtasks, User,request/Issue Comment, Project (Version), Board Sprint, Issuetype,Customfield, Priority, AutoCompleteData — "Queues"/"Queues Issue" map toJira Service Desk and "Tempo Worklog" to the third-party Tempo plugin,neither of which this REST-v2-platform-+-Agile-only server implements, sothose three are not covered), then for each matched category kept the oneor two operations that fit that name plus minimal same-category CRUD,capped at 30 total:
| Category | Kept tools (2026-08-04) | Why |
|---|---|---|
| issue | get/create/edit/delete issue, get/add comment, get sub-tasks (7) | core work-item CRUD + "Issue Comment"/"request Comment" + "subtasks" |
| worklog | get ids deleted/modified since, get worklogs for ids (3) | matches MSPbots' incremental-sync pattern for "Worklog" more closely than per-issue worklog CRUD |
| agile | get all boards, get board, get all/one sprint for board, get issues for sprint (5) | "Board Sprint" |
| version | get paginated, create, delete, get by id (4) | "Project Version" |
| project | get all projects, get project (2) | "Project" |
| issuetype | get all types, get by id (2) | "Issuetype" |
| user | get user, find users (2) | "User" |
| customfields | get custom fields (1) | "Customfield" |
| priority | get priorities (1) | "Priority" |
| search | search via JQL (1) | "Issue Search" |
| jql | get auto-complete data (1) | "AutoCompleteData" |
Everything else from the original 214-tool build — attachment, comment(the standalone properties-only category; real comment CRUD lives inissue), component, customfieldoption, dashboard, field, filter,group, groups, groupuserpicker, issuelink(Type), mypermissions,mypreferences, myself, permissions, projectcategory,projectvalidate, resolution, role, securitylevel, serverinfo,status, statuscategory (24 categories, ~184 tools) — was removed asunused by MSPbots and out of scope for this server's purpose.
Original sourcing (for context on where the removed categories came from,and where to look if one needs to be re-added):
- Platform API: parsed from Atlassian's official machine-readable WADLspec for Jira 9.4.0(
https://docs.atlassian.com/software/jira/docs/api/REST/9.4.0/jira-rest-plugin.wadl). - Agile API: manually curated from Atlassian's HTML docs at
https://docs.atlassian.com/jira-software/REST/9.4.0/— no WADL ispublished for this API.
Authentication
Jira Data Center/Server uses HTTP Basic Authentication(Authorization: Basic base64(username:password)) — confirmed againstthe credentials MSPbots stores for this integration (its token field isliterally base64(username:password), not a separate secret). Thisserver builds that header itself from the raw username/password on everyrequest; the site's base URL is also per-tenant (each MSPbots tenant maypoint at a different Jira instance), so it is supplied as a header too,not a fixed environment variable.
HEADER authentication parameters
| Header | Type | Required | Default | Allowed values | Description | Example |
|---|---|---|---|---|---|---|
X-Jira-Site |
string | Yes | None | None | Jira instance address (domain or full URL; if the protocol is omitted, https:// is added automatically) | jira.example.com |
X-Jira-Username |
string | Yes | None | None | Basic Auth username | api_user |
X-Jira-Password |
string | Yes | None | None | Basic Auth password | Sample_Passw0rd! |
Missing any header returns 401:
{
"error": "Missing credentials",
"message": "This server requires the X-Jira-Site, X-Jira-Username and X-Jira-Password headers",
"required_headers": ["X-Jira-Site", "X-Jira-Username", "X-Jira-Password"],
"optional_headers": []
}
Environment Variables
| Variable | Type | Required | Default | Description |
|---|---|---|---|---|
MCP_HTTP_PORT |
int | No | 8080 |
HTTP listen port |
MCP_HTTP_HOST |
string | No | 0.0.0.0 |
HTTP listen address |
MCP Endpoint
POST /mcp— MCP protocol (streamable HTTP transport)GET /health— health check, returns{"status": "ok"}(pure local probe; does not depend on Jira availability)
Tool List
Tool names are jira_<category>_<operationId>, derived from the WADL<method id="..."> / manually-curated Agile operation_id. bodyparameters are accepted as a generic dict — see the Jira Server RESTAPI reference (linked below) for each resource's exact JSON schema.
| Category | Tool | Description | Method + Path | Params |
|---|---|---|---|---|
| agile | jira_agile_get_all_boards |
Get all boards. | GET /rest/agile/1.0/board | start_at(optional), max_results(optional), type(optional), name(optional), project_key_or_id(optional) |
| agile | jira_agile_get_all_sprints_for_board |
Get all sprints for a board. | GET /rest/agile/1.0/board/{boardId}/sprint | board_id(required), start_at(optional), max_results(optional), state(optional) |
| agile | jira_agile_get_issues_for_sprint |
Get issues for sprint. | GET /rest/agile/1.0/sprint/{sprintId}/issue | sprint_id(required), start_at(optional), max_results(optional), jql(optional), validate_query(optional), fields(optional), expand(optional) |
| issue | jira_issue_add_comment |
Adds a new comment to an issue. | POST /rest/api/2/issue/{issueIdOrKey}/comment | issue_id_or_key(required), body(required), expand(optional) |
| issue | jira_issue_create_issue |
Creates an issue or a sub-task from a JSON representation. | POST /rest/api/2/issue | body(required), update_history(optional) |
| issue | jira_issue_delete_issue |
Delete an issue. | DELETE /rest/api/2/issue/{issueIdOrKey} | issue_id_or_key(required), delete_subtasks(optional) |
| issue | jira_issue_edit_issue |
Edits an issue from a JSON representation. | PUT /rest/api/2/issue/{issueIdOrKey} | issue_id_or_key(required), body(required), notify_users(optional) |
| issue | jira_issue_get_comments |
Returns all comments for an issue. | GET /rest/api/2/issue/{issueIdOrKey}/comment | issue_id_or_key(required), start_at(optional), max_results(optional), order_by(optional), expand(optional) |
| issue | jira_issue_get_issue |
Returns a full representation of the issue for the given issue key. | GET /rest/api/2/issue/{issueIdOrKey} | issue_id_or_key(required), fields(optional), expand(optional), properties(optional), update_history(optional) |
| issue | jira_issue_get_sub_tasks |
Returns an issue's subtask list. | GET /rest/api/2/issue/{issueIdOrKey}/subtask | issue_id_or_key(required) |
| project | jira_project_get_all_projects |
Returns all projects which are visible for the currently logged in user. If no user is logged in, it returns the. | GET /rest/api/2/project | expand(optional), recent(optional), include_archived(optional), browse_archive(optional) |
| project | jira_project_get_project |
Contains a full representation of a project in JSON format. | GET /rest/api/2/project/{projectIdOrKey} | project_id_or_key(required), expand(optional) |
| search | jira_search_search |
Searches for issues using JQL. | GET /rest/api/2/search | jql(optional), start_at(optional), max_results(optional), validate_query(optional), fields(optional), expand(optional) |
| user | jira_user_find_users |
Returns a list of users that match the search string. This resource cannot be accessed anonymously. | GET /rest/api/2/user/search | username(optional), start_at(optional), max_results(optional), include_active(optional), include_inactive(optional) |
| user | jira_user_get_user |
Returns a user. This resource cannot be accessed anonymously. | GET /rest/api/2/user | username(optional), key(optional), include_deleted(optional) |
Result Limits
Every list-style tool sends an explicit, clamped maxResults — none ofthem ever request an unbounded result set:
| Tool(s) | Default | Hard cap | Why |
|---|---|---|---|
jira_agile_* (boards/sprints/sprint-issues) |
50 | 50 | Jira's Agile REST API (/rest/agile/1.0/...) silently ignores any maxResults above 50 and returns 50 anyway (confirmed vendor behavior) — clamping to 50 avoids a misleading request. |
jira_user_find_users |
50 | 100 | Jira Data Center 10.x truncates /rest/api/2/user/search results past 100 regardless of the requested value; older versions allow up to 1000, so 100 is the safe, version-agnostic ceiling. |
jira_search_search, jira_issue_get_comments |
50 | 200 | No stricter vendor ceiling is documented for these endpoints (Jira's own jira.search.views.default.max defaults to 1000), so this server's own 200-item token-economy ceiling governs. |
Responses are also capped at ~20,000 characters and truncated (with atruncated/original_count marker) rather than ever returned unbounded.
Test Example
# Health check
curl -s http://localhost:8080/health
# Call a tool via the MCP protocol (streamable HTTP) — requires an
# initialize handshake first per the MCP spec; abbreviated example below
# shows the tool-call request body only:
curl -s -X POST http://localhost:8080/mcp \
-H "X-Jira-Site: jira.example.com" \
-H "X-Jira-Username: api_user" \
-H "X-Jira-Password: Sample_Passw0rd!" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: <session-id-from-initialize>" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "jira_myself_get_user",
"arguments": {}
}
}'
Self-test limitation (2026-07-29): the provided test account(jira.mspbots.ai, user mspbots_api) could not be live-verified fromthis build environment — direct requests to jira.mspbots.ai (boththrough this server and via plain curl) consistently return a generic404 page not found, and DNS resolves the host to a sandbox-localaddress. This is consistent with MSPbots' internal servers beingRDP-only / network-isolated from this environment, not a bug in theserver itself. What was verified end-to-end from this environment:the MCP protocol handshake, tools/list returning all 214 registeredtools, the 401 credential-gating behavior, and that a live call reachesthe constructed URL and receives an HTTP response (proving therequest/auth-header plumbing works) — only the vendor-side reachabilityof the real instance could not be confirmed. A real functionalself-test against jira.mspbots.ai should be run from a network thatcan actually reach it (e.g. via RDP to an MSPbots-internal host).
API Reference
- Platform API WADL: https://docs.atlassian.com/software/jira/docs/api/REST/9.4.0/jira-rest-plugin.wadl
- Platform API docs: https://docs.atlassian.com/software/jira/docs/api/REST/9.4.0/
- Agile API docs: https://docs.atlassian.com/jira-software/REST/9.4.0/
Known Gaps
- Trimmed from 29 to 15 tools on 2026-08-07, focused on coreissue/search/project/user/agile-sprint operations. Dropped: the nichemetadata-lookup categories (
issuetype,priority,jqlautocomplete,customfields) and the less-common bulk/sync tools(versionproject-version management,worklogsync-since-timestamp endpoints), plus 2 of 5agiletools(jira_agile_get_board,jira_agile_get_sprint). See the Scopesection above for the exact category→tool mapping. - Trimmed from 214 to 29 tools on 2026-08-04 (dropped the one write op,
jira_agile_create_sprint, that wasn't part of MSPbots' read-only "Board Sprint" usage, to land under 30). The original buildexpanded beyond MSPbots' 17 named endpoints to full core work-itemcategories per an earlier scope decision. A later scope decision cutthis back down to what those 17 endpoint names actually map to, plusminimal same-category CRUD — see the Scope section above for the exactcategory→tool mapping and the full list of removed categories (24categories, ~184 tools). If a future need requires one of the removedcategories, Atlassian's WADL spec (linked above) still documents itsexact operations and they can be re-added the same way the kept toolswere generated. - "Queues"/"Queues Issue" (Jira Service Desk) and "Tempo Worklog"(third-party plugin) are not covered at all — neither is part of theplatform-v2-REST-API-plus-Agile-API surface this server implements, so2 of MSPbots' 17 configured endpoint names have no corresponding toolhere even after the trim.
bodyparameters are untyped (dict) rather than fully modeled —the Jira REST API reference documents the exact schema per resource,but reproducing all of them as typed Python parameters was out of scopefor a mechanically-generated server.- Live functional self-test could not be completed from this buildenvironment due to
jira.mspbots.aibeing unreachable here (seeTest Example above for exactly what was and wasn't verified). - Several kept operations mutate or delete real data(
jira_issue_delete_issue,jira_issue_create_issue,jira_issue_edit_issue,jira_issue_add_comment, etc.) — treat anyDELETE/destructivePOST/PUTtool as irreversible against aproduction Jira instance and confirm with a human before invoking.