mcp-atlassian 0.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.

Potentially problematic release.


This version of mcp-atlassian might be problematic. Click here for more details.

@@ -0,0 +1,3 @@
1
+ CONFLUENCE_CLOUD_URL=https://lunit.atlassian.net/wiki
2
+ CONFLUENCE_CLOUD_USER=hslee@lunit.io
3
+ CONFLUENCE_CLOUD_TOKEN=ATATT3xFfGF0Kc0ls46wfOZlSkxQ-7rrD4cTZXUmFfug9uFJDRjs4saEG-F4eKQmC87KM9sLaQ5PouzrueMjDohkiW43XDEGLBn7RLNWXt3dxAtze_-x0NGJFZ4OWrZ1IqAeM0ItffsR54anvLxDcjpb_iZShYeETIUWB0EubvD0YWYUBy8rWhE=BE4C0ABA
@@ -0,0 +1,3 @@
1
+ CONFLUENCE_CLOUD_URL=your_confluence_url
2
+ CONFLUENCE_CLOUD_USER=your_username
3
+ CONFLUENCE_CLOUD_TOKEN=your_api_token
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.3
2
+ Name: mcp-atlassian
3
+ Version: 0.1.0
4
+ Summary: The Model Context Protocol (MCP) Atlassian integration is an open-source implementation that bridges Atlassian products (Jira and Confluence) with AI language models following Anthropic's MCP specification. This project enables secure, contextual AI interactions with Atlassian tools while maintaining data privacy and security. Key features include:
5
+ Author-email: sooperset <soomiles.dev@gmail.com>
6
+ Requires-Python: >=3.13
7
+ Requires-Dist: atlassian-python-api>=3.41.16
8
+ Requires-Dist: beautifulsoup4>=4.12.3
9
+ Requires-Dist: httpx>=0.28.0
10
+ Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: python-dotenv>=1.0.1
12
+ Description-Content-Type: text/markdown
13
+
14
+ # mcp-atlassian
15
+
16
+ MCP server to interact with Atlassian products (currently supporting Confluence).
17
+
18
+ ## Features
19
+
20
+ ### Tools
21
+
22
+ - search_confluence: Search Confluence content using natural language
23
+ - get_page_content: Get content of a specific Confluence page
24
+ - get_page_comments: Get comments for a specific page
25
+
26
+ ### Example prompts
27
+
28
+ - "Search for all documentation related to authentication and summarize the key points"
29
+ - "Get the content of the onboarding guide and create a checklist from it"
30
+ - "Find all comments on the project requirements page and highlight any concerns raised"
31
+
32
+ ## Setup
33
+
34
+ ### Requirements
35
+
36
+ Create a `.env` file with:
37
+ ```
38
+ CONFLUENCE_CLOUD_URL=your_confluence_url
39
+ CONFLUENCE_CLOUD_USER=your_username
40
+ CONFLUENCE_CLOUD_TOKEN=your_api_token
41
+ ```
42
+
43
+ To get an API token:
44
+ 1. Log in to https://id.atlassian.com/manage-profile/security/api-tokens
45
+ 2. Click Create API token
46
+ 3. Enter a memorable Label for your token and click Create
47
+ 4. Click Copy to clipboard to save your token securely
48
+
49
+ ### Claude Desktop Configuration
50
+
51
+ Location:
52
+ - MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
53
+ - Windows: `%APPDATA%/Claude/claude_desktop_config.json`
54
+
55
+ Configuration:
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "mcp-atlassian": {
60
+ "command": "uv",
61
+ "args": [
62
+ "--directory",
63
+ "<dir_to>/mcp-atlassian",
64
+ "run",
65
+ "mcp-atlassian"
66
+ ],
67
+ "env": {
68
+ "CONFLUENCE_CLOUD_URL": "your_confluence_url",
69
+ "CONFLUENCE_CLOUD_USER": "your_username",
70
+ "CONFLUENCE_CLOUD_TOKEN": "your_api_token"
71
+ }
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## Development
78
+
79
+ ### Building
80
+
81
+ ```bash
82
+ # Install dependencies
83
+ uv sync
84
+
85
+ # Build package
86
+ uv build
87
+
88
+ # Publish to PyPI
89
+ uv publish
90
+ ```
91
+
92
+ ### Debugging
93
+
94
+ Use MCP Inspector:
95
+ ```bash
96
+ npx @modelcontextprotocol/inspector uv --directory /path/to/mcp-atlassian run mcp-atlassian
97
+ ```
98
+
99
+ View logs:
100
+ ```bash
101
+ tail -n 20 -f ~/Library/Logs/Claude/mcp-server-mcp-atlassian.log
102
+ ```
103
+
104
+ ## Todo
105
+
106
+ - [ ] Jira integration
@@ -0,0 +1,93 @@
1
+ # mcp-atlassian
2
+
3
+ MCP server to interact with Atlassian products (currently supporting Confluence).
4
+
5
+ ## Features
6
+
7
+ ### Tools
8
+
9
+ - search_confluence: Search Confluence content using natural language
10
+ - get_page_content: Get content of a specific Confluence page
11
+ - get_page_comments: Get comments for a specific page
12
+
13
+ ### Example prompts
14
+
15
+ - "Search for all documentation related to authentication and summarize the key points"
16
+ - "Get the content of the onboarding guide and create a checklist from it"
17
+ - "Find all comments on the project requirements page and highlight any concerns raised"
18
+
19
+ ## Setup
20
+
21
+ ### Requirements
22
+
23
+ Create a `.env` file with:
24
+ ```
25
+ CONFLUENCE_CLOUD_URL=your_confluence_url
26
+ CONFLUENCE_CLOUD_USER=your_username
27
+ CONFLUENCE_CLOUD_TOKEN=your_api_token
28
+ ```
29
+
30
+ To get an API token:
31
+ 1. Log in to https://id.atlassian.com/manage-profile/security/api-tokens
32
+ 2. Click Create API token
33
+ 3. Enter a memorable Label for your token and click Create
34
+ 4. Click Copy to clipboard to save your token securely
35
+
36
+ ### Claude Desktop Configuration
37
+
38
+ Location:
39
+ - MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
40
+ - Windows: `%APPDATA%/Claude/claude_desktop_config.json`
41
+
42
+ Configuration:
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "mcp-atlassian": {
47
+ "command": "uv",
48
+ "args": [
49
+ "--directory",
50
+ "<dir_to>/mcp-atlassian",
51
+ "run",
52
+ "mcp-atlassian"
53
+ ],
54
+ "env": {
55
+ "CONFLUENCE_CLOUD_URL": "your_confluence_url",
56
+ "CONFLUENCE_CLOUD_USER": "your_username",
57
+ "CONFLUENCE_CLOUD_TOKEN": "your_api_token"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Development
65
+
66
+ ### Building
67
+
68
+ ```bash
69
+ # Install dependencies
70
+ uv sync
71
+
72
+ # Build package
73
+ uv build
74
+
75
+ # Publish to PyPI
76
+ uv publish
77
+ ```
78
+
79
+ ### Debugging
80
+
81
+ Use MCP Inspector:
82
+ ```bash
83
+ npx @modelcontextprotocol/inspector uv --directory /path/to/mcp-atlassian run mcp-atlassian
84
+ ```
85
+
86
+ View logs:
87
+ ```bash
88
+ tail -n 20 -f ~/Library/Logs/Claude/mcp-server-mcp-atlassian.log
89
+ ```
90
+
91
+ ## Todo
92
+
93
+ - [ ] Jira integration
@@ -0,0 +1,23 @@
1
+ [project]
2
+ name = "mcp-atlassian"
3
+ version = "0.1.0"
4
+ description = "The Model Context Protocol (MCP) Atlassian integration is an open-source implementation that bridges Atlassian products (Jira and Confluence) with AI language models following Anthropic's MCP specification. This project enables secure, contextual AI interactions with Atlassian tools while maintaining data privacy and security. Key features include:"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "atlassian-python-api>=3.41.16",
9
+ "beautifulsoup4>=4.12.3",
10
+ "httpx>=0.28.0",
11
+ "mcp>=1.0.0",
12
+ "python-dotenv>=1.0.1",
13
+ ]
14
+ [[project.authors]]
15
+ name = "sooperset"
16
+ email = "soomiles.dev@gmail.com"
17
+
18
+ [build-system]
19
+ requires = [ "hatchling",]
20
+ build-backend = "hatchling.build"
21
+
22
+ [project.scripts]
23
+ mcp-atlassian = "mcp_atlassian:main"
@@ -0,0 +1,11 @@
1
+ import asyncio
2
+
3
+ from . import server
4
+
5
+
6
+ def main():
7
+ """Main entry point for the package."""
8
+ asyncio.run(server.main())
9
+
10
+
11
+ __all__ = ["main", "server"]
@@ -0,0 +1,154 @@
1
+ import logging
2
+ import os
3
+ from dataclasses import dataclass
4
+ from typing import Dict, Optional
5
+
6
+ from atlassian import Confluence
7
+ from bs4 import BeautifulSoup
8
+ from dotenv import load_dotenv
9
+
10
+ # Load environment variables
11
+ load_dotenv()
12
+
13
+ # Configure logging
14
+ logger = logging.getLogger("mcp-atlassian")
15
+
16
+
17
+ @dataclass
18
+ class Document:
19
+ """Class to represent a document with content and metadata."""
20
+
21
+ page_content: str
22
+ metadata: Dict[str, any]
23
+
24
+
25
+ class ConfluenceFetcher:
26
+ """Handles fetching and parsing content from Confluence."""
27
+
28
+ def __init__(self):
29
+ self.url = os.getenv("CONFLUENCE_CLOUD_URL")
30
+ self.username = os.getenv("CONFLUENCE_CLOUD_USER")
31
+ self.api_key = os.getenv("CONFLUENCE_CLOUD_TOKEN")
32
+
33
+ if not all([self.url, self.username, self.api_key]):
34
+ raise ValueError("Missing required Confluence environment variables")
35
+
36
+ self.confluence = Confluence(url=self.url, username=self.username, password=self.api_key, cloud=True)
37
+
38
+ def _clean_html_content(self, html_content: str) -> str:
39
+ """Clean HTML content and return plain text."""
40
+ soup = BeautifulSoup(html_content, "html.parser")
41
+ return soup.get_text(separator=" ", strip=True)
42
+
43
+ def get_spaces(self, start: int = 0, limit: int = 10):
44
+ """Get all available spaces."""
45
+ return self.confluence.get_all_spaces(start=start, limit=limit)
46
+
47
+ def get_page_content(self, page_id: str, clean_html: bool = True) -> Document:
48
+ """Get content of a specific page."""
49
+ page = self.confluence.get_page_by_id(page_id=page_id, expand="body.storage,version")
50
+
51
+ content = page["body"]["storage"]["value"]
52
+ if clean_html:
53
+ content = self._clean_html_content(content)
54
+
55
+ metadata = {
56
+ "page_id": page_id,
57
+ "title": page["title"],
58
+ "version": page.get("version", {}).get("number"),
59
+ "url": f"{self.url}/wiki/spaces/{page.get('space', {}).get('key')}/pages/{page_id}",
60
+ }
61
+
62
+ return Document(page_content=content, metadata=metadata)
63
+
64
+ def get_page_by_title(self, space_key: str, title: str, clean_html: bool = True) -> Optional[Document]:
65
+ """Get page content by space key and title."""
66
+ try:
67
+ page = self.confluence.get_page_by_title(space=space_key, title=title, expand="body.storage,version")
68
+
69
+ if not page:
70
+ return None
71
+
72
+ content = page["body"]["storage"]["value"]
73
+ if clean_html:
74
+ content = self._clean_html_content(content)
75
+
76
+ metadata = {
77
+ "page_id": page["id"],
78
+ "title": page["title"],
79
+ "version": page.get("version", {}).get("number"),
80
+ "space_key": space_key,
81
+ "url": f"{self.url}/wiki/spaces/{space_key}/pages/{page['id']}",
82
+ }
83
+
84
+ return Document(page_content=content, metadata=metadata)
85
+
86
+ except Exception as e:
87
+ logger.error(f"Error fetching page: {str(e)}")
88
+ return None
89
+
90
+ def get_space_pages(
91
+ self, space_key: str, start: int = 0, limit: int = 10, clean_html: bool = True
92
+ ) -> list[Document]:
93
+ """Get all pages from a specific space."""
94
+ pages = self.confluence.get_all_pages_from_space(
95
+ space=space_key, start=start, limit=limit, expand="body.storage"
96
+ )
97
+
98
+ documents = []
99
+ for page in pages:
100
+ content = page["body"]["storage"]["value"]
101
+ if clean_html:
102
+ content = self._clean_html_content(content)
103
+
104
+ metadata = {
105
+ "page_id": page["id"],
106
+ "title": page["title"],
107
+ "space_key": space_key,
108
+ "version": page.get("version", {}).get("number"),
109
+ "url": f"{self.url}/wiki/spaces/{space_key}/pages/{page['id']}",
110
+ }
111
+
112
+ documents.append(Document(page_content=content, metadata=metadata))
113
+
114
+ return documents
115
+
116
+ def get_page_comments(self, page_id: str, clean_html: bool = True) -> list[Document]:
117
+ """Get all comments for a specific page."""
118
+ comments = self.confluence.get_page_comments(content_id=page_id, expand="body.view.value", depth="all")[
119
+ "results"
120
+ ]
121
+
122
+ comment_documents = []
123
+ for comment in comments:
124
+ body = comment["body"]["view"]["value"]
125
+ if clean_html:
126
+ body = self._clean_html_content(body)
127
+
128
+ metadata = {
129
+ "page_id": page_id,
130
+ "comment_id": comment["id"],
131
+ "created": comment.get("created"),
132
+ "type": "comment",
133
+ "author": comment.get("author", {}).get("displayName"),
134
+ }
135
+
136
+ comment_documents.append(Document(page_content=body, metadata=metadata))
137
+
138
+ return comment_documents
139
+
140
+ def search(self, cql: str, limit: int = 10, clean_html: bool = True) -> list[Document]:
141
+ """Search content using Confluence Query Language (CQL)."""
142
+ results = self.confluence.cql(cql=cql, limit=limit, expand="body.storage")
143
+
144
+ documents = []
145
+ for result in results.get("results", []):
146
+ content = result.get("content", {})
147
+ if content.get("type") == "page":
148
+ doc = self.get_page_content(content["id"], clean_html)
149
+ # Add page ID to metadata if not already present
150
+ if "page_id" not in doc.metadata:
151
+ doc.metadata["page_id"] = content["id"]
152
+ documents.append(doc)
153
+
154
+ return documents
@@ -0,0 +1,176 @@
1
+ import json
2
+ import logging
3
+ from collections.abc import Sequence
4
+ from typing import Any
5
+
6
+ from mcp.server import Server
7
+ from mcp.types import Resource, TextContent, Tool
8
+ from pydantic import AnyUrl
9
+
10
+ from .confluence import ConfluenceFetcher
11
+
12
+ # Configure logging
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger("mcp-atlassian")
15
+
16
+ # Initialize the content fetcher
17
+ fetcher = ConfluenceFetcher()
18
+ app = Server("mcp-atlassian")
19
+
20
+
21
+ @app.list_resources()
22
+ async def list_resources() -> list[Resource]:
23
+ """List available Confluence spaces as resources."""
24
+ spaces = fetcher.get_spaces()
25
+ return [
26
+ Resource(
27
+ uri=AnyUrl(f"confluence://{space['key']}"),
28
+ name=f"Confluence Space: {space['name']}",
29
+ mimeType="text/plain",
30
+ description=space.get("description", {}).get("plain", {}).get("value", ""),
31
+ )
32
+ for space in spaces
33
+ ]
34
+
35
+
36
+ @app.read_resource()
37
+ async def read_resource(uri: AnyUrl) -> str:
38
+ """Read content from Confluence."""
39
+ parts = str(uri).replace("confluence://", "").split("/")
40
+
41
+ # Handle space listing
42
+ if len(parts) == 1:
43
+ space_key = parts[0]
44
+ documents = fetcher.get_space_pages(space_key)
45
+ content = []
46
+ for doc in documents:
47
+ content.append(f"# {doc.metadata['title']}\n\n{doc.page_content}\n---")
48
+ return "\n\n".join(content)
49
+
50
+ # Handle specific page
51
+ elif len(parts) >= 3 and parts[1] == "pages":
52
+ space_key = parts[0]
53
+ title = parts[2]
54
+ doc = fetcher.get_page_by_title(space_key, title)
55
+
56
+ if not doc:
57
+ raise ValueError(f"Page not found: {title}")
58
+
59
+ return doc.page_content
60
+
61
+ raise ValueError(f"Invalid resource URI: {uri}")
62
+
63
+
64
+ @app.list_tools()
65
+ async def list_tools() -> list[Tool]:
66
+ """List available Confluence tools."""
67
+ return [
68
+ Tool(
69
+ name="search_confluence",
70
+ description="Search Confluence content using CQL",
71
+ inputSchema={
72
+ "type": "object",
73
+ "properties": {
74
+ "query": {"type": "string", "description": "CQL query string (e.g. 'type=page AND space=DEV')"},
75
+ "limit": {
76
+ "type": "number",
77
+ "description": "Maximum number of results (1-50)",
78
+ "default": 10,
79
+ "minimum": 1,
80
+ "maximum": 50,
81
+ },
82
+ },
83
+ "required": ["query"],
84
+ },
85
+ ),
86
+ Tool(
87
+ name="get_page_content",
88
+ description="Get content of a specific Confluence page by ID",
89
+ inputSchema={
90
+ "type": "object",
91
+ "properties": {
92
+ "page_id": {"type": "string", "description": "Confluence page ID"},
93
+ "include_metadata": {
94
+ "type": "boolean",
95
+ "description": "Whether to include page metadata",
96
+ "default": True,
97
+ },
98
+ },
99
+ "required": ["page_id"],
100
+ },
101
+ ),
102
+ Tool(
103
+ name="get_page_comments",
104
+ description="Get comments for a specific Confluence page",
105
+ inputSchema={
106
+ "type": "object",
107
+ "properties": {"page_id": {"type": "string", "description": "Confluence page ID"}},
108
+ "required": ["page_id"],
109
+ },
110
+ ),
111
+ ]
112
+
113
+
114
+ @app.call_tool()
115
+ async def call_tool(name: str, arguments: Any) -> Sequence[TextContent]:
116
+ """Handle tool calls for Confluence operations."""
117
+ try:
118
+ if name == "search_confluence":
119
+ limit = min(int(arguments.get("limit", 10)), 50)
120
+ documents = fetcher.search(arguments["query"], limit)
121
+ search_results = [
122
+ {
123
+ "page_id": doc.metadata["page_id"],
124
+ "title": doc.metadata["title"],
125
+ "space": doc.metadata.get("space_key"),
126
+ "excerpt": doc.page_content[:500] + "...",
127
+ "url": doc.metadata.get("url", ""),
128
+ }
129
+ for doc in documents
130
+ ]
131
+
132
+ return [TextContent(type="text", text=json.dumps(search_results, indent=2))]
133
+
134
+ elif name == "get_page_content":
135
+ doc = fetcher.get_page_content(arguments["page_id"])
136
+ include_metadata = arguments.get("include_metadata", True)
137
+
138
+ if include_metadata:
139
+ result = {"content": doc.page_content, "metadata": doc.metadata}
140
+ else:
141
+ result = {"content": doc.page_content}
142
+
143
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
144
+
145
+ elif name == "get_page_comments":
146
+ comments = fetcher.get_page_comments(arguments["page_id"])
147
+ formatted_comments = [
148
+ {
149
+ "author": comment.metadata["author"],
150
+ "created": comment.metadata["created"],
151
+ "content": comment.page_content,
152
+ }
153
+ for comment in comments
154
+ ]
155
+
156
+ return [TextContent(type="text", text=json.dumps(formatted_comments, indent=2))]
157
+
158
+ raise ValueError(f"Unknown tool: {name}")
159
+
160
+ except Exception as e:
161
+ logger.error(f"Tool execution error: {str(e)}")
162
+ raise RuntimeError(f"Tool execution failed: {str(e)}")
163
+
164
+
165
+ async def main():
166
+ # Import here to avoid issues with event loops
167
+ from mcp.server.stdio import stdio_server
168
+
169
+ async with stdio_server() as (read_stream, write_stream):
170
+ await app.run(read_stream, write_stream, app.create_initialization_options())
171
+
172
+
173
+ if __name__ == "__main__":
174
+ import asyncio
175
+
176
+ asyncio.run(main())
@@ -0,0 +1,418 @@
1
+ version = 1
2
+ requires-python = ">=3.13"
3
+
4
+ [[package]]
5
+ name = "annotated-types"
6
+ version = "0.7.0"
7
+ source = { registry = "https://pypi.org/simple" }
8
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
9
+ wheels = [
10
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
11
+ ]
12
+
13
+ [[package]]
14
+ name = "anyio"
15
+ version = "4.6.2.post1"
16
+ source = { registry = "https://pypi.org/simple" }
17
+ dependencies = [
18
+ { name = "idna" },
19
+ { name = "sniffio" },
20
+ ]
21
+ sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
22
+ wheels = [
23
+ { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
24
+ ]
25
+
26
+ [[package]]
27
+ name = "atlassian-python-api"
28
+ version = "3.41.16"
29
+ source = { registry = "https://pypi.org/simple" }
30
+ dependencies = [
31
+ { name = "beautifulsoup4" },
32
+ { name = "deprecated" },
33
+ { name = "jmespath" },
34
+ { name = "oauthlib" },
35
+ { name = "requests" },
36
+ { name = "requests-oauthlib" },
37
+ { name = "six" },
38
+ ]
39
+ sdist = { url = "https://files.pythonhosted.org/packages/9a/04/15839ae4b60f8f15195a75bf512ab926374832affdbd83463da8edae2b62/atlassian_python_api-3.41.16.tar.gz", hash = "sha256:dc0144ff8b8884562bb2af650586292524ad25f120cd21940df80f0d2ac64411", size = 382425 }
40
+ wheels = [
41
+ { url = "https://files.pythonhosted.org/packages/28/5b/73d6e52274fa35c3a08f62336945b49eedd50aa02c6929f1ed62ae5874c2/atlassian_python_api-3.41.16-py3-none-any.whl", hash = "sha256:99e5587233a96d22c45a61b19523dd98e8266c620ba2d289f23e4ea35c9cf316", size = 177883 },
42
+ ]
43
+
44
+ [[package]]
45
+ name = "beautifulsoup4"
46
+ version = "4.12.3"
47
+ source = { registry = "https://pypi.org/simple" }
48
+ dependencies = [
49
+ { name = "soupsieve" },
50
+ ]
51
+ sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 }
52
+ wheels = [
53
+ { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 },
54
+ ]
55
+
56
+ [[package]]
57
+ name = "certifi"
58
+ version = "2024.8.30"
59
+ source = { registry = "https://pypi.org/simple" }
60
+ sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 }
61
+ wheels = [
62
+ { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 },
63
+ ]
64
+
65
+ [[package]]
66
+ name = "charset-normalizer"
67
+ version = "3.4.0"
68
+ source = { registry = "https://pypi.org/simple" }
69
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 }
70
+ wheels = [
71
+ { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 },
72
+ { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 },
73
+ { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 },
74
+ { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 },
75
+ { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 },
76
+ { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 },
77
+ { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 },
78
+ { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 },
79
+ { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 },
80
+ { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 },
81
+ { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 },
82
+ { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 },
83
+ { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 },
84
+ { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 },
85
+ { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 },
86
+ { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 },
87
+ ]
88
+
89
+ [[package]]
90
+ name = "click"
91
+ version = "8.1.7"
92
+ source = { registry = "https://pypi.org/simple" }
93
+ dependencies = [
94
+ { name = "colorama", marker = "platform_system == 'Windows'" },
95
+ ]
96
+ sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
97
+ wheels = [
98
+ { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 },
99
+ ]
100
+
101
+ [[package]]
102
+ name = "colorama"
103
+ version = "0.4.6"
104
+ source = { registry = "https://pypi.org/simple" }
105
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
106
+ wheels = [
107
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
108
+ ]
109
+
110
+ [[package]]
111
+ name = "deprecated"
112
+ version = "1.2.15"
113
+ source = { registry = "https://pypi.org/simple" }
114
+ dependencies = [
115
+ { name = "wrapt" },
116
+ ]
117
+ sdist = { url = "https://files.pythonhosted.org/packages/2e/a3/53e7d78a6850ffdd394d7048a31a6f14e44900adedf190f9a165f6b69439/deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d", size = 2977612 }
118
+ wheels = [
119
+ { url = "https://files.pythonhosted.org/packages/1d/8f/c7f227eb42cfeaddce3eb0c96c60cbca37797fa7b34f8e1aeadf6c5c0983/Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", size = 9941 },
120
+ ]
121
+
122
+ [[package]]
123
+ name = "h11"
124
+ version = "0.14.0"
125
+ source = { registry = "https://pypi.org/simple" }
126
+ sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
127
+ wheels = [
128
+ { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
129
+ ]
130
+
131
+ [[package]]
132
+ name = "httpcore"
133
+ version = "1.0.7"
134
+ source = { registry = "https://pypi.org/simple" }
135
+ dependencies = [
136
+ { name = "certifi" },
137
+ { name = "h11" },
138
+ ]
139
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 }
140
+ wheels = [
141
+ { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 },
142
+ ]
143
+
144
+ [[package]]
145
+ name = "httpx"
146
+ version = "0.28.0"
147
+ source = { registry = "https://pypi.org/simple" }
148
+ dependencies = [
149
+ { name = "anyio" },
150
+ { name = "certifi" },
151
+ { name = "httpcore" },
152
+ { name = "idna" },
153
+ ]
154
+ sdist = { url = "https://files.pythonhosted.org/packages/10/df/676b7cf674dd1bdc71a64ad393c89879f75e4a0ab8395165b498262ae106/httpx-0.28.0.tar.gz", hash = "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0", size = 141307 }
155
+ wheels = [
156
+ { url = "https://files.pythonhosted.org/packages/8f/fb/a19866137577ba60c6d8b69498dc36be479b13ba454f691348ddf428f185/httpx-0.28.0-py3-none-any.whl", hash = "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc", size = 73551 },
157
+ ]
158
+
159
+ [[package]]
160
+ name = "httpx-sse"
161
+ version = "0.4.0"
162
+ source = { registry = "https://pypi.org/simple" }
163
+ sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
164
+ wheels = [
165
+ { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
166
+ ]
167
+
168
+ [[package]]
169
+ name = "idna"
170
+ version = "3.10"
171
+ source = { registry = "https://pypi.org/simple" }
172
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
173
+ wheels = [
174
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
175
+ ]
176
+
177
+ [[package]]
178
+ name = "jmespath"
179
+ version = "1.0.1"
180
+ source = { registry = "https://pypi.org/simple" }
181
+ sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 }
182
+ wheels = [
183
+ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 },
184
+ ]
185
+
186
+ [[package]]
187
+ name = "mcp"
188
+ version = "1.0.0"
189
+ source = { registry = "https://pypi.org/simple" }
190
+ dependencies = [
191
+ { name = "anyio" },
192
+ { name = "httpx" },
193
+ { name = "httpx-sse" },
194
+ { name = "pydantic" },
195
+ { name = "sse-starlette" },
196
+ { name = "starlette" },
197
+ ]
198
+ sdist = { url = "https://files.pythonhosted.org/packages/97/de/a9ec0a1b6439f90ea59f89004bb2e7ec6890dfaeef809751d9e6577dca7e/mcp-1.0.0.tar.gz", hash = "sha256:dba51ce0b5c6a80e25576f606760c49a91ee90210fed805b530ca165d3bbc9b7", size = 82891 }
199
+ wheels = [
200
+ { url = "https://files.pythonhosted.org/packages/56/89/900c0c8445ec001d3725e475fc553b0feb2e8a51be018f3bb7de51e683db/mcp-1.0.0-py3-none-any.whl", hash = "sha256:bbe70ffa3341cd4da78b5eb504958355c68381fb29971471cea1e642a2af5b8a", size = 36361 },
201
+ ]
202
+
203
+ [[package]]
204
+ name = "mcp-atlassian"
205
+ version = "0.1.0"
206
+ source = { editable = "." }
207
+ dependencies = [
208
+ { name = "atlassian-python-api" },
209
+ { name = "beautifulsoup4" },
210
+ { name = "httpx" },
211
+ { name = "mcp" },
212
+ { name = "python-dotenv" },
213
+ ]
214
+
215
+ [package.metadata]
216
+ requires-dist = [
217
+ { name = "atlassian-python-api", specifier = ">=3.41.16" },
218
+ { name = "beautifulsoup4", specifier = ">=4.12.3" },
219
+ { name = "httpx", specifier = ">=0.28.0" },
220
+ { name = "mcp", specifier = ">=1.0.0" },
221
+ { name = "python-dotenv", specifier = ">=1.0.1" },
222
+ ]
223
+
224
+ [[package]]
225
+ name = "oauthlib"
226
+ version = "3.2.2"
227
+ source = { registry = "https://pypi.org/simple" }
228
+ sdist = { url = "https://files.pythonhosted.org/packages/6d/fa/fbf4001037904031639e6bfbfc02badfc7e12f137a8afa254df6c4c8a670/oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918", size = 177352 }
229
+ wheels = [
230
+ { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688 },
231
+ ]
232
+
233
+ [[package]]
234
+ name = "pydantic"
235
+ version = "2.10.2"
236
+ source = { registry = "https://pypi.org/simple" }
237
+ dependencies = [
238
+ { name = "annotated-types" },
239
+ { name = "pydantic-core" },
240
+ { name = "typing-extensions" },
241
+ ]
242
+ sdist = { url = "https://files.pythonhosted.org/packages/41/86/a03390cb12cf64e2a8df07c267f3eb8d5035e0f9a04bb20fb79403d2a00e/pydantic-2.10.2.tar.gz", hash = "sha256:2bc2d7f17232e0841cbba4641e65ba1eb6fafb3a08de3a091ff3ce14a197c4fa", size = 785401 }
243
+ wheels = [
244
+ { url = "https://files.pythonhosted.org/packages/d5/74/da832196702d0c56eb86b75bfa346db9238617e29b0b7ee3b8b4eccfe654/pydantic-2.10.2-py3-none-any.whl", hash = "sha256:cfb96e45951117c3024e6b67b25cdc33a3cb7b2fa62e239f7af1378358a1d99e", size = 456364 },
245
+ ]
246
+
247
+ [[package]]
248
+ name = "pydantic-core"
249
+ version = "2.27.1"
250
+ source = { registry = "https://pypi.org/simple" }
251
+ dependencies = [
252
+ { name = "typing-extensions" },
253
+ ]
254
+ sdist = { url = "https://files.pythonhosted.org/packages/a6/9f/7de1f19b6aea45aeb441838782d68352e71bfa98ee6fa048d5041991b33e/pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", size = 412785 }
255
+ wheels = [
256
+ { url = "https://files.pythonhosted.org/packages/0f/d6/91cb99a3c59d7b072bded9959fbeab0a9613d5a4935773c0801f1764c156/pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", size = 1895033 },
257
+ { url = "https://files.pythonhosted.org/packages/07/42/d35033f81a28b27dedcade9e967e8a40981a765795c9ebae2045bcef05d3/pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", size = 1807542 },
258
+ { url = "https://files.pythonhosted.org/packages/41/c2/491b59e222ec7e72236e512108ecad532c7f4391a14e971c963f624f7569/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", size = 1827854 },
259
+ { url = "https://files.pythonhosted.org/packages/e3/f3/363652651779113189cefdbbb619b7b07b7a67ebb6840325117cc8cc3460/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737", size = 1857389 },
260
+ { url = "https://files.pythonhosted.org/packages/5f/97/be804aed6b479af5a945daec7538d8bf358d668bdadde4c7888a2506bdfb/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2", size = 2037934 },
261
+ { url = "https://files.pythonhosted.org/packages/42/01/295f0bd4abf58902917e342ddfe5f76cf66ffabfc57c2e23c7681a1a1197/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107", size = 2735176 },
262
+ { url = "https://files.pythonhosted.org/packages/9d/a0/cd8e9c940ead89cc37812a1a9f310fef59ba2f0b22b4e417d84ab09fa970/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51", size = 2160720 },
263
+ { url = "https://files.pythonhosted.org/packages/73/ae/9d0980e286627e0aeca4c352a60bd760331622c12d576e5ea4441ac7e15e/pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a", size = 1992972 },
264
+ { url = "https://files.pythonhosted.org/packages/bf/ba/ae4480bc0292d54b85cfb954e9d6bd226982949f8316338677d56541b85f/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc", size = 2001477 },
265
+ { url = "https://files.pythonhosted.org/packages/55/b7/e26adf48c2f943092ce54ae14c3c08d0d221ad34ce80b18a50de8ed2cba8/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960", size = 2091186 },
266
+ { url = "https://files.pythonhosted.org/packages/ba/cc/8491fff5b608b3862eb36e7d29d36a1af1c945463ca4c5040bf46cc73f40/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23", size = 2154429 },
267
+ { url = "https://files.pythonhosted.org/packages/78/d8/c080592d80edd3441ab7f88f865f51dae94a157fc64283c680e9f32cf6da/pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", size = 1833713 },
268
+ { url = "https://files.pythonhosted.org/packages/83/84/5ab82a9ee2538ac95a66e51f6838d6aba6e0a03a42aa185ad2fe404a4e8f/pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", size = 1987897 },
269
+ { url = "https://files.pythonhosted.org/packages/df/c3/b15fb833926d91d982fde29c0624c9f225da743c7af801dace0d4e187e71/pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", size = 1882983 },
270
+ ]
271
+
272
+ [[package]]
273
+ name = "python-dotenv"
274
+ version = "1.0.1"
275
+ source = { registry = "https://pypi.org/simple" }
276
+ sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
277
+ wheels = [
278
+ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
279
+ ]
280
+
281
+ [[package]]
282
+ name = "requests"
283
+ version = "2.32.3"
284
+ source = { registry = "https://pypi.org/simple" }
285
+ dependencies = [
286
+ { name = "certifi" },
287
+ { name = "charset-normalizer" },
288
+ { name = "idna" },
289
+ { name = "urllib3" },
290
+ ]
291
+ sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 }
292
+ wheels = [
293
+ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
294
+ ]
295
+
296
+ [[package]]
297
+ name = "requests-oauthlib"
298
+ version = "2.0.0"
299
+ source = { registry = "https://pypi.org/simple" }
300
+ dependencies = [
301
+ { name = "oauthlib" },
302
+ { name = "requests" },
303
+ ]
304
+ sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650 }
305
+ wheels = [
306
+ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179 },
307
+ ]
308
+
309
+ [[package]]
310
+ name = "six"
311
+ version = "1.16.0"
312
+ source = { registry = "https://pypi.org/simple" }
313
+ sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 }
314
+ wheels = [
315
+ { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 },
316
+ ]
317
+
318
+ [[package]]
319
+ name = "sniffio"
320
+ version = "1.3.1"
321
+ source = { registry = "https://pypi.org/simple" }
322
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
323
+ wheels = [
324
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
325
+ ]
326
+
327
+ [[package]]
328
+ name = "soupsieve"
329
+ version = "2.6"
330
+ source = { registry = "https://pypi.org/simple" }
331
+ sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 }
332
+ wheels = [
333
+ { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
334
+ ]
335
+
336
+ [[package]]
337
+ name = "sse-starlette"
338
+ version = "2.1.3"
339
+ source = { registry = "https://pypi.org/simple" }
340
+ dependencies = [
341
+ { name = "anyio" },
342
+ { name = "starlette" },
343
+ { name = "uvicorn" },
344
+ ]
345
+ sdist = { url = "https://files.pythonhosted.org/packages/72/fc/56ab9f116b2133521f532fce8d03194cf04dcac25f583cf3d839be4c0496/sse_starlette-2.1.3.tar.gz", hash = "sha256:9cd27eb35319e1414e3d2558ee7414487f9529ce3b3cf9b21434fd110e017169", size = 19678 }
346
+ wheels = [
347
+ { url = "https://files.pythonhosted.org/packages/52/aa/36b271bc4fa1d2796311ee7c7283a3a1c348bad426d37293609ca4300eef/sse_starlette-2.1.3-py3-none-any.whl", hash = "sha256:8ec846438b4665b9e8c560fcdea6bc8081a3abf7942faa95e5a744999d219772", size = 9383 },
348
+ ]
349
+
350
+ [[package]]
351
+ name = "starlette"
352
+ version = "0.41.3"
353
+ source = { registry = "https://pypi.org/simple" }
354
+ dependencies = [
355
+ { name = "anyio" },
356
+ ]
357
+ sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159 }
358
+ wheels = [
359
+ { url = "https://files.pythonhosted.org/packages/96/00/2b325970b3060c7cecebab6d295afe763365822b1306a12eeab198f74323/starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7", size = 73225 },
360
+ ]
361
+
362
+ [[package]]
363
+ name = "typing-extensions"
364
+ version = "4.12.2"
365
+ source = { registry = "https://pypi.org/simple" }
366
+ sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
367
+ wheels = [
368
+ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
369
+ ]
370
+
371
+ [[package]]
372
+ name = "urllib3"
373
+ version = "2.2.3"
374
+ source = { registry = "https://pypi.org/simple" }
375
+ sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 }
376
+ wheels = [
377
+ { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 },
378
+ ]
379
+
380
+ [[package]]
381
+ name = "uvicorn"
382
+ version = "0.32.1"
383
+ source = { registry = "https://pypi.org/simple" }
384
+ dependencies = [
385
+ { name = "click" },
386
+ { name = "h11" },
387
+ ]
388
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/3c/21dba3e7d76138725ef307e3d7ddd29b763119b3aa459d02cc05fefcff75/uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175", size = 77630 }
389
+ wheels = [
390
+ { url = "https://files.pythonhosted.org/packages/50/c1/2d27b0a15826c2b71dcf6e2f5402181ef85acf439617bb2f1453125ce1f3/uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e", size = 63828 },
391
+ ]
392
+
393
+ [[package]]
394
+ name = "wrapt"
395
+ version = "1.17.0"
396
+ source = { registry = "https://pypi.org/simple" }
397
+ sdist = { url = "https://files.pythonhosted.org/packages/24/a1/fc03dca9b0432725c2e8cdbf91a349d2194cf03d8523c124faebe581de09/wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", size = 55542 }
398
+ wheels = [
399
+ { url = "https://files.pythonhosted.org/packages/67/9c/38294e1bb92b055222d1b8b6591604ca4468b77b1250f59c15256437644f/wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", size = 38904 },
400
+ { url = "https://files.pythonhosted.org/packages/78/b6/76597fb362cbf8913a481d41b14b049a8813cd402a5d2f84e57957c813ae/wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", size = 88608 },
401
+ { url = "https://files.pythonhosted.org/packages/bc/69/b500884e45b3881926b5f69188dc542fb5880019d15c8a0df1ab1dfda1f7/wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", size = 80879 },
402
+ { url = "https://files.pythonhosted.org/packages/52/31/f4cc58afe29eab8a50ac5969963010c8b60987e719c478a5024bce39bc42/wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", size = 89119 },
403
+ { url = "https://files.pythonhosted.org/packages/aa/9c/05ab6bf75dbae7a9d34975fb6ee577e086c1c26cde3b6cf6051726d33c7c/wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", size = 86778 },
404
+ { url = "https://files.pythonhosted.org/packages/0e/6c/4b8d42e3db355603d35fe5c9db79c28f2472a6fd1ccf4dc25ae46739672a/wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", size = 79793 },
405
+ { url = "https://files.pythonhosted.org/packages/69/23/90e3a2ee210c0843b2c2a49b3b97ffcf9cad1387cb18cbeef9218631ed5a/wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", size = 87606 },
406
+ { url = "https://files.pythonhosted.org/packages/5f/06/3683126491ca787d8d71d8d340e775d40767c5efedb35039d987203393b7/wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", size = 36651 },
407
+ { url = "https://files.pythonhosted.org/packages/f1/bc/3bf6d2ca0d2c030d324ef9272bea0a8fdaff68f3d1fa7be7a61da88e51f7/wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838", size = 38835 },
408
+ { url = "https://files.pythonhosted.org/packages/ce/b5/251165c232d87197a81cd362eeb5104d661a2dd3aa1f0b33e4bf61dda8b8/wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", size = 40146 },
409
+ { url = "https://files.pythonhosted.org/packages/89/33/1e1bdd3e866eeb73d8c4755db1ceb8a80d5bd51ee4648b3f2247adec4e67/wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", size = 113444 },
410
+ { url = "https://files.pythonhosted.org/packages/9f/7c/94f53b065a43f5dc1fbdd8b80fd8f41284315b543805c956619c0b8d92f0/wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", size = 101246 },
411
+ { url = "https://files.pythonhosted.org/packages/62/5d/640360baac6ea6018ed5e34e6e80e33cfbae2aefde24f117587cd5efd4b7/wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", size = 109320 },
412
+ { url = "https://files.pythonhosted.org/packages/e3/cf/6c7a00ae86a2e9482c91170aefe93f4ccda06c1ac86c4de637c69133da59/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", size = 110193 },
413
+ { url = "https://files.pythonhosted.org/packages/cd/cc/aa718df0d20287e8f953ce0e2f70c0af0fba1d3c367db7ee8bdc46ea7003/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", size = 100460 },
414
+ { url = "https://files.pythonhosted.org/packages/f7/16/9f3ac99fe1f6caaa789d67b4e3c562898b532c250769f5255fa8b8b93983/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", size = 106347 },
415
+ { url = "https://files.pythonhosted.org/packages/64/85/c77a331b2c06af49a687f8b926fc2d111047a51e6f0b0a4baa01ff3a673a/wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", size = 37971 },
416
+ { url = "https://files.pythonhosted.org/packages/05/9b/b2469f8be9efed24283fd7b9eeb8e913e9bc0715cf919ea8645e428ab7af/wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", size = 40755 },
417
+ { url = "https://files.pythonhosted.org/packages/4b/d9/a8ba5e9507a9af1917285d118388c5eb7a81834873f45df213a6fe923774/wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", size = 23592 },
418
+ ]