mcp-ticketer 0.1.30__py3-none-any.whl → 1.2.11__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 +3 -3
- mcp_ticketer/adapters/__init__.py +2 -0
- mcp_ticketer/adapters/aitrackdown.py +796 -46
- mcp_ticketer/adapters/asana/__init__.py +15 -0
- mcp_ticketer/adapters/asana/adapter.py +1416 -0
- mcp_ticketer/adapters/asana/client.py +292 -0
- mcp_ticketer/adapters/asana/mappers.py +348 -0
- mcp_ticketer/adapters/asana/types.py +146 -0
- mcp_ticketer/adapters/github.py +879 -129
- mcp_ticketer/adapters/hybrid.py +11 -11
- mcp_ticketer/adapters/jira.py +973 -73
- mcp_ticketer/adapters/linear/__init__.py +24 -0
- mcp_ticketer/adapters/linear/adapter.py +2732 -0
- mcp_ticketer/adapters/linear/client.py +344 -0
- mcp_ticketer/adapters/linear/mappers.py +420 -0
- mcp_ticketer/adapters/linear/queries.py +479 -0
- mcp_ticketer/adapters/linear/types.py +360 -0
- mcp_ticketer/adapters/linear.py +10 -2315
- mcp_ticketer/analysis/__init__.py +23 -0
- mcp_ticketer/analysis/orphaned.py +218 -0
- mcp_ticketer/analysis/similarity.py +224 -0
- mcp_ticketer/analysis/staleness.py +266 -0
- mcp_ticketer/cache/memory.py +9 -8
- mcp_ticketer/cli/adapter_diagnostics.py +421 -0
- mcp_ticketer/cli/auggie_configure.py +116 -15
- mcp_ticketer/cli/codex_configure.py +274 -82
- mcp_ticketer/cli/configure.py +888 -151
- mcp_ticketer/cli/diagnostics.py +400 -157
- mcp_ticketer/cli/discover.py +297 -26
- mcp_ticketer/cli/gemini_configure.py +119 -26
- mcp_ticketer/cli/init_command.py +880 -0
- mcp_ticketer/cli/instruction_commands.py +435 -0
- mcp_ticketer/cli/linear_commands.py +616 -0
- mcp_ticketer/cli/main.py +203 -1165
- mcp_ticketer/cli/mcp_configure.py +474 -90
- mcp_ticketer/cli/mcp_server_commands.py +415 -0
- mcp_ticketer/cli/migrate_config.py +12 -8
- mcp_ticketer/cli/platform_commands.py +123 -0
- mcp_ticketer/cli/platform_detection.py +418 -0
- mcp_ticketer/cli/platform_installer.py +513 -0
- mcp_ticketer/cli/python_detection.py +126 -0
- mcp_ticketer/cli/queue_commands.py +15 -15
- mcp_ticketer/cli/setup_command.py +639 -0
- mcp_ticketer/cli/simple_health.py +90 -65
- mcp_ticketer/cli/ticket_commands.py +1013 -0
- mcp_ticketer/cli/update_checker.py +313 -0
- mcp_ticketer/cli/utils.py +114 -66
- mcp_ticketer/core/__init__.py +24 -1
- mcp_ticketer/core/adapter.py +250 -16
- mcp_ticketer/core/config.py +145 -37
- mcp_ticketer/core/env_discovery.py +101 -22
- mcp_ticketer/core/env_loader.py +349 -0
- mcp_ticketer/core/exceptions.py +160 -0
- mcp_ticketer/core/http_client.py +26 -26
- mcp_ticketer/core/instructions.py +405 -0
- mcp_ticketer/core/label_manager.py +732 -0
- mcp_ticketer/core/mappers.py +42 -30
- mcp_ticketer/core/models.py +280 -28
- mcp_ticketer/core/onepassword_secrets.py +379 -0
- mcp_ticketer/core/project_config.py +183 -49
- mcp_ticketer/core/registry.py +3 -3
- 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/defaults/ticket_instructions.md +644 -0
- mcp_ticketer/mcp/__init__.py +29 -1
- mcp_ticketer/mcp/__main__.py +60 -0
- mcp_ticketer/mcp/server/__init__.py +25 -0
- mcp_ticketer/mcp/server/__main__.py +60 -0
- mcp_ticketer/mcp/server/constants.py +58 -0
- mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
- mcp_ticketer/mcp/server/dto.py +195 -0
- mcp_ticketer/mcp/server/main.py +1343 -0
- mcp_ticketer/mcp/server/response_builder.py +206 -0
- mcp_ticketer/mcp/server/routing.py +655 -0
- mcp_ticketer/mcp/server/server_sdk.py +151 -0
- mcp_ticketer/mcp/server/tools/__init__.py +56 -0
- mcp_ticketer/mcp/server/tools/analysis_tools.py +495 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +226 -0
- mcp_ticketer/mcp/server/tools/bulk_tools.py +273 -0
- mcp_ticketer/mcp/server/tools/comment_tools.py +152 -0
- mcp_ticketer/mcp/server/tools/config_tools.py +1439 -0
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +921 -0
- mcp_ticketer/mcp/server/tools/instruction_tools.py +300 -0
- mcp_ticketer/mcp/server/tools/label_tools.py +948 -0
- mcp_ticketer/mcp/server/tools/pr_tools.py +152 -0
- mcp_ticketer/mcp/server/tools/search_tools.py +215 -0
- mcp_ticketer/mcp/server/tools/session_tools.py +170 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1268 -0
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +547 -0
- mcp_ticketer/queue/__init__.py +1 -0
- mcp_ticketer/queue/health_monitor.py +168 -136
- mcp_ticketer/queue/manager.py +95 -25
- mcp_ticketer/queue/queue.py +40 -21
- mcp_ticketer/queue/run_worker.py +6 -1
- mcp_ticketer/queue/ticket_registry.py +213 -155
- mcp_ticketer/queue/worker.py +109 -49
- mcp_ticketer-1.2.11.dist-info/METADATA +792 -0
- mcp_ticketer-1.2.11.dist-info/RECORD +110 -0
- mcp_ticketer/mcp/server.py +0 -1895
- mcp_ticketer-0.1.30.dist-info/METADATA +0 -413
- mcp_ticketer-0.1.30.dist-info/RECORD +0 -49
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""Adapter diagnostics and configuration validation."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from ..core import AdapterRegistry
|
|
10
|
+
from ..core.env_discovery import discover_config
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def diagnose_adapter_configuration(console: Console) -> None:
|
|
14
|
+
"""Diagnose adapter configuration and provide recommendations.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
----
|
|
18
|
+
console: Rich console for output
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
console.print(
|
|
22
|
+
"\n[bold blue]🔍 MCP Ticketer Adapter Configuration Diagnostics[/bold blue]\n"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# 1. Check .env files
|
|
26
|
+
_check_env_files(console)
|
|
27
|
+
|
|
28
|
+
# 2. Check configuration files
|
|
29
|
+
_check_configuration_files(console)
|
|
30
|
+
|
|
31
|
+
# 3. Check adapter discovery
|
|
32
|
+
_check_adapter_discovery(console)
|
|
33
|
+
|
|
34
|
+
# 4. Test adapter instantiation
|
|
35
|
+
_test_adapter_instantiation(console)
|
|
36
|
+
|
|
37
|
+
# 5. Provide recommendations
|
|
38
|
+
_provide_recommendations(console)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _check_env_files(console: Console) -> None:
|
|
42
|
+
"""Check .env files for configuration."""
|
|
43
|
+
console.print("[bold]1. .env File Configuration[/bold]")
|
|
44
|
+
|
|
45
|
+
# Load .env files
|
|
46
|
+
from ..mcp.server import _load_env_configuration
|
|
47
|
+
|
|
48
|
+
env_config = _load_env_configuration()
|
|
49
|
+
|
|
50
|
+
# Check for .env files
|
|
51
|
+
env_files = [".env.local", ".env"]
|
|
52
|
+
|
|
53
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
54
|
+
table.add_column("File", style="cyan")
|
|
55
|
+
table.add_column("Status", style="green")
|
|
56
|
+
table.add_column("Variables Found", style="yellow")
|
|
57
|
+
|
|
58
|
+
for env_file in env_files:
|
|
59
|
+
env_path = Path.cwd() / env_file
|
|
60
|
+
if env_path.exists():
|
|
61
|
+
try:
|
|
62
|
+
# Count variables in file
|
|
63
|
+
var_count = 0
|
|
64
|
+
with open(env_path) as f:
|
|
65
|
+
for line in f:
|
|
66
|
+
line = line.strip()
|
|
67
|
+
if line and not line.startswith("#") and "=" in line:
|
|
68
|
+
var_count += 1
|
|
69
|
+
|
|
70
|
+
status = "✅ Found"
|
|
71
|
+
variables = f"{var_count} variables"
|
|
72
|
+
except Exception:
|
|
73
|
+
status = "⚠️ Error reading"
|
|
74
|
+
variables = "Unknown"
|
|
75
|
+
else:
|
|
76
|
+
status = "❌ Missing"
|
|
77
|
+
variables = "N/A"
|
|
78
|
+
|
|
79
|
+
table.add_row(env_file, status, variables)
|
|
80
|
+
|
|
81
|
+
console.print(table)
|
|
82
|
+
|
|
83
|
+
# Show discovered configuration
|
|
84
|
+
if env_config:
|
|
85
|
+
console.print(
|
|
86
|
+
f"\n[green]✅ Discovered adapter: {env_config['adapter_type']}[/green]"
|
|
87
|
+
)
|
|
88
|
+
config_keys = list(env_config["adapter_config"].keys())
|
|
89
|
+
console.print(f"[dim]Configuration keys: {config_keys}[/dim]")
|
|
90
|
+
else:
|
|
91
|
+
console.print(
|
|
92
|
+
"\n[yellow]⚠️ No adapter configuration found in .env files[/yellow]"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
console.print()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _check_configuration_files(console: Console) -> None:
|
|
99
|
+
"""Check configuration files."""
|
|
100
|
+
console.print("[bold]2. Configuration Files[/bold]")
|
|
101
|
+
|
|
102
|
+
config_files = [
|
|
103
|
+
(".env.local", "Local environment file (highest priority)"),
|
|
104
|
+
(".env", "Environment file"),
|
|
105
|
+
(".mcp-ticketer/config.json", "Project configuration"),
|
|
106
|
+
(str(Path.home() / ".mcp-ticketer" / "config.json"), "Global configuration"),
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
110
|
+
table.add_column("File", style="cyan")
|
|
111
|
+
table.add_column("Description", style="white")
|
|
112
|
+
table.add_column("Status", style="green")
|
|
113
|
+
table.add_column("Size", style="yellow")
|
|
114
|
+
|
|
115
|
+
for file_path, description in config_files:
|
|
116
|
+
path = Path(file_path)
|
|
117
|
+
if path.exists():
|
|
118
|
+
try:
|
|
119
|
+
size = path.stat().st_size
|
|
120
|
+
status = "✅ Found"
|
|
121
|
+
size_str = f"{size} bytes"
|
|
122
|
+
except Exception:
|
|
123
|
+
status = "⚠️ Error"
|
|
124
|
+
size_str = "Unknown"
|
|
125
|
+
else:
|
|
126
|
+
status = "❌ Missing"
|
|
127
|
+
size_str = "N/A"
|
|
128
|
+
|
|
129
|
+
table.add_row(str(path), description, status, size_str)
|
|
130
|
+
|
|
131
|
+
console.print(table)
|
|
132
|
+
console.print()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _check_adapter_discovery(console: Console) -> None:
|
|
136
|
+
"""Check adapter discovery from configuration."""
|
|
137
|
+
console.print("[bold]3. Adapter Discovery[/bold]")
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
# Discover configuration
|
|
141
|
+
discovered = discover_config(Path.cwd())
|
|
142
|
+
|
|
143
|
+
if discovered and discovered.adapters:
|
|
144
|
+
primary = discovered.get_primary_adapter()
|
|
145
|
+
|
|
146
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
147
|
+
table.add_column("Adapter", style="cyan")
|
|
148
|
+
table.add_column("Confidence", style="white")
|
|
149
|
+
table.add_column("Source", style="green")
|
|
150
|
+
table.add_column("Status", style="yellow")
|
|
151
|
+
|
|
152
|
+
for adapter_info in discovered.adapters:
|
|
153
|
+
confidence = f"{adapter_info.confidence:.0%}"
|
|
154
|
+
status = "✅ Primary" if adapter_info == primary else "⚪ Available"
|
|
155
|
+
|
|
156
|
+
table.add_row(
|
|
157
|
+
adapter_info.adapter_type, confidence, adapter_info.found_in, status
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
console.print(table)
|
|
161
|
+
|
|
162
|
+
if primary:
|
|
163
|
+
console.print(
|
|
164
|
+
f"\n[green]✅ Primary adapter detected: {primary.adapter_type}[/green]"
|
|
165
|
+
)
|
|
166
|
+
console.print(f"[dim]Source: {primary.found_in}[/dim]")
|
|
167
|
+
console.print(f"[dim]Confidence: {primary.confidence:.0%}[/dim]")
|
|
168
|
+
else:
|
|
169
|
+
console.print("\n[yellow]⚠️ No primary adapter detected[/yellow]")
|
|
170
|
+
else:
|
|
171
|
+
console.print("[red]❌ No adapters discovered[/red]")
|
|
172
|
+
console.print("[dim]This usually means no credentials are configured[/dim]")
|
|
173
|
+
|
|
174
|
+
except Exception as e:
|
|
175
|
+
console.print(f"[red]❌ Error during discovery: {e}[/red]")
|
|
176
|
+
|
|
177
|
+
console.print()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _test_adapter_instantiation(console: Console) -> None:
|
|
181
|
+
"""Test adapter instantiation."""
|
|
182
|
+
console.print("[bold]4. Adapter Instantiation Test[/bold]")
|
|
183
|
+
|
|
184
|
+
# Determine which adapter to test from .env files
|
|
185
|
+
from ..mcp.server import _load_env_configuration
|
|
186
|
+
|
|
187
|
+
env_config = _load_env_configuration()
|
|
188
|
+
|
|
189
|
+
if env_config:
|
|
190
|
+
adapter_type = env_config["adapter_type"]
|
|
191
|
+
config = env_config["adapter_config"]
|
|
192
|
+
else:
|
|
193
|
+
# Try to discover from existing discovery system
|
|
194
|
+
try:
|
|
195
|
+
discovered = discover_config(Path.cwd())
|
|
196
|
+
if discovered and discovered.adapters:
|
|
197
|
+
primary = discovered.get_primary_adapter()
|
|
198
|
+
if primary:
|
|
199
|
+
adapter_type = primary.adapter_type
|
|
200
|
+
# Build config from discovery
|
|
201
|
+
from ..mcp.server import _build_adapter_config_from_env_vars
|
|
202
|
+
|
|
203
|
+
config = _build_adapter_config_from_env_vars(adapter_type, {})
|
|
204
|
+
else:
|
|
205
|
+
adapter_type = "aitrackdown"
|
|
206
|
+
config = {"base_path": ".aitrackdown"}
|
|
207
|
+
else:
|
|
208
|
+
adapter_type = "aitrackdown"
|
|
209
|
+
config = {"base_path": ".aitrackdown"}
|
|
210
|
+
except Exception:
|
|
211
|
+
adapter_type = "aitrackdown"
|
|
212
|
+
config = {"base_path": ".aitrackdown"}
|
|
213
|
+
|
|
214
|
+
console.print(f"Testing adapter: [cyan]{adapter_type}[/cyan]")
|
|
215
|
+
console.print(f"Configuration keys: [yellow]{list(config.keys())}[/yellow]")
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
# Try to instantiate adapter
|
|
219
|
+
adapter = AdapterRegistry.get_adapter(adapter_type, config)
|
|
220
|
+
|
|
221
|
+
console.print(
|
|
222
|
+
f"[green]✅ Adapter instantiated successfully: {adapter.__class__.__name__}[/green]"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# Test basic functionality
|
|
226
|
+
if hasattr(adapter, "validate_credentials"):
|
|
227
|
+
try:
|
|
228
|
+
is_valid, error_msg = adapter.validate_credentials()
|
|
229
|
+
if is_valid:
|
|
230
|
+
console.print("[green]✅ Credentials validation passed[/green]")
|
|
231
|
+
else:
|
|
232
|
+
console.print(
|
|
233
|
+
f"[red]❌ Credentials validation failed: {error_msg}[/red]"
|
|
234
|
+
)
|
|
235
|
+
except Exception as e:
|
|
236
|
+
console.print(f"[yellow]⚠️ Credentials validation error: {e}[/yellow]")
|
|
237
|
+
|
|
238
|
+
except Exception as e:
|
|
239
|
+
console.print(f"[red]❌ Adapter instantiation failed: {e}[/red]")
|
|
240
|
+
|
|
241
|
+
# Provide specific guidance based on adapter type
|
|
242
|
+
if adapter_type == "linear":
|
|
243
|
+
console.print(
|
|
244
|
+
"\n[yellow]Linear adapter requires in .env/.env.local:[/yellow]"
|
|
245
|
+
)
|
|
246
|
+
console.print("• LINEAR_API_KEY=your_api_key")
|
|
247
|
+
console.print(
|
|
248
|
+
"• LINEAR_TEAM_ID=your_team_id (or LINEAR_TEAM_KEY=your_team_key)"
|
|
249
|
+
)
|
|
250
|
+
elif adapter_type == "github":
|
|
251
|
+
console.print(
|
|
252
|
+
"\n[yellow]GitHub adapter requires in .env/.env.local:[/yellow]"
|
|
253
|
+
)
|
|
254
|
+
console.print("• GITHUB_TOKEN=your_token")
|
|
255
|
+
console.print("• GITHUB_OWNER=your_username")
|
|
256
|
+
console.print("• GITHUB_REPO=your_repository")
|
|
257
|
+
elif adapter_type == "jira":
|
|
258
|
+
console.print(
|
|
259
|
+
"\n[yellow]JIRA adapter requires in .env/.env.local:[/yellow]"
|
|
260
|
+
)
|
|
261
|
+
console.print("• JIRA_SERVER=your_server_url")
|
|
262
|
+
console.print("• JIRA_EMAIL=your_email")
|
|
263
|
+
console.print("• JIRA_API_TOKEN=your_token")
|
|
264
|
+
|
|
265
|
+
console.print()
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _provide_recommendations(console: Console) -> None:
|
|
269
|
+
"""Provide configuration recommendations."""
|
|
270
|
+
console.print("[bold]5. Recommendations[/bold]")
|
|
271
|
+
|
|
272
|
+
# Check .env configuration
|
|
273
|
+
from ..mcp.server import _load_env_configuration
|
|
274
|
+
|
|
275
|
+
env_config = _load_env_configuration()
|
|
276
|
+
|
|
277
|
+
recommendations = []
|
|
278
|
+
|
|
279
|
+
if not env_config:
|
|
280
|
+
recommendations.append(
|
|
281
|
+
"Create .env.local or .env file with adapter configuration"
|
|
282
|
+
)
|
|
283
|
+
recommendations.append(
|
|
284
|
+
"Add MCP_TICKETER_ADAPTER=linear (or github, jira) to specify adapter type"
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
adapter_type = env_config["adapter_type"]
|
|
288
|
+
config = env_config["adapter_config"]
|
|
289
|
+
|
|
290
|
+
# Check for incomplete configurations
|
|
291
|
+
if adapter_type == "linear":
|
|
292
|
+
if not config.get("api_key"):
|
|
293
|
+
recommendations.append("Add LINEAR_API_KEY to .env file")
|
|
294
|
+
if not config.get("team_id") and not config.get("team_key"):
|
|
295
|
+
recommendations.append(
|
|
296
|
+
"Add LINEAR_TEAM_ID or LINEAR_TEAM_KEY to .env file"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
elif adapter_type == "github":
|
|
300
|
+
missing = []
|
|
301
|
+
if not config.get("token"):
|
|
302
|
+
missing.append("GITHUB_TOKEN")
|
|
303
|
+
if not config.get("owner"):
|
|
304
|
+
missing.append("GITHUB_OWNER")
|
|
305
|
+
if not config.get("repo"):
|
|
306
|
+
missing.append("GITHUB_REPO")
|
|
307
|
+
if missing:
|
|
308
|
+
recommendations.append(
|
|
309
|
+
f"Add missing GitHub variables to .env: {', '.join(missing)}"
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
elif adapter_type == "jira":
|
|
313
|
+
missing = []
|
|
314
|
+
if not config.get("server"):
|
|
315
|
+
missing.append("JIRA_SERVER")
|
|
316
|
+
if not config.get("email"):
|
|
317
|
+
missing.append("JIRA_EMAIL")
|
|
318
|
+
if not config.get("api_token"):
|
|
319
|
+
missing.append("JIRA_API_TOKEN")
|
|
320
|
+
if missing:
|
|
321
|
+
recommendations.append(
|
|
322
|
+
f"Add missing JIRA variables to .env: {', '.join(missing)}"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if recommendations:
|
|
326
|
+
for i, rec in enumerate(recommendations, 1):
|
|
327
|
+
console.print(f"{i}. [yellow]{rec}[/yellow]")
|
|
328
|
+
else:
|
|
329
|
+
console.print("[green]✅ Configuration looks good![/green]")
|
|
330
|
+
|
|
331
|
+
# Show .env file examples
|
|
332
|
+
console.print("\n[bold].env File Examples:[/bold]")
|
|
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
|
+
)
|
|
339
|
+
|
|
340
|
+
console.print("\n[bold]Quick Setup Commands:[/bold]")
|
|
341
|
+
console.print("• For Linear: [cyan]mcp-ticketer init linear[/cyan]")
|
|
342
|
+
console.print("• For GitHub: [cyan]mcp-ticketer init github[/cyan]")
|
|
343
|
+
console.print("• For JIRA: [cyan]mcp-ticketer init jira[/cyan]")
|
|
344
|
+
console.print("• For local files: [cyan]mcp-ticketer init aitrackdown[/cyan]")
|
|
345
|
+
|
|
346
|
+
console.print("\n[bold]Test Configuration:[/bold]")
|
|
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
|
+
)
|
|
351
|
+
console.print("• List tickets: [cyan]mcp-ticketer list[/cyan]")
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def get_adapter_status() -> dict[str, Any]:
|
|
355
|
+
"""Get current adapter status for programmatic use.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
-------
|
|
359
|
+
Dictionary with adapter status information
|
|
360
|
+
|
|
361
|
+
"""
|
|
362
|
+
status: dict[str, Any] = {
|
|
363
|
+
"adapter_type": None,
|
|
364
|
+
"configuration_source": None,
|
|
365
|
+
"credentials_valid": False,
|
|
366
|
+
"error_message": None,
|
|
367
|
+
"recommendations": [],
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
# Check .env files first
|
|
372
|
+
from ..mcp.server import _load_env_configuration
|
|
373
|
+
|
|
374
|
+
env_config = _load_env_configuration()
|
|
375
|
+
|
|
376
|
+
if env_config:
|
|
377
|
+
adapter_type = env_config["adapter_type"]
|
|
378
|
+
config = env_config["adapter_config"]
|
|
379
|
+
status["configuration_source"] = ".env files"
|
|
380
|
+
else:
|
|
381
|
+
# Try discovery system
|
|
382
|
+
discovered = discover_config(Path.cwd())
|
|
383
|
+
if discovered and discovered.adapters:
|
|
384
|
+
primary = discovered.get_primary_adapter()
|
|
385
|
+
if primary:
|
|
386
|
+
adapter_type = primary.adapter_type
|
|
387
|
+
status["configuration_source"] = primary.found_in
|
|
388
|
+
# Build basic config
|
|
389
|
+
from ..mcp.server import _build_adapter_config_from_env_vars
|
|
390
|
+
|
|
391
|
+
config = _build_adapter_config_from_env_vars(adapter_type, {})
|
|
392
|
+
else:
|
|
393
|
+
adapter_type = "aitrackdown"
|
|
394
|
+
config = {"base_path": ".aitrackdown"}
|
|
395
|
+
status["configuration_source"] = "default"
|
|
396
|
+
else:
|
|
397
|
+
adapter_type = "aitrackdown"
|
|
398
|
+
config = {"base_path": ".aitrackdown"}
|
|
399
|
+
status["configuration_source"] = "default"
|
|
400
|
+
|
|
401
|
+
status["adapter_type"] = adapter_type
|
|
402
|
+
|
|
403
|
+
# Test adapter instantiation
|
|
404
|
+
adapter = AdapterRegistry.get_adapter(adapter_type, config)
|
|
405
|
+
|
|
406
|
+
# Test credentials if possible
|
|
407
|
+
if hasattr(adapter, "validate_credentials"):
|
|
408
|
+
is_valid, error_msg = adapter.validate_credentials()
|
|
409
|
+
status["credentials_valid"] = is_valid
|
|
410
|
+
if not is_valid:
|
|
411
|
+
status["error_message"] = error_msg
|
|
412
|
+
else:
|
|
413
|
+
status["credentials_valid"] = True # Assume valid if no validation method
|
|
414
|
+
|
|
415
|
+
except Exception as e:
|
|
416
|
+
status["error_message"] = str(e)
|
|
417
|
+
status["recommendations"].append(
|
|
418
|
+
"Check .env file configuration and credentials"
|
|
419
|
+
)
|
|
420
|
+
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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":
|
|
134
|
-
"args":
|
|
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
|
|
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
|
|
156
|
-
console.print("[cyan]🔍 Finding mcp-ticketer
|
|
247
|
+
# Step 1: Find Python executable
|
|
248
|
+
console.print("[cyan]🔍 Finding mcp-ticketer Python executable...[/cyan]")
|
|
157
249
|
try:
|
|
158
|
-
|
|
159
|
-
console.print(f"[green]✓[/green] Found: {
|
|
160
|
-
except
|
|
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
|
-
|
|
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"
|
|
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())}"
|