mcp-ticketer 0.12.0__py3-none-any.whl → 2.0.1__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/__init__.py +10 -10
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/adapters/aitrackdown.py +385 -6
- mcp_ticketer/adapters/asana/adapter.py +108 -0
- mcp_ticketer/adapters/asana/mappers.py +14 -0
- mcp_ticketer/adapters/github.py +525 -11
- mcp_ticketer/adapters/hybrid.py +47 -5
- mcp_ticketer/adapters/jira.py +521 -0
- mcp_ticketer/adapters/linear/adapter.py +1784 -101
- mcp_ticketer/adapters/linear/client.py +85 -3
- mcp_ticketer/adapters/linear/mappers.py +96 -8
- mcp_ticketer/adapters/linear/queries.py +168 -1
- mcp_ticketer/adapters/linear/types.py +80 -4
- mcp_ticketer/analysis/__init__.py +56 -0
- mcp_ticketer/analysis/dependency_graph.py +255 -0
- mcp_ticketer/analysis/health_assessment.py +304 -0
- mcp_ticketer/analysis/orphaned.py +218 -0
- mcp_ticketer/analysis/project_status.py +594 -0
- mcp_ticketer/analysis/similarity.py +224 -0
- mcp_ticketer/analysis/staleness.py +266 -0
- mcp_ticketer/automation/__init__.py +11 -0
- mcp_ticketer/automation/project_updates.py +378 -0
- mcp_ticketer/cli/adapter_diagnostics.py +3 -1
- mcp_ticketer/cli/auggie_configure.py +17 -5
- mcp_ticketer/cli/codex_configure.py +97 -61
- mcp_ticketer/cli/configure.py +851 -103
- mcp_ticketer/cli/cursor_configure.py +314 -0
- mcp_ticketer/cli/diagnostics.py +13 -12
- mcp_ticketer/cli/discover.py +5 -0
- mcp_ticketer/cli/gemini_configure.py +17 -5
- mcp_ticketer/cli/init_command.py +880 -0
- mcp_ticketer/cli/instruction_commands.py +6 -0
- mcp_ticketer/cli/main.py +233 -3151
- mcp_ticketer/cli/mcp_configure.py +672 -98
- mcp_ticketer/cli/mcp_server_commands.py +415 -0
- mcp_ticketer/cli/platform_detection.py +77 -12
- mcp_ticketer/cli/platform_installer.py +536 -0
- mcp_ticketer/cli/project_update_commands.py +350 -0
- mcp_ticketer/cli/setup_command.py +639 -0
- mcp_ticketer/cli/simple_health.py +12 -10
- mcp_ticketer/cli/ticket_commands.py +264 -24
- mcp_ticketer/core/__init__.py +28 -6
- mcp_ticketer/core/adapter.py +166 -1
- mcp_ticketer/core/config.py +21 -21
- mcp_ticketer/core/exceptions.py +7 -1
- mcp_ticketer/core/label_manager.py +732 -0
- mcp_ticketer/core/mappers.py +31 -19
- mcp_ticketer/core/models.py +135 -0
- mcp_ticketer/core/onepassword_secrets.py +1 -1
- mcp_ticketer/core/priority_matcher.py +463 -0
- mcp_ticketer/core/project_config.py +132 -14
- mcp_ticketer/core/session_state.py +171 -0
- mcp_ticketer/core/state_matcher.py +592 -0
- mcp_ticketer/core/url_parser.py +425 -0
- mcp_ticketer/core/validators.py +69 -0
- mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
- mcp_ticketer/mcp/server/main.py +106 -25
- mcp_ticketer/mcp/server/routing.py +655 -0
- mcp_ticketer/mcp/server/server_sdk.py +58 -0
- mcp_ticketer/mcp/server/tools/__init__.py +31 -12
- mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +6 -8
- mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
- mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
- mcp_ticketer/mcp/server/tools/config_tools.py +1184 -136
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +870 -460
- mcp_ticketer/mcp/server/tools/instruction_tools.py +7 -5
- mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
- mcp_ticketer/mcp/server/tools/pr_tools.py +3 -7
- mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
- mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
- mcp_ticketer/mcp/server/tools/search_tools.py +180 -97
- mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1070 -123
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +218 -236
- mcp_ticketer/queue/worker.py +1 -1
- mcp_ticketer/utils/__init__.py +5 -0
- mcp_ticketer/utils/token_utils.py +246 -0
- mcp_ticketer-2.0.1.dist-info/METADATA +1366 -0
- mcp_ticketer-2.0.1.dist-info/RECORD +122 -0
- mcp_ticketer-0.12.0.dist-info/METADATA +0 -550
- mcp_ticketer-0.12.0.dist-info/RECORD +0 -91
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/top_level.txt +0 -0
mcp_ticketer/mcp/server/main.py
CHANGED
|
@@ -58,6 +58,7 @@ class MCPTicketServer:
|
|
|
58
58
|
"""Initialize MCP server.
|
|
59
59
|
|
|
60
60
|
Args:
|
|
61
|
+
----
|
|
61
62
|
adapter_type: Type of adapter to use
|
|
62
63
|
config: Adapter configuration
|
|
63
64
|
|
|
@@ -71,9 +72,11 @@ class MCPTicketServer:
|
|
|
71
72
|
"""Handle JSON-RPC request.
|
|
72
73
|
|
|
73
74
|
Args:
|
|
75
|
+
----
|
|
74
76
|
request: JSON-RPC request
|
|
75
77
|
|
|
76
78
|
Returns:
|
|
79
|
+
-------
|
|
77
80
|
JSON-RPC response
|
|
78
81
|
|
|
79
82
|
"""
|
|
@@ -158,11 +161,13 @@ class MCPTicketServer:
|
|
|
158
161
|
"""Create error response.
|
|
159
162
|
|
|
160
163
|
Args:
|
|
164
|
+
----
|
|
161
165
|
request_id: Request ID
|
|
162
166
|
code: Error code
|
|
163
167
|
message: Error message
|
|
164
168
|
|
|
165
169
|
Returns:
|
|
170
|
+
-------
|
|
166
171
|
Error response
|
|
167
172
|
|
|
168
173
|
"""
|
|
@@ -178,7 +183,7 @@ class MCPTicketServer:
|
|
|
178
183
|
request = CreateTicketRequest(**params)
|
|
179
184
|
|
|
180
185
|
# Build task from validated DTO
|
|
181
|
-
task = Task(
|
|
186
|
+
task = Task( # type: ignore[call-arg]
|
|
182
187
|
title=request.title,
|
|
183
188
|
description=request.description,
|
|
184
189
|
priority=Priority(request.priority),
|
|
@@ -256,7 +261,7 @@ class MCPTicketServer:
|
|
|
256
261
|
|
|
257
262
|
async def _handle_search(self, params: dict[str, Any]) -> dict[str, Any]:
|
|
258
263
|
"""Handle ticket search - SYNCHRONOUS."""
|
|
259
|
-
query = SearchQuery(
|
|
264
|
+
query = SearchQuery( # type: ignore[call-arg]
|
|
260
265
|
query=params.get("query"),
|
|
261
266
|
state=TicketState(params["state"]) if params.get("state") else None,
|
|
262
267
|
priority=Priority(params["priority"]) if params.get("priority") else None,
|
|
@@ -292,7 +297,7 @@ class MCPTicketServer:
|
|
|
292
297
|
operation = params.get("operation", "add")
|
|
293
298
|
|
|
294
299
|
if operation == "add":
|
|
295
|
-
comment = Comment(
|
|
300
|
+
comment = Comment( # type: ignore[call-arg]
|
|
296
301
|
ticket_id=params["ticket_id"],
|
|
297
302
|
content=params["content"],
|
|
298
303
|
author=params.get("author"),
|
|
@@ -326,12 +331,17 @@ class MCPTicketServer:
|
|
|
326
331
|
request = CreateEpicRequest(**params)
|
|
327
332
|
|
|
328
333
|
# Build epic from validated DTO
|
|
329
|
-
|
|
334
|
+
metadata: dict[str, Any] = {}
|
|
335
|
+
if request.target_date:
|
|
336
|
+
metadata["target_date"] = request.target_date
|
|
337
|
+
if request.lead_id:
|
|
338
|
+
metadata["lead_id"] = request.lead_id
|
|
339
|
+
|
|
340
|
+
epic = Epic( # type: ignore[call-arg]
|
|
330
341
|
title=request.title,
|
|
331
342
|
description=request.description,
|
|
332
343
|
child_issues=request.child_issues,
|
|
333
|
-
|
|
334
|
-
lead_id=request.lead_id,
|
|
344
|
+
metadata=metadata,
|
|
335
345
|
)
|
|
336
346
|
|
|
337
347
|
# Create directly
|
|
@@ -372,7 +382,7 @@ class MCPTicketServer:
|
|
|
372
382
|
request = CreateIssueRequest(**params)
|
|
373
383
|
|
|
374
384
|
# Build task (issue) from validated DTO
|
|
375
|
-
task = Task(
|
|
385
|
+
task = Task( # type: ignore[call-arg]
|
|
376
386
|
title=request.title,
|
|
377
387
|
description=request.description,
|
|
378
388
|
parent_epic=request.epic_id, # Issues are tasks under epics
|
|
@@ -405,7 +415,7 @@ class MCPTicketServer:
|
|
|
405
415
|
request = CreateTaskRequest(**params)
|
|
406
416
|
|
|
407
417
|
# Build task from validated DTO
|
|
408
|
-
task = Task(
|
|
418
|
+
task = Task( # type: ignore[call-arg]
|
|
409
419
|
title=request.title,
|
|
410
420
|
parent_issue=request.parent_id,
|
|
411
421
|
description=request.description,
|
|
@@ -437,16 +447,19 @@ class MCPTicketServer:
|
|
|
437
447
|
)
|
|
438
448
|
|
|
439
449
|
# Build tree structure
|
|
440
|
-
tree = {"epic": epic.model_dump(), "issues": []}
|
|
450
|
+
tree: dict[str, Any] = {"epic": epic.model_dump(), "issues": []}
|
|
441
451
|
|
|
442
452
|
# Get issues in epic if depth allows (depth 1 = epic only, depth 2+ = issues)
|
|
443
453
|
if max_depth > 1:
|
|
444
454
|
issues = await self.adapter.list_issues_by_epic(epic_id)
|
|
445
455
|
for issue in issues:
|
|
446
|
-
issue_node
|
|
456
|
+
issue_node: dict[str, Any] = {
|
|
457
|
+
"issue": issue.model_dump(),
|
|
458
|
+
"tasks": [],
|
|
459
|
+
}
|
|
447
460
|
|
|
448
461
|
# Get tasks in issue if depth allows (depth 3+ = tasks)
|
|
449
|
-
if max_depth > 2:
|
|
462
|
+
if max_depth > 2 and issue.id:
|
|
450
463
|
tasks = await self.adapter.list_tasks_by_issue(issue.id)
|
|
451
464
|
issue_node["tasks"] = [task.model_dump() for task in tasks]
|
|
452
465
|
|
|
@@ -544,7 +557,7 @@ class MCPTicketServer:
|
|
|
544
557
|
include_parents = params.get("include_parents", True)
|
|
545
558
|
|
|
546
559
|
# Perform basic search
|
|
547
|
-
search_query = SearchQuery(
|
|
560
|
+
search_query = SearchQuery( # type: ignore[call-arg]
|
|
548
561
|
query=query,
|
|
549
562
|
state=TicketState(params["state"]) if params.get("state") else None,
|
|
550
563
|
priority=Priority(params["priority"]) if params.get("priority") else None,
|
|
@@ -649,6 +662,12 @@ class MCPTicketServer:
|
|
|
649
662
|
"error": str(e),
|
|
650
663
|
"ticket_id": ticket_id,
|
|
651
664
|
}
|
|
665
|
+
# Fallback if not GitHub adapter instance
|
|
666
|
+
return {
|
|
667
|
+
"success": False,
|
|
668
|
+
"error": "GitHub adapter not properly initialized",
|
|
669
|
+
"ticket_id": ticket_id,
|
|
670
|
+
}
|
|
652
671
|
elif "linear" in adapter_name:
|
|
653
672
|
# Linear adapter needs GitHub config for PR creation
|
|
654
673
|
from ..adapters.linear import LinearAdapter
|
|
@@ -693,6 +712,12 @@ class MCPTicketServer:
|
|
|
693
712
|
"error": str(e),
|
|
694
713
|
"ticket_id": ticket_id,
|
|
695
714
|
}
|
|
715
|
+
# Fallback if not Linear adapter instance
|
|
716
|
+
return {
|
|
717
|
+
"success": False,
|
|
718
|
+
"error": "Linear adapter not properly initialized",
|
|
719
|
+
"ticket_id": ticket_id,
|
|
720
|
+
}
|
|
696
721
|
else:
|
|
697
722
|
return {
|
|
698
723
|
"success": False,
|
|
@@ -717,9 +742,11 @@ class MCPTicketServer:
|
|
|
717
742
|
|
|
718
743
|
if isinstance(self.adapter, GitHubAdapter):
|
|
719
744
|
try:
|
|
720
|
-
result =
|
|
721
|
-
|
|
722
|
-
|
|
745
|
+
result: dict[str, Any] = (
|
|
746
|
+
await self.adapter.link_existing_pull_request(
|
|
747
|
+
ticket_id=ticket_id,
|
|
748
|
+
pr_url=pr_url,
|
|
749
|
+
)
|
|
723
750
|
)
|
|
724
751
|
return result
|
|
725
752
|
except Exception as e:
|
|
@@ -729,16 +756,25 @@ class MCPTicketServer:
|
|
|
729
756
|
"ticket_id": ticket_id,
|
|
730
757
|
"pr_url": pr_url,
|
|
731
758
|
}
|
|
759
|
+
# Fallback if not GitHub adapter instance
|
|
760
|
+
return {
|
|
761
|
+
"success": False,
|
|
762
|
+
"error": "GitHub adapter not properly initialized",
|
|
763
|
+
"ticket_id": ticket_id,
|
|
764
|
+
"pr_url": pr_url,
|
|
765
|
+
}
|
|
732
766
|
elif "linear" in adapter_name:
|
|
733
767
|
from ..adapters.linear import LinearAdapter
|
|
734
768
|
|
|
735
769
|
if isinstance(self.adapter, LinearAdapter):
|
|
736
770
|
try:
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
771
|
+
link_result: dict[str, Any] = (
|
|
772
|
+
await self.adapter.link_to_pull_request(
|
|
773
|
+
ticket_id=ticket_id,
|
|
774
|
+
pr_url=pr_url,
|
|
775
|
+
)
|
|
740
776
|
)
|
|
741
|
-
return
|
|
777
|
+
return link_result
|
|
742
778
|
except Exception as e:
|
|
743
779
|
return {
|
|
744
780
|
"success": False,
|
|
@@ -746,6 +782,13 @@ class MCPTicketServer:
|
|
|
746
782
|
"ticket_id": ticket_id,
|
|
747
783
|
"pr_url": pr_url,
|
|
748
784
|
}
|
|
785
|
+
# Fallback if not Linear adapter instance
|
|
786
|
+
return {
|
|
787
|
+
"success": False,
|
|
788
|
+
"error": "Linear adapter not properly initialized",
|
|
789
|
+
"ticket_id": ticket_id,
|
|
790
|
+
"pr_url": pr_url,
|
|
791
|
+
}
|
|
749
792
|
else:
|
|
750
793
|
return {
|
|
751
794
|
"success": False,
|
|
@@ -758,9 +801,11 @@ class MCPTicketServer:
|
|
|
758
801
|
"""Handle initialize request from MCP client.
|
|
759
802
|
|
|
760
803
|
Args:
|
|
804
|
+
----
|
|
761
805
|
params: Initialize parameters
|
|
762
806
|
|
|
763
807
|
Returns:
|
|
808
|
+
-------
|
|
764
809
|
Server capabilities
|
|
765
810
|
|
|
766
811
|
"""
|
|
@@ -889,9 +934,11 @@ class MCPTicketServer:
|
|
|
889
934
|
"""Handle tool invocation from MCP client.
|
|
890
935
|
|
|
891
936
|
Args:
|
|
937
|
+
----
|
|
892
938
|
params: Contains 'name' and 'arguments' fields
|
|
893
939
|
|
|
894
940
|
Returns:
|
|
941
|
+
-------
|
|
895
942
|
MCP formatted response with content array
|
|
896
943
|
|
|
897
944
|
"""
|
|
@@ -1145,18 +1192,48 @@ async def main() -> None:
|
|
|
1145
1192
|
|
|
1146
1193
|
|
|
1147
1194
|
def _load_env_configuration() -> dict[str, Any] | None:
|
|
1148
|
-
"""Load adapter configuration from .env files.
|
|
1195
|
+
"""Load adapter configuration from environment variables and .env files.
|
|
1149
1196
|
|
|
1150
|
-
|
|
1197
|
+
Priority order (highest to lowest):
|
|
1198
|
+
1. os.environ (set by MCP clients like Claude Desktop)
|
|
1199
|
+
2. .env.local file (local overrides)
|
|
1200
|
+
3. .env file (default configuration)
|
|
1151
1201
|
|
|
1152
1202
|
Returns:
|
|
1203
|
+
-------
|
|
1153
1204
|
Dictionary with 'adapter_type' and 'adapter_config' keys, or None if no config found
|
|
1154
1205
|
|
|
1155
1206
|
"""
|
|
1156
|
-
|
|
1157
|
-
|
|
1207
|
+
import os
|
|
1208
|
+
|
|
1158
1209
|
env_vars = {}
|
|
1159
1210
|
|
|
1211
|
+
# Priority 1: Check process environment variables (set by MCP client)
|
|
1212
|
+
# This allows Claude Desktop and other MCP clients to configure the adapter
|
|
1213
|
+
relevant_env_keys = [
|
|
1214
|
+
"MCP_TICKETER_ADAPTER",
|
|
1215
|
+
"LINEAR_API_KEY",
|
|
1216
|
+
"LINEAR_TEAM_ID",
|
|
1217
|
+
"LINEAR_TEAM_KEY",
|
|
1218
|
+
"LINEAR_API_URL",
|
|
1219
|
+
"JIRA_SERVER",
|
|
1220
|
+
"JIRA_EMAIL",
|
|
1221
|
+
"JIRA_API_TOKEN",
|
|
1222
|
+
"JIRA_PROJECT_KEY",
|
|
1223
|
+
"GITHUB_TOKEN",
|
|
1224
|
+
"GITHUB_OWNER",
|
|
1225
|
+
"GITHUB_REPO",
|
|
1226
|
+
"MCP_TICKETER_BASE_PATH",
|
|
1227
|
+
]
|
|
1228
|
+
|
|
1229
|
+
for key in relevant_env_keys:
|
|
1230
|
+
if os.environ.get(key):
|
|
1231
|
+
env_vars[key] = os.environ[key]
|
|
1232
|
+
|
|
1233
|
+
# Priority 2: Check .env files (only for keys not already set)
|
|
1234
|
+
# This allows .env files to provide fallback values
|
|
1235
|
+
env_files = [".env.local", ".env"]
|
|
1236
|
+
|
|
1160
1237
|
for env_file in env_files:
|
|
1161
1238
|
env_path = Path.cwd() / env_file
|
|
1162
1239
|
if env_path.exists():
|
|
@@ -1169,7 +1246,9 @@ def _load_env_configuration() -> dict[str, Any] | None:
|
|
|
1169
1246
|
key, value = line.split("=", 1)
|
|
1170
1247
|
key = key.strip()
|
|
1171
1248
|
value = value.strip().strip('"').strip("'")
|
|
1172
|
-
|
|
1249
|
+
|
|
1250
|
+
# Only set if not already in env_vars (os.environ takes priority)
|
|
1251
|
+
if key not in env_vars and value:
|
|
1173
1252
|
env_vars[key] = value
|
|
1174
1253
|
except Exception:
|
|
1175
1254
|
continue
|
|
@@ -1205,14 +1284,16 @@ def _build_adapter_config_from_env_vars(
|
|
|
1205
1284
|
"""Build adapter configuration from parsed environment variables.
|
|
1206
1285
|
|
|
1207
1286
|
Args:
|
|
1287
|
+
----
|
|
1208
1288
|
adapter_type: Type of adapter to configure
|
|
1209
1289
|
env_vars: Dictionary of environment variables from .env files
|
|
1210
1290
|
|
|
1211
1291
|
Returns:
|
|
1292
|
+
-------
|
|
1212
1293
|
Dictionary of adapter configuration
|
|
1213
1294
|
|
|
1214
1295
|
"""
|
|
1215
|
-
config = {}
|
|
1296
|
+
config: dict[str, Any] = {}
|
|
1216
1297
|
|
|
1217
1298
|
if adapter_type == "linear":
|
|
1218
1299
|
# Linear adapter configuration
|