mcp-ticketer 0.3.1__py3-none-any.whl → 0.3.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/adapters/aitrackdown.py +12 -15
- mcp_ticketer/adapters/github.py +7 -4
- mcp_ticketer/adapters/jira.py +23 -22
- mcp_ticketer/adapters/linear/__init__.py +1 -1
- mcp_ticketer/adapters/linear/adapter.py +88 -89
- mcp_ticketer/adapters/linear/client.py +71 -52
- mcp_ticketer/adapters/linear/mappers.py +88 -68
- mcp_ticketer/adapters/linear/queries.py +28 -7
- mcp_ticketer/adapters/linear/types.py +57 -50
- mcp_ticketer/adapters/linear.py +2 -2
- mcp_ticketer/cli/adapter_diagnostics.py +86 -51
- mcp_ticketer/cli/diagnostics.py +165 -72
- mcp_ticketer/cli/linear_commands.py +156 -113
- mcp_ticketer/cli/main.py +153 -82
- mcp_ticketer/cli/simple_health.py +73 -45
- mcp_ticketer/cli/utils.py +15 -10
- mcp_ticketer/core/config.py +23 -19
- mcp_ticketer/core/env_discovery.py +5 -4
- mcp_ticketer/core/env_loader.py +109 -86
- mcp_ticketer/core/exceptions.py +20 -18
- mcp_ticketer/core/models.py +9 -0
- mcp_ticketer/core/project_config.py +1 -1
- mcp_ticketer/mcp/server.py +294 -139
- mcp_ticketer/queue/health_monitor.py +152 -121
- mcp_ticketer/queue/manager.py +11 -4
- mcp_ticketer/queue/queue.py +15 -3
- mcp_ticketer/queue/run_worker.py +1 -1
- mcp_ticketer/queue/ticket_registry.py +190 -132
- mcp_ticketer/queue/worker.py +54 -25
- {mcp_ticketer-0.3.1.dist-info → mcp_ticketer-0.3.2.dist-info}/METADATA +1 -1
- mcp_ticketer-0.3.2.dist-info/RECORD +59 -0
- mcp_ticketer-0.3.1.dist-info/RECORD +0 -59
- {mcp_ticketer-0.3.1.dist-info → mcp_ticketer-0.3.2.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.3.1.dist-info → mcp_ticketer-0.3.2.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.3.1.dist-info → mcp_ticketer-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.3.1.dist-info → mcp_ticketer-0.3.2.dist-info}/top_level.txt +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
|
|
4
|
+
from typing import Any, Dict
|
|
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,27 @@ 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:
|
|
21
17
|
console: Rich console for output
|
|
18
|
+
|
|
22
19
|
"""
|
|
23
|
-
console.print(
|
|
20
|
+
console.print(
|
|
21
|
+
"\n[bold blue]🔍 MCP Ticketer Adapter Configuration Diagnostics[/bold blue]\n"
|
|
22
|
+
)
|
|
24
23
|
|
|
25
24
|
# 1. Check .env files
|
|
26
25
|
_check_env_files(console)
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
# 2. Check configuration files
|
|
29
28
|
_check_configuration_files(console)
|
|
30
|
-
|
|
29
|
+
|
|
31
30
|
# 3. Check adapter discovery
|
|
32
31
|
_check_adapter_discovery(console)
|
|
33
|
-
|
|
32
|
+
|
|
34
33
|
# 4. Test adapter instantiation
|
|
35
34
|
_test_adapter_instantiation(console)
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
# 5. Provide recommendations
|
|
38
37
|
_provide_recommendations(console)
|
|
39
38
|
|
|
@@ -44,6 +43,7 @@ def _check_env_files(console: Console) -> None:
|
|
|
44
43
|
|
|
45
44
|
# Load .env files
|
|
46
45
|
from ..mcp.server import _load_env_configuration
|
|
46
|
+
|
|
47
47
|
env_config = _load_env_configuration()
|
|
48
48
|
|
|
49
49
|
# Check for .env files
|
|
@@ -60,10 +60,10 @@ def _check_env_files(console: Console) -> None:
|
|
|
60
60
|
try:
|
|
61
61
|
# Count variables in file
|
|
62
62
|
var_count = 0
|
|
63
|
-
with open(env_path
|
|
63
|
+
with open(env_path) as f:
|
|
64
64
|
for line in f:
|
|
65
65
|
line = line.strip()
|
|
66
|
-
if line and not line.startswith(
|
|
66
|
+
if line and not line.startswith("#") and "=" in line:
|
|
67
67
|
var_count += 1
|
|
68
68
|
|
|
69
69
|
status = "✅ Found"
|
|
@@ -81,11 +81,15 @@ def _check_env_files(console: Console) -> None:
|
|
|
81
81
|
|
|
82
82
|
# Show discovered configuration
|
|
83
83
|
if env_config:
|
|
84
|
-
console.print(
|
|
85
|
-
|
|
84
|
+
console.print(
|
|
85
|
+
f"\n[green]✅ Discovered adapter: {env_config['adapter_type']}[/green]"
|
|
86
|
+
)
|
|
87
|
+
config_keys = list(env_config["adapter_config"].keys())
|
|
86
88
|
console.print(f"[dim]Configuration keys: {config_keys}[/dim]")
|
|
87
89
|
else:
|
|
88
|
-
console.print(
|
|
90
|
+
console.print(
|
|
91
|
+
"\n[yellow]⚠️ No adapter configuration found in .env files[/yellow]"
|
|
92
|
+
)
|
|
89
93
|
|
|
90
94
|
console.print()
|
|
91
95
|
|
|
@@ -93,20 +97,20 @@ def _check_env_files(console: Console) -> None:
|
|
|
93
97
|
def _check_configuration_files(console: Console) -> None:
|
|
94
98
|
"""Check configuration files."""
|
|
95
99
|
console.print("[bold]2. Configuration Files[/bold]")
|
|
96
|
-
|
|
100
|
+
|
|
97
101
|
config_files = [
|
|
98
102
|
(".env.local", "Local environment file (highest priority)"),
|
|
99
103
|
(".env", "Environment file"),
|
|
100
104
|
(".mcp-ticketer/config.json", "Project configuration"),
|
|
101
105
|
(str(Path.home() / ".mcp-ticketer" / "config.json"), "Global configuration"),
|
|
102
106
|
]
|
|
103
|
-
|
|
107
|
+
|
|
104
108
|
table = Table(show_header=True, header_style="bold magenta")
|
|
105
109
|
table.add_column("File", style="cyan")
|
|
106
110
|
table.add_column("Description", style="white")
|
|
107
111
|
table.add_column("Status", style="green")
|
|
108
112
|
table.add_column("Size", style="yellow")
|
|
109
|
-
|
|
113
|
+
|
|
110
114
|
for file_path, description in config_files:
|
|
111
115
|
path = Path(file_path)
|
|
112
116
|
if path.exists():
|
|
@@ -120,9 +124,9 @@ def _check_configuration_files(console: Console) -> None:
|
|
|
120
124
|
else:
|
|
121
125
|
status = "❌ Missing"
|
|
122
126
|
size_str = "N/A"
|
|
123
|
-
|
|
127
|
+
|
|
124
128
|
table.add_row(str(path), description, status, size_str)
|
|
125
|
-
|
|
129
|
+
|
|
126
130
|
console.print(table)
|
|
127
131
|
console.print()
|
|
128
132
|
|
|
@@ -130,35 +134,34 @@ def _check_configuration_files(console: Console) -> None:
|
|
|
130
134
|
def _check_adapter_discovery(console: Console) -> None:
|
|
131
135
|
"""Check adapter discovery from configuration."""
|
|
132
136
|
console.print("[bold]3. Adapter Discovery[/bold]")
|
|
133
|
-
|
|
137
|
+
|
|
134
138
|
try:
|
|
135
139
|
# Discover configuration
|
|
136
140
|
discovered = discover_config(Path.cwd())
|
|
137
|
-
|
|
141
|
+
|
|
138
142
|
if discovered and discovered.adapters:
|
|
139
143
|
primary = discovered.get_primary_adapter()
|
|
140
|
-
|
|
144
|
+
|
|
141
145
|
table = Table(show_header=True, header_style="bold magenta")
|
|
142
146
|
table.add_column("Adapter", style="cyan")
|
|
143
147
|
table.add_column("Confidence", style="white")
|
|
144
148
|
table.add_column("Source", style="green")
|
|
145
149
|
table.add_column("Status", style="yellow")
|
|
146
|
-
|
|
150
|
+
|
|
147
151
|
for adapter_info in discovered.adapters:
|
|
148
152
|
confidence = f"{adapter_info.confidence:.0%}"
|
|
149
153
|
status = "✅ Primary" if adapter_info == primary else "⚪ Available"
|
|
150
|
-
|
|
154
|
+
|
|
151
155
|
table.add_row(
|
|
152
|
-
adapter_info.adapter_type,
|
|
153
|
-
confidence,
|
|
154
|
-
adapter_info.found_in,
|
|
155
|
-
status
|
|
156
|
+
adapter_info.adapter_type, confidence, adapter_info.found_in, status
|
|
156
157
|
)
|
|
157
|
-
|
|
158
|
+
|
|
158
159
|
console.print(table)
|
|
159
|
-
|
|
160
|
+
|
|
160
161
|
if primary:
|
|
161
|
-
console.print(
|
|
162
|
+
console.print(
|
|
163
|
+
f"\n[green]✅ Primary adapter detected: {primary.adapter_type}[/green]"
|
|
164
|
+
)
|
|
162
165
|
console.print(f"[dim]Source: {primary.found_in}[/dim]")
|
|
163
166
|
console.print(f"[dim]Confidence: {primary.confidence:.0%}[/dim]")
|
|
164
167
|
else:
|
|
@@ -166,10 +169,10 @@ def _check_adapter_discovery(console: Console) -> None:
|
|
|
166
169
|
else:
|
|
167
170
|
console.print("[red]❌ No adapters discovered[/red]")
|
|
168
171
|
console.print("[dim]This usually means no credentials are configured[/dim]")
|
|
169
|
-
|
|
172
|
+
|
|
170
173
|
except Exception as e:
|
|
171
174
|
console.print(f"[red]❌ Error during discovery: {e}[/red]")
|
|
172
|
-
|
|
175
|
+
|
|
173
176
|
console.print()
|
|
174
177
|
|
|
175
178
|
|
|
@@ -179,6 +182,7 @@ def _test_adapter_instantiation(console: Console) -> None:
|
|
|
179
182
|
|
|
180
183
|
# Determine which adapter to test from .env files
|
|
181
184
|
from ..mcp.server import _load_env_configuration
|
|
185
|
+
|
|
182
186
|
env_config = _load_env_configuration()
|
|
183
187
|
|
|
184
188
|
if env_config:
|
|
@@ -194,6 +198,7 @@ def _test_adapter_instantiation(console: Console) -> None:
|
|
|
194
198
|
adapter_type = primary.adapter_type
|
|
195
199
|
# Build config from discovery
|
|
196
200
|
from ..mcp.server import _build_adapter_config_from_env_vars
|
|
201
|
+
|
|
197
202
|
config = _build_adapter_config_from_env_vars(adapter_type, {})
|
|
198
203
|
else:
|
|
199
204
|
adapter_type = "aitrackdown"
|
|
@@ -212,16 +217,20 @@ def _test_adapter_instantiation(console: Console) -> None:
|
|
|
212
217
|
# Try to instantiate adapter
|
|
213
218
|
adapter = AdapterRegistry.get_adapter(adapter_type, config)
|
|
214
219
|
|
|
215
|
-
console.print(
|
|
220
|
+
console.print(
|
|
221
|
+
f"[green]✅ Adapter instantiated successfully: {adapter.__class__.__name__}[/green]"
|
|
222
|
+
)
|
|
216
223
|
|
|
217
224
|
# Test basic functionality
|
|
218
|
-
if hasattr(adapter,
|
|
225
|
+
if hasattr(adapter, "validate_credentials"):
|
|
219
226
|
try:
|
|
220
227
|
is_valid, error_msg = adapter.validate_credentials()
|
|
221
228
|
if is_valid:
|
|
222
229
|
console.print("[green]✅ Credentials validation passed[/green]")
|
|
223
230
|
else:
|
|
224
|
-
console.print(
|
|
231
|
+
console.print(
|
|
232
|
+
f"[red]❌ Credentials validation failed: {error_msg}[/red]"
|
|
233
|
+
)
|
|
225
234
|
except Exception as e:
|
|
226
235
|
console.print(f"[yellow]⚠️ Credentials validation error: {e}[/yellow]")
|
|
227
236
|
|
|
@@ -230,16 +239,24 @@ def _test_adapter_instantiation(console: Console) -> None:
|
|
|
230
239
|
|
|
231
240
|
# Provide specific guidance based on adapter type
|
|
232
241
|
if adapter_type == "linear":
|
|
233
|
-
console.print(
|
|
242
|
+
console.print(
|
|
243
|
+
"\n[yellow]Linear adapter requires in .env/.env.local:[/yellow]"
|
|
244
|
+
)
|
|
234
245
|
console.print("• LINEAR_API_KEY=your_api_key")
|
|
235
|
-
console.print(
|
|
246
|
+
console.print(
|
|
247
|
+
"• LINEAR_TEAM_ID=your_team_id (or LINEAR_TEAM_KEY=your_team_key)"
|
|
248
|
+
)
|
|
236
249
|
elif adapter_type == "github":
|
|
237
|
-
console.print(
|
|
250
|
+
console.print(
|
|
251
|
+
"\n[yellow]GitHub adapter requires in .env/.env.local:[/yellow]"
|
|
252
|
+
)
|
|
238
253
|
console.print("• GITHUB_TOKEN=your_token")
|
|
239
254
|
console.print("• GITHUB_OWNER=your_username")
|
|
240
255
|
console.print("• GITHUB_REPO=your_repository")
|
|
241
256
|
elif adapter_type == "jira":
|
|
242
|
-
console.print(
|
|
257
|
+
console.print(
|
|
258
|
+
"\n[yellow]JIRA adapter requires in .env/.env.local:[/yellow]"
|
|
259
|
+
)
|
|
243
260
|
console.print("• JIRA_SERVER=your_server_url")
|
|
244
261
|
console.print("• JIRA_EMAIL=your_email")
|
|
245
262
|
console.print("• JIRA_API_TOKEN=your_token")
|
|
@@ -253,6 +270,7 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
253
270
|
|
|
254
271
|
# Check .env configuration
|
|
255
272
|
from ..mcp.server import _load_env_configuration
|
|
273
|
+
|
|
256
274
|
env_config = _load_env_configuration()
|
|
257
275
|
|
|
258
276
|
recommendations = []
|
|
@@ -273,7 +291,9 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
273
291
|
if not config.get("api_key"):
|
|
274
292
|
recommendations.append("Add LINEAR_API_KEY to .env file")
|
|
275
293
|
if not config.get("team_id") and not config.get("team_key"):
|
|
276
|
-
recommendations.append(
|
|
294
|
+
recommendations.append(
|
|
295
|
+
"Add LINEAR_TEAM_ID or LINEAR_TEAM_KEY to .env file"
|
|
296
|
+
)
|
|
277
297
|
|
|
278
298
|
elif adapter_type == "github":
|
|
279
299
|
missing = []
|
|
@@ -284,7 +304,9 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
284
304
|
if not config.get("repo"):
|
|
285
305
|
missing.append("GITHUB_REPO")
|
|
286
306
|
if missing:
|
|
287
|
-
recommendations.append(
|
|
307
|
+
recommendations.append(
|
|
308
|
+
f"Add missing GitHub variables to .env: {', '.join(missing)}"
|
|
309
|
+
)
|
|
288
310
|
|
|
289
311
|
elif adapter_type == "jira":
|
|
290
312
|
missing = []
|
|
@@ -295,7 +317,9 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
295
317
|
if not config.get("api_token"):
|
|
296
318
|
missing.append("JIRA_API_TOKEN")
|
|
297
319
|
if missing:
|
|
298
|
-
recommendations.append(
|
|
320
|
+
recommendations.append(
|
|
321
|
+
f"Add missing JIRA variables to .env: {', '.join(missing)}"
|
|
322
|
+
)
|
|
299
323
|
|
|
300
324
|
if recommendations:
|
|
301
325
|
for i, rec in enumerate(recommendations, 1):
|
|
@@ -305,8 +329,12 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
305
329
|
|
|
306
330
|
# Show .env file examples
|
|
307
331
|
console.print("\n[bold].env File Examples:[/bold]")
|
|
308
|
-
console.print(
|
|
309
|
-
|
|
332
|
+
console.print(
|
|
333
|
+
"• Linear: [cyan]echo 'MCP_TICKETER_ADAPTER=linear\\nLINEAR_API_KEY=your_key\\nLINEAR_TEAM_ID=your_team' > .env.local[/cyan]"
|
|
334
|
+
)
|
|
335
|
+
console.print(
|
|
336
|
+
"• GitHub: [cyan]echo 'MCP_TICKETER_ADAPTER=github\\nGITHUB_TOKEN=your_token\\nGITHUB_OWNER=user\\nGITHUB_REPO=repo' > .env.local[/cyan]"
|
|
337
|
+
)
|
|
310
338
|
|
|
311
339
|
console.print("\n[bold]Quick Setup Commands:[/bold]")
|
|
312
340
|
console.print("• For Linear: [cyan]mcp-ticketer init linear[/cyan]")
|
|
@@ -316,7 +344,9 @@ def _provide_recommendations(console: Console) -> None:
|
|
|
316
344
|
|
|
317
345
|
console.print("\n[bold]Test Configuration:[/bold]")
|
|
318
346
|
console.print("• Run diagnostics: [cyan]mcp-ticketer diagnose[/cyan]")
|
|
319
|
-
console.print(
|
|
347
|
+
console.print(
|
|
348
|
+
"• Test ticket creation: [cyan]mcp-ticketer create 'Test ticket'[/cyan]"
|
|
349
|
+
)
|
|
320
350
|
console.print("• List tickets: [cyan]mcp-ticketer list[/cyan]")
|
|
321
351
|
|
|
322
352
|
|
|
@@ -325,18 +355,20 @@ def get_adapter_status() -> Dict[str, Any]:
|
|
|
325
355
|
|
|
326
356
|
Returns:
|
|
327
357
|
Dictionary with adapter status information
|
|
358
|
+
|
|
328
359
|
"""
|
|
329
360
|
status = {
|
|
330
361
|
"adapter_type": None,
|
|
331
362
|
"configuration_source": None,
|
|
332
363
|
"credentials_valid": False,
|
|
333
364
|
"error_message": None,
|
|
334
|
-
"recommendations": []
|
|
365
|
+
"recommendations": [],
|
|
335
366
|
}
|
|
336
367
|
|
|
337
368
|
try:
|
|
338
369
|
# Check .env files first
|
|
339
370
|
from ..mcp.server import _load_env_configuration
|
|
371
|
+
|
|
340
372
|
env_config = _load_env_configuration()
|
|
341
373
|
|
|
342
374
|
if env_config:
|
|
@@ -353,6 +385,7 @@ def get_adapter_status() -> Dict[str, Any]:
|
|
|
353
385
|
status["configuration_source"] = primary.found_in
|
|
354
386
|
# Build basic config
|
|
355
387
|
from ..mcp.server import _build_adapter_config_from_env_vars
|
|
388
|
+
|
|
356
389
|
config = _build_adapter_config_from_env_vars(adapter_type, {})
|
|
357
390
|
else:
|
|
358
391
|
adapter_type = "aitrackdown"
|
|
@@ -369,7 +402,7 @@ def get_adapter_status() -> Dict[str, Any]:
|
|
|
369
402
|
adapter = AdapterRegistry.get_adapter(adapter_type, config)
|
|
370
403
|
|
|
371
404
|
# Test credentials if possible
|
|
372
|
-
if hasattr(adapter,
|
|
405
|
+
if hasattr(adapter, "validate_credentials"):
|
|
373
406
|
is_valid, error_msg = adapter.validate_credentials()
|
|
374
407
|
status["credentials_valid"] = is_valid
|
|
375
408
|
if not is_valid:
|
|
@@ -379,6 +412,8 @@ def get_adapter_status() -> Dict[str, Any]:
|
|
|
379
412
|
|
|
380
413
|
except Exception as e:
|
|
381
414
|
status["error_message"] = str(e)
|
|
382
|
-
status["recommendations"].append(
|
|
415
|
+
status["recommendations"].append(
|
|
416
|
+
"Check .env file configuration and credentials"
|
|
417
|
+
)
|
|
383
418
|
|
|
384
419
|
return status
|