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.
- mcp_ticketer/__init__.py +10 -10
- mcp_ticketer/__version__.py +3 -3
- mcp_ticketer/_version_scm.py +1 -0
- mcp_ticketer/adapters/__init__.py +2 -0
- mcp_ticketer/adapters/aitrackdown.py +930 -52
- mcp_ticketer/adapters/asana/__init__.py +15 -0
- mcp_ticketer/adapters/asana/adapter.py +1537 -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/__init__.py +26 -0
- mcp_ticketer/adapters/github/adapter.py +3229 -0
- mcp_ticketer/adapters/github/client.py +335 -0
- mcp_ticketer/adapters/github/mappers.py +797 -0
- mcp_ticketer/adapters/github/queries.py +692 -0
- mcp_ticketer/adapters/github/types.py +460 -0
- mcp_ticketer/adapters/hybrid.py +58 -16
- mcp_ticketer/adapters/jira/__init__.py +35 -0
- mcp_ticketer/adapters/jira/adapter.py +1351 -0
- mcp_ticketer/adapters/jira/client.py +271 -0
- mcp_ticketer/adapters/jira/mappers.py +246 -0
- mcp_ticketer/adapters/jira/queries.py +216 -0
- mcp_ticketer/adapters/jira/types.py +304 -0
- mcp_ticketer/adapters/linear/__init__.py +1 -1
- mcp_ticketer/adapters/linear/adapter.py +3810 -462
- mcp_ticketer/adapters/linear/client.py +312 -69
- mcp_ticketer/adapters/linear/mappers.py +305 -85
- mcp_ticketer/adapters/linear/queries.py +317 -17
- mcp_ticketer/adapters/linear/types.py +187 -64
- mcp_ticketer/adapters/linear.py +2 -2
- 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/cache/memory.py +9 -8
- mcp_ticketer/cli/adapter_diagnostics.py +91 -54
- mcp_ticketer/cli/auggie_configure.py +116 -15
- mcp_ticketer/cli/codex_configure.py +274 -82
- mcp_ticketer/cli/configure.py +1323 -151
- mcp_ticketer/cli/cursor_configure.py +314 -0
- mcp_ticketer/cli/diagnostics.py +209 -114
- 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/install_mcp_server.py +418 -0
- mcp_ticketer/cli/instruction_commands.py +435 -0
- mcp_ticketer/cli/linear_commands.py +256 -130
- mcp_ticketer/cli/main.py +140 -1544
- mcp_ticketer/cli/mcp_configure.py +1013 -100
- 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 +477 -0
- mcp_ticketer/cli/platform_installer.py +545 -0
- mcp_ticketer/cli/project_update_commands.py +350 -0
- mcp_ticketer/cli/python_detection.py +126 -0
- mcp_ticketer/cli/queue_commands.py +15 -15
- mcp_ticketer/cli/setup_command.py +794 -0
- mcp_ticketer/cli/simple_health.py +84 -59
- mcp_ticketer/cli/ticket_commands.py +1375 -0
- mcp_ticketer/cli/update_checker.py +313 -0
- mcp_ticketer/cli/utils.py +195 -72
- mcp_ticketer/core/__init__.py +64 -1
- mcp_ticketer/core/adapter.py +618 -18
- mcp_ticketer/core/config.py +77 -68
- mcp_ticketer/core/env_discovery.py +75 -16
- mcp_ticketer/core/env_loader.py +121 -97
- mcp_ticketer/core/exceptions.py +32 -24
- 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/milestone_manager.py +252 -0
- mcp_ticketer/core/models.py +566 -19
- mcp_ticketer/core/onepassword_secrets.py +379 -0
- mcp_ticketer/core/priority_matcher.py +463 -0
- mcp_ticketer/core/project_config.py +189 -49
- mcp_ticketer/core/project_utils.py +281 -0
- mcp_ticketer/core/project_validator.py +376 -0
- mcp_ticketer/core/registry.py +3 -3
- mcp_ticketer/core/session_state.py +176 -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 +723 -0
- mcp_ticketer/mcp/server/server_sdk.py +151 -0
- mcp_ticketer/mcp/server/tools/__init__.py +69 -0
- mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +224 -0
- mcp_ticketer/mcp/server/tools/bulk_tools.py +330 -0
- mcp_ticketer/mcp/server/tools/comment_tools.py +152 -0
- mcp_ticketer/mcp/server/tools/config_tools.py +1564 -0
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +942 -0
- mcp_ticketer/mcp/server/tools/instruction_tools.py +295 -0
- mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
- mcp_ticketer/mcp/server/tools/milestone_tools.py +338 -0
- mcp_ticketer/mcp/server/tools/pr_tools.py +150 -0
- 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 +318 -0
- mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1413 -0
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +364 -0
- mcp_ticketer/queue/__init__.py +1 -0
- mcp_ticketer/queue/health_monitor.py +168 -136
- mcp_ticketer/queue/manager.py +78 -63
- mcp_ticketer/queue/queue.py +108 -21
- mcp_ticketer/queue/run_worker.py +2 -2
- mcp_ticketer/queue/ticket_registry.py +213 -155
- mcp_ticketer/queue/worker.py +96 -58
- mcp_ticketer/utils/__init__.py +5 -0
- mcp_ticketer/utils/token_utils.py +246 -0
- mcp_ticketer-2.2.9.dist-info/METADATA +1396 -0
- mcp_ticketer-2.2.9.dist-info/RECORD +158 -0
- mcp_ticketer-2.2.9.dist-info/top_level.txt +2 -0
- py_mcp_installer/examples/phase3_demo.py +178 -0
- py_mcp_installer/scripts/manage_version.py +54 -0
- py_mcp_installer/setup.py +6 -0
- py_mcp_installer/src/py_mcp_installer/__init__.py +153 -0
- py_mcp_installer/src/py_mcp_installer/command_builder.py +445 -0
- py_mcp_installer/src/py_mcp_installer/config_manager.py +541 -0
- py_mcp_installer/src/py_mcp_installer/exceptions.py +243 -0
- py_mcp_installer/src/py_mcp_installer/installation_strategy.py +617 -0
- py_mcp_installer/src/py_mcp_installer/installer.py +656 -0
- py_mcp_installer/src/py_mcp_installer/mcp_inspector.py +750 -0
- py_mcp_installer/src/py_mcp_installer/platform_detector.py +451 -0
- py_mcp_installer/src/py_mcp_installer/platforms/__init__.py +26 -0
- py_mcp_installer/src/py_mcp_installer/platforms/claude_code.py +225 -0
- py_mcp_installer/src/py_mcp_installer/platforms/codex.py +181 -0
- py_mcp_installer/src/py_mcp_installer/platforms/cursor.py +191 -0
- py_mcp_installer/src/py_mcp_installer/types.py +222 -0
- py_mcp_installer/src/py_mcp_installer/utils.py +463 -0
- py_mcp_installer/tests/__init__.py +0 -0
- py_mcp_installer/tests/platforms/__init__.py +0 -0
- py_mcp_installer/tests/test_platform_detector.py +17 -0
- mcp_ticketer/adapters/github.py +0 -1354
- mcp_ticketer/adapters/jira.py +0 -1011
- mcp_ticketer/mcp/server.py +0 -2030
- mcp_ticketer-0.3.0.dist-info/METADATA +0 -414
- mcp_ticketer-0.3.0.dist-info/RECORD +0 -59
- mcp_ticketer-0.3.0.dist-info/top_level.txt +0 -1
- {mcp_ticketer-0.3.0.dist-info → mcp_ticketer-2.2.9.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.3.0.dist-info → mcp_ticketer-2.2.9.dist-info}/entry_points.txt +0 -0
- {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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
85
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
309
|
-
|
|
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
|
|
319
|
-
console.print(
|
|
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() ->
|
|
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,
|
|
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(
|
|
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
|
|
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())}"
|