mcp-ticketer 0.4.2__py3-none-any.whl → 0.4.4__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 +254 -11
- mcp_ticketer/adapters/github.py +13 -13
- mcp_ticketer/adapters/hybrid.py +11 -11
- mcp_ticketer/adapters/jira.py +20 -24
- mcp_ticketer/cache/memory.py +6 -5
- mcp_ticketer/cli/codex_configure.py +2 -2
- mcp_ticketer/cli/configure.py +4 -5
- mcp_ticketer/cli/diagnostics.py +2 -2
- mcp_ticketer/cli/discover.py +4 -5
- mcp_ticketer/cli/gemini_configure.py +2 -2
- mcp_ticketer/cli/linear_commands.py +6 -7
- mcp_ticketer/cli/main.py +341 -250
- mcp_ticketer/cli/mcp_configure.py +1 -2
- mcp_ticketer/cli/ticket_commands.py +27 -30
- mcp_ticketer/cli/utils.py +23 -22
- mcp_ticketer/core/__init__.py +2 -1
- mcp_ticketer/core/adapter.py +82 -13
- mcp_ticketer/core/config.py +27 -29
- mcp_ticketer/core/env_discovery.py +10 -10
- mcp_ticketer/core/env_loader.py +8 -8
- mcp_ticketer/core/http_client.py +16 -16
- mcp_ticketer/core/mappers.py +10 -10
- mcp_ticketer/core/models.py +50 -20
- mcp_ticketer/core/project_config.py +40 -34
- mcp_ticketer/core/registry.py +2 -2
- mcp_ticketer/mcp/dto.py +32 -32
- mcp_ticketer/mcp/response_builder.py +2 -2
- mcp_ticketer/mcp/server.py +3 -3
- mcp_ticketer/mcp/server_sdk.py +2 -2
- mcp_ticketer/mcp/tools/attachment_tools.py +3 -4
- mcp_ticketer/mcp/tools/comment_tools.py +2 -2
- mcp_ticketer/mcp/tools/hierarchy_tools.py +8 -8
- mcp_ticketer/mcp/tools/pr_tools.py +2 -2
- mcp_ticketer/mcp/tools/search_tools.py +6 -6
- mcp_ticketer/mcp/tools/ticket_tools.py +12 -12
- mcp_ticketer/queue/health_monitor.py +4 -4
- mcp_ticketer/queue/manager.py +2 -2
- mcp_ticketer/queue/queue.py +16 -16
- mcp_ticketer/queue/ticket_registry.py +7 -7
- mcp_ticketer/queue/worker.py +2 -2
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.4.dist-info}/METADATA +61 -2
- mcp_ticketer-0.4.4.dist-info/RECORD +73 -0
- mcp_ticketer-0.4.2.dist-info/RECORD +0 -73
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.4.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.4.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.4.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.4.dist-info}/top_level.txt +0 -0
mcp_ticketer/cli/main.py
CHANGED
|
@@ -5,7 +5,6 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import typer
|
|
11
10
|
from dotenv import load_dotenv
|
|
@@ -84,7 +83,7 @@ class AdapterType(str, Enum):
|
|
|
84
83
|
GITHUB = "github"
|
|
85
84
|
|
|
86
85
|
|
|
87
|
-
def load_config(project_dir:
|
|
86
|
+
def load_config(project_dir: Path | None = None) -> dict:
|
|
88
87
|
"""Load configuration from project-local config file ONLY.
|
|
89
88
|
|
|
90
89
|
SECURITY: This method ONLY reads from the current project directory
|
|
@@ -146,7 +145,7 @@ def load_config(project_dir: Optional[Path] = None) -> dict:
|
|
|
146
145
|
return {"adapter": "aitrackdown", "config": {"base_path": ".aitrackdown"}}
|
|
147
146
|
|
|
148
147
|
|
|
149
|
-
def _discover_from_env_files() ->
|
|
148
|
+
def _discover_from_env_files() -> str | None:
|
|
150
149
|
"""Discover adapter configuration from .env or .env.local files.
|
|
151
150
|
|
|
152
151
|
Returns:
|
|
@@ -270,7 +269,7 @@ def merge_config(updates: dict) -> dict:
|
|
|
270
269
|
|
|
271
270
|
|
|
272
271
|
def get_adapter(
|
|
273
|
-
override_adapter:
|
|
272
|
+
override_adapter: str | None = None, override_config: dict | None = None
|
|
274
273
|
):
|
|
275
274
|
"""Get configured adapter instance.
|
|
276
275
|
|
|
@@ -387,13 +386,13 @@ def _prompt_for_adapter_selection(console: Console) -> str:
|
|
|
387
386
|
|
|
388
387
|
@app.command()
|
|
389
388
|
def setup(
|
|
390
|
-
adapter:
|
|
389
|
+
adapter: str | None = typer.Option(
|
|
391
390
|
None,
|
|
392
391
|
"--adapter",
|
|
393
392
|
"-a",
|
|
394
393
|
help="Adapter type to use (interactive prompt if not specified)",
|
|
395
394
|
),
|
|
396
|
-
project_path:
|
|
395
|
+
project_path: str | None = typer.Option(
|
|
397
396
|
None, "--path", help="Project path (default: current directory)"
|
|
398
397
|
),
|
|
399
398
|
global_config: bool = typer.Option(
|
|
@@ -402,36 +401,36 @@ def setup(
|
|
|
402
401
|
"-g",
|
|
403
402
|
help="Save to global config instead of project-specific",
|
|
404
403
|
),
|
|
405
|
-
base_path:
|
|
404
|
+
base_path: str | None = typer.Option(
|
|
406
405
|
None,
|
|
407
406
|
"--base-path",
|
|
408
407
|
"-p",
|
|
409
408
|
help="Base path for ticket storage (AITrackdown only)",
|
|
410
409
|
),
|
|
411
|
-
api_key:
|
|
410
|
+
api_key: str | None = typer.Option(
|
|
412
411
|
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
413
412
|
),
|
|
414
|
-
team_id:
|
|
413
|
+
team_id: str | None = typer.Option(
|
|
415
414
|
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
416
415
|
),
|
|
417
|
-
jira_server:
|
|
416
|
+
jira_server: str | None = typer.Option(
|
|
418
417
|
None,
|
|
419
418
|
"--jira-server",
|
|
420
419
|
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
421
420
|
),
|
|
422
|
-
jira_email:
|
|
421
|
+
jira_email: str | None = typer.Option(
|
|
423
422
|
None, "--jira-email", help="JIRA user email for authentication"
|
|
424
423
|
),
|
|
425
|
-
jira_project:
|
|
424
|
+
jira_project: str | None = typer.Option(
|
|
426
425
|
None, "--jira-project", help="Default JIRA project key"
|
|
427
426
|
),
|
|
428
|
-
github_owner:
|
|
427
|
+
github_owner: str | None = typer.Option(
|
|
429
428
|
None, "--github-owner", help="GitHub repository owner"
|
|
430
429
|
),
|
|
431
|
-
github_repo:
|
|
430
|
+
github_repo: str | None = typer.Option(
|
|
432
431
|
None, "--github-repo", help="GitHub repository name"
|
|
433
432
|
),
|
|
434
|
-
github_token:
|
|
433
|
+
github_token: str | None = typer.Option(
|
|
435
434
|
None, "--github-token", help="GitHub Personal Access Token"
|
|
436
435
|
),
|
|
437
436
|
) -> None:
|
|
@@ -471,13 +470,13 @@ def setup(
|
|
|
471
470
|
|
|
472
471
|
@app.command()
|
|
473
472
|
def init(
|
|
474
|
-
adapter:
|
|
473
|
+
adapter: str | None = typer.Option(
|
|
475
474
|
None,
|
|
476
475
|
"--adapter",
|
|
477
476
|
"-a",
|
|
478
477
|
help="Adapter type to use (interactive prompt if not specified)",
|
|
479
478
|
),
|
|
480
|
-
project_path:
|
|
479
|
+
project_path: str | None = typer.Option(
|
|
481
480
|
None, "--path", help="Project path (default: current directory)"
|
|
482
481
|
),
|
|
483
482
|
global_config: bool = typer.Option(
|
|
@@ -486,40 +485,40 @@ def init(
|
|
|
486
485
|
"-g",
|
|
487
486
|
help="Save to global config instead of project-specific",
|
|
488
487
|
),
|
|
489
|
-
base_path:
|
|
488
|
+
base_path: str | None = typer.Option(
|
|
490
489
|
None,
|
|
491
490
|
"--base-path",
|
|
492
491
|
"-p",
|
|
493
492
|
help="Base path for ticket storage (AITrackdown only)",
|
|
494
493
|
),
|
|
495
|
-
api_key:
|
|
494
|
+
api_key: str | None = typer.Option(
|
|
496
495
|
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
497
496
|
),
|
|
498
|
-
team_id:
|
|
497
|
+
team_id: str | None = typer.Option(
|
|
499
498
|
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
500
499
|
),
|
|
501
|
-
jira_server:
|
|
500
|
+
jira_server: str | None = typer.Option(
|
|
502
501
|
None,
|
|
503
502
|
"--jira-server",
|
|
504
503
|
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
505
504
|
),
|
|
506
|
-
jira_email:
|
|
505
|
+
jira_email: str | None = typer.Option(
|
|
507
506
|
None, "--jira-email", help="JIRA user email for authentication"
|
|
508
507
|
),
|
|
509
|
-
jira_project:
|
|
508
|
+
jira_project: str | None = typer.Option(
|
|
510
509
|
None, "--jira-project", help="Default JIRA project key"
|
|
511
510
|
),
|
|
512
|
-
github_owner:
|
|
511
|
+
github_owner: str | None = typer.Option(
|
|
513
512
|
None, "--github-owner", help="GitHub repository owner"
|
|
514
513
|
),
|
|
515
|
-
github_repo:
|
|
514
|
+
github_repo: str | None = typer.Option(
|
|
516
515
|
None, "--github-repo", help="GitHub repository name"
|
|
517
516
|
),
|
|
518
|
-
github_token:
|
|
517
|
+
github_token: str | None = typer.Option(
|
|
519
518
|
None, "--github-token", help="GitHub Personal Access Token"
|
|
520
519
|
),
|
|
521
520
|
) -> None:
|
|
522
|
-
"""Initialize mcp-ticketer for the current project.
|
|
521
|
+
"""Initialize mcp-ticketer for the current project (synonymous with 'install' and 'setup').
|
|
523
522
|
|
|
524
523
|
This command sets up MCP Ticketer configuration with interactive prompts
|
|
525
524
|
to guide you through the process. It auto-detects adapter configuration
|
|
@@ -528,11 +527,13 @@ def init(
|
|
|
528
527
|
Creates .mcp-ticketer/config.json in the current directory with
|
|
529
528
|
auto-detected or specified adapter configuration.
|
|
530
529
|
|
|
531
|
-
Note: '
|
|
530
|
+
Note: 'init', 'install', and 'setup' are all synonyms - use whichever feels natural.
|
|
532
531
|
|
|
533
532
|
Examples:
|
|
534
|
-
# Interactive setup (
|
|
533
|
+
# Interactive setup (all three commands are identical)
|
|
535
534
|
mcp-ticketer init
|
|
535
|
+
mcp-ticketer install
|
|
536
|
+
mcp-ticketer setup
|
|
536
537
|
|
|
537
538
|
# Force specific adapter
|
|
538
539
|
mcp-ticketer init --adapter linear
|
|
@@ -669,20 +670,31 @@ def init(
|
|
|
669
670
|
if linear_api_key:
|
|
670
671
|
linear_config["api_key"] = linear_api_key
|
|
671
672
|
|
|
672
|
-
# Team ID
|
|
673
|
+
# Team ID or Team Key
|
|
674
|
+
# Try environment variables first
|
|
675
|
+
linear_team_key = os.getenv("LINEAR_TEAM_KEY")
|
|
673
676
|
linear_team_id = team_id or os.getenv("LINEAR_TEAM_ID")
|
|
674
|
-
if not linear_team_id and not discovered:
|
|
675
|
-
console.print("\nYou need your Linear team ID.")
|
|
676
|
-
console.print("[dim]Find it in Linear settings or team URL[/dim]\n")
|
|
677
677
|
|
|
678
|
-
|
|
678
|
+
if not linear_team_key and not linear_team_id and not discovered:
|
|
679
|
+
console.print("\n[bold]Linear Team Configuration[/bold]")
|
|
680
|
+
console.print("Enter your team key (e.g., 'ENG', 'DESIGN', 'PRODUCT')")
|
|
681
|
+
console.print(
|
|
682
|
+
"[dim]Find it in: Linear Settings → Teams → Your Team → Key field[/dim]\n"
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
linear_team_key = typer.prompt("Team key")
|
|
679
686
|
|
|
687
|
+
# Save whichever was provided
|
|
688
|
+
if linear_team_key:
|
|
689
|
+
linear_config["team_key"] = linear_team_key
|
|
680
690
|
if linear_team_id:
|
|
681
691
|
linear_config["team_id"] = linear_team_id
|
|
682
692
|
|
|
683
|
-
if not linear_config.get("api_key") or
|
|
693
|
+
if not linear_config.get("api_key") or (
|
|
694
|
+
not linear_config.get("team_id") and not linear_config.get("team_key")
|
|
695
|
+
):
|
|
684
696
|
console.print(
|
|
685
|
-
"[red]Error:[/red] Linear requires both API key and team ID"
|
|
697
|
+
"[red]Error:[/red] Linear requires both API key and team ID/key"
|
|
686
698
|
)
|
|
687
699
|
console.print(
|
|
688
700
|
"Run 'mcp-ticketer init --adapter linear' with proper credentials"
|
|
@@ -882,107 +894,30 @@ def _show_next_steps(
|
|
|
882
894
|
console.print("\n3. [cyan]Check local ticket storage:[/cyan]")
|
|
883
895
|
console.print(" ls .aitrackdown/")
|
|
884
896
|
|
|
885
|
-
console.print("\n4. [cyan]
|
|
886
|
-
console.print(" mcp-ticketer
|
|
887
|
-
console.print(" mcp-ticketer
|
|
888
|
-
console.print(" mcp-ticketer
|
|
897
|
+
console.print("\n4. [cyan]Install MCP for AI clients (optional):[/cyan]")
|
|
898
|
+
console.print(" mcp-ticketer install claude-code # For Claude Code")
|
|
899
|
+
console.print(" mcp-ticketer install claude-desktop # For Claude Desktop")
|
|
900
|
+
console.print(" mcp-ticketer install auggie # For Auggie")
|
|
901
|
+
console.print(" mcp-ticketer install gemini # For Gemini CLI")
|
|
889
902
|
|
|
890
903
|
console.print(f"\n[dim]Configuration saved to: {config_file_path}[/dim]")
|
|
891
904
|
console.print("[dim]Run 'mcp-ticketer --help' for more commands[/dim]")
|
|
892
905
|
|
|
893
906
|
|
|
894
|
-
# Keep the old install command as deprecated alias to init
|
|
895
|
-
@app.command(deprecated=True, hidden=True)
|
|
896
|
-
def install(
|
|
897
|
-
adapter: Optional[str] = typer.Option(
|
|
898
|
-
None,
|
|
899
|
-
"--adapter",
|
|
900
|
-
"-a",
|
|
901
|
-
help="Adapter type to use (auto-detected from .env if not specified)",
|
|
902
|
-
),
|
|
903
|
-
project_path: Optional[str] = typer.Option(
|
|
904
|
-
None, "--path", help="Project path (default: current directory)"
|
|
905
|
-
),
|
|
906
|
-
global_config: bool = typer.Option(
|
|
907
|
-
False,
|
|
908
|
-
"--global",
|
|
909
|
-
"-g",
|
|
910
|
-
help="Save to global config instead of project-specific",
|
|
911
|
-
),
|
|
912
|
-
base_path: Optional[str] = typer.Option(
|
|
913
|
-
None,
|
|
914
|
-
"--base-path",
|
|
915
|
-
"-p",
|
|
916
|
-
help="Base path for ticket storage (AITrackdown only)",
|
|
917
|
-
),
|
|
918
|
-
api_key: Optional[str] = typer.Option(
|
|
919
|
-
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
920
|
-
),
|
|
921
|
-
team_id: Optional[str] = typer.Option(
|
|
922
|
-
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
923
|
-
),
|
|
924
|
-
jira_server: Optional[str] = typer.Option(
|
|
925
|
-
None,
|
|
926
|
-
"--jira-server",
|
|
927
|
-
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
928
|
-
),
|
|
929
|
-
jira_email: Optional[str] = typer.Option(
|
|
930
|
-
None, "--jira-email", help="JIRA user email for authentication"
|
|
931
|
-
),
|
|
932
|
-
jira_project: Optional[str] = typer.Option(
|
|
933
|
-
None, "--jira-project", help="Default JIRA project key"
|
|
934
|
-
),
|
|
935
|
-
github_owner: Optional[str] = typer.Option(
|
|
936
|
-
None, "--github-owner", help="GitHub repository owner"
|
|
937
|
-
),
|
|
938
|
-
github_repo: Optional[str] = typer.Option(
|
|
939
|
-
None, "--github-repo", help="GitHub repository name"
|
|
940
|
-
),
|
|
941
|
-
github_token: Optional[str] = typer.Option(
|
|
942
|
-
None, "--github-token", help="GitHub Personal Access Token"
|
|
943
|
-
),
|
|
944
|
-
) -> None:
|
|
945
|
-
"""DEPRECATED: Use 'mcp-ticketer init' instead.
|
|
946
|
-
|
|
947
|
-
This command is deprecated. Use 'mcp-ticketer init' for project initialization.
|
|
948
|
-
|
|
949
|
-
"""
|
|
950
|
-
console.print(
|
|
951
|
-
"[yellow]⚠️ 'install' is deprecated. Use 'mcp-ticketer init' instead.[/yellow]\n"
|
|
952
|
-
)
|
|
953
|
-
# Call init with all parameters
|
|
954
|
-
init(
|
|
955
|
-
adapter=adapter,
|
|
956
|
-
project_path=project_path,
|
|
957
|
-
global_config=global_config,
|
|
958
|
-
base_path=base_path,
|
|
959
|
-
api_key=api_key,
|
|
960
|
-
team_id=team_id,
|
|
961
|
-
jira_server=jira_server,
|
|
962
|
-
jira_email=jira_email,
|
|
963
|
-
jira_project=jira_project,
|
|
964
|
-
github_owner=github_owner,
|
|
965
|
-
github_repo=github_repo,
|
|
966
|
-
github_token=github_token,
|
|
967
|
-
)
|
|
968
|
-
|
|
969
|
-
|
|
970
907
|
@app.command("set")
|
|
971
908
|
def set_config(
|
|
972
|
-
adapter:
|
|
909
|
+
adapter: AdapterType | None = typer.Option(
|
|
973
910
|
None, "--adapter", "-a", help="Set default adapter"
|
|
974
911
|
),
|
|
975
|
-
team_key:
|
|
912
|
+
team_key: str | None = typer.Option(
|
|
976
913
|
None, "--team-key", help="Linear team key (e.g., BTA)"
|
|
977
914
|
),
|
|
978
|
-
team_id:
|
|
979
|
-
owner:
|
|
980
|
-
|
|
981
|
-
),
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
project: Optional[str] = typer.Option(None, "--project", help="JIRA project key"),
|
|
985
|
-
base_path: Optional[str] = typer.Option(
|
|
915
|
+
team_id: str | None = typer.Option(None, "--team-id", help="Linear team ID"),
|
|
916
|
+
owner: str | None = typer.Option(None, "--owner", help="GitHub repository owner"),
|
|
917
|
+
repo: str | None = typer.Option(None, "--repo", help="GitHub repository name"),
|
|
918
|
+
server: str | None = typer.Option(None, "--server", help="JIRA server URL"),
|
|
919
|
+
project: str | None = typer.Option(None, "--project", help="JIRA project key"),
|
|
920
|
+
base_path: str | None = typer.Option(
|
|
986
921
|
None, "--base-path", help="AITrackdown base path"
|
|
987
922
|
),
|
|
988
923
|
) -> None:
|
|
@@ -1072,16 +1007,12 @@ def set_config(
|
|
|
1072
1007
|
@app.command("configure")
|
|
1073
1008
|
def configure_command(
|
|
1074
1009
|
show: bool = typer.Option(False, "--show", help="Show current configuration"),
|
|
1075
|
-
adapter:
|
|
1010
|
+
adapter: str | None = typer.Option(
|
|
1076
1011
|
None, "--adapter", help="Set default adapter type"
|
|
1077
1012
|
),
|
|
1078
|
-
api_key:
|
|
1079
|
-
project_id:
|
|
1080
|
-
|
|
1081
|
-
),
|
|
1082
|
-
team_id: Optional[str] = typer.Option(
|
|
1083
|
-
None, "--team-id", help="Set team ID (Linear)"
|
|
1084
|
-
),
|
|
1013
|
+
api_key: str | None = typer.Option(None, "--api-key", help="Set API key/token"),
|
|
1014
|
+
project_id: str | None = typer.Option(None, "--project-id", help="Set project ID"),
|
|
1015
|
+
team_id: str | None = typer.Option(None, "--team-id", help="Set team ID (Linear)"),
|
|
1085
1016
|
global_scope: bool = typer.Option(
|
|
1086
1017
|
False,
|
|
1087
1018
|
"--global",
|
|
@@ -1257,29 +1188,29 @@ def old_queue_health_command(
|
|
|
1257
1188
|
@app.command(deprecated=True, hidden=True)
|
|
1258
1189
|
def create(
|
|
1259
1190
|
title: str = typer.Argument(..., help="Ticket title"),
|
|
1260
|
-
description:
|
|
1191
|
+
description: str | None = typer.Option(
|
|
1261
1192
|
None, "--description", "-d", help="Ticket description"
|
|
1262
1193
|
),
|
|
1263
1194
|
priority: Priority = typer.Option(
|
|
1264
1195
|
Priority.MEDIUM, "--priority", "-p", help="Priority level"
|
|
1265
1196
|
),
|
|
1266
|
-
tags:
|
|
1197
|
+
tags: list[str] | None = typer.Option(
|
|
1267
1198
|
None, "--tag", "-t", help="Tags (can be specified multiple times)"
|
|
1268
1199
|
),
|
|
1269
|
-
assignee:
|
|
1200
|
+
assignee: str | None = typer.Option(
|
|
1270
1201
|
None, "--assignee", "-a", help="Assignee username"
|
|
1271
1202
|
),
|
|
1272
|
-
project:
|
|
1203
|
+
project: str | None = typer.Option(
|
|
1273
1204
|
None,
|
|
1274
1205
|
"--project",
|
|
1275
1206
|
help="Parent project/epic ID (synonym for --epic)",
|
|
1276
1207
|
),
|
|
1277
|
-
epic:
|
|
1208
|
+
epic: str | None = typer.Option(
|
|
1278
1209
|
None,
|
|
1279
1210
|
"--epic",
|
|
1280
1211
|
help="Parent epic/project ID (synonym for --project)",
|
|
1281
1212
|
),
|
|
1282
|
-
adapter:
|
|
1213
|
+
adapter: AdapterType | None = typer.Option(
|
|
1283
1214
|
None, "--adapter", help="Override default adapter"
|
|
1284
1215
|
),
|
|
1285
1216
|
) -> None:
|
|
@@ -1488,14 +1419,14 @@ def create(
|
|
|
1488
1419
|
|
|
1489
1420
|
@app.command("list", deprecated=True, hidden=True)
|
|
1490
1421
|
def list_tickets(
|
|
1491
|
-
state:
|
|
1422
|
+
state: TicketState | None = typer.Option(
|
|
1492
1423
|
None, "--state", "-s", help="Filter by state"
|
|
1493
1424
|
),
|
|
1494
|
-
priority:
|
|
1425
|
+
priority: Priority | None = typer.Option(
|
|
1495
1426
|
None, "--priority", "-p", help="Filter by priority"
|
|
1496
1427
|
),
|
|
1497
1428
|
limit: int = typer.Option(10, "--limit", "-l", help="Maximum number of tickets"),
|
|
1498
|
-
adapter:
|
|
1429
|
+
adapter: AdapterType | None = typer.Option(
|
|
1499
1430
|
None, "--adapter", help="Override default adapter"
|
|
1500
1431
|
),
|
|
1501
1432
|
) -> None:
|
|
@@ -1551,7 +1482,7 @@ def list_tickets(
|
|
|
1551
1482
|
def show(
|
|
1552
1483
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1553
1484
|
comments: bool = typer.Option(False, "--comments", "-c", help="Show comments"),
|
|
1554
|
-
adapter:
|
|
1485
|
+
adapter: AdapterType | None = typer.Option(
|
|
1555
1486
|
None, "--adapter", help="Override default adapter"
|
|
1556
1487
|
),
|
|
1557
1488
|
) -> None:
|
|
@@ -1607,7 +1538,7 @@ def show(
|
|
|
1607
1538
|
def comment(
|
|
1608
1539
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1609
1540
|
content: str = typer.Argument(..., help="Comment content"),
|
|
1610
|
-
adapter:
|
|
1541
|
+
adapter: AdapterType | None = typer.Option(
|
|
1611
1542
|
None, "--adapter", help="Override default adapter"
|
|
1612
1543
|
),
|
|
1613
1544
|
) -> None:
|
|
@@ -1648,17 +1579,15 @@ def comment(
|
|
|
1648
1579
|
@app.command(deprecated=True, hidden=True)
|
|
1649
1580
|
def update(
|
|
1650
1581
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1651
|
-
title:
|
|
1652
|
-
description:
|
|
1582
|
+
title: str | None = typer.Option(None, "--title", help="New title"),
|
|
1583
|
+
description: str | None = typer.Option(
|
|
1653
1584
|
None, "--description", "-d", help="New description"
|
|
1654
1585
|
),
|
|
1655
|
-
priority:
|
|
1586
|
+
priority: Priority | None = typer.Option(
|
|
1656
1587
|
None, "--priority", "-p", help="New priority"
|
|
1657
1588
|
),
|
|
1658
|
-
assignee:
|
|
1659
|
-
|
|
1660
|
-
),
|
|
1661
|
-
adapter: Optional[AdapterType] = typer.Option(
|
|
1589
|
+
assignee: str | None = typer.Option(None, "--assignee", "-a", help="New assignee"),
|
|
1590
|
+
adapter: AdapterType | None = typer.Option(
|
|
1662
1591
|
None, "--adapter", help="Override default adapter"
|
|
1663
1592
|
),
|
|
1664
1593
|
) -> None:
|
|
@@ -1718,13 +1647,13 @@ def update(
|
|
|
1718
1647
|
@app.command(deprecated=True, hidden=True)
|
|
1719
1648
|
def transition(
|
|
1720
1649
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1721
|
-
state_positional:
|
|
1650
|
+
state_positional: TicketState | None = typer.Argument(
|
|
1722
1651
|
None, help="Target state (positional - deprecated, use --state instead)"
|
|
1723
1652
|
),
|
|
1724
|
-
state:
|
|
1653
|
+
state: TicketState | None = typer.Option(
|
|
1725
1654
|
None, "--state", "-s", help="Target state (recommended)"
|
|
1726
1655
|
),
|
|
1727
|
-
adapter:
|
|
1656
|
+
adapter: AdapterType | None = typer.Option(
|
|
1728
1657
|
None, "--adapter", help="Override default adapter"
|
|
1729
1658
|
),
|
|
1730
1659
|
) -> None:
|
|
@@ -1789,12 +1718,12 @@ def transition(
|
|
|
1789
1718
|
|
|
1790
1719
|
@app.command(deprecated=True, hidden=True)
|
|
1791
1720
|
def search(
|
|
1792
|
-
query:
|
|
1793
|
-
state:
|
|
1794
|
-
priority:
|
|
1795
|
-
assignee:
|
|
1721
|
+
query: str | None = typer.Argument(None, help="Search query"),
|
|
1722
|
+
state: TicketState | None = typer.Option(None, "--state", "-s"),
|
|
1723
|
+
priority: Priority | None = typer.Option(None, "--priority", "-p"),
|
|
1724
|
+
assignee: str | None = typer.Option(None, "--assignee", "-a"),
|
|
1796
1725
|
limit: int = typer.Option(10, "--limit", "-l"),
|
|
1797
|
-
adapter:
|
|
1726
|
+
adapter: AdapterType | None = typer.Option(
|
|
1798
1727
|
None, "--adapter", help="Override default adapter"
|
|
1799
1728
|
),
|
|
1800
1729
|
) -> None:
|
|
@@ -1852,7 +1781,7 @@ app.add_typer(discover_app, name="discover")
|
|
|
1852
1781
|
# Add diagnostics command
|
|
1853
1782
|
@app.command("diagnose")
|
|
1854
1783
|
def diagnose_command(
|
|
1855
|
-
output_file:
|
|
1784
|
+
output_file: str | None = typer.Option(
|
|
1856
1785
|
None, "--output", "-o", help="Save full report to file"
|
|
1857
1786
|
),
|
|
1858
1787
|
json_output: bool = typer.Option(
|
|
@@ -1899,7 +1828,7 @@ def diagnose_command(
|
|
|
1899
1828
|
|
|
1900
1829
|
@app.command("doctor")
|
|
1901
1830
|
def doctor_alias(
|
|
1902
|
-
output_file:
|
|
1831
|
+
output_file: str | None = typer.Option(
|
|
1903
1832
|
None, "--output", "-o", help="Save full report to file"
|
|
1904
1833
|
),
|
|
1905
1834
|
json_output: bool = typer.Option(
|
|
@@ -1944,111 +1873,154 @@ mcp_app = typer.Typer(
|
|
|
1944
1873
|
|
|
1945
1874
|
@app.command()
|
|
1946
1875
|
def install(
|
|
1947
|
-
platform:
|
|
1876
|
+
platform: str | None = typer.Argument(
|
|
1948
1877
|
None,
|
|
1949
|
-
help="Platform to install (claude-code, claude-desktop,
|
|
1878
|
+
help="Platform to install (claude-code, claude-desktop, gemini, codex, auggie)",
|
|
1879
|
+
),
|
|
1880
|
+
adapter: str | None = typer.Option(
|
|
1881
|
+
None,
|
|
1882
|
+
"--adapter",
|
|
1883
|
+
"-a",
|
|
1884
|
+
help="Adapter type to use (interactive prompt if not specified)",
|
|
1885
|
+
),
|
|
1886
|
+
project_path: str | None = typer.Option(
|
|
1887
|
+
None, "--path", help="Project path (default: current directory)"
|
|
1888
|
+
),
|
|
1889
|
+
global_config: bool = typer.Option(
|
|
1890
|
+
False,
|
|
1891
|
+
"--global",
|
|
1892
|
+
"-g",
|
|
1893
|
+
help="Save to global config instead of project-specific",
|
|
1894
|
+
),
|
|
1895
|
+
base_path: str | None = typer.Option(
|
|
1896
|
+
None,
|
|
1897
|
+
"--base-path",
|
|
1898
|
+
"-p",
|
|
1899
|
+
help="Base path for ticket storage (AITrackdown only)",
|
|
1900
|
+
),
|
|
1901
|
+
api_key: str | None = typer.Option(
|
|
1902
|
+
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
1903
|
+
),
|
|
1904
|
+
team_id: str | None = typer.Option(
|
|
1905
|
+
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
1906
|
+
),
|
|
1907
|
+
jira_server: str | None = typer.Option(
|
|
1908
|
+
None,
|
|
1909
|
+
"--jira-server",
|
|
1910
|
+
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
1911
|
+
),
|
|
1912
|
+
jira_email: str | None = typer.Option(
|
|
1913
|
+
None, "--jira-email", help="JIRA user email for authentication"
|
|
1914
|
+
),
|
|
1915
|
+
jira_project: str | None = typer.Option(
|
|
1916
|
+
None, "--jira-project", help="Default JIRA project key"
|
|
1917
|
+
),
|
|
1918
|
+
github_owner: str | None = typer.Option(
|
|
1919
|
+
None, "--github-owner", help="GitHub repository owner"
|
|
1920
|
+
),
|
|
1921
|
+
github_repo: str | None = typer.Option(
|
|
1922
|
+
None, "--github-repo", help="GitHub repository name"
|
|
1923
|
+
),
|
|
1924
|
+
github_token: str | None = typer.Option(
|
|
1925
|
+
None, "--github-token", help="GitHub Personal Access Token"
|
|
1950
1926
|
),
|
|
1951
1927
|
dry_run: bool = typer.Option(
|
|
1952
|
-
False,
|
|
1928
|
+
False,
|
|
1929
|
+
"--dry-run",
|
|
1930
|
+
help="Show what would be done without making changes (for platform installation)",
|
|
1953
1931
|
),
|
|
1954
1932
|
) -> None:
|
|
1955
|
-
"""Install
|
|
1956
|
-
|
|
1957
|
-
Without arguments, shows installation status and available platforms.
|
|
1958
|
-
With a platform argument, installs MCP configuration for that platform.
|
|
1933
|
+
"""Install MCP for AI platforms OR initialize adapter setup.
|
|
1959
1934
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
- claude-desktop: Global MCP server
|
|
1963
|
-
- auggie: Project-level MCP server
|
|
1964
|
-
- gemini: Project-level MCP server
|
|
1965
|
-
- codex: Project-level MCP server
|
|
1935
|
+
With platform argument (new syntax): Install MCP configuration for AI platforms
|
|
1936
|
+
Without platform argument (legacy): Run adapter setup wizard (same as 'init' and 'setup')
|
|
1966
1937
|
|
|
1967
|
-
|
|
1968
|
-
#
|
|
1969
|
-
mcp-ticketer install
|
|
1938
|
+
New Command Structure:
|
|
1939
|
+
# Install MCP for AI platforms
|
|
1940
|
+
mcp-ticketer install claude-code # Claude Code (project-level)
|
|
1941
|
+
mcp-ticketer install claude-desktop # Claude Desktop (global)
|
|
1942
|
+
mcp-ticketer install gemini # Gemini CLI
|
|
1943
|
+
mcp-ticketer install codex # Codex
|
|
1944
|
+
mcp-ticketer install auggie # Auggie
|
|
1970
1945
|
|
|
1971
|
-
|
|
1972
|
-
mcp-ticketer install
|
|
1973
|
-
|
|
1974
|
-
# Install for Claude Desktop (global)
|
|
1975
|
-
mcp-ticketer install claude-desktop
|
|
1976
|
-
|
|
1977
|
-
# Install for Auggie
|
|
1978
|
-
mcp-ticketer install auggie
|
|
1979
|
-
|
|
1980
|
-
# Dry run to preview changes
|
|
1981
|
-
mcp-ticketer install claude-code --dry-run
|
|
1946
|
+
Legacy Adapter Setup (still supported):
|
|
1947
|
+
mcp-ticketer install # Interactive setup wizard
|
|
1948
|
+
mcp-ticketer install --adapter linear
|
|
1982
1949
|
|
|
1983
1950
|
"""
|
|
1984
|
-
# If
|
|
1985
|
-
if platform is None:
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1951
|
+
# If platform argument is provided, handle MCP platform installation (NEW SYNTAX)
|
|
1952
|
+
if platform is not None:
|
|
1953
|
+
# Import configuration functions
|
|
1954
|
+
from .auggie_configure import configure_auggie_mcp
|
|
1955
|
+
from .codex_configure import configure_codex_mcp
|
|
1956
|
+
from .gemini_configure import configure_gemini_mcp
|
|
1957
|
+
from .mcp_configure import configure_claude_mcp
|
|
1958
|
+
|
|
1959
|
+
# Map platform names to configuration functions
|
|
1960
|
+
platform_mapping = {
|
|
1961
|
+
"claude-code": {
|
|
1962
|
+
"func": lambda: configure_claude_mcp(global_config=False, force=True),
|
|
1963
|
+
"name": "Claude Code",
|
|
1964
|
+
},
|
|
1965
|
+
"claude-desktop": {
|
|
1966
|
+
"func": lambda: configure_claude_mcp(global_config=True, force=True),
|
|
1967
|
+
"name": "Claude Desktop",
|
|
1968
|
+
},
|
|
1969
|
+
"auggie": {
|
|
1970
|
+
"func": lambda: configure_auggie_mcp(force=True),
|
|
1971
|
+
"name": "Auggie",
|
|
1972
|
+
},
|
|
1973
|
+
"gemini": {
|
|
1974
|
+
"func": lambda: configure_gemini_mcp(scope="project", force=True),
|
|
1975
|
+
"name": "Gemini CLI",
|
|
1976
|
+
},
|
|
1977
|
+
"codex": {
|
|
1978
|
+
"func": lambda: configure_codex_mcp(force=True),
|
|
1979
|
+
"name": "Codex",
|
|
1980
|
+
},
|
|
1981
|
+
}
|
|
1998
1982
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
1983
|
+
if platform not in platform_mapping:
|
|
1984
|
+
console.print(f"[red]Unknown platform: {platform}[/red]")
|
|
1985
|
+
console.print("\n[bold]Available platforms:[/bold]")
|
|
1986
|
+
for p in platform_mapping.keys():
|
|
1987
|
+
console.print(f" • {p}")
|
|
1988
|
+
raise typer.Exit(1)
|
|
2004
1989
|
|
|
2005
|
-
|
|
2006
|
-
platform_mapping = {
|
|
2007
|
-
"claude-code": {
|
|
2008
|
-
"func": lambda: configure_claude_mcp(global_config=False, force=True),
|
|
2009
|
-
"name": "Claude Code",
|
|
2010
|
-
},
|
|
2011
|
-
"claude-desktop": {
|
|
2012
|
-
"func": lambda: configure_claude_mcp(global_config=True, force=True),
|
|
2013
|
-
"name": "Claude Desktop",
|
|
2014
|
-
},
|
|
2015
|
-
"auggie": {
|
|
2016
|
-
"func": lambda: configure_auggie_mcp(force=True),
|
|
2017
|
-
"name": "Auggie",
|
|
2018
|
-
},
|
|
2019
|
-
"gemini": {
|
|
2020
|
-
"func": lambda: configure_gemini_mcp(scope="project", force=True),
|
|
2021
|
-
"name": "Gemini CLI",
|
|
2022
|
-
},
|
|
2023
|
-
"codex": {
|
|
2024
|
-
"func": lambda: configure_codex_mcp(force=True),
|
|
2025
|
-
"name": "Codex",
|
|
2026
|
-
},
|
|
2027
|
-
}
|
|
1990
|
+
config = platform_mapping[platform]
|
|
2028
1991
|
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
for p in platform_mapping.keys():
|
|
2033
|
-
console.print(f" • {p}")
|
|
2034
|
-
raise typer.Exit(1)
|
|
2035
|
-
|
|
2036
|
-
config = platform_mapping[platform]
|
|
1992
|
+
if dry_run:
|
|
1993
|
+
console.print(f"[cyan]DRY RUN - Would install for {config['name']}[/cyan]")
|
|
1994
|
+
return
|
|
2037
1995
|
|
|
2038
|
-
|
|
2039
|
-
|
|
1996
|
+
try:
|
|
1997
|
+
config["func"]()
|
|
1998
|
+
except Exception as e:
|
|
1999
|
+
console.print(f"[red]Installation failed: {e}[/red]")
|
|
2000
|
+
raise typer.Exit(1)
|
|
2040
2001
|
return
|
|
2041
2002
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2003
|
+
# Otherwise, delegate to init for adapter initialization (LEGACY BEHAVIOR)
|
|
2004
|
+
# This makes 'install' and 'init' synonymous when called without platform argument
|
|
2005
|
+
init(
|
|
2006
|
+
adapter=adapter,
|
|
2007
|
+
project_path=project_path,
|
|
2008
|
+
global_config=global_config,
|
|
2009
|
+
base_path=base_path,
|
|
2010
|
+
api_key=api_key,
|
|
2011
|
+
team_id=team_id,
|
|
2012
|
+
jira_server=jira_server,
|
|
2013
|
+
jira_email=jira_email,
|
|
2014
|
+
jira_project=jira_project,
|
|
2015
|
+
github_owner=github_owner,
|
|
2016
|
+
github_repo=github_repo,
|
|
2017
|
+
github_token=github_token,
|
|
2018
|
+
)
|
|
2047
2019
|
|
|
2048
2020
|
|
|
2049
2021
|
@app.command()
|
|
2050
2022
|
def remove(
|
|
2051
|
-
platform:
|
|
2023
|
+
platform: str | None = typer.Argument(
|
|
2052
2024
|
None,
|
|
2053
2025
|
help="Platform to remove (claude-code, claude-desktop, auggie, gemini, codex)",
|
|
2054
2026
|
),
|
|
@@ -2135,7 +2107,7 @@ def remove(
|
|
|
2135
2107
|
|
|
2136
2108
|
@app.command()
|
|
2137
2109
|
def uninstall(
|
|
2138
|
-
platform:
|
|
2110
|
+
platform: str | None = typer.Argument(
|
|
2139
2111
|
None,
|
|
2140
2112
|
help="Platform to uninstall (claude-code, claude-desktop, auggie, gemini, codex)",
|
|
2141
2113
|
),
|
|
@@ -2218,10 +2190,10 @@ def check(queue_id: str = typer.Argument(..., help="Queue ID to check")):
|
|
|
2218
2190
|
|
|
2219
2191
|
@mcp_app.command(name="serve")
|
|
2220
2192
|
def mcp_serve(
|
|
2221
|
-
adapter:
|
|
2193
|
+
adapter: AdapterType | None = typer.Option(
|
|
2222
2194
|
None, "--adapter", "-a", help="Override default adapter type"
|
|
2223
2195
|
),
|
|
2224
|
-
base_path:
|
|
2196
|
+
base_path: str | None = typer.Option(
|
|
2225
2197
|
None, "--base-path", help="Base path for AITrackdown adapter"
|
|
2226
2198
|
),
|
|
2227
2199
|
):
|
|
@@ -2453,6 +2425,125 @@ def mcp_auggie(
|
|
|
2453
2425
|
raise typer.Exit(1)
|
|
2454
2426
|
|
|
2455
2427
|
|
|
2428
|
+
@mcp_app.command(name="status")
|
|
2429
|
+
def mcp_status():
|
|
2430
|
+
"""Check MCP server status.
|
|
2431
|
+
|
|
2432
|
+
Shows whether the MCP server is configured and running for various platforms.
|
|
2433
|
+
|
|
2434
|
+
Examples:
|
|
2435
|
+
mcp-ticketer mcp status
|
|
2436
|
+
|
|
2437
|
+
"""
|
|
2438
|
+
import json
|
|
2439
|
+
from pathlib import Path
|
|
2440
|
+
|
|
2441
|
+
console.print("[bold]MCP Server Status[/bold]\n")
|
|
2442
|
+
|
|
2443
|
+
# Check project-level configuration
|
|
2444
|
+
project_config = Path.cwd() / ".mcp-ticketer" / "config.json"
|
|
2445
|
+
if project_config.exists():
|
|
2446
|
+
console.print(f"[green]✓[/green] Project config found: {project_config}")
|
|
2447
|
+
try:
|
|
2448
|
+
with open(project_config) as f:
|
|
2449
|
+
config = json.load(f)
|
|
2450
|
+
adapter = config.get("default_adapter", "aitrackdown")
|
|
2451
|
+
console.print(f" Default adapter: [cyan]{adapter}[/cyan]")
|
|
2452
|
+
except Exception as e:
|
|
2453
|
+
console.print(f" [yellow]Warning: Could not read config: {e}[/yellow]")
|
|
2454
|
+
else:
|
|
2455
|
+
console.print("[yellow]○[/yellow] No project config found")
|
|
2456
|
+
|
|
2457
|
+
# Check Claude Code configuration
|
|
2458
|
+
claude_code_config = Path.cwd() / ".mcp" / "config.json"
|
|
2459
|
+
if claude_code_config.exists():
|
|
2460
|
+
console.print(
|
|
2461
|
+
f"\n[green]✓[/green] Claude Code configured: {claude_code_config}"
|
|
2462
|
+
)
|
|
2463
|
+
else:
|
|
2464
|
+
console.print("\n[yellow]○[/yellow] Claude Code not configured")
|
|
2465
|
+
|
|
2466
|
+
# Check Claude Desktop configuration
|
|
2467
|
+
claude_desktop_config = (
|
|
2468
|
+
Path.home()
|
|
2469
|
+
/ "Library"
|
|
2470
|
+
/ "Application Support"
|
|
2471
|
+
/ "Claude"
|
|
2472
|
+
/ "claude_desktop_config.json"
|
|
2473
|
+
)
|
|
2474
|
+
if claude_desktop_config.exists():
|
|
2475
|
+
try:
|
|
2476
|
+
with open(claude_desktop_config) as f:
|
|
2477
|
+
config = json.load(f)
|
|
2478
|
+
if "mcpServers" in config and "mcp-ticketer" in config["mcpServers"]:
|
|
2479
|
+
console.print(
|
|
2480
|
+
f"[green]✓[/green] Claude Desktop configured: {claude_desktop_config}"
|
|
2481
|
+
)
|
|
2482
|
+
else:
|
|
2483
|
+
console.print(
|
|
2484
|
+
"[yellow]○[/yellow] Claude Desktop config exists but mcp-ticketer not found"
|
|
2485
|
+
)
|
|
2486
|
+
except Exception:
|
|
2487
|
+
console.print(
|
|
2488
|
+
"[yellow]○[/yellow] Claude Desktop config exists but could not be read"
|
|
2489
|
+
)
|
|
2490
|
+
else:
|
|
2491
|
+
console.print("[yellow]○[/yellow] Claude Desktop not configured")
|
|
2492
|
+
|
|
2493
|
+
# Check Gemini configuration
|
|
2494
|
+
gemini_project_config = Path.cwd() / ".gemini" / "settings.json"
|
|
2495
|
+
gemini_user_config = Path.home() / ".gemini" / "settings.json"
|
|
2496
|
+
if gemini_project_config.exists():
|
|
2497
|
+
console.print(
|
|
2498
|
+
f"\n[green]✓[/green] Gemini (project) configured: {gemini_project_config}"
|
|
2499
|
+
)
|
|
2500
|
+
elif gemini_user_config.exists():
|
|
2501
|
+
console.print(
|
|
2502
|
+
f"\n[green]✓[/green] Gemini (user) configured: {gemini_user_config}"
|
|
2503
|
+
)
|
|
2504
|
+
else:
|
|
2505
|
+
console.print("\n[yellow]○[/yellow] Gemini not configured")
|
|
2506
|
+
|
|
2507
|
+
# Check Codex configuration
|
|
2508
|
+
codex_config = Path.home() / ".codex" / "config.toml"
|
|
2509
|
+
if codex_config.exists():
|
|
2510
|
+
console.print(f"[green]✓[/green] Codex configured: {codex_config}")
|
|
2511
|
+
else:
|
|
2512
|
+
console.print("[yellow]○[/yellow] Codex not configured")
|
|
2513
|
+
|
|
2514
|
+
# Check Auggie configuration
|
|
2515
|
+
auggie_config = Path.home() / ".augment" / "settings.json"
|
|
2516
|
+
if auggie_config.exists():
|
|
2517
|
+
console.print(f"[green]✓[/green] Auggie configured: {auggie_config}")
|
|
2518
|
+
else:
|
|
2519
|
+
console.print("[yellow]○[/yellow] Auggie not configured")
|
|
2520
|
+
|
|
2521
|
+
console.print(
|
|
2522
|
+
"\n[dim]Run 'mcp-ticketer install <platform>' to configure a platform[/dim]"
|
|
2523
|
+
)
|
|
2524
|
+
|
|
2525
|
+
|
|
2526
|
+
@mcp_app.command(name="stop")
|
|
2527
|
+
def mcp_stop():
|
|
2528
|
+
"""Stop MCP server (placeholder - MCP runs on-demand via stdio).
|
|
2529
|
+
|
|
2530
|
+
Note: The MCP server runs on-demand when AI clients connect via stdio.
|
|
2531
|
+
It doesn't run as a persistent background service, so there's nothing to stop.
|
|
2532
|
+
This command is provided for consistency but has no effect.
|
|
2533
|
+
|
|
2534
|
+
Examples:
|
|
2535
|
+
mcp-ticketer mcp stop
|
|
2536
|
+
|
|
2537
|
+
"""
|
|
2538
|
+
console.print(
|
|
2539
|
+
"[yellow]ℹ[/yellow] MCP server runs on-demand via stdio (not as a background service)"
|
|
2540
|
+
)
|
|
2541
|
+
console.print("There is no persistent server process to stop.")
|
|
2542
|
+
console.print(
|
|
2543
|
+
"\n[dim]The server starts automatically when AI clients connect and stops when they disconnect.[/dim]"
|
|
2544
|
+
)
|
|
2545
|
+
|
|
2546
|
+
|
|
2456
2547
|
# Add command groups to main app (must be after all subcommands are defined)
|
|
2457
2548
|
app.add_typer(mcp_app, name="mcp")
|
|
2458
2549
|
|