et-devops-mcp-atlassian 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- et_devops_mcp_atlassian-1.0/PKG-INFO +175 -0
- et_devops_mcp_atlassian-1.0/README.md +136 -0
- et_devops_mcp_atlassian-1.0/app/__init__.py +0 -0
- et_devops_mcp_atlassian-1.0/app/__main__.py +35 -0
- et_devops_mcp_atlassian-1.0/app/confluence/__init__.py +52 -0
- et_devops_mcp_atlassian-1.0/app/confluence/analytics.py +173 -0
- et_devops_mcp_atlassian-1.0/app/confluence/attachments.py +561 -0
- et_devops_mcp_atlassian-1.0/app/confluence/client.py +223 -0
- et_devops_mcp_atlassian-1.0/app/confluence/comments.py +238 -0
- et_devops_mcp_atlassian-1.0/app/confluence/config.py +266 -0
- et_devops_mcp_atlassian-1.0/app/confluence/constants.py +50 -0
- et_devops_mcp_atlassian-1.0/app/confluence/labels.py +79 -0
- et_devops_mcp_atlassian-1.0/app/confluence/pages.py +1202 -0
- et_devops_mcp_atlassian-1.0/app/confluence/protocols.py +106 -0
- et_devops_mcp_atlassian-1.0/app/confluence/search.py +198 -0
- et_devops_mcp_atlassian-1.0/app/confluence/spaces.py +100 -0
- et_devops_mcp_atlassian-1.0/app/confluence/users.py +100 -0
- et_devops_mcp_atlassian-1.0/app/confluence/utils.py +122 -0
- et_devops_mcp_atlassian-1.0/app/confluence/v2_adapter.py +1128 -0
- et_devops_mcp_atlassian-1.0/app/core/__init__.py +0 -0
- et_devops_mcp_atlassian-1.0/app/core/auth.py +88 -0
- et_devops_mcp_atlassian-1.0/app/core/confluence.py +2239 -0
- et_devops_mcp_atlassian-1.0/app/core/context.py +23 -0
- et_devops_mcp_atlassian-1.0/app/core/dependencies.py +795 -0
- et_devops_mcp_atlassian-1.0/app/core/jira.py +3722 -0
- et_devops_mcp_atlassian-1.0/app/core/server.py +835 -0
- et_devops_mcp_atlassian-1.0/app/core/session_store.py +104 -0
- et_devops_mcp_atlassian-1.0/app/core/tools.py +11 -0
- et_devops_mcp_atlassian-1.0/app/exceptions.py +2 -0
- et_devops_mcp_atlassian-1.0/app/jira/__init__.py +98 -0
- et_devops_mcp_atlassian-1.0/app/jira/attachments.py +467 -0
- et_devops_mcp_atlassian-1.0/app/jira/boards.py +88 -0
- et_devops_mcp_atlassian-1.0/app/jira/client.py +389 -0
- et_devops_mcp_atlassian-1.0/app/jira/comments.py +264 -0
- et_devops_mcp_atlassian-1.0/app/jira/config.py +342 -0
- et_devops_mcp_atlassian-1.0/app/jira/configuration.py +25 -0
- et_devops_mcp_atlassian-1.0/app/jira/constants.py +216 -0
- et_devops_mcp_atlassian-1.0/app/jira/development.py +410 -0
- et_devops_mcp_atlassian-1.0/app/jira/epics.py +946 -0
- et_devops_mcp_atlassian-1.0/app/jira/field_options.py +235 -0
- et_devops_mcp_atlassian-1.0/app/jira/fields.py +862 -0
- et_devops_mcp_atlassian-1.0/app/jira/formatting.py +345 -0
- et_devops_mcp_atlassian-1.0/app/jira/forms.py +225 -0
- et_devops_mcp_atlassian-1.0/app/jira/forms_api.py +408 -0
- et_devops_mcp_atlassian-1.0/app/jira/forms_common.py +133 -0
- et_devops_mcp_atlassian-1.0/app/jira/issues.py +1612 -0
- et_devops_mcp_atlassian-1.0/app/jira/links.py +224 -0
- et_devops_mcp_atlassian-1.0/app/jira/metrics.py +408 -0
- et_devops_mcp_atlassian-1.0/app/jira/projects.py +465 -0
- et_devops_mcp_atlassian-1.0/app/jira/protocols.py +285 -0
- et_devops_mcp_atlassian-1.0/app/jira/queues.py +218 -0
- et_devops_mcp_atlassian-1.0/app/jira/search.py +307 -0
- et_devops_mcp_atlassian-1.0/app/jira/sla.py +678 -0
- et_devops_mcp_atlassian-1.0/app/jira/sprints.py +218 -0
- et_devops_mcp_atlassian-1.0/app/jira/transitions.py +409 -0
- et_devops_mcp_atlassian-1.0/app/jira/users.py +413 -0
- et_devops_mcp_atlassian-1.0/app/jira/utils.py +123 -0
- et_devops_mcp_atlassian-1.0/app/jira/watchers.py +98 -0
- et_devops_mcp_atlassian-1.0/app/jira/worklog.py +246 -0
- et_devops_mcp_atlassian-1.0/app/k8s_probes.py +13 -0
- et_devops_mcp_atlassian-1.0/app/main.py +43 -0
- et_devops_mcp_atlassian-1.0/app/models/__init__.py +107 -0
- et_devops_mcp_atlassian-1.0/app/models/base.py +126 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/__init__.py +38 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/analytics.py +52 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/comment.py +109 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/common.py +175 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/label.py +62 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/page.py +296 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/search.py +74 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/space.py +57 -0
- et_devops_mcp_atlassian-1.0/app/models/confluence/user_search.py +145 -0
- et_devops_mcp_atlassian-1.0/app/models/constants.py +63 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/__init__.py +110 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/adf.py +362 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/agile.py +152 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/comment.py +97 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/common.py +597 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/field_option.py +105 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/forms.py +162 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/issue.py +815 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/link.py +285 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/metrics.py +231 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/project.py +111 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/queue.py +246 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/search.py +114 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/sla.py +221 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/version.py +46 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/workflow.py +93 -0
- et_devops_mcp_atlassian-1.0/app/models/jira/worklog.py +109 -0
- et_devops_mcp_atlassian-1.0/app/preprocessing/__init__.py +15 -0
- et_devops_mcp_atlassian-1.0/app/preprocessing/base.py +419 -0
- et_devops_mcp_atlassian-1.0/app/preprocessing/confluence.py +105 -0
- et_devops_mcp_atlassian-1.0/app/preprocessing/jira.py +608 -0
- et_devops_mcp_atlassian-1.0/app/routers/__init__.py +0 -0
- et_devops_mcp_atlassian-1.0/app/routers/k8s_health.py +31 -0
- et_devops_mcp_atlassian-1.0/app/routers/metrics.py +61 -0
- et_devops_mcp_atlassian-1.0/app/utils/__init__.py +45 -0
- et_devops_mcp_atlassian-1.0/app/utils/client_storage.py +180 -0
- et_devops_mcp_atlassian-1.0/app/utils/date.py +65 -0
- et_devops_mcp_atlassian-1.0/app/utils/decorators.py +173 -0
- et_devops_mcp_atlassian-1.0/app/utils/env.py +93 -0
- et_devops_mcp_atlassian-1.0/app/utils/environment.py +179 -0
- et_devops_mcp_atlassian-1.0/app/utils/io.py +58 -0
- et_devops_mcp_atlassian-1.0/app/utils/lifecycle.py +85 -0
- et_devops_mcp_atlassian-1.0/app/utils/logging.py +118 -0
- et_devops_mcp_atlassian-1.0/app/utils/media.py +128 -0
- et_devops_mcp_atlassian-1.0/app/utils/oauth.py +724 -0
- et_devops_mcp_atlassian-1.0/app/utils/oauth_proxy.py +73 -0
- et_devops_mcp_atlassian-1.0/app/utils/oauth_setup.py +450 -0
- et_devops_mcp_atlassian-1.0/app/utils/ssl.py +122 -0
- et_devops_mcp_atlassian-1.0/app/utils/token_verifier.py +29 -0
- et_devops_mcp_atlassian-1.0/app/utils/tools.py +63 -0
- et_devops_mcp_atlassian-1.0/app/utils/toolsets.py +271 -0
- et_devops_mcp_atlassian-1.0/app/utils/urls.py +205 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/PKG-INFO +175 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/SOURCES.txt +121 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/dependency_links.txt +1 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/entry_points.txt +2 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/requires.txt +32 -0
- et_devops_mcp_atlassian-1.0/et_devops_mcp_atlassian.egg-info/top_level.txt +1 -0
- et_devops_mcp_atlassian-1.0/pyproject.toml +97 -0
- et_devops_mcp_atlassian-1.0/setup.cfg +4 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: et-devops-mcp-atlassian
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: MCP server for Jira and Confluence Data Center — Kubernetes-ready
|
|
5
|
+
Author: ET AI Solutions
|
|
6
|
+
Maintainer: ET AI Solutions
|
|
7
|
+
Requires-Python: <3.14,>=3.13
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: fastmcp<3.0.0,>=2.14.1
|
|
10
|
+
Requires-Dist: mcp<2.0.0,>=1.8.0
|
|
11
|
+
Requires-Dist: atlassian-python-api>=4.0.0
|
|
12
|
+
Requires-Dist: requests[socks]>=2.31.0
|
|
13
|
+
Requires-Dist: beautifulsoup4>=4.12.3
|
|
14
|
+
Requires-Dist: httpx>=0.28.0
|
|
15
|
+
Requires-Dist: markdownify>=0.11.6
|
|
16
|
+
Requires-Dist: markdown>=3.7.0
|
|
17
|
+
Requires-Dist: markdown-to-confluence<0.4.0,>=0.3.4
|
|
18
|
+
Requires-Dist: pydantic<3.0,>=2.10.6
|
|
19
|
+
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
20
|
+
Requires-Dist: types-python-dateutil>=2.9.0.20241206
|
|
21
|
+
Requires-Dist: unidecode>=1.3.0
|
|
22
|
+
Requires-Dist: thefuzz>=0.22.1
|
|
23
|
+
Requires-Dist: uvicorn>=0.27.1
|
|
24
|
+
Requires-Dist: starlette>=0.49.1
|
|
25
|
+
Requires-Dist: fastapi>=0.124.4
|
|
26
|
+
Requires-Dist: aiohttp>=3.13.2
|
|
27
|
+
Requires-Dist: urllib3>=2.6.3
|
|
28
|
+
Requires-Dist: keyring>=25.6.0
|
|
29
|
+
Requires-Dist: truststore>=0.10.0
|
|
30
|
+
Requires-Dist: cachetools>=5.0.0
|
|
31
|
+
Requires-Dist: types-cachetools>=5.5.0.20240820
|
|
32
|
+
Requires-Dist: click>=8.1.7
|
|
33
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
34
|
+
Requires-Dist: trio>=0.29.0
|
|
35
|
+
Requires-Dist: prometheus-fastapi-instrumentator>=7.1.0
|
|
36
|
+
Requires-Dist: psutil>=7.1.3
|
|
37
|
+
Requires-Dist: fakeredis<2.35.0,>=2.32.1
|
|
38
|
+
Requires-Dist: tzdata>=2024.1; platform_system == "Windows"
|
|
39
|
+
|
|
40
|
+
# et-devops-mcp-atlassian-dc
|
|
41
|
+
|
|
42
|
+
MCP server for Atlassian Data Center — exposes Jira and Confluence operations as tools for AI assistants.
|
|
43
|
+
|
|
44
|
+
## Overview
|
|
45
|
+
|
|
46
|
+
Provides Jira and Confluence tools via the [Model Context Protocol](https://modelcontextprotocol.io). Authentication is per-call using a Personal Access Token (PAT) passed directly as a tool argument.
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
### Jira (60 tools)
|
|
51
|
+
|
|
52
|
+
| Toolset | Tool | Description |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `jira_issues` | `jira_get_issue` | Get issue details by key |
|
|
55
|
+
| `jira_issues` | `jira_search` | Search issues using JQL |
|
|
56
|
+
| `jira_issues` | `jira_create_issue` | Create a new issue |
|
|
57
|
+
| `jira_issues` | `jira_update_issue` | Update an existing issue |
|
|
58
|
+
| `jira_issues` | `jira_batch_create_issues` | Bulk-create issues |
|
|
59
|
+
| `jira_issues` | `jira_batch_get_changelogs` | Get changelogs for multiple issues |
|
|
60
|
+
| `jira_comments` | `jira_add_comment` | Add a comment to an issue |
|
|
61
|
+
| `jira_comments` | `jira_edit_comment` | Edit an existing comment |
|
|
62
|
+
| `jira_fields` | `jira_search_fields` | Search available fields |
|
|
63
|
+
| `jira_fields` | `jira_get_field_options` | Get options for a field |
|
|
64
|
+
| `jira_transitions` | `jira_get_transitions` | Get available transitions for an issue |
|
|
65
|
+
| `jira_transitions` | `jira_transition_issue` | Move an issue to a new status |
|
|
66
|
+
| `jira_projects` | `jira_get_all_projects` | List all accessible projects |
|
|
67
|
+
| `jira_projects` | `jira_get_project_issues` | List issues in a project |
|
|
68
|
+
| `jira_projects` | `jira_get_project_versions` | List versions for a project |
|
|
69
|
+
| `jira_projects` | `jira_get_project_components` | List components for a project |
|
|
70
|
+
| `jira_projects` | `jira_get_project_issue_types` | List issue types for a project |
|
|
71
|
+
| `jira_projects` | `jira_create_version` | Create a project version |
|
|
72
|
+
| `jira_projects` | `jira_batch_create_versions` | Bulk-create project versions |
|
|
73
|
+
| `jira_agile` | `jira_get_agile_boards` | List agile boards |
|
|
74
|
+
| `jira_agile` | `jira_get_board_issues` | List issues on a board |
|
|
75
|
+
| `jira_agile` | `jira_get_sprints_from_board` | List sprints for a board |
|
|
76
|
+
| `jira_agile` | `jira_get_sprint_issues` | List issues in a sprint |
|
|
77
|
+
| `jira_agile` | `jira_create_sprint` | Create a sprint |
|
|
78
|
+
| `jira_agile` | `jira_update_sprint` | Update a sprint |
|
|
79
|
+
| `jira_agile` | `jira_add_issues_to_sprint` | Add issues to a sprint |
|
|
80
|
+
| `jira_links` | `jira_get_link_types` | List issue link types |
|
|
81
|
+
| `jira_links` | `jira_create_issue_link` | Link two issues |
|
|
82
|
+
| `jira_links` | `jira_create_remote_issue_link` | Create a remote issue link |
|
|
83
|
+
| `jira_links` | `jira_remove_issue_link` | Remove an issue link |
|
|
84
|
+
| `jira_links` | `jira_link_to_epic` | Link an issue to an epic |
|
|
85
|
+
| `jira_worklog` | `jira_get_worklog` | Get worklogs for an issue |
|
|
86
|
+
| `jira_worklog` | `jira_add_worklog` | Log time on an issue |
|
|
87
|
+
| `jira_attachments` | `jira_download_attachments` | Download issue attachments |
|
|
88
|
+
| `jira_attachments` | `jira_get_issue_images` | Get images from an issue |
|
|
89
|
+
| `jira_users` | `jira_get_user_profile` | Get a user's profile |
|
|
90
|
+
| `jira_users` | `jira_search_users` | Search users by name, username, or email |
|
|
91
|
+
| `jira_watchers` | `jira_get_issue_watchers` | List watchers on an issue |
|
|
92
|
+
| `jira_watchers` | `jira_add_watcher` | Add a watcher to an issue |
|
|
93
|
+
| `jira_watchers` | `jira_remove_watcher` | Remove a watcher from an issue |
|
|
94
|
+
| `jira_service_desk` | `jira_get_service_desk_for_project` | Get service desk for a project |
|
|
95
|
+
| `jira_service_desk` | `jira_get_service_desk_queues` | List queues for a service desk |
|
|
96
|
+
| `jira_service_desk` | `jira_get_queue_issues` | List issues in a queue |
|
|
97
|
+
| `jira_service_desk` | `jira_get_request_types` | List request types for a service desk |
|
|
98
|
+
| `jira_service_desk` | `jira_get_request_type_fields` | Get fields for a request type |
|
|
99
|
+
| `jira_service_desk` | `jira_get_approvals` | List approvals for a service desk issue |
|
|
100
|
+
| `jira_service_desk` | `jira_get_approval` | Get a specific approval |
|
|
101
|
+
| `jira_service_desk` | `jira_answer_approval` | Approve or decline a pending approval |
|
|
102
|
+
| `jira_filters` | `jira_get_filter` | Get a saved JQL filter by ID |
|
|
103
|
+
| `jira_filters` | `jira_create_filter` | Create a saved JQL filter |
|
|
104
|
+
| `jira_filters` | `jira_update_filter` | Update a saved JQL filter |
|
|
105
|
+
| `jira_metrics` | `jira_get_issue_dates` | Get date fields for an issue |
|
|
106
|
+
| `jira_metrics` | `jira_get_issue_sla` | Get SLA metrics for a service desk issue |
|
|
107
|
+
| `jira_development` | `jira_get_issue_development_info` | Get dev info (branches, PRs, commits) for an issue |
|
|
108
|
+
| `jira_development` | `jira_get_issues_development_info` | Get dev info for multiple issues |
|
|
109
|
+
| `jira_configuration` | `jira_get_configuration` | Get global Jira configuration |
|
|
110
|
+
| `jira_configuration` | `jira_get_server_info` | Get server version and deployment type |
|
|
111
|
+
| `jira_configuration` | `jira_get_all_priorities` | List all configured priorities |
|
|
112
|
+
| `jira_configuration` | `jira_get_all_resolutions` | List all configured resolutions |
|
|
113
|
+
| `jira_configuration` | `jira_get_all_statuses` | List all configured statuses |
|
|
114
|
+
|
|
115
|
+
### Confluence (25 tools)
|
|
116
|
+
|
|
117
|
+
| Toolset | Tool | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `confluence_pages` | `confluence_search` | Search pages using CQL |
|
|
120
|
+
| `confluence_pages` | `confluence_get_page` | Get page content by ID |
|
|
121
|
+
| `confluence_pages` | `confluence_get_page_children` | List child pages |
|
|
122
|
+
| `confluence_pages` | `confluence_get_space_page_tree` | Get page tree for a space |
|
|
123
|
+
| `confluence_pages` | `confluence_create_page` | Create a new page |
|
|
124
|
+
| `confluence_pages` | `confluence_update_page` | Update an existing page |
|
|
125
|
+
| `confluence_pages` | `confluence_move_page` | Move a page to a new parent |
|
|
126
|
+
| `confluence_pages` | `confluence_get_page_history` | Get revision history for a page |
|
|
127
|
+
| `confluence_pages` | `confluence_get_page_diff` | Get diff between page versions |
|
|
128
|
+
| `confluence_comments` | `confluence_get_comments` | Get comments on a page |
|
|
129
|
+
| `confluence_comments` | `confluence_add_comment` | Add a comment to a page |
|
|
130
|
+
| `confluence_comments` | `confluence_reply_to_comment` | Reply to an existing comment |
|
|
131
|
+
| `confluence_labels` | `confluence_get_labels` | Get labels on a page |
|
|
132
|
+
| `confluence_labels` | `confluence_add_label` | Add a label to a page |
|
|
133
|
+
| `confluence_users` | `confluence_search_user` | Search Confluence users |
|
|
134
|
+
| `confluence_analytics` | `confluence_get_page_views` | Get view analytics for a page |
|
|
135
|
+
| `confluence_attachments` | `confluence_upload_attachment` | Upload a single attachment |
|
|
136
|
+
| `confluence_attachments` | `confluence_upload_attachments` | Upload multiple attachments |
|
|
137
|
+
| `confluence_attachments` | `confluence_get_attachments` | List attachments on a page |
|
|
138
|
+
| `confluence_attachments` | `confluence_download_attachment` | Download an attachment |
|
|
139
|
+
| `confluence_attachments` | `confluence_download_content_attachments` | Download all attachments for a page |
|
|
140
|
+
| `confluence_attachments` | `confluence_get_page_images` | Get images from a page |
|
|
141
|
+
| `confluence_spaces` | `confluence_get_spaces` | List accessible spaces |
|
|
142
|
+
| `confluence_spaces` | `confluence_get_space` | Get a space by key |
|
|
143
|
+
| `confluence_spaces` | `confluence_get_page_restrictions` | Get content restrictions for a page |
|
|
144
|
+
|
|
145
|
+
## MCP Client Configuration
|
|
146
|
+
|
|
147
|
+
Add to your `.mcp.json`:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"mcpServers": {
|
|
152
|
+
"atlassian_dc": {
|
|
153
|
+
"type": "http",
|
|
154
|
+
"url": "https://gateway-dev.mcp.zurich.com/servers/7bf9b1c86d3b4dd9b087f82b26406a9a/mcp",
|
|
155
|
+
"headers": {
|
|
156
|
+
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb3NlYW5nZWwubXVub3pAenVyaWNoLmNvbSIsImp0aSI6IjBmNGNiZWQ3LTdiYjYtNDYzNC1hYjQ3LWQ3ZjZhODk3MTRkNyIsInRva2VuX3VzZSI6ImFwaSIsImlhdCI6MTc4MTAwNzgxMywiaXNzIjoienVyaWNoIiwiYXVkIjoibWNwZ2F0ZXdheS1hcGkiLCJ1c2VyIjp7ImVtYWlsIjoiam9zZWFuZ2VsLm11bm96QHp1cmljaC5jb20iLCJmdWxsX25hbWUiOiJBUEkgVG9rZW4gVXNlciIsImlzX2FkbWluIjp0cnVlLCJhdXRoX3Byb3ZpZGVyIjoiYXBpX3Rva2VuIn0sInRlYW1zIjpudWxsLCJzY29wZXMiOnsic2VydmVyX2lkIjoiN2JmOWIxYzg2ZDNiNGRkOWIwODdmODJiMjY0MDZhOWEiLCJwZXJtaXNzaW9ucyI6W10sImlwX3Jlc3RyaWN0aW9ucyI6W10sInRpbWVfcmVzdHJpY3Rpb25zIjp7fX0sImV4cCI6MTgxMjU0MzgxM30.8wg6CIIYco5rvjscrcrpFL8kYW0hMVKSOznE2N9DuEM"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
> PATs are not configured here — the AI assistant will ask for them when needed and pass them as tool arguments on each call.
|
|
164
|
+
|
|
165
|
+
## Environment Variables
|
|
166
|
+
|
|
167
|
+
| Variable | Required | Description |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `ATLASSIAN_DC_JIRA_URL` | Yes | Jira base URL |
|
|
170
|
+
| `ATLASSIAN_DC_CONFLUENCE_URL` | Yes | Confluence base URL |
|
|
171
|
+
| `ATLASSIAN_OAUTH_ENABLE` | No | Enable OAuth mode |
|
|
172
|
+
| `TOOLSETS` | No | Comma-separated toolset names, `all`, or `default` |
|
|
173
|
+
| `READ_ONLY` | No | Disable all write tools |
|
|
174
|
+
| `LOG_LEVEL` | No | Logging level (default: `INFO`) |
|
|
175
|
+
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# et-devops-mcp-atlassian-dc
|
|
2
|
+
|
|
3
|
+
MCP server for Atlassian Data Center — exposes Jira and Confluence operations as tools for AI assistants.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Provides Jira and Confluence tools via the [Model Context Protocol](https://modelcontextprotocol.io). Authentication is per-call using a Personal Access Token (PAT) passed directly as a tool argument.
|
|
8
|
+
|
|
9
|
+
## Tools
|
|
10
|
+
|
|
11
|
+
### Jira (60 tools)
|
|
12
|
+
|
|
13
|
+
| Toolset | Tool | Description |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `jira_issues` | `jira_get_issue` | Get issue details by key |
|
|
16
|
+
| `jira_issues` | `jira_search` | Search issues using JQL |
|
|
17
|
+
| `jira_issues` | `jira_create_issue` | Create a new issue |
|
|
18
|
+
| `jira_issues` | `jira_update_issue` | Update an existing issue |
|
|
19
|
+
| `jira_issues` | `jira_batch_create_issues` | Bulk-create issues |
|
|
20
|
+
| `jira_issues` | `jira_batch_get_changelogs` | Get changelogs for multiple issues |
|
|
21
|
+
| `jira_comments` | `jira_add_comment` | Add a comment to an issue |
|
|
22
|
+
| `jira_comments` | `jira_edit_comment` | Edit an existing comment |
|
|
23
|
+
| `jira_fields` | `jira_search_fields` | Search available fields |
|
|
24
|
+
| `jira_fields` | `jira_get_field_options` | Get options for a field |
|
|
25
|
+
| `jira_transitions` | `jira_get_transitions` | Get available transitions for an issue |
|
|
26
|
+
| `jira_transitions` | `jira_transition_issue` | Move an issue to a new status |
|
|
27
|
+
| `jira_projects` | `jira_get_all_projects` | List all accessible projects |
|
|
28
|
+
| `jira_projects` | `jira_get_project_issues` | List issues in a project |
|
|
29
|
+
| `jira_projects` | `jira_get_project_versions` | List versions for a project |
|
|
30
|
+
| `jira_projects` | `jira_get_project_components` | List components for a project |
|
|
31
|
+
| `jira_projects` | `jira_get_project_issue_types` | List issue types for a project |
|
|
32
|
+
| `jira_projects` | `jira_create_version` | Create a project version |
|
|
33
|
+
| `jira_projects` | `jira_batch_create_versions` | Bulk-create project versions |
|
|
34
|
+
| `jira_agile` | `jira_get_agile_boards` | List agile boards |
|
|
35
|
+
| `jira_agile` | `jira_get_board_issues` | List issues on a board |
|
|
36
|
+
| `jira_agile` | `jira_get_sprints_from_board` | List sprints for a board |
|
|
37
|
+
| `jira_agile` | `jira_get_sprint_issues` | List issues in a sprint |
|
|
38
|
+
| `jira_agile` | `jira_create_sprint` | Create a sprint |
|
|
39
|
+
| `jira_agile` | `jira_update_sprint` | Update a sprint |
|
|
40
|
+
| `jira_agile` | `jira_add_issues_to_sprint` | Add issues to a sprint |
|
|
41
|
+
| `jira_links` | `jira_get_link_types` | List issue link types |
|
|
42
|
+
| `jira_links` | `jira_create_issue_link` | Link two issues |
|
|
43
|
+
| `jira_links` | `jira_create_remote_issue_link` | Create a remote issue link |
|
|
44
|
+
| `jira_links` | `jira_remove_issue_link` | Remove an issue link |
|
|
45
|
+
| `jira_links` | `jira_link_to_epic` | Link an issue to an epic |
|
|
46
|
+
| `jira_worklog` | `jira_get_worklog` | Get worklogs for an issue |
|
|
47
|
+
| `jira_worklog` | `jira_add_worklog` | Log time on an issue |
|
|
48
|
+
| `jira_attachments` | `jira_download_attachments` | Download issue attachments |
|
|
49
|
+
| `jira_attachments` | `jira_get_issue_images` | Get images from an issue |
|
|
50
|
+
| `jira_users` | `jira_get_user_profile` | Get a user's profile |
|
|
51
|
+
| `jira_users` | `jira_search_users` | Search users by name, username, or email |
|
|
52
|
+
| `jira_watchers` | `jira_get_issue_watchers` | List watchers on an issue |
|
|
53
|
+
| `jira_watchers` | `jira_add_watcher` | Add a watcher to an issue |
|
|
54
|
+
| `jira_watchers` | `jira_remove_watcher` | Remove a watcher from an issue |
|
|
55
|
+
| `jira_service_desk` | `jira_get_service_desk_for_project` | Get service desk for a project |
|
|
56
|
+
| `jira_service_desk` | `jira_get_service_desk_queues` | List queues for a service desk |
|
|
57
|
+
| `jira_service_desk` | `jira_get_queue_issues` | List issues in a queue |
|
|
58
|
+
| `jira_service_desk` | `jira_get_request_types` | List request types for a service desk |
|
|
59
|
+
| `jira_service_desk` | `jira_get_request_type_fields` | Get fields for a request type |
|
|
60
|
+
| `jira_service_desk` | `jira_get_approvals` | List approvals for a service desk issue |
|
|
61
|
+
| `jira_service_desk` | `jira_get_approval` | Get a specific approval |
|
|
62
|
+
| `jira_service_desk` | `jira_answer_approval` | Approve or decline a pending approval |
|
|
63
|
+
| `jira_filters` | `jira_get_filter` | Get a saved JQL filter by ID |
|
|
64
|
+
| `jira_filters` | `jira_create_filter` | Create a saved JQL filter |
|
|
65
|
+
| `jira_filters` | `jira_update_filter` | Update a saved JQL filter |
|
|
66
|
+
| `jira_metrics` | `jira_get_issue_dates` | Get date fields for an issue |
|
|
67
|
+
| `jira_metrics` | `jira_get_issue_sla` | Get SLA metrics for a service desk issue |
|
|
68
|
+
| `jira_development` | `jira_get_issue_development_info` | Get dev info (branches, PRs, commits) for an issue |
|
|
69
|
+
| `jira_development` | `jira_get_issues_development_info` | Get dev info for multiple issues |
|
|
70
|
+
| `jira_configuration` | `jira_get_configuration` | Get global Jira configuration |
|
|
71
|
+
| `jira_configuration` | `jira_get_server_info` | Get server version and deployment type |
|
|
72
|
+
| `jira_configuration` | `jira_get_all_priorities` | List all configured priorities |
|
|
73
|
+
| `jira_configuration` | `jira_get_all_resolutions` | List all configured resolutions |
|
|
74
|
+
| `jira_configuration` | `jira_get_all_statuses` | List all configured statuses |
|
|
75
|
+
|
|
76
|
+
### Confluence (25 tools)
|
|
77
|
+
|
|
78
|
+
| Toolset | Tool | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `confluence_pages` | `confluence_search` | Search pages using CQL |
|
|
81
|
+
| `confluence_pages` | `confluence_get_page` | Get page content by ID |
|
|
82
|
+
| `confluence_pages` | `confluence_get_page_children` | List child pages |
|
|
83
|
+
| `confluence_pages` | `confluence_get_space_page_tree` | Get page tree for a space |
|
|
84
|
+
| `confluence_pages` | `confluence_create_page` | Create a new page |
|
|
85
|
+
| `confluence_pages` | `confluence_update_page` | Update an existing page |
|
|
86
|
+
| `confluence_pages` | `confluence_move_page` | Move a page to a new parent |
|
|
87
|
+
| `confluence_pages` | `confluence_get_page_history` | Get revision history for a page |
|
|
88
|
+
| `confluence_pages` | `confluence_get_page_diff` | Get diff between page versions |
|
|
89
|
+
| `confluence_comments` | `confluence_get_comments` | Get comments on a page |
|
|
90
|
+
| `confluence_comments` | `confluence_add_comment` | Add a comment to a page |
|
|
91
|
+
| `confluence_comments` | `confluence_reply_to_comment` | Reply to an existing comment |
|
|
92
|
+
| `confluence_labels` | `confluence_get_labels` | Get labels on a page |
|
|
93
|
+
| `confluence_labels` | `confluence_add_label` | Add a label to a page |
|
|
94
|
+
| `confluence_users` | `confluence_search_user` | Search Confluence users |
|
|
95
|
+
| `confluence_analytics` | `confluence_get_page_views` | Get view analytics for a page |
|
|
96
|
+
| `confluence_attachments` | `confluence_upload_attachment` | Upload a single attachment |
|
|
97
|
+
| `confluence_attachments` | `confluence_upload_attachments` | Upload multiple attachments |
|
|
98
|
+
| `confluence_attachments` | `confluence_get_attachments` | List attachments on a page |
|
|
99
|
+
| `confluence_attachments` | `confluence_download_attachment` | Download an attachment |
|
|
100
|
+
| `confluence_attachments` | `confluence_download_content_attachments` | Download all attachments for a page |
|
|
101
|
+
| `confluence_attachments` | `confluence_get_page_images` | Get images from a page |
|
|
102
|
+
| `confluence_spaces` | `confluence_get_spaces` | List accessible spaces |
|
|
103
|
+
| `confluence_spaces` | `confluence_get_space` | Get a space by key |
|
|
104
|
+
| `confluence_spaces` | `confluence_get_page_restrictions` | Get content restrictions for a page |
|
|
105
|
+
|
|
106
|
+
## MCP Client Configuration
|
|
107
|
+
|
|
108
|
+
Add to your `.mcp.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"mcpServers": {
|
|
113
|
+
"atlassian_dc": {
|
|
114
|
+
"type": "http",
|
|
115
|
+
"url": "https://gateway-dev.mcp.zurich.com/servers/7bf9b1c86d3b4dd9b087f82b26406a9a/mcp",
|
|
116
|
+
"headers": {
|
|
117
|
+
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb3NlYW5nZWwubXVub3pAenVyaWNoLmNvbSIsImp0aSI6IjBmNGNiZWQ3LTdiYjYtNDYzNC1hYjQ3LWQ3ZjZhODk3MTRkNyIsInRva2VuX3VzZSI6ImFwaSIsImlhdCI6MTc4MTAwNzgxMywiaXNzIjoienVyaWNoIiwiYXVkIjoibWNwZ2F0ZXdheS1hcGkiLCJ1c2VyIjp7ImVtYWlsIjoiam9zZWFuZ2VsLm11bm96QHp1cmljaC5jb20iLCJmdWxsX25hbWUiOiJBUEkgVG9rZW4gVXNlciIsImlzX2FkbWluIjp0cnVlLCJhdXRoX3Byb3ZpZGVyIjoiYXBpX3Rva2VuIn0sInRlYW1zIjpudWxsLCJzY29wZXMiOnsic2VydmVyX2lkIjoiN2JmOWIxYzg2ZDNiNGRkOWIwODdmODJiMjY0MDZhOWEiLCJwZXJtaXNzaW9ucyI6W10sImlwX3Jlc3RyaWN0aW9ucyI6W10sInRpbWVfcmVzdHJpY3Rpb25zIjp7fX0sImV4cCI6MTgxMjU0MzgxM30.8wg6CIIYco5rvjscrcrpFL8kYW0hMVKSOznE2N9DuEM"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
> PATs are not configured here — the AI assistant will ask for them when needed and pass them as tool arguments on each call.
|
|
125
|
+
|
|
126
|
+
## Environment Variables
|
|
127
|
+
|
|
128
|
+
| Variable | Required | Description |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `ATLASSIAN_DC_JIRA_URL` | Yes | Jira base URL |
|
|
131
|
+
| `ATLASSIAN_DC_CONFLUENCE_URL` | Yes | Confluence base URL |
|
|
132
|
+
| `ATLASSIAN_OAUTH_ENABLE` | No | Enable OAuth mode |
|
|
133
|
+
| `TOOLSETS` | No | Comma-separated toolset names, `all`, or `default` |
|
|
134
|
+
| `READ_ONLY` | No | Disable all write tools |
|
|
135
|
+
| `LOG_LEVEL` | No | Logging level (default: `INFO`) |
|
|
136
|
+
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
load_dotenv(override=False)
|
|
6
|
+
|
|
7
|
+
if not os.getenv("JIRA_URL") and os.getenv("ATLASSIAN_DC_JIRA_URL"):
|
|
8
|
+
os.environ["JIRA_URL"] = os.getenv("ATLASSIAN_DC_JIRA_URL") or ""
|
|
9
|
+
if not os.getenv("CONFLUENCE_URL") and os.getenv("ATLASSIAN_DC_CONFLUENCE_URL"):
|
|
10
|
+
os.environ["CONFLUENCE_URL"] = os.getenv("ATLASSIAN_DC_CONFLUENCE_URL") or ""
|
|
11
|
+
|
|
12
|
+
from app.core import tools # noqa: E402
|
|
13
|
+
from app.core.server import create_mcp # noqa: E402
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
mcp = create_mcp(
|
|
18
|
+
name="Atlassian MCP",
|
|
19
|
+
instructions="""
|
|
20
|
+
This server provides tools to interact with Atlassian Jira and Confluence.
|
|
21
|
+
|
|
22
|
+
AUTHENTICATION: Every Jira tool requires a jira_pat parameter and every Confluence tool requires a confluence_pat parameter.
|
|
23
|
+
Jira and Confluence are separate systems and always require separate PATs — never reuse a Jira PAT for Confluence or vice versa.
|
|
24
|
+
Ask the user for the relevant PAT before calling any tool, then pass it in every call.
|
|
25
|
+
|
|
26
|
+
Use the Jira tools to manage issues, projects, sprints, and workflows.
|
|
27
|
+
Use the Confluence tools to search, read, and manage pages and spaces.
|
|
28
|
+
""",
|
|
29
|
+
)
|
|
30
|
+
mcp.mount(tools.mcp)
|
|
31
|
+
mcp.run()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Confluence API integration module.
|
|
2
|
+
|
|
3
|
+
This module provides access to Confluence content through the Model Context Protocol.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .analytics import AnalyticsMixin
|
|
7
|
+
from .attachments import AttachmentsMixin
|
|
8
|
+
from .client import ConfluenceClient
|
|
9
|
+
from .comments import CommentsMixin
|
|
10
|
+
from .config import ConfluenceConfig
|
|
11
|
+
from .labels import LabelsMixin
|
|
12
|
+
from .pages import PagesMixin
|
|
13
|
+
from .search import SearchMixin
|
|
14
|
+
from .spaces import SpacesMixin
|
|
15
|
+
from .users import UsersMixin
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ConfluenceFetcher(
|
|
19
|
+
SearchMixin,
|
|
20
|
+
SpacesMixin,
|
|
21
|
+
PagesMixin,
|
|
22
|
+
CommentsMixin,
|
|
23
|
+
LabelsMixin,
|
|
24
|
+
UsersMixin,
|
|
25
|
+
AnalyticsMixin,
|
|
26
|
+
AttachmentsMixin,
|
|
27
|
+
):
|
|
28
|
+
"""Main entry point for Confluence operations, providing backward compatibility.
|
|
29
|
+
|
|
30
|
+
This class combines functionality from various mixins to maintain the same
|
|
31
|
+
API as the original ConfluenceFetcher class.
|
|
32
|
+
|
|
33
|
+
Available mixins:
|
|
34
|
+
- SearchMixin: CQL search operations
|
|
35
|
+
- SpacesMixin: Space operations
|
|
36
|
+
- PagesMixin: Page operations
|
|
37
|
+
- CommentsMixin: Comment operations
|
|
38
|
+
- LabelsMixin: Label operations
|
|
39
|
+
- UsersMixin: User operations
|
|
40
|
+
- AnalyticsMixin: Page view analytics (Cloud only)
|
|
41
|
+
- AttachmentsMixin: Attachment operations
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"ConfluenceFetcher",
|
|
49
|
+
"ConfluenceConfig",
|
|
50
|
+
"ConfluenceClient",
|
|
51
|
+
"AnalyticsMixin",
|
|
52
|
+
]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Analytics mixin for Confluence page view statistics.
|
|
2
|
+
|
|
3
|
+
This module provides functionality to retrieve page view statistics
|
|
4
|
+
from Confluence Cloud using the Analytics API.
|
|
5
|
+
|
|
6
|
+
Note: The Analytics API is only available for Confluence Cloud.
|
|
7
|
+
Server/Data Center instances do not support this API.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from requests.exceptions import HTTPError
|
|
15
|
+
|
|
16
|
+
from ..models.confluence.analytics import PageViews, PageViewsBatchResponse
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger("mcp-atlassian")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AnalyticsMixin:
|
|
22
|
+
"""Mixin providing Confluence page view analytics functionality.
|
|
23
|
+
|
|
24
|
+
This mixin requires the class to have:
|
|
25
|
+
- self.confluence: Atlassian Confluence client
|
|
26
|
+
- self.config: ConfluenceConfig instance
|
|
27
|
+
- self.v2_adapter: Optional ConfluenceV2Adapter for OAuth
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Type hints for attributes expected from the base class
|
|
31
|
+
confluence: Any
|
|
32
|
+
config: Any
|
|
33
|
+
v2_adapter: Any
|
|
34
|
+
|
|
35
|
+
def get_page_views(
|
|
36
|
+
self,
|
|
37
|
+
page_id: str,
|
|
38
|
+
include_title: bool = True,
|
|
39
|
+
) -> PageViews:
|
|
40
|
+
"""Get view statistics for a Confluence page.
|
|
41
|
+
|
|
42
|
+
Note: This API is only available for Confluence Cloud.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
page_id: The ID of the page
|
|
46
|
+
include_title: Whether to fetch and include the page title
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
PageViews with view statistics
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ValueError: If the page is not found or API fails
|
|
53
|
+
HTTPError: If authentication fails (401/403 are propagated)
|
|
54
|
+
"""
|
|
55
|
+
if not self.config.is_cloud:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
"Page view analytics is only available for Confluence Cloud. "
|
|
58
|
+
"Server/Data Center instances do not support the Analytics API."
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Get page title if requested
|
|
62
|
+
page_title = None
|
|
63
|
+
if include_title:
|
|
64
|
+
try:
|
|
65
|
+
page_info = self.confluence.get_page_by_id(page_id, expand="title")
|
|
66
|
+
page_title = page_info.get("title")
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logger.warning(f"Could not fetch title for page {page_id}: {e}")
|
|
69
|
+
|
|
70
|
+
# Get view statistics using v2 adapter or direct API
|
|
71
|
+
try:
|
|
72
|
+
if hasattr(self, "v2_adapter") and self.v2_adapter:
|
|
73
|
+
views_data = self.v2_adapter.get_page_views(page_id)
|
|
74
|
+
else:
|
|
75
|
+
views_data = self._get_page_views_direct(page_id)
|
|
76
|
+
|
|
77
|
+
# Parse the response
|
|
78
|
+
total_views = views_data.get("count", 0)
|
|
79
|
+
|
|
80
|
+
# Parse last viewed timestamp if available
|
|
81
|
+
last_viewed = None
|
|
82
|
+
last_seen_str = views_data.get("lastSeen")
|
|
83
|
+
if last_seen_str:
|
|
84
|
+
try:
|
|
85
|
+
# Try parsing ISO format timestamp
|
|
86
|
+
last_viewed = datetime.fromisoformat(
|
|
87
|
+
last_seen_str.replace("Z", "+00:00")
|
|
88
|
+
)
|
|
89
|
+
except (ValueError, AttributeError):
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
return PageViews(
|
|
93
|
+
page_id=page_id,
|
|
94
|
+
page_title=page_title,
|
|
95
|
+
total_views=total_views,
|
|
96
|
+
last_viewed=last_viewed,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
except HTTPError as e:
|
|
100
|
+
# Propagate auth errors
|
|
101
|
+
if e.response is not None and e.response.status_code in [401, 403]:
|
|
102
|
+
raise
|
|
103
|
+
logger.warning(f"Failed to get views for page {page_id}: {e}")
|
|
104
|
+
# Return zero views on error (non-auth)
|
|
105
|
+
return PageViews(
|
|
106
|
+
page_id=page_id,
|
|
107
|
+
page_title=page_title,
|
|
108
|
+
total_views=0,
|
|
109
|
+
)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.warning(f"Unexpected error getting views for page {page_id}: {e}")
|
|
112
|
+
return PageViews(
|
|
113
|
+
page_id=page_id,
|
|
114
|
+
page_title=page_title,
|
|
115
|
+
total_views=0,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def _get_page_views_direct(
|
|
119
|
+
self,
|
|
120
|
+
page_id: str,
|
|
121
|
+
) -> dict:
|
|
122
|
+
"""Get page views using direct API call.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
page_id: The ID of the page
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Dictionary with view statistics
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
HTTPError: If the API request fails
|
|
132
|
+
"""
|
|
133
|
+
url = f"{self.confluence.url}/rest/api/analytics/content/{page_id}/views"
|
|
134
|
+
response = self.confluence._session.get(url)
|
|
135
|
+
response.raise_for_status()
|
|
136
|
+
return response.json()
|
|
137
|
+
|
|
138
|
+
def batch_get_page_views(
|
|
139
|
+
self,
|
|
140
|
+
page_ids: list[str],
|
|
141
|
+
include_title: bool = True,
|
|
142
|
+
) -> PageViewsBatchResponse:
|
|
143
|
+
"""Get view statistics for multiple pages.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
page_ids: List of page IDs
|
|
147
|
+
include_title: Whether to fetch and include page titles
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
PageViewsBatchResponse with results for all pages
|
|
151
|
+
"""
|
|
152
|
+
pages: list[PageViews] = []
|
|
153
|
+
errors: list[dict[str, str]] = []
|
|
154
|
+
|
|
155
|
+
for page_id in page_ids:
|
|
156
|
+
try:
|
|
157
|
+
page_views = self.get_page_views(page_id, include_title=include_title)
|
|
158
|
+
pages.append(page_views)
|
|
159
|
+
except HTTPError as e:
|
|
160
|
+
# Propagate auth errors
|
|
161
|
+
if e.response is not None and e.response.status_code in [401, 403]:
|
|
162
|
+
raise
|
|
163
|
+
errors.append({"page_id": page_id, "error": str(e)})
|
|
164
|
+
except Exception as e:
|
|
165
|
+
errors.append({"page_id": page_id, "error": str(e)})
|
|
166
|
+
|
|
167
|
+
return PageViewsBatchResponse(
|
|
168
|
+
pages=pages,
|
|
169
|
+
total_count=len(page_ids),
|
|
170
|
+
success_count=len(pages),
|
|
171
|
+
error_count=len(errors),
|
|
172
|
+
errors=errors,
|
|
173
|
+
)
|