mcp-ticketer 0.4.1__py3-none-any.whl → 0.4.2__py3-none-any.whl
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-ticketer might be problematic. Click here for more details.
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/cli/auggie_configure.py +66 -0
- mcp_ticketer/cli/codex_configure.py +68 -0
- mcp_ticketer/cli/gemini_configure.py +66 -0
- mcp_ticketer/cli/main.py +194 -32
- mcp_ticketer/cli/mcp_configure.py +60 -0
- mcp_ticketer/mcp/server_sdk.py +93 -0
- mcp_ticketer/mcp/tools/__init__.py +38 -0
- mcp_ticketer/mcp/tools/attachment_tools.py +180 -0
- mcp_ticketer/mcp/tools/bulk_tools.py +273 -0
- mcp_ticketer/mcp/tools/comment_tools.py +90 -0
- mcp_ticketer/mcp/tools/hierarchy_tools.py +383 -0
- mcp_ticketer/mcp/tools/pr_tools.py +154 -0
- mcp_ticketer/mcp/tools/search_tools.py +206 -0
- mcp_ticketer/mcp/tools/ticket_tools.py +277 -0
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/METADATA +30 -16
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/RECORD +21 -12
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.1.dist-info → mcp_ticketer-0.4.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""Search and query tools for finding tickets.
|
|
2
|
+
|
|
3
|
+
This module implements advanced search capabilities for tickets using
|
|
4
|
+
various filters and criteria.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
from ...core.models import Priority, SearchQuery, TicketState
|
|
10
|
+
from ..server_sdk import get_adapter, mcp
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@mcp.tool()
|
|
14
|
+
async def ticket_search(
|
|
15
|
+
query: Optional[str] = None,
|
|
16
|
+
state: Optional[str] = None,
|
|
17
|
+
priority: Optional[str] = None,
|
|
18
|
+
tags: Optional[list[str]] = None,
|
|
19
|
+
assignee: Optional[str] = None,
|
|
20
|
+
limit: int = 10,
|
|
21
|
+
) -> dict[str, Any]:
|
|
22
|
+
"""Search tickets using advanced filters.
|
|
23
|
+
|
|
24
|
+
Searches for tickets matching the specified criteria. All filters are
|
|
25
|
+
optional and can be combined.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
query: Text search query to match against title and description
|
|
29
|
+
state: Filter by state - must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked
|
|
30
|
+
priority: Filter by priority - must be one of: low, medium, high, critical
|
|
31
|
+
tags: Filter by tags - tickets must have all specified tags
|
|
32
|
+
assignee: Filter by assigned user ID or email
|
|
33
|
+
limit: Maximum number of results to return (default: 10, max: 100)
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
List of tickets matching search criteria, or error information
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
adapter = get_adapter()
|
|
41
|
+
|
|
42
|
+
# Validate and build search query
|
|
43
|
+
state_enum = None
|
|
44
|
+
if state is not None:
|
|
45
|
+
try:
|
|
46
|
+
state_enum = TicketState(state.lower())
|
|
47
|
+
except ValueError:
|
|
48
|
+
return {
|
|
49
|
+
"status": "error",
|
|
50
|
+
"error": f"Invalid state '{state}'. Must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
priority_enum = None
|
|
54
|
+
if priority is not None:
|
|
55
|
+
try:
|
|
56
|
+
priority_enum = Priority(priority.lower())
|
|
57
|
+
except ValueError:
|
|
58
|
+
return {
|
|
59
|
+
"status": "error",
|
|
60
|
+
"error": f"Invalid priority '{priority}'. Must be one of: low, medium, high, critical",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Create search query
|
|
64
|
+
search_query = SearchQuery(
|
|
65
|
+
query=query,
|
|
66
|
+
state=state_enum,
|
|
67
|
+
priority=priority_enum,
|
|
68
|
+
tags=tags,
|
|
69
|
+
assignee=assignee,
|
|
70
|
+
limit=min(limit, 100), # Enforce max limit
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Execute search via adapter
|
|
74
|
+
results = await adapter.search(search_query)
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
"status": "completed",
|
|
78
|
+
"tickets": [ticket.model_dump() for ticket in results],
|
|
79
|
+
"count": len(results),
|
|
80
|
+
"query": {
|
|
81
|
+
"text": query,
|
|
82
|
+
"state": state,
|
|
83
|
+
"priority": priority,
|
|
84
|
+
"tags": tags,
|
|
85
|
+
"assignee": assignee,
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
except Exception as e:
|
|
89
|
+
return {
|
|
90
|
+
"status": "error",
|
|
91
|
+
"error": f"Failed to search tickets: {str(e)}",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@mcp.tool()
|
|
96
|
+
async def ticket_search_hierarchy(
|
|
97
|
+
query: str,
|
|
98
|
+
include_children: bool = True,
|
|
99
|
+
max_depth: int = 3,
|
|
100
|
+
) -> dict[str, Any]:
|
|
101
|
+
"""Search tickets and include their hierarchy.
|
|
102
|
+
|
|
103
|
+
Performs a text search and returns matching tickets along with their
|
|
104
|
+
hierarchical context (parent epics/issues and child issues/tasks).
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
query: Text search query to match against title and description
|
|
108
|
+
include_children: Whether to include child tickets in results
|
|
109
|
+
max_depth: Maximum hierarchy depth to include (1-3, default: 3)
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
List of tickets with hierarchy information, or error information
|
|
113
|
+
|
|
114
|
+
"""
|
|
115
|
+
try:
|
|
116
|
+
adapter = get_adapter()
|
|
117
|
+
|
|
118
|
+
# Validate max_depth
|
|
119
|
+
if max_depth < 1 or max_depth > 3:
|
|
120
|
+
return {
|
|
121
|
+
"status": "error",
|
|
122
|
+
"error": "max_depth must be between 1 and 3",
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Create search query
|
|
126
|
+
search_query = SearchQuery(
|
|
127
|
+
query=query,
|
|
128
|
+
limit=50, # Reasonable limit for hierarchical search
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Execute search via adapter
|
|
132
|
+
results = await adapter.search(search_query)
|
|
133
|
+
|
|
134
|
+
# Build hierarchical results
|
|
135
|
+
hierarchical_results = []
|
|
136
|
+
for ticket in results:
|
|
137
|
+
ticket_data = {
|
|
138
|
+
"ticket": ticket.model_dump(),
|
|
139
|
+
"hierarchy": {},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Get parent epic if applicable
|
|
143
|
+
parent_epic_id = getattr(ticket, "parent_epic", None)
|
|
144
|
+
if parent_epic_id and max_depth >= 2:
|
|
145
|
+
try:
|
|
146
|
+
parent_epic = await adapter.read(parent_epic_id)
|
|
147
|
+
if parent_epic:
|
|
148
|
+
ticket_data["hierarchy"][
|
|
149
|
+
"parent_epic"
|
|
150
|
+
] = parent_epic.model_dump()
|
|
151
|
+
except Exception:
|
|
152
|
+
pass # Parent not found, continue
|
|
153
|
+
|
|
154
|
+
# Get parent issue if applicable (for tasks)
|
|
155
|
+
parent_issue_id = getattr(ticket, "parent_issue", None)
|
|
156
|
+
if parent_issue_id and max_depth >= 2:
|
|
157
|
+
try:
|
|
158
|
+
parent_issue = await adapter.read(parent_issue_id)
|
|
159
|
+
if parent_issue:
|
|
160
|
+
ticket_data["hierarchy"][
|
|
161
|
+
"parent_issue"
|
|
162
|
+
] = parent_issue.model_dump()
|
|
163
|
+
except Exception:
|
|
164
|
+
pass # Parent not found, continue
|
|
165
|
+
|
|
166
|
+
# Get children if requested
|
|
167
|
+
if include_children and max_depth >= 2:
|
|
168
|
+
children = []
|
|
169
|
+
|
|
170
|
+
# Get child issues (for epics)
|
|
171
|
+
child_issue_ids = getattr(ticket, "child_issues", [])
|
|
172
|
+
for child_id in child_issue_ids:
|
|
173
|
+
try:
|
|
174
|
+
child = await adapter.read(child_id)
|
|
175
|
+
if child:
|
|
176
|
+
children.append(child.model_dump())
|
|
177
|
+
except Exception:
|
|
178
|
+
pass # Child not found, continue
|
|
179
|
+
|
|
180
|
+
# Get child tasks (for issues)
|
|
181
|
+
child_task_ids = getattr(ticket, "children", [])
|
|
182
|
+
for child_id in child_task_ids:
|
|
183
|
+
try:
|
|
184
|
+
child = await adapter.read(child_id)
|
|
185
|
+
if child:
|
|
186
|
+
children.append(child.model_dump())
|
|
187
|
+
except Exception:
|
|
188
|
+
pass # Child not found, continue
|
|
189
|
+
|
|
190
|
+
if children:
|
|
191
|
+
ticket_data["hierarchy"]["children"] = children
|
|
192
|
+
|
|
193
|
+
hierarchical_results.append(ticket_data)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
"status": "completed",
|
|
197
|
+
"results": hierarchical_results,
|
|
198
|
+
"count": len(hierarchical_results),
|
|
199
|
+
"query": query,
|
|
200
|
+
"max_depth": max_depth,
|
|
201
|
+
}
|
|
202
|
+
except Exception as e:
|
|
203
|
+
return {
|
|
204
|
+
"status": "error",
|
|
205
|
+
"error": f"Failed to search with hierarchy: {str(e)}",
|
|
206
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""Basic CRUD operations for tickets.
|
|
2
|
+
|
|
3
|
+
This module implements the core create, read, update, delete, and list
|
|
4
|
+
operations for tickets using the FastMCP SDK.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
from ...core.models import Priority, Task, TicketState
|
|
10
|
+
from ..server_sdk import get_adapter, mcp
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@mcp.tool()
|
|
14
|
+
async def ticket_create(
|
|
15
|
+
title: str,
|
|
16
|
+
description: str = "",
|
|
17
|
+
priority: str = "medium",
|
|
18
|
+
tags: Optional[list[str]] = None,
|
|
19
|
+
assignee: Optional[str] = None,
|
|
20
|
+
) -> dict[str, Any]:
|
|
21
|
+
"""Create a new ticket with specified details.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
title: Ticket title (required)
|
|
25
|
+
description: Detailed description of the ticket
|
|
26
|
+
priority: Priority level - must be one of: low, medium, high, critical
|
|
27
|
+
tags: List of tags to categorize the ticket
|
|
28
|
+
assignee: User ID or email to assign the ticket to
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Created ticket details including ID and metadata, or error information
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
adapter = get_adapter()
|
|
36
|
+
|
|
37
|
+
# Validate and convert priority
|
|
38
|
+
try:
|
|
39
|
+
priority_enum = Priority(priority.lower())
|
|
40
|
+
except ValueError:
|
|
41
|
+
return {
|
|
42
|
+
"status": "error",
|
|
43
|
+
"error": f"Invalid priority '{priority}'. Must be one of: low, medium, high, critical",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Create task object
|
|
47
|
+
task = Task(
|
|
48
|
+
title=title,
|
|
49
|
+
description=description or "",
|
|
50
|
+
priority=priority_enum,
|
|
51
|
+
tags=tags or [],
|
|
52
|
+
assignee=assignee,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Create via adapter
|
|
56
|
+
created = await adapter.create(task)
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
"status": "completed",
|
|
60
|
+
"ticket": created.model_dump(),
|
|
61
|
+
}
|
|
62
|
+
except Exception as e:
|
|
63
|
+
return {
|
|
64
|
+
"status": "error",
|
|
65
|
+
"error": f"Failed to create ticket: {str(e)}",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@mcp.tool()
|
|
70
|
+
async def ticket_read(ticket_id: str) -> dict[str, Any]:
|
|
71
|
+
"""Read a ticket by its ID.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
ticket_id: Unique identifier of the ticket to retrieve
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Ticket details if found, or error information
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
adapter = get_adapter()
|
|
82
|
+
ticket = await adapter.read(ticket_id)
|
|
83
|
+
|
|
84
|
+
if ticket is None:
|
|
85
|
+
return {
|
|
86
|
+
"status": "error",
|
|
87
|
+
"error": f"Ticket {ticket_id} not found",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
"status": "completed",
|
|
92
|
+
"ticket": ticket.model_dump(),
|
|
93
|
+
}
|
|
94
|
+
except Exception as e:
|
|
95
|
+
return {
|
|
96
|
+
"status": "error",
|
|
97
|
+
"error": f"Failed to read ticket: {str(e)}",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@mcp.tool()
|
|
102
|
+
async def ticket_update(
|
|
103
|
+
ticket_id: str,
|
|
104
|
+
title: Optional[str] = None,
|
|
105
|
+
description: Optional[str] = None,
|
|
106
|
+
priority: Optional[str] = None,
|
|
107
|
+
state: Optional[str] = None,
|
|
108
|
+
assignee: Optional[str] = None,
|
|
109
|
+
tags: Optional[list[str]] = None,
|
|
110
|
+
) -> dict[str, Any]:
|
|
111
|
+
"""Update an existing ticket.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
ticket_id: Unique identifier of the ticket to update
|
|
115
|
+
title: New title for the ticket
|
|
116
|
+
description: New description for the ticket
|
|
117
|
+
priority: New priority - must be one of: low, medium, high, critical
|
|
118
|
+
state: New state - must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked
|
|
119
|
+
assignee: User ID or email to assign the ticket to
|
|
120
|
+
tags: New list of tags (replaces existing tags)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Updated ticket details, or error information
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
adapter = get_adapter()
|
|
128
|
+
|
|
129
|
+
# Build updates dictionary with only provided fields
|
|
130
|
+
updates: dict[str, Any] = {}
|
|
131
|
+
|
|
132
|
+
if title is not None:
|
|
133
|
+
updates["title"] = title
|
|
134
|
+
if description is not None:
|
|
135
|
+
updates["description"] = description
|
|
136
|
+
if assignee is not None:
|
|
137
|
+
updates["assignee"] = assignee
|
|
138
|
+
if tags is not None:
|
|
139
|
+
updates["tags"] = tags
|
|
140
|
+
|
|
141
|
+
# Validate and convert priority if provided
|
|
142
|
+
if priority is not None:
|
|
143
|
+
try:
|
|
144
|
+
updates["priority"] = Priority(priority.lower())
|
|
145
|
+
except ValueError:
|
|
146
|
+
return {
|
|
147
|
+
"status": "error",
|
|
148
|
+
"error": f"Invalid priority '{priority}'. Must be one of: low, medium, high, critical",
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# Validate and convert state if provided
|
|
152
|
+
if state is not None:
|
|
153
|
+
try:
|
|
154
|
+
updates["state"] = TicketState(state.lower())
|
|
155
|
+
except ValueError:
|
|
156
|
+
return {
|
|
157
|
+
"status": "error",
|
|
158
|
+
"error": f"Invalid state '{state}'. Must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked",
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# Update via adapter
|
|
162
|
+
updated = await adapter.update(ticket_id, updates)
|
|
163
|
+
|
|
164
|
+
if updated is None:
|
|
165
|
+
return {
|
|
166
|
+
"status": "error",
|
|
167
|
+
"error": f"Ticket {ticket_id} not found or update failed",
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
"status": "completed",
|
|
172
|
+
"ticket": updated.model_dump(),
|
|
173
|
+
}
|
|
174
|
+
except Exception as e:
|
|
175
|
+
return {
|
|
176
|
+
"status": "error",
|
|
177
|
+
"error": f"Failed to update ticket: {str(e)}",
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@mcp.tool()
|
|
182
|
+
async def ticket_delete(ticket_id: str) -> dict[str, Any]:
|
|
183
|
+
"""Delete a ticket by its ID.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
ticket_id: Unique identifier of the ticket to delete
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Success confirmation or error information
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
try:
|
|
193
|
+
adapter = get_adapter()
|
|
194
|
+
success = await adapter.delete(ticket_id)
|
|
195
|
+
|
|
196
|
+
if not success:
|
|
197
|
+
return {
|
|
198
|
+
"status": "error",
|
|
199
|
+
"error": f"Ticket {ticket_id} not found or delete failed",
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
"status": "completed",
|
|
204
|
+
"message": f"Ticket {ticket_id} deleted successfully",
|
|
205
|
+
}
|
|
206
|
+
except Exception as e:
|
|
207
|
+
return {
|
|
208
|
+
"status": "error",
|
|
209
|
+
"error": f"Failed to delete ticket: {str(e)}",
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@mcp.tool()
|
|
214
|
+
async def ticket_list(
|
|
215
|
+
limit: int = 10,
|
|
216
|
+
offset: int = 0,
|
|
217
|
+
state: Optional[str] = None,
|
|
218
|
+
priority: Optional[str] = None,
|
|
219
|
+
assignee: Optional[str] = None,
|
|
220
|
+
) -> dict[str, Any]:
|
|
221
|
+
"""List tickets with pagination and optional filters.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
limit: Maximum number of tickets to return (default: 10)
|
|
225
|
+
offset: Number of tickets to skip for pagination (default: 0)
|
|
226
|
+
state: Filter by state - must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked
|
|
227
|
+
priority: Filter by priority - must be one of: low, medium, high, critical
|
|
228
|
+
assignee: Filter by assigned user ID or email
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
List of tickets matching criteria, or error information
|
|
232
|
+
|
|
233
|
+
"""
|
|
234
|
+
try:
|
|
235
|
+
adapter = get_adapter()
|
|
236
|
+
|
|
237
|
+
# Build filters dictionary
|
|
238
|
+
filters: dict[str, Any] = {}
|
|
239
|
+
|
|
240
|
+
if state is not None:
|
|
241
|
+
try:
|
|
242
|
+
filters["state"] = TicketState(state.lower())
|
|
243
|
+
except ValueError:
|
|
244
|
+
return {
|
|
245
|
+
"status": "error",
|
|
246
|
+
"error": f"Invalid state '{state}'. Must be one of: open, in_progress, ready, tested, done, closed, waiting, blocked",
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if priority is not None:
|
|
250
|
+
try:
|
|
251
|
+
filters["priority"] = Priority(priority.lower())
|
|
252
|
+
except ValueError:
|
|
253
|
+
return {
|
|
254
|
+
"status": "error",
|
|
255
|
+
"error": f"Invalid priority '{priority}'. Must be one of: low, medium, high, critical",
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if assignee is not None:
|
|
259
|
+
filters["assignee"] = assignee
|
|
260
|
+
|
|
261
|
+
# List tickets via adapter
|
|
262
|
+
tickets = await adapter.list(
|
|
263
|
+
limit=limit, offset=offset, filters=filters if filters else None
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
"status": "completed",
|
|
268
|
+
"tickets": [ticket.model_dump() for ticket in tickets],
|
|
269
|
+
"count": len(tickets),
|
|
270
|
+
"limit": limit,
|
|
271
|
+
"offset": offset,
|
|
272
|
+
}
|
|
273
|
+
except Exception as e:
|
|
274
|
+
return {
|
|
275
|
+
"status": "error",
|
|
276
|
+
"error": f"Failed to list tickets: {str(e)}",
|
|
277
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-ticketer
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Universal ticket management interface for AI agents with MCP support
|
|
5
5
|
Author-email: MCP Ticketer Team <support@mcp-ticketer.io>
|
|
6
6
|
Maintainer-email: MCP Ticketer Team <support@mcp-ticketer.io>
|
|
@@ -35,6 +35,7 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
License-File: LICENSE
|
|
36
36
|
Requires-Dist: gql[httpx]>=3.0.0
|
|
37
37
|
Requires-Dist: httpx>=0.25.0
|
|
38
|
+
Requires-Dist: mcp>=1.2.0
|
|
38
39
|
Requires-Dist: psutil>=5.9.0
|
|
39
40
|
Requires-Dist: pydantic>=2.0
|
|
40
41
|
Requires-Dist: python-dotenv>=1.0.0
|
|
@@ -65,7 +66,7 @@ Requires-Dist: sphinx-autodoc-typehints>=1.25.0; extra == "docs"
|
|
|
65
66
|
Requires-Dist: sphinx-click>=5.1.0; extra == "docs"
|
|
66
67
|
Requires-Dist: myst-parser>=2.0.0; extra == "docs"
|
|
67
68
|
Provides-Extra: mcp
|
|
68
|
-
Requires-Dist: mcp>=
|
|
69
|
+
Requires-Dist: mcp>=1.2.0; extra == "mcp"
|
|
69
70
|
Provides-Extra: jira
|
|
70
71
|
Requires-Dist: jira>=3.5.0; extra == "jira"
|
|
71
72
|
Requires-Dist: ai-trackdown-pytools>=1.5.0; extra == "jira"
|
|
@@ -138,29 +139,37 @@ MCP Ticketer integrates with multiple AI clients via the Model Context Protocol
|
|
|
138
139
|
|
|
139
140
|
| AI Client | Support | Config Type | Project-Level | Setup Command |
|
|
140
141
|
|-----------|---------|-------------|---------------|---------------|
|
|
141
|
-
| **Claude Code** | ✅ Native | JSON | ✅ Yes | `mcp-ticketer
|
|
142
|
-
| **
|
|
143
|
-
| **
|
|
144
|
-
| **
|
|
142
|
+
| **Claude Code** | ✅ Native | JSON | ✅ Yes | `mcp-ticketer install claude-code` |
|
|
143
|
+
| **Claude Desktop** | ✅ Full | JSON | ❌ Global only | `mcp-ticketer install claude-desktop` |
|
|
144
|
+
| **Gemini CLI** | ✅ Full | JSON | ✅ Yes | `mcp-ticketer install gemini` |
|
|
145
|
+
| **Codex CLI** | ✅ Full | TOML | ❌ Global only | `mcp-ticketer install codex` |
|
|
146
|
+
| **Auggie** | ✅ Full | JSON | ❌ Global only | `mcp-ticketer install auggie` |
|
|
145
147
|
|
|
146
148
|
### Quick MCP Setup
|
|
147
149
|
|
|
148
150
|
```bash
|
|
149
151
|
# Claude Code (recommended for project-specific workflows)
|
|
150
|
-
mcp-ticketer init --adapter aitrackdown
|
|
151
|
-
mcp-ticketer
|
|
152
|
+
mcp-ticketer init --adapter aitrackdown # First, initialize an adapter
|
|
153
|
+
mcp-ticketer install claude-code # Then install MCP configuration
|
|
154
|
+
|
|
155
|
+
# Claude Desktop (global configuration)
|
|
156
|
+
mcp-ticketer init --adapter aitrackdown
|
|
157
|
+
mcp-ticketer install claude-desktop
|
|
152
158
|
|
|
153
159
|
# Gemini CLI (Google's AI client)
|
|
154
160
|
mcp-ticketer init --adapter aitrackdown
|
|
155
|
-
mcp-ticketer
|
|
161
|
+
mcp-ticketer install gemini
|
|
156
162
|
|
|
157
163
|
# Codex CLI (global configuration, requires restart)
|
|
158
164
|
mcp-ticketer init --adapter aitrackdown
|
|
159
|
-
mcp-ticketer
|
|
165
|
+
mcp-ticketer install codex
|
|
160
166
|
|
|
161
167
|
# Auggie (simple global setup)
|
|
162
168
|
mcp-ticketer init --adapter aitrackdown
|
|
163
|
-
mcp-ticketer
|
|
169
|
+
mcp-ticketer install auggie
|
|
170
|
+
|
|
171
|
+
# Show available platforms
|
|
172
|
+
mcp-ticketer install
|
|
164
173
|
```
|
|
165
174
|
|
|
166
175
|
**See [AI Client Integration Guide](docs/AI_CLIENT_INTEGRATION.md) for detailed setup instructions.**
|
|
@@ -221,11 +230,16 @@ MCP Ticketer provides seamless integration with AI clients through automatic con
|
|
|
221
230
|
# Run MCP server manually (for testing)
|
|
222
231
|
mcp-ticketer serve
|
|
223
232
|
|
|
224
|
-
# Or
|
|
225
|
-
mcp-ticketer
|
|
226
|
-
mcp-ticketer
|
|
227
|
-
mcp-ticketer
|
|
228
|
-
mcp-ticketer
|
|
233
|
+
# Or install MCP configuration automatically (recommended)
|
|
234
|
+
mcp-ticketer install claude-code # For Claude Code (project-level)
|
|
235
|
+
mcp-ticketer install claude-desktop # For Claude Desktop (global)
|
|
236
|
+
mcp-ticketer install gemini # For Gemini CLI
|
|
237
|
+
mcp-ticketer install codex # For Codex CLI
|
|
238
|
+
mcp-ticketer install auggie # For Auggie
|
|
239
|
+
|
|
240
|
+
# Remove MCP configuration when needed
|
|
241
|
+
mcp-ticketer remove claude-code # Remove from Claude Code
|
|
242
|
+
mcp-ticketer uninstall auggie # Alias for remove
|
|
229
243
|
```
|
|
230
244
|
|
|
231
245
|
**Configuration is automatic** - the commands above will:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
mcp_ticketer/__init__.py,sha256=Xx4WaprO5PXhVPbYi1L6tBmwmJMkYS-lMyG4ieN6QP0,717
|
|
2
|
-
mcp_ticketer/__version__.py,sha256=
|
|
2
|
+
mcp_ticketer/__version__.py,sha256=18IyD89l9QaevRmlqimfDbO1Pv8UUAbNSMOUePQFRIo,1117
|
|
3
3
|
mcp_ticketer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
mcp_ticketer/adapters/__init__.py,sha256=B5DFllWn23hkhmrLykNO5uMMSdcFuuPHXyLw_jyFzuE,358
|
|
5
5
|
mcp_ticketer/adapters/aitrackdown.py,sha256=Ecw2SQAGVQs5yMH6m2pj61LxCJsuy-g2bvF8uwTpLUE,22588
|
|
@@ -17,15 +17,15 @@ mcp_ticketer/cache/__init__.py,sha256=Xcd-cKnt-Cx7jBzvfzUUUPaGkmyXFi5XUFWw3Z4b7d
|
|
|
17
17
|
mcp_ticketer/cache/memory.py,sha256=2yBqGi9i0SanlUhJoOC7nijWjoMa3_ntPe-V-AV-LfU,5042
|
|
18
18
|
mcp_ticketer/cli/__init__.py,sha256=l9Q8iKmfGkTu0cssHBVqNZTsL4eAtFzOB25AED_0G6g,89
|
|
19
19
|
mcp_ticketer/cli/adapter_diagnostics.py,sha256=pQDdtDgBwSW04wdFEPVzwbul3KgfB9g6ZMS85qpYulY,14988
|
|
20
|
-
mcp_ticketer/cli/auggie_configure.py,sha256=
|
|
21
|
-
mcp_ticketer/cli/codex_configure.py,sha256=
|
|
20
|
+
mcp_ticketer/cli/auggie_configure.py,sha256=Kd28n16s-X3_KtNfi2fXKij6iK-SnZRHrpgDns3Kq7g,10808
|
|
21
|
+
mcp_ticketer/cli/codex_configure.py,sha256=WRtsdCot7FG4qZwbl4VEl032WyEX7KZoK2e-SrAg9i0,11777
|
|
22
22
|
mcp_ticketer/cli/configure.py,sha256=BsA_pSHQMQS0t1bJO_wMM8LWsd5sWJDASjEPRHvwC18,16198
|
|
23
23
|
mcp_ticketer/cli/diagnostics.py,sha256=jHF68ydW3RNVGumBnHUjUmq6YOjQD2UDkx0O7M__xv0,29965
|
|
24
24
|
mcp_ticketer/cli/discover.py,sha256=AF_qlQc1Oo0UkWayoF5pmRChS5J3fJjH6f2YZzd_k8w,13188
|
|
25
|
-
mcp_ticketer/cli/gemini_configure.py,sha256=
|
|
25
|
+
mcp_ticketer/cli/gemini_configure.py,sha256=dz3YM52JfKEU34utyxvodDgCEGa8o8Nl4GODjUwMumA,12023
|
|
26
26
|
mcp_ticketer/cli/linear_commands.py,sha256=_8f8ze_1MbiUweU6RFHpldgfHLirysIdPjHr2_S0YhI,17319
|
|
27
|
-
mcp_ticketer/cli/main.py,sha256=
|
|
28
|
-
mcp_ticketer/cli/mcp_configure.py,sha256=
|
|
27
|
+
mcp_ticketer/cli/main.py,sha256=ixqTZg2-mZqndLvdQZUO3dH5OMe6yK-tkhWfDlnTmMs,85345
|
|
28
|
+
mcp_ticketer/cli/mcp_configure.py,sha256=TJQREItlnQyzaOhCmK1210Yeo1AtRVxsgW2iUwONEog,12355
|
|
29
29
|
mcp_ticketer/cli/migrate_config.py,sha256=MYsr_C5ZxsGg0P13etWTWNrJ_lc6ElRCkzfQADYr3DM,5956
|
|
30
30
|
mcp_ticketer/cli/platform_commands.py,sha256=pTLRT2wot8dAmy1-roJWWOT0Cxu7j-06BlWDnZ9a4jY,3624
|
|
31
31
|
mcp_ticketer/cli/queue_commands.py,sha256=mm-3H6jmkUGJDyU_E46o9iRpek8tvFCm77F19OtHiZI,7884
|
|
@@ -48,6 +48,15 @@ mcp_ticketer/mcp/constants.py,sha256=EBGsJtBPaTCvAm5rOMknckrXActrNIls7lRklnh1L4s
|
|
|
48
48
|
mcp_ticketer/mcp/dto.py,sha256=fUNAdCnPNp80s6RYLFqSmgqQZX04BHYry4GArmFkdG0,7336
|
|
49
49
|
mcp_ticketer/mcp/response_builder.py,sha256=sEYiwQddlfQmIOcbQ-yBsDvH1EJfbTDwCEUJNf7q5Vk,4946
|
|
50
50
|
mcp_ticketer/mcp/server.py,sha256=SZ8lHdXJJAfV3jVRiZcR2uNYpHY-Lcbt2xXy_Tc728E,48848
|
|
51
|
+
mcp_ticketer/mcp/server_sdk.py,sha256=Q4ujW2_uyGJ4NKjFRo2smjL2hpfigqij-RGDWYaKUHA,2565
|
|
52
|
+
mcp_ticketer/mcp/tools/__init__.py,sha256=6miiC2Cru8u2TCrm9RYF1jxd7vu9SI7BPLUjtzwOxT8,1056
|
|
53
|
+
mcp_ticketer/mcp/tools/attachment_tools.py,sha256=201dhSaKW0_7It4PqmXzJ6aBf8P7_qiqmszfNr4YZZk,5606
|
|
54
|
+
mcp_ticketer/mcp/tools/bulk_tools.py,sha256=UWY1T5DnWhpBJnqMdLMu7Feen515UAlcn_hOjTmDncc,9199
|
|
55
|
+
mcp_ticketer/mcp/tools/comment_tools.py,sha256=57nOwAn3cIkJufJbRbc7-ayDV31ZWnw1nxvYDkTrsk8,2714
|
|
56
|
+
mcp_ticketer/mcp/tools/hierarchy_tools.py,sha256=Xuk-zcv4GbqiaM_iQUGPJGo-pm_X1YVi8cTd3M4hbMk,10532
|
|
57
|
+
mcp_ticketer/mcp/tools/pr_tools.py,sha256=6ntbgJXWfIhPHv50eM85FA_C7RTqPht3TtoFZ3sH8Uw,4552
|
|
58
|
+
mcp_ticketer/mcp/tools/search_tools.py,sha256=RECc9JKLzl_4H65vkz7hQ4Z4-yrVsHcNA0FOz6zSIDA,6976
|
|
59
|
+
mcp_ticketer/mcp/tools/ticket_tools.py,sha256=vSOFKCQ8A_CzJwONmaoEcrYHmrTLRPODt5RLInwPFuc,8164
|
|
51
60
|
mcp_ticketer/queue/__init__.py,sha256=1YIaCpZpFqPcqvDEQXiEvDLiw94DXRdCJkBaVIFQrms,231
|
|
52
61
|
mcp_ticketer/queue/__main__.py,sha256=gc_tE9NUdK07OJfTZuD4t6KeBD_vxFQIhknGTQUG_jk,109
|
|
53
62
|
mcp_ticketer/queue/health_monitor.py,sha256=KFOzksomUFnS94XKBiuHFPmGK6b4QXWzsrjwhHkR9vI,12245
|
|
@@ -56,9 +65,9 @@ mcp_ticketer/queue/queue.py,sha256=PIB_8gOE4rCb5_tBNKw9qD6YhSgH3Ei3IzVrUSY3F_o,1
|
|
|
56
65
|
mcp_ticketer/queue/run_worker.py,sha256=WhoeamL8LKZ66TM8W1PkMPwjF2w_EDFMP-mevs6C1TM,1019
|
|
57
66
|
mcp_ticketer/queue/ticket_registry.py,sha256=FE6W_D8NA-66cJQ6VqghChF3JasYW845JVfEZdiqLbA,15449
|
|
58
67
|
mcp_ticketer/queue/worker.py,sha256=AF6W1bdxWnHiJd6-iBWqTHkZ4lFflsS65CAtgFPR0FA,20983
|
|
59
|
-
mcp_ticketer-0.4.
|
|
60
|
-
mcp_ticketer-0.4.
|
|
61
|
-
mcp_ticketer-0.4.
|
|
62
|
-
mcp_ticketer-0.4.
|
|
63
|
-
mcp_ticketer-0.4.
|
|
64
|
-
mcp_ticketer-0.4.
|
|
68
|
+
mcp_ticketer-0.4.2.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
|
|
69
|
+
mcp_ticketer-0.4.2.dist-info/METADATA,sha256=BckK8wdIMurSKyM9GPGQDfgS3Iv5zP_nCQgwj_dlzOk,13833
|
|
70
|
+
mcp_ticketer-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
71
|
+
mcp_ticketer-0.4.2.dist-info/entry_points.txt,sha256=o1IxVhnHnBNG7FZzbFq-Whcs1Djbofs0qMjiUYBLx2s,60
|
|
72
|
+
mcp_ticketer-0.4.2.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
|
|
73
|
+
mcp_ticketer-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|