mcp-ticketer 0.3.0__py3-none-any.whl → 2.2.9__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.
Files changed (160) hide show
  1. mcp_ticketer/__init__.py +10 -10
  2. mcp_ticketer/__version__.py +3 -3
  3. mcp_ticketer/_version_scm.py +1 -0
  4. mcp_ticketer/adapters/__init__.py +2 -0
  5. mcp_ticketer/adapters/aitrackdown.py +930 -52
  6. mcp_ticketer/adapters/asana/__init__.py +15 -0
  7. mcp_ticketer/adapters/asana/adapter.py +1537 -0
  8. mcp_ticketer/adapters/asana/client.py +292 -0
  9. mcp_ticketer/adapters/asana/mappers.py +348 -0
  10. mcp_ticketer/adapters/asana/types.py +146 -0
  11. mcp_ticketer/adapters/github/__init__.py +26 -0
  12. mcp_ticketer/adapters/github/adapter.py +3229 -0
  13. mcp_ticketer/adapters/github/client.py +335 -0
  14. mcp_ticketer/adapters/github/mappers.py +797 -0
  15. mcp_ticketer/adapters/github/queries.py +692 -0
  16. mcp_ticketer/adapters/github/types.py +460 -0
  17. mcp_ticketer/adapters/hybrid.py +58 -16
  18. mcp_ticketer/adapters/jira/__init__.py +35 -0
  19. mcp_ticketer/adapters/jira/adapter.py +1351 -0
  20. mcp_ticketer/adapters/jira/client.py +271 -0
  21. mcp_ticketer/adapters/jira/mappers.py +246 -0
  22. mcp_ticketer/adapters/jira/queries.py +216 -0
  23. mcp_ticketer/adapters/jira/types.py +304 -0
  24. mcp_ticketer/adapters/linear/__init__.py +1 -1
  25. mcp_ticketer/adapters/linear/adapter.py +3810 -462
  26. mcp_ticketer/adapters/linear/client.py +312 -69
  27. mcp_ticketer/adapters/linear/mappers.py +305 -85
  28. mcp_ticketer/adapters/linear/queries.py +317 -17
  29. mcp_ticketer/adapters/linear/types.py +187 -64
  30. mcp_ticketer/adapters/linear.py +2 -2
  31. mcp_ticketer/analysis/__init__.py +56 -0
  32. mcp_ticketer/analysis/dependency_graph.py +255 -0
  33. mcp_ticketer/analysis/health_assessment.py +304 -0
  34. mcp_ticketer/analysis/orphaned.py +218 -0
  35. mcp_ticketer/analysis/project_status.py +594 -0
  36. mcp_ticketer/analysis/similarity.py +224 -0
  37. mcp_ticketer/analysis/staleness.py +266 -0
  38. mcp_ticketer/automation/__init__.py +11 -0
  39. mcp_ticketer/automation/project_updates.py +378 -0
  40. mcp_ticketer/cache/memory.py +9 -8
  41. mcp_ticketer/cli/adapter_diagnostics.py +91 -54
  42. mcp_ticketer/cli/auggie_configure.py +116 -15
  43. mcp_ticketer/cli/codex_configure.py +274 -82
  44. mcp_ticketer/cli/configure.py +1323 -151
  45. mcp_ticketer/cli/cursor_configure.py +314 -0
  46. mcp_ticketer/cli/diagnostics.py +209 -114
  47. mcp_ticketer/cli/discover.py +297 -26
  48. mcp_ticketer/cli/gemini_configure.py +119 -26
  49. mcp_ticketer/cli/init_command.py +880 -0
  50. mcp_ticketer/cli/install_mcp_server.py +418 -0
  51. mcp_ticketer/cli/instruction_commands.py +435 -0
  52. mcp_ticketer/cli/linear_commands.py +256 -130
  53. mcp_ticketer/cli/main.py +140 -1544
  54. mcp_ticketer/cli/mcp_configure.py +1013 -100
  55. mcp_ticketer/cli/mcp_server_commands.py +415 -0
  56. mcp_ticketer/cli/migrate_config.py +12 -8
  57. mcp_ticketer/cli/platform_commands.py +123 -0
  58. mcp_ticketer/cli/platform_detection.py +477 -0
  59. mcp_ticketer/cli/platform_installer.py +545 -0
  60. mcp_ticketer/cli/project_update_commands.py +350 -0
  61. mcp_ticketer/cli/python_detection.py +126 -0
  62. mcp_ticketer/cli/queue_commands.py +15 -15
  63. mcp_ticketer/cli/setup_command.py +794 -0
  64. mcp_ticketer/cli/simple_health.py +84 -59
  65. mcp_ticketer/cli/ticket_commands.py +1375 -0
  66. mcp_ticketer/cli/update_checker.py +313 -0
  67. mcp_ticketer/cli/utils.py +195 -72
  68. mcp_ticketer/core/__init__.py +64 -1
  69. mcp_ticketer/core/adapter.py +618 -18
  70. mcp_ticketer/core/config.py +77 -68
  71. mcp_ticketer/core/env_discovery.py +75 -16
  72. mcp_ticketer/core/env_loader.py +121 -97
  73. mcp_ticketer/core/exceptions.py +32 -24
  74. mcp_ticketer/core/http_client.py +26 -26
  75. mcp_ticketer/core/instructions.py +405 -0
  76. mcp_ticketer/core/label_manager.py +732 -0
  77. mcp_ticketer/core/mappers.py +42 -30
  78. mcp_ticketer/core/milestone_manager.py +252 -0
  79. mcp_ticketer/core/models.py +566 -19
  80. mcp_ticketer/core/onepassword_secrets.py +379 -0
  81. mcp_ticketer/core/priority_matcher.py +463 -0
  82. mcp_ticketer/core/project_config.py +189 -49
  83. mcp_ticketer/core/project_utils.py +281 -0
  84. mcp_ticketer/core/project_validator.py +376 -0
  85. mcp_ticketer/core/registry.py +3 -3
  86. mcp_ticketer/core/session_state.py +176 -0
  87. mcp_ticketer/core/state_matcher.py +592 -0
  88. mcp_ticketer/core/url_parser.py +425 -0
  89. mcp_ticketer/core/validators.py +69 -0
  90. mcp_ticketer/defaults/ticket_instructions.md +644 -0
  91. mcp_ticketer/mcp/__init__.py +29 -1
  92. mcp_ticketer/mcp/__main__.py +60 -0
  93. mcp_ticketer/mcp/server/__init__.py +25 -0
  94. mcp_ticketer/mcp/server/__main__.py +60 -0
  95. mcp_ticketer/mcp/server/constants.py +58 -0
  96. mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
  97. mcp_ticketer/mcp/server/dto.py +195 -0
  98. mcp_ticketer/mcp/server/main.py +1343 -0
  99. mcp_ticketer/mcp/server/response_builder.py +206 -0
  100. mcp_ticketer/mcp/server/routing.py +723 -0
  101. mcp_ticketer/mcp/server/server_sdk.py +151 -0
  102. mcp_ticketer/mcp/server/tools/__init__.py +69 -0
  103. mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
  104. mcp_ticketer/mcp/server/tools/attachment_tools.py +224 -0
  105. mcp_ticketer/mcp/server/tools/bulk_tools.py +330 -0
  106. mcp_ticketer/mcp/server/tools/comment_tools.py +152 -0
  107. mcp_ticketer/mcp/server/tools/config_tools.py +1564 -0
  108. mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
  109. mcp_ticketer/mcp/server/tools/hierarchy_tools.py +942 -0
  110. mcp_ticketer/mcp/server/tools/instruction_tools.py +295 -0
  111. mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
  112. mcp_ticketer/mcp/server/tools/milestone_tools.py +338 -0
  113. mcp_ticketer/mcp/server/tools/pr_tools.py +150 -0
  114. mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
  115. mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
  116. mcp_ticketer/mcp/server/tools/search_tools.py +318 -0
  117. mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
  118. mcp_ticketer/mcp/server/tools/ticket_tools.py +1413 -0
  119. mcp_ticketer/mcp/server/tools/user_ticket_tools.py +364 -0
  120. mcp_ticketer/queue/__init__.py +1 -0
  121. mcp_ticketer/queue/health_monitor.py +168 -136
  122. mcp_ticketer/queue/manager.py +78 -63
  123. mcp_ticketer/queue/queue.py +108 -21
  124. mcp_ticketer/queue/run_worker.py +2 -2
  125. mcp_ticketer/queue/ticket_registry.py +213 -155
  126. mcp_ticketer/queue/worker.py +96 -58
  127. mcp_ticketer/utils/__init__.py +5 -0
  128. mcp_ticketer/utils/token_utils.py +246 -0
  129. mcp_ticketer-2.2.9.dist-info/METADATA +1396 -0
  130. mcp_ticketer-2.2.9.dist-info/RECORD +158 -0
  131. mcp_ticketer-2.2.9.dist-info/top_level.txt +2 -0
  132. py_mcp_installer/examples/phase3_demo.py +178 -0
  133. py_mcp_installer/scripts/manage_version.py +54 -0
  134. py_mcp_installer/setup.py +6 -0
  135. py_mcp_installer/src/py_mcp_installer/__init__.py +153 -0
  136. py_mcp_installer/src/py_mcp_installer/command_builder.py +445 -0
  137. py_mcp_installer/src/py_mcp_installer/config_manager.py +541 -0
  138. py_mcp_installer/src/py_mcp_installer/exceptions.py +243 -0
  139. py_mcp_installer/src/py_mcp_installer/installation_strategy.py +617 -0
  140. py_mcp_installer/src/py_mcp_installer/installer.py +656 -0
  141. py_mcp_installer/src/py_mcp_installer/mcp_inspector.py +750 -0
  142. py_mcp_installer/src/py_mcp_installer/platform_detector.py +451 -0
  143. py_mcp_installer/src/py_mcp_installer/platforms/__init__.py +26 -0
  144. py_mcp_installer/src/py_mcp_installer/platforms/claude_code.py +225 -0
  145. py_mcp_installer/src/py_mcp_installer/platforms/codex.py +181 -0
  146. py_mcp_installer/src/py_mcp_installer/platforms/cursor.py +191 -0
  147. py_mcp_installer/src/py_mcp_installer/types.py +222 -0
  148. py_mcp_installer/src/py_mcp_installer/utils.py +463 -0
  149. py_mcp_installer/tests/__init__.py +0 -0
  150. py_mcp_installer/tests/platforms/__init__.py +0 -0
  151. py_mcp_installer/tests/test_platform_detector.py +17 -0
  152. mcp_ticketer/adapters/github.py +0 -1354
  153. mcp_ticketer/adapters/jira.py +0 -1011
  154. mcp_ticketer/mcp/server.py +0 -2030
  155. mcp_ticketer-0.3.0.dist-info/METADATA +0 -414
  156. mcp_ticketer-0.3.0.dist-info/RECORD +0 -59
  157. mcp_ticketer-0.3.0.dist-info/top_level.txt +0 -1
  158. {mcp_ticketer-0.3.0.dist-info → mcp_ticketer-2.2.9.dist-info}/WHEEL +0 -0
  159. {mcp_ticketer-0.3.0.dist-info → mcp_ticketer-2.2.9.dist-info}/entry_points.txt +0 -0
  160. {mcp_ticketer-0.3.0.dist-info → mcp_ticketer-2.2.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,10 @@
1
1
  """Adapter diagnostics and configuration validation."""
2
2
 
3
- import os
4
- import sys
5
3
  from pathlib import Path
6
- from typing import Any, Dict, List, Optional, Tuple
4
+ from typing import Any
7
5
 
8
6
  from rich.console import Console
9
- from rich.panel import Panel
10
7
  from rich.table import Table
11
- from rich.text import Text
12
8
 
13
9
  from ..core import AdapterRegistry
14
10
  from ..core.env_discovery import discover_config
@@ -16,24 +12,28 @@ from ..core.env_discovery import discover_config
16
12
 
17
13
  def diagnose_adapter_configuration(console: Console) -> None:
18
14
  """Diagnose adapter configuration and provide recommendations.
19
-
15
+
20
16
  Args:
17
+ ----
21
18
  console: Rich console for output
19
+
22
20
  """
23
- console.print("\n[bold blue]🔍 MCP Ticketer Adapter Configuration Diagnostics[/bold blue]\n")
21
+ console.print(
22
+ "\n[bold blue]🔍 MCP Ticketer Adapter Configuration Diagnostics[/bold blue]\n"
23
+ )
24
24
 
25
25
  # 1. Check .env files
26
26
  _check_env_files(console)
27
-
27
+
28
28
  # 2. Check configuration files
29
29
  _check_configuration_files(console)
30
-
30
+
31
31
  # 3. Check adapter discovery
32
32
  _check_adapter_discovery(console)
33
-
33
+
34
34
  # 4. Test adapter instantiation
35
35
  _test_adapter_instantiation(console)
36
-
36
+
37
37
  # 5. Provide recommendations
38
38
  _provide_recommendations(console)
39
39
 
@@ -44,6 +44,7 @@ def _check_env_files(console: Console) -> None:
44
44
 
45
45
  # Load .env files
46
46
  from ..mcp.server import _load_env_configuration
47
+
47
48
  env_config = _load_env_configuration()
48
49
 
49
50
  # Check for .env files
@@ -60,10 +61,10 @@ def _check_env_files(console: Console) -> None:
60
61
  try:
61
62
  # Count variables in file
62
63
  var_count = 0
63
- with open(env_path, 'r') as f:
64
+ with open(env_path) as f:
64
65
  for line in f:
65
66
  line = line.strip()
66
- if line and not line.startswith('#') and '=' in line:
67
+ if line and not line.startswith("#") and "=" in line:
67
68
  var_count += 1
68
69
 
69
70
  status = "✅ Found"
@@ -81,11 +82,15 @@ def _check_env_files(console: Console) -> None:
81
82
 
82
83
  # Show discovered configuration
83
84
  if env_config:
84
- console.print(f"\n[green]✅ Discovered adapter: {env_config['adapter_type']}[/green]")
85
- config_keys = list(env_config['adapter_config'].keys())
85
+ console.print(
86
+ f"\n[green]✅ Discovered adapter: {env_config['adapter_type']}[/green]"
87
+ )
88
+ config_keys = list(env_config["adapter_config"].keys())
86
89
  console.print(f"[dim]Configuration keys: {config_keys}[/dim]")
87
90
  else:
88
- console.print("\n[yellow]⚠️ No adapter configuration found in .env files[/yellow]")
91
+ console.print(
92
+ "\n[yellow]⚠️ No adapter configuration found in .env files[/yellow]"
93
+ )
89
94
 
90
95
  console.print()
91
96
 
@@ -93,20 +98,20 @@ def _check_env_files(console: Console) -> None:
93
98
  def _check_configuration_files(console: Console) -> None:
94
99
  """Check configuration files."""
95
100
  console.print("[bold]2. Configuration Files[/bold]")
96
-
101
+
97
102
  config_files = [
98
103
  (".env.local", "Local environment file (highest priority)"),
99
104
  (".env", "Environment file"),
100
105
  (".mcp-ticketer/config.json", "Project configuration"),
101
106
  (str(Path.home() / ".mcp-ticketer" / "config.json"), "Global configuration"),
102
107
  ]
103
-
108
+
104
109
  table = Table(show_header=True, header_style="bold magenta")
105
110
  table.add_column("File", style="cyan")
106
111
  table.add_column("Description", style="white")
107
112
  table.add_column("Status", style="green")
108
113
  table.add_column("Size", style="yellow")
109
-
114
+
110
115
  for file_path, description in config_files:
111
116
  path = Path(file_path)
112
117
  if path.exists():
@@ -120,9 +125,9 @@ def _check_configuration_files(console: Console) -> None:
120
125
  else:
121
126
  status = "❌ Missing"
122
127
  size_str = "N/A"
123
-
128
+
124
129
  table.add_row(str(path), description, status, size_str)
125
-
130
+
126
131
  console.print(table)
127
132
  console.print()
128
133
 
@@ -130,35 +135,34 @@ def _check_configuration_files(console: Console) -> None:
130
135
  def _check_adapter_discovery(console: Console) -> None:
131
136
  """Check adapter discovery from configuration."""
132
137
  console.print("[bold]3. Adapter Discovery[/bold]")
133
-
138
+
134
139
  try:
135
140
  # Discover configuration
136
141
  discovered = discover_config(Path.cwd())
137
-
142
+
138
143
  if discovered and discovered.adapters:
139
144
  primary = discovered.get_primary_adapter()
140
-
145
+
141
146
  table = Table(show_header=True, header_style="bold magenta")
142
147
  table.add_column("Adapter", style="cyan")
143
148
  table.add_column("Confidence", style="white")
144
149
  table.add_column("Source", style="green")
145
150
  table.add_column("Status", style="yellow")
146
-
151
+
147
152
  for adapter_info in discovered.adapters:
148
153
  confidence = f"{adapter_info.confidence:.0%}"
149
154
  status = "✅ Primary" if adapter_info == primary else "⚪ Available"
150
-
155
+
151
156
  table.add_row(
152
- adapter_info.adapter_type,
153
- confidence,
154
- adapter_info.found_in,
155
- status
157
+ adapter_info.adapter_type, confidence, adapter_info.found_in, status
156
158
  )
157
-
159
+
158
160
  console.print(table)
159
-
161
+
160
162
  if primary:
161
- console.print(f"\n[green]✅ Primary adapter detected: {primary.adapter_type}[/green]")
163
+ console.print(
164
+ f"\n[green]✅ Primary adapter detected: {primary.adapter_type}[/green]"
165
+ )
162
166
  console.print(f"[dim]Source: {primary.found_in}[/dim]")
163
167
  console.print(f"[dim]Confidence: {primary.confidence:.0%}[/dim]")
164
168
  else:
@@ -166,10 +170,10 @@ def _check_adapter_discovery(console: Console) -> None:
166
170
  else:
167
171
  console.print("[red]❌ No adapters discovered[/red]")
168
172
  console.print("[dim]This usually means no credentials are configured[/dim]")
169
-
173
+
170
174
  except Exception as e:
171
175
  console.print(f"[red]❌ Error during discovery: {e}[/red]")
172
-
176
+
173
177
  console.print()
174
178
 
175
179
 
@@ -179,6 +183,7 @@ def _test_adapter_instantiation(console: Console) -> None:
179
183
 
180
184
  # Determine which adapter to test from .env files
181
185
  from ..mcp.server import _load_env_configuration
186
+
182
187
  env_config = _load_env_configuration()
183
188
 
184
189
  if env_config:
@@ -194,6 +199,7 @@ def _test_adapter_instantiation(console: Console) -> None:
194
199
  adapter_type = primary.adapter_type
195
200
  # Build config from discovery
196
201
  from ..mcp.server import _build_adapter_config_from_env_vars
202
+
197
203
  config = _build_adapter_config_from_env_vars(adapter_type, {})
198
204
  else:
199
205
  adapter_type = "aitrackdown"
@@ -212,16 +218,20 @@ def _test_adapter_instantiation(console: Console) -> None:
212
218
  # Try to instantiate adapter
213
219
  adapter = AdapterRegistry.get_adapter(adapter_type, config)
214
220
 
215
- console.print(f"[green]✅ Adapter instantiated successfully: {adapter.__class__.__name__}[/green]")
221
+ console.print(
222
+ f"[green]✅ Adapter instantiated successfully: {adapter.__class__.__name__}[/green]"
223
+ )
216
224
 
217
225
  # Test basic functionality
218
- if hasattr(adapter, 'validate_credentials'):
226
+ if hasattr(adapter, "validate_credentials"):
219
227
  try:
220
228
  is_valid, error_msg = adapter.validate_credentials()
221
229
  if is_valid:
222
230
  console.print("[green]✅ Credentials validation passed[/green]")
223
231
  else:
224
- console.print(f"[red]❌ Credentials validation failed: {error_msg}[/red]")
232
+ console.print(
233
+ f"[red]❌ Credentials validation failed: {error_msg}[/red]"
234
+ )
225
235
  except Exception as e:
226
236
  console.print(f"[yellow]⚠️ Credentials validation error: {e}[/yellow]")
227
237
 
@@ -230,16 +240,24 @@ def _test_adapter_instantiation(console: Console) -> None:
230
240
 
231
241
  # Provide specific guidance based on adapter type
232
242
  if adapter_type == "linear":
233
- console.print("\n[yellow]Linear adapter requires in .env/.env.local:[/yellow]")
243
+ console.print(
244
+ "\n[yellow]Linear adapter requires in .env/.env.local:[/yellow]"
245
+ )
234
246
  console.print("• LINEAR_API_KEY=your_api_key")
235
- console.print("• LINEAR_TEAM_ID=your_team_id (or LINEAR_TEAM_KEY=your_team_key)")
247
+ console.print(
248
+ "• LINEAR_TEAM_ID=your_team_id (or LINEAR_TEAM_KEY=your_team_key)"
249
+ )
236
250
  elif adapter_type == "github":
237
- console.print("\n[yellow]GitHub adapter requires in .env/.env.local:[/yellow]")
251
+ console.print(
252
+ "\n[yellow]GitHub adapter requires in .env/.env.local:[/yellow]"
253
+ )
238
254
  console.print("• GITHUB_TOKEN=your_token")
239
255
  console.print("• GITHUB_OWNER=your_username")
240
256
  console.print("• GITHUB_REPO=your_repository")
241
257
  elif adapter_type == "jira":
242
- console.print("\n[yellow]JIRA adapter requires in .env/.env.local:[/yellow]")
258
+ console.print(
259
+ "\n[yellow]JIRA adapter requires in .env/.env.local:[/yellow]"
260
+ )
243
261
  console.print("• JIRA_SERVER=your_server_url")
244
262
  console.print("• JIRA_EMAIL=your_email")
245
263
  console.print("• JIRA_API_TOKEN=your_token")
@@ -253,6 +271,7 @@ def _provide_recommendations(console: Console) -> None:
253
271
 
254
272
  # Check .env configuration
255
273
  from ..mcp.server import _load_env_configuration
274
+
256
275
  env_config = _load_env_configuration()
257
276
 
258
277
  recommendations = []
@@ -273,7 +292,9 @@ def _provide_recommendations(console: Console) -> None:
273
292
  if not config.get("api_key"):
274
293
  recommendations.append("Add LINEAR_API_KEY to .env file")
275
294
  if not config.get("team_id") and not config.get("team_key"):
276
- recommendations.append("Add LINEAR_TEAM_ID or LINEAR_TEAM_KEY to .env file")
295
+ recommendations.append(
296
+ "Add LINEAR_TEAM_ID or LINEAR_TEAM_KEY to .env file"
297
+ )
277
298
 
278
299
  elif adapter_type == "github":
279
300
  missing = []
@@ -284,7 +305,9 @@ def _provide_recommendations(console: Console) -> None:
284
305
  if not config.get("repo"):
285
306
  missing.append("GITHUB_REPO")
286
307
  if missing:
287
- recommendations.append(f"Add missing GitHub variables to .env: {', '.join(missing)}")
308
+ recommendations.append(
309
+ f"Add missing GitHub variables to .env: {', '.join(missing)}"
310
+ )
288
311
 
289
312
  elif adapter_type == "jira":
290
313
  missing = []
@@ -295,7 +318,9 @@ def _provide_recommendations(console: Console) -> None:
295
318
  if not config.get("api_token"):
296
319
  missing.append("JIRA_API_TOKEN")
297
320
  if missing:
298
- recommendations.append(f"Add missing JIRA variables to .env: {', '.join(missing)}")
321
+ recommendations.append(
322
+ f"Add missing JIRA variables to .env: {', '.join(missing)}"
323
+ )
299
324
 
300
325
  if recommendations:
301
326
  for i, rec in enumerate(recommendations, 1):
@@ -305,8 +330,12 @@ def _provide_recommendations(console: Console) -> None:
305
330
 
306
331
  # Show .env file examples
307
332
  console.print("\n[bold].env File Examples:[/bold]")
308
- console.print("• Linear: [cyan]echo 'MCP_TICKETER_ADAPTER=linear\\nLINEAR_API_KEY=your_key\\nLINEAR_TEAM_ID=your_team' > .env.local[/cyan]")
309
- console.print("• GitHub: [cyan]echo 'MCP_TICKETER_ADAPTER=github\\nGITHUB_TOKEN=your_token\\nGITHUB_OWNER=user\\nGITHUB_REPO=repo' > .env.local[/cyan]")
333
+ console.print(
334
+ "• Linear: [cyan]echo 'MCP_TICKETER_ADAPTER=linear\\nLINEAR_API_KEY=your_key\\nLINEAR_TEAM_ID=your_team' > .env.local[/cyan]"
335
+ )
336
+ console.print(
337
+ "• GitHub: [cyan]echo 'MCP_TICKETER_ADAPTER=github\\nGITHUB_TOKEN=your_token\\nGITHUB_OWNER=user\\nGITHUB_REPO=repo' > .env.local[/cyan]"
338
+ )
310
339
 
311
340
  console.print("\n[bold]Quick Setup Commands:[/bold]")
312
341
  console.print("• For Linear: [cyan]mcp-ticketer init linear[/cyan]")
@@ -315,28 +344,33 @@ def _provide_recommendations(console: Console) -> None:
315
344
  console.print("• For local files: [cyan]mcp-ticketer init aitrackdown[/cyan]")
316
345
 
317
346
  console.print("\n[bold]Test Configuration:[/bold]")
318
- console.print("• Run diagnostics: [cyan]mcp-ticketer diagnose[/cyan]")
319
- console.print("• Test ticket creation: [cyan]mcp-ticketer create 'Test ticket'[/cyan]")
347
+ console.print("• Run diagnostics: [cyan]mcp-ticketer doctor[/cyan]")
348
+ console.print(
349
+ "• Test ticket creation: [cyan]mcp-ticketer create 'Test ticket'[/cyan]"
350
+ )
320
351
  console.print("• List tickets: [cyan]mcp-ticketer list[/cyan]")
321
352
 
322
353
 
323
- def get_adapter_status() -> Dict[str, Any]:
354
+ def get_adapter_status() -> dict[str, Any]:
324
355
  """Get current adapter status for programmatic use.
325
356
 
326
357
  Returns:
358
+ -------
327
359
  Dictionary with adapter status information
360
+
328
361
  """
329
- status = {
362
+ status: dict[str, Any] = {
330
363
  "adapter_type": None,
331
364
  "configuration_source": None,
332
365
  "credentials_valid": False,
333
366
  "error_message": None,
334
- "recommendations": []
367
+ "recommendations": [],
335
368
  }
336
369
 
337
370
  try:
338
371
  # Check .env files first
339
372
  from ..mcp.server import _load_env_configuration
373
+
340
374
  env_config = _load_env_configuration()
341
375
 
342
376
  if env_config:
@@ -353,6 +387,7 @@ def get_adapter_status() -> Dict[str, Any]:
353
387
  status["configuration_source"] = primary.found_in
354
388
  # Build basic config
355
389
  from ..mcp.server import _build_adapter_config_from_env_vars
390
+
356
391
  config = _build_adapter_config_from_env_vars(adapter_type, {})
357
392
  else:
358
393
  adapter_type = "aitrackdown"
@@ -369,7 +404,7 @@ def get_adapter_status() -> Dict[str, Any]:
369
404
  adapter = AdapterRegistry.get_adapter(adapter_type, config)
370
405
 
371
406
  # Test credentials if possible
372
- if hasattr(adapter, 'validate_credentials'):
407
+ if hasattr(adapter, "validate_credentials"):
373
408
  is_valid, error_msg = adapter.validate_credentials()
374
409
  status["credentials_valid"] = is_valid
375
410
  if not is_valid:
@@ -379,6 +414,8 @@ def get_adapter_status() -> Dict[str, Any]:
379
414
 
380
415
  except Exception as e:
381
416
  status["error_message"] = str(e)
382
- status["recommendations"].append("Check .env file configuration and credentials")
417
+ status["recommendations"].append(
418
+ "Check .env file configuration and credentials"
419
+ )
383
420
 
384
421
  return status
@@ -10,7 +10,8 @@ from typing import Any
10
10
 
11
11
  from rich.console import Console
12
12
 
13
- from .mcp_configure import find_mcp_ticketer_binary, load_project_config
13
+ from .mcp_configure import load_project_config
14
+ from .python_detection import get_mcp_ticketer_python
14
15
 
15
16
  console = Console()
16
17
 
@@ -71,18 +72,27 @@ def save_auggie_config(config_path: Path, config: dict[str, Any]) -> None:
71
72
 
72
73
 
73
74
  def create_auggie_server_config(
74
- binary_path: str, project_config: dict[str, Any]
75
+ python_path: str, project_config: dict[str, Any], project_path: str | None = None
75
76
  ) -> dict[str, Any]:
76
77
  """Create Auggie MCP server configuration for mcp-ticketer.
77
78
 
79
+ Uses the CLI command (mcp-ticketer mcp) which implements proper
80
+ Content-Length framing via FastMCP SDK, required for modern MCP clients.
81
+
78
82
  Args:
79
- binary_path: Path to mcp-ticketer binary
83
+ python_path: Path to Python executable in mcp-ticketer venv
80
84
  project_config: Project configuration from .mcp-ticketer/config.json
85
+ project_path: Project directory path (optional)
81
86
 
82
87
  Returns:
83
88
  Auggie MCP server configuration dict
84
89
 
85
90
  """
91
+ # IMPORTANT: Use CLI command, NOT Python module invocation
92
+ # The CLI uses FastMCP SDK which implements proper Content-Length framing
93
+ # Legacy python -m mcp_ticketer.mcp.server uses line-delimited JSON (incompatible)
94
+ from pathlib import Path
95
+
86
96
  # Get adapter configuration
87
97
  adapter = project_config.get("default_adapter", "aitrackdown")
88
98
  adapters_config = project_config.get("adapters", {})
@@ -91,6 +101,10 @@ def create_auggie_server_config(
91
101
  # Build environment variables
92
102
  env_vars = {}
93
103
 
104
+ # Add PYTHONPATH for project context
105
+ if project_path:
106
+ env_vars["PYTHONPATH"] = project_path
107
+
94
108
  # Add adapter type
95
109
  env_vars["MCP_TICKETER_ADAPTER"] = adapter
96
110
 
@@ -128,16 +142,94 @@ def create_auggie_server_config(
128
142
  if "project_key" in adapter_config:
129
143
  env_vars["JIRA_PROJECT_KEY"] = adapter_config["project_key"]
130
144
 
145
+ # Get mcp-ticketer CLI path from Python path
146
+ # If python_path is /path/to/venv/bin/python, CLI is /path/to/venv/bin/mcp-ticketer
147
+ python_dir = Path(python_path).parent
148
+ cli_path = str(python_dir / "mcp-ticketer")
149
+
150
+ # Build CLI arguments
151
+ args = ["mcp"]
152
+ if project_path:
153
+ args.extend(["--path", project_path])
154
+
131
155
  # Create server configuration (simpler than Gemini - no timeout/trust)
156
+ # NOTE: Environment variables below are optional fallbacks
157
+ # The CLI loads config from .mcp-ticketer/config.json
132
158
  config = {
133
- "command": binary_path,
134
- "args": ["serve"],
159
+ "command": cli_path,
160
+ "args": args,
135
161
  "env": env_vars,
136
162
  }
137
163
 
138
164
  return config
139
165
 
140
166
 
167
+ def remove_auggie_mcp(dry_run: bool = False) -> None:
168
+ """Remove mcp-ticketer from Auggie CLI configuration.
169
+
170
+ IMPORTANT: Auggie CLI ONLY supports global configuration.
171
+ This will remove mcp-ticketer from ~/.augment/settings.json.
172
+
173
+ Args:
174
+ dry_run: Show what would be removed without making changes
175
+
176
+ """
177
+ # Step 1: Find Auggie config location
178
+ console.print("[cyan]🔍 Removing Auggie CLI global configuration...[/cyan]")
179
+ console.print(
180
+ "[yellow]⚠ NOTE: Auggie only supports global configuration (affects all projects)[/yellow]"
181
+ )
182
+
183
+ auggie_config_path = find_auggie_config()
184
+ console.print(f"[dim]Config location: {auggie_config_path}[/dim]")
185
+
186
+ # Step 2: Check if config file exists
187
+ if not auggie_config_path.exists():
188
+ console.print(
189
+ f"[yellow]⚠ No configuration found at {auggie_config_path}[/yellow]"
190
+ )
191
+ console.print("[dim]mcp-ticketer is not configured for Auggie[/dim]")
192
+ return
193
+
194
+ # Step 3: Load existing Auggie configuration
195
+ auggie_config = load_auggie_config(auggie_config_path)
196
+
197
+ # Step 4: Check if mcp-ticketer is configured
198
+ if "mcp-ticketer" not in auggie_config.get("mcpServers", {}):
199
+ console.print("[yellow]⚠ mcp-ticketer is not configured[/yellow]")
200
+ console.print(f"[dim]No mcp-ticketer entry found in {auggie_config_path}[/dim]")
201
+ return
202
+
203
+ # Step 5: Show what would be removed (dry run or actual removal)
204
+ if dry_run:
205
+ console.print("\n[cyan]DRY RUN - Would remove:[/cyan]")
206
+ console.print(" Server name: mcp-ticketer")
207
+ console.print(f" From: {auggie_config_path}")
208
+ console.print(" Scope: Global (all projects)")
209
+ return
210
+
211
+ # Step 6: Remove mcp-ticketer from configuration
212
+ del auggie_config["mcpServers"]["mcp-ticketer"]
213
+
214
+ # Step 7: Save updated configuration
215
+ try:
216
+ save_auggie_config(auggie_config_path, auggie_config)
217
+ console.print("\n[green]✓ Successfully removed mcp-ticketer[/green]")
218
+ console.print(f"[dim]Configuration updated: {auggie_config_path}[/dim]")
219
+
220
+ # Next steps
221
+ console.print("\n[bold cyan]Next Steps:[/bold cyan]")
222
+ console.print("1. Restart Auggie CLI for changes to take effect")
223
+ console.print("2. mcp-ticketer will no longer be available via MCP")
224
+ console.print(
225
+ "\n[yellow]⚠ Note: This removes global configuration affecting all projects[/yellow]"
226
+ )
227
+
228
+ except Exception as e:
229
+ console.print(f"\n[red]✗ Failed to update configuration:[/red] {e}")
230
+ raise
231
+
232
+
141
233
  def configure_auggie_mcp(force: bool = False) -> None:
142
234
  """Configure Auggie CLI to use mcp-ticketer.
143
235
 
@@ -148,18 +240,22 @@ def configure_auggie_mcp(force: bool = False) -> None:
148
240
  force: Overwrite existing configuration
149
241
 
150
242
  Raises:
151
- FileNotFoundError: If binary or project config not found
243
+ FileNotFoundError: If Python executable or project config not found
152
244
  ValueError: If configuration is invalid
153
245
 
154
246
  """
155
- # Step 1: Find mcp-ticketer binary
156
- console.print("[cyan]🔍 Finding mcp-ticketer binary...[/cyan]")
247
+ # Step 1: Find Python executable
248
+ console.print("[cyan]🔍 Finding mcp-ticketer Python executable...[/cyan]")
157
249
  try:
158
- binary_path = find_mcp_ticketer_binary()
159
- console.print(f"[green]✓[/green] Found: {binary_path}")
160
- except FileNotFoundError as e:
161
- console.print(f"[red]✗[/red] {e}")
162
- raise
250
+ python_path = get_mcp_ticketer_python()
251
+ console.print(f"[green]✓[/green] Found: {python_path}")
252
+ except Exception as e:
253
+ console.print(f"[red]✗[/red] Could not find Python executable: {e}")
254
+ raise FileNotFoundError(
255
+ "Could not find mcp-ticketer Python executable. "
256
+ "Please ensure mcp-ticketer is installed.\n"
257
+ "Install with: pip install mcp-ticketer or pipx install mcp-ticketer"
258
+ ) from e
163
259
 
164
260
  # Step 2: Load project configuration
165
261
  console.print("\n[cyan]📖 Reading project configuration...[/cyan]")
@@ -193,8 +289,11 @@ def configure_auggie_mcp(force: bool = False) -> None:
193
289
  console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
194
290
 
195
291
  # Step 6: Create mcp-ticketer server config
292
+ project_path = str(Path.cwd())
196
293
  server_config = create_auggie_server_config(
197
- binary_path=binary_path, project_config=project_config
294
+ python_path=python_path,
295
+ project_config=project_config,
296
+ project_path=project_path,
198
297
  )
199
298
 
200
299
  # Step 7: Update Auggie configuration
@@ -213,8 +312,10 @@ def configure_auggie_mcp(force: bool = False) -> None:
213
312
  console.print("\n[bold]Configuration Details:[/bold]")
214
313
  console.print(" Server name: mcp-ticketer")
215
314
  console.print(f" Adapter: {adapter}")
216
- console.print(f" Binary: {binary_path}")
315
+ console.print(f" Python: {python_path}")
316
+ console.print(" Command: python -m mcp_ticketer.mcp.server")
217
317
  console.print(" Scope: Global (affects all projects)")
318
+ console.print(f" Project path: {project_path}")
218
319
  if "env" in server_config:
219
320
  console.print(
220
321
  f" Environment variables: {list(server_config['env'].keys())}"