mcp-ticketer 0.12.0__py3-none-any.whl → 2.2.13__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.

Files changed (129) hide show
  1. mcp_ticketer/__init__.py +10 -10
  2. mcp_ticketer/__version__.py +1 -1
  3. mcp_ticketer/_version_scm.py +1 -0
  4. mcp_ticketer/adapters/aitrackdown.py +507 -6
  5. mcp_ticketer/adapters/asana/adapter.py +229 -0
  6. mcp_ticketer/adapters/asana/mappers.py +14 -0
  7. mcp_ticketer/adapters/github/__init__.py +26 -0
  8. mcp_ticketer/adapters/github/adapter.py +3229 -0
  9. mcp_ticketer/adapters/github/client.py +335 -0
  10. mcp_ticketer/adapters/github/mappers.py +797 -0
  11. mcp_ticketer/adapters/github/queries.py +692 -0
  12. mcp_ticketer/adapters/github/types.py +460 -0
  13. mcp_ticketer/adapters/hybrid.py +47 -5
  14. mcp_ticketer/adapters/jira/__init__.py +35 -0
  15. mcp_ticketer/adapters/jira/adapter.py +1351 -0
  16. mcp_ticketer/adapters/jira/client.py +271 -0
  17. mcp_ticketer/adapters/jira/mappers.py +246 -0
  18. mcp_ticketer/adapters/jira/queries.py +216 -0
  19. mcp_ticketer/adapters/jira/types.py +304 -0
  20. mcp_ticketer/adapters/linear/adapter.py +2730 -139
  21. mcp_ticketer/adapters/linear/client.py +175 -3
  22. mcp_ticketer/adapters/linear/mappers.py +203 -8
  23. mcp_ticketer/adapters/linear/queries.py +280 -3
  24. mcp_ticketer/adapters/linear/types.py +120 -4
  25. mcp_ticketer/analysis/__init__.py +56 -0
  26. mcp_ticketer/analysis/dependency_graph.py +255 -0
  27. mcp_ticketer/analysis/health_assessment.py +304 -0
  28. mcp_ticketer/analysis/orphaned.py +218 -0
  29. mcp_ticketer/analysis/project_status.py +594 -0
  30. mcp_ticketer/analysis/similarity.py +224 -0
  31. mcp_ticketer/analysis/staleness.py +266 -0
  32. mcp_ticketer/automation/__init__.py +11 -0
  33. mcp_ticketer/automation/project_updates.py +378 -0
  34. mcp_ticketer/cli/adapter_diagnostics.py +3 -1
  35. mcp_ticketer/cli/auggie_configure.py +17 -5
  36. mcp_ticketer/cli/codex_configure.py +97 -61
  37. mcp_ticketer/cli/configure.py +1288 -105
  38. mcp_ticketer/cli/cursor_configure.py +314 -0
  39. mcp_ticketer/cli/diagnostics.py +13 -12
  40. mcp_ticketer/cli/discover.py +5 -0
  41. mcp_ticketer/cli/gemini_configure.py +17 -5
  42. mcp_ticketer/cli/init_command.py +880 -0
  43. mcp_ticketer/cli/install_mcp_server.py +418 -0
  44. mcp_ticketer/cli/instruction_commands.py +6 -0
  45. mcp_ticketer/cli/main.py +267 -3175
  46. mcp_ticketer/cli/mcp_configure.py +821 -119
  47. mcp_ticketer/cli/mcp_server_commands.py +415 -0
  48. mcp_ticketer/cli/platform_detection.py +77 -12
  49. mcp_ticketer/cli/platform_installer.py +545 -0
  50. mcp_ticketer/cli/project_update_commands.py +350 -0
  51. mcp_ticketer/cli/setup_command.py +795 -0
  52. mcp_ticketer/cli/simple_health.py +12 -10
  53. mcp_ticketer/cli/ticket_commands.py +705 -103
  54. mcp_ticketer/cli/utils.py +113 -0
  55. mcp_ticketer/core/__init__.py +56 -6
  56. mcp_ticketer/core/adapter.py +533 -2
  57. mcp_ticketer/core/config.py +21 -21
  58. mcp_ticketer/core/exceptions.py +7 -1
  59. mcp_ticketer/core/label_manager.py +732 -0
  60. mcp_ticketer/core/mappers.py +31 -19
  61. mcp_ticketer/core/milestone_manager.py +252 -0
  62. mcp_ticketer/core/models.py +480 -0
  63. mcp_ticketer/core/onepassword_secrets.py +1 -1
  64. mcp_ticketer/core/priority_matcher.py +463 -0
  65. mcp_ticketer/core/project_config.py +132 -14
  66. mcp_ticketer/core/project_utils.py +281 -0
  67. mcp_ticketer/core/project_validator.py +376 -0
  68. mcp_ticketer/core/session_state.py +176 -0
  69. mcp_ticketer/core/state_matcher.py +625 -0
  70. mcp_ticketer/core/url_parser.py +425 -0
  71. mcp_ticketer/core/validators.py +69 -0
  72. mcp_ticketer/mcp/server/__main__.py +2 -1
  73. mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
  74. mcp_ticketer/mcp/server/main.py +106 -25
  75. mcp_ticketer/mcp/server/routing.py +723 -0
  76. mcp_ticketer/mcp/server/server_sdk.py +58 -0
  77. mcp_ticketer/mcp/server/tools/__init__.py +33 -11
  78. mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
  79. mcp_ticketer/mcp/server/tools/attachment_tools.py +5 -5
  80. mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
  81. mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
  82. mcp_ticketer/mcp/server/tools/config_tools.py +1391 -145
  83. mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
  84. mcp_ticketer/mcp/server/tools/hierarchy_tools.py +870 -460
  85. mcp_ticketer/mcp/server/tools/instruction_tools.py +7 -5
  86. mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
  87. mcp_ticketer/mcp/server/tools/milestone_tools.py +338 -0
  88. mcp_ticketer/mcp/server/tools/pr_tools.py +3 -7
  89. mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
  90. mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
  91. mcp_ticketer/mcp/server/tools/search_tools.py +209 -97
  92. mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
  93. mcp_ticketer/mcp/server/tools/ticket_tools.py +1107 -124
  94. mcp_ticketer/mcp/server/tools/user_ticket_tools.py +218 -236
  95. mcp_ticketer/queue/queue.py +68 -0
  96. mcp_ticketer/queue/worker.py +1 -1
  97. mcp_ticketer/utils/__init__.py +5 -0
  98. mcp_ticketer/utils/token_utils.py +246 -0
  99. mcp_ticketer-2.2.13.dist-info/METADATA +1396 -0
  100. mcp_ticketer-2.2.13.dist-info/RECORD +158 -0
  101. mcp_ticketer-2.2.13.dist-info/top_level.txt +2 -0
  102. py_mcp_installer/examples/phase3_demo.py +178 -0
  103. py_mcp_installer/scripts/manage_version.py +54 -0
  104. py_mcp_installer/setup.py +6 -0
  105. py_mcp_installer/src/py_mcp_installer/__init__.py +153 -0
  106. py_mcp_installer/src/py_mcp_installer/command_builder.py +445 -0
  107. py_mcp_installer/src/py_mcp_installer/config_manager.py +541 -0
  108. py_mcp_installer/src/py_mcp_installer/exceptions.py +243 -0
  109. py_mcp_installer/src/py_mcp_installer/installation_strategy.py +617 -0
  110. py_mcp_installer/src/py_mcp_installer/installer.py +656 -0
  111. py_mcp_installer/src/py_mcp_installer/mcp_inspector.py +750 -0
  112. py_mcp_installer/src/py_mcp_installer/platform_detector.py +451 -0
  113. py_mcp_installer/src/py_mcp_installer/platforms/__init__.py +26 -0
  114. py_mcp_installer/src/py_mcp_installer/platforms/claude_code.py +225 -0
  115. py_mcp_installer/src/py_mcp_installer/platforms/codex.py +181 -0
  116. py_mcp_installer/src/py_mcp_installer/platforms/cursor.py +191 -0
  117. py_mcp_installer/src/py_mcp_installer/types.py +222 -0
  118. py_mcp_installer/src/py_mcp_installer/utils.py +463 -0
  119. py_mcp_installer/tests/__init__.py +0 -0
  120. py_mcp_installer/tests/platforms/__init__.py +0 -0
  121. py_mcp_installer/tests/test_platform_detector.py +17 -0
  122. mcp_ticketer/adapters/github.py +0 -1574
  123. mcp_ticketer/adapters/jira.py +0 -1258
  124. mcp_ticketer-0.12.0.dist-info/METADATA +0 -550
  125. mcp_ticketer-0.12.0.dist-info/RECORD +0 -91
  126. mcp_ticketer-0.12.0.dist-info/top_level.txt +0 -1
  127. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.2.13.dist-info}/WHEEL +0 -0
  128. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.2.13.dist-info}/entry_points.txt +0 -0
  129. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.2.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,181 @@
1
+ """Codex platform implementation.
2
+
3
+ This module provides platform-specific logic for Codex, including
4
+ configuration paths, installation strategies, and validation.
5
+
6
+ Codex supports:
7
+ - Global config only: ~/.codex/config.toml
8
+ - TOML format (not JSON)
9
+ - TOML manipulation strategy
10
+ """
11
+
12
+ from pathlib import Path
13
+
14
+ from ..command_builder import CommandBuilder
15
+ from ..installation_strategy import (
16
+ InstallationStrategy,
17
+ TOMLManipulationStrategy,
18
+ )
19
+ from ..types import InstallMethod, MCPServerConfig, Platform, Scope
20
+ from ..utils import resolve_command_path
21
+
22
+
23
+ class CodexStrategy:
24
+ """Codex platform implementation.
25
+
26
+ Provides configuration paths and installation strategies for Codex.
27
+
28
+ Note: Codex uses TOML format instead of JSON, and only supports
29
+ global-level configuration.
30
+
31
+ Example:
32
+ >>> strategy = CodexStrategy()
33
+ >>> config_path = strategy.get_config_path(Scope.GLOBAL)
34
+ >>> installer = strategy.get_strategy(Scope.GLOBAL)
35
+ >>> result = installer.install(server, Scope.GLOBAL)
36
+ """
37
+
38
+ def __init__(self) -> None:
39
+ """Initialize Codex strategy."""
40
+ self.platform = Platform.CODEX
41
+ self.config_format = "toml"
42
+
43
+ def get_config_path(self, scope: Scope) -> Path:
44
+ """Get configuration path for scope.
45
+
46
+ Codex only supports global configuration.
47
+
48
+ Args:
49
+ scope: Installation scope (only GLOBAL supported)
50
+
51
+ Returns:
52
+ Path to TOML configuration file
53
+
54
+ Example:
55
+ >>> strategy = CodexStrategy()
56
+ >>> path = strategy.get_config_path(Scope.GLOBAL)
57
+ >>> print(path)
58
+ /home/user/.codex/config.toml
59
+ """
60
+ # Codex only has global config
61
+ return Path.home() / ".codex" / "config.toml"
62
+
63
+ def get_strategy(self, scope: Scope) -> InstallationStrategy:
64
+ """Get appropriate installation strategy for scope.
65
+
66
+ Codex only supports TOML manipulation.
67
+
68
+ Args:
69
+ scope: Installation scope
70
+
71
+ Returns:
72
+ TOML manipulation strategy
73
+
74
+ Example:
75
+ >>> strategy = CodexStrategy()
76
+ >>> installer = strategy.get_strategy(Scope.GLOBAL)
77
+ >>> result = installer.install(server, Scope.GLOBAL)
78
+ """
79
+ config_path = self.get_config_path(scope)
80
+ return TOMLManipulationStrategy(self.platform, config_path)
81
+
82
+ def validate_installation(self) -> bool:
83
+ """Validate Codex is available.
84
+
85
+ Checks for config directory or codex CLI.
86
+
87
+ Returns:
88
+ True if Codex appears to be installed
89
+
90
+ Example:
91
+ >>> strategy = CodexStrategy()
92
+ >>> if strategy.validate_installation():
93
+ ... print("Codex is available")
94
+ """
95
+ # Check for config directory
96
+ codex_dir = Path.home() / ".codex"
97
+ has_config_dir = codex_dir.exists() and codex_dir.is_dir()
98
+
99
+ # Check for codex CLI
100
+ has_cli = resolve_command_path("codex") is not None
101
+
102
+ return has_config_dir or has_cli
103
+
104
+ def build_server_config(
105
+ self,
106
+ package: str,
107
+ install_method: InstallMethod | None = None,
108
+ env: dict[str, str] | None = None,
109
+ description: str = "",
110
+ ) -> MCPServerConfig:
111
+ """Build server configuration for Codex.
112
+
113
+ Uses CommandBuilder to auto-detect best installation method.
114
+
115
+ Note: Codex uses TOML format with snake_case keys.
116
+
117
+ Args:
118
+ package: Package name (e.g., "mcp-ticketer")
119
+ install_method: Installation method (auto-detected if None)
120
+ env: Environment variables
121
+ description: Server description
122
+
123
+ Returns:
124
+ Complete server configuration
125
+
126
+ Example:
127
+ >>> strategy = CodexStrategy()
128
+ >>> config = strategy.build_server_config(
129
+ ... "mcp-ticketer",
130
+ ... env={"LINEAR_API_KEY": "..."}
131
+ ... )
132
+ >>> print(f"{config.command} {' '.join(config.args)}")
133
+ uv run mcp-ticketer mcp
134
+ """
135
+ builder = CommandBuilder(self.platform)
136
+ return builder.to_server_config(
137
+ package=package,
138
+ install_method=install_method,
139
+ env=env,
140
+ description=description,
141
+ )
142
+
143
+ def get_platform_info(self) -> dict[str, str]:
144
+ """Get platform information.
145
+
146
+ Returns:
147
+ Dict with platform details
148
+
149
+ Example:
150
+ >>> strategy = CodexStrategy()
151
+ >>> info = strategy.get_platform_info()
152
+ >>> print(info["name"])
153
+ Codex
154
+ """
155
+ return {
156
+ "name": "Codex",
157
+ "platform": self.platform.value,
158
+ "config_format": "toml",
159
+ "scope_support": "global_only",
160
+ "cli_available": str(resolve_command_path("codex") is not None),
161
+ "config_key": "mcp_servers", # TOML uses snake_case
162
+ }
163
+
164
+ def get_toml_specific_notes(self) -> dict[str, str]:
165
+ """Get TOML-specific configuration notes.
166
+
167
+ Returns:
168
+ Dict with TOML-specific guidance
169
+
170
+ Example:
171
+ >>> strategy = CodexStrategy()
172
+ >>> notes = strategy.get_toml_specific_notes()
173
+ >>> print(notes["key_format"])
174
+ snake_case
175
+ """
176
+ return {
177
+ "key_format": "snake_case",
178
+ "section_name": "mcp_servers",
179
+ "env_handling": "May require special quoting for environment variables",
180
+ "config_location": str(Path.home() / ".codex" / "config.toml"),
181
+ }
@@ -0,0 +1,191 @@
1
+ """Cursor platform implementation.
2
+
3
+ This module provides platform-specific logic for Cursor, including
4
+ configuration paths, installation strategies, and validation.
5
+
6
+ Cursor supports:
7
+ - Project-level config: .cursor/mcp.json
8
+ - Global config: ~/.cursor/mcp.json
9
+ - JSON manipulation only (no native CLI for MCP)
10
+ """
11
+
12
+ from pathlib import Path
13
+
14
+ from ..command_builder import CommandBuilder
15
+ from ..installation_strategy import (
16
+ InstallationStrategy,
17
+ JSONManipulationStrategy,
18
+ )
19
+ from ..types import InstallMethod, MCPServerConfig, Platform, Scope
20
+ from ..utils import resolve_command_path
21
+
22
+
23
+ class CursorStrategy:
24
+ """Cursor platform implementation.
25
+
26
+ Provides configuration paths and installation strategies for Cursor.
27
+
28
+ Note: Cursor does not have a native CLI for MCP configuration,
29
+ so only JSON manipulation strategy is available.
30
+
31
+ Example:
32
+ >>> strategy = CursorStrategy()
33
+ >>> config_path = strategy.get_config_path(Scope.PROJECT)
34
+ >>> installer = strategy.get_strategy(Scope.PROJECT)
35
+ >>> result = installer.install(server, Scope.PROJECT)
36
+ """
37
+
38
+ def __init__(self) -> None:
39
+ """Initialize Cursor strategy."""
40
+ self.platform = Platform.CURSOR
41
+ self.config_format = "json"
42
+
43
+ def get_config_path(self, scope: Scope) -> Path:
44
+ """Get configuration path for scope.
45
+
46
+ Cursor config locations:
47
+ - Project: .cursor/mcp.json (if exists)
48
+ - Global: ~/.cursor/mcp.json
49
+
50
+ Args:
51
+ scope: Installation scope (PROJECT or GLOBAL)
52
+
53
+ Returns:
54
+ Path to configuration file
55
+
56
+ Example:
57
+ >>> strategy = CursorStrategy()
58
+ >>> path = strategy.get_config_path(Scope.GLOBAL)
59
+ >>> print(path)
60
+ /home/user/.cursor/mcp.json
61
+ """
62
+ if scope == Scope.PROJECT:
63
+ # Check for project-level config
64
+ project_config = Path(".cursor") / "mcp.json"
65
+ if project_config.exists():
66
+ return project_config
67
+
68
+ # Default to global if project config doesn't exist
69
+ return Path.home() / ".cursor" / "mcp.json"
70
+
71
+ else: # Scope.GLOBAL
72
+ return Path.home() / ".cursor" / "mcp.json"
73
+
74
+ def get_strategy(self, scope: Scope) -> InstallationStrategy:
75
+ """Get appropriate installation strategy for scope.
76
+
77
+ Cursor only supports JSON manipulation (no native CLI).
78
+
79
+ Args:
80
+ scope: Installation scope
81
+
82
+ Returns:
83
+ JSON manipulation strategy
84
+
85
+ Example:
86
+ >>> strategy = CursorStrategy()
87
+ >>> installer = strategy.get_strategy(Scope.GLOBAL)
88
+ >>> result = installer.install(server, Scope.GLOBAL)
89
+ """
90
+ config_path = self.get_config_path(scope)
91
+ return JSONManipulationStrategy(self.platform, config_path)
92
+
93
+ def validate_installation(self) -> bool:
94
+ """Validate Cursor is available.
95
+
96
+ Checks for config directory or cursor CLI.
97
+
98
+ Returns:
99
+ True if Cursor appears to be installed
100
+
101
+ Example:
102
+ >>> strategy = CursorStrategy()
103
+ >>> if strategy.validate_installation():
104
+ ... print("Cursor is available")
105
+ """
106
+ # Check for config directory
107
+ cursor_dir = Path.home() / ".cursor"
108
+ has_config_dir = cursor_dir.exists() and cursor_dir.is_dir()
109
+
110
+ # Check for cursor CLI
111
+ has_cli = resolve_command_path("cursor") is not None
112
+
113
+ return has_config_dir or has_cli
114
+
115
+ def build_server_config(
116
+ self,
117
+ package: str,
118
+ install_method: InstallMethod | None = None,
119
+ env: dict[str, str] | None = None,
120
+ description: str = "",
121
+ ) -> MCPServerConfig:
122
+ """Build server configuration for Cursor.
123
+
124
+ Uses CommandBuilder to auto-detect best installation method.
125
+
126
+ Note: Cursor may require absolute paths for better reliability.
127
+
128
+ Args:
129
+ package: Package name (e.g., "mcp-ticketer")
130
+ install_method: Installation method (auto-detected if None)
131
+ env: Environment variables
132
+ description: Server description
133
+
134
+ Returns:
135
+ Complete server configuration
136
+
137
+ Example:
138
+ >>> strategy = CursorStrategy()
139
+ >>> config = strategy.build_server_config(
140
+ ... "mcp-ticketer",
141
+ ... env={"LINEAR_API_KEY": "..."}
142
+ ... )
143
+ >>> print(f"{config.command} {' '.join(config.args)}")
144
+ uv run mcp-ticketer mcp
145
+ """
146
+ builder = CommandBuilder(self.platform)
147
+ return builder.to_server_config(
148
+ package=package,
149
+ install_method=install_method,
150
+ env=env,
151
+ description=description,
152
+ )
153
+
154
+ def get_platform_info(self) -> dict[str, str]:
155
+ """Get platform information.
156
+
157
+ Returns:
158
+ Dict with platform details
159
+
160
+ Example:
161
+ >>> strategy = CursorStrategy()
162
+ >>> info = strategy.get_platform_info()
163
+ >>> print(info["name"])
164
+ Cursor
165
+ """
166
+ return {
167
+ "name": "Cursor",
168
+ "platform": self.platform.value,
169
+ "config_format": "json",
170
+ "scope_support": "both",
171
+ "cli_available": "false", # No MCP CLI support
172
+ "config_key": "mcp_servers", # Cursor uses snake_case
173
+ }
174
+
175
+ def get_recommended_config(self) -> dict[str, str]:
176
+ """Get Cursor-specific configuration recommendations.
177
+
178
+ Returns:
179
+ Dict with recommended settings
180
+
181
+ Example:
182
+ >>> strategy = CursorStrategy()
183
+ >>> recs = strategy.get_recommended_config()
184
+ >>> print(recs["path_style"])
185
+ absolute
186
+ """
187
+ return {
188
+ "path_style": "absolute", # Cursor prefers absolute paths
189
+ "restart_required": "yes", # Must restart Cursor after config changes
190
+ "config_location": str(Path.home() / ".cursor" / "mcp.json"),
191
+ }
@@ -0,0 +1,222 @@
1
+ """Type definitions for py-mcp-installer-service.
2
+
3
+ This module provides comprehensive type definitions for the entire library,
4
+ including enums, dataclasses, and protocols for platform detection and
5
+ installation strategies.
6
+
7
+ Design Philosophy:
8
+ - Use Python 3.10+ syntax (list[str], dict[str, Any], Path | None)
9
+ - 100% type coverage for mypy --strict
10
+ - Immutable dataclasses where possible (frozen=True)
11
+ - Clear separation between public API and internal types
12
+ """
13
+
14
+ from dataclasses import dataclass, field
15
+ from enum import Enum
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ # ============================================================================
20
+ # Core Enums
21
+ # ============================================================================
22
+
23
+
24
+ class Platform(str, Enum):
25
+ """Supported AI coding tool platforms.
26
+
27
+ Each platform has its own configuration format and installation method.
28
+ """
29
+
30
+ CLAUDE_CODE = "claude_code"
31
+ CLAUDE_DESKTOP = "claude_desktop"
32
+ CURSOR = "cursor"
33
+ AUGGIE = "auggie"
34
+ CODEX = "codex"
35
+ GEMINI_CLI = "gemini_cli"
36
+ WINDSURF = "windsurf"
37
+ ANTIGRAVITY = "antigravity"
38
+ UNKNOWN = "unknown"
39
+
40
+
41
+ class InstallMethod(str, Enum):
42
+ """Installation methods for MCP servers.
43
+
44
+ Priority order (fastest to slowest):
45
+ 1. UV_RUN: uv run mcp-ticketer mcp (recommended, fastest)
46
+ 2. PIPX: mcp-ticketer (installed via pipx)
47
+ 3. DIRECT: Direct binary in PATH
48
+ 4. PYTHON_MODULE: python -m mcp_ticketer.mcp.server (fallback)
49
+ """
50
+
51
+ UV_RUN = "uv_run"
52
+ PIPX = "pipx"
53
+ DIRECT = "direct"
54
+ PYTHON_MODULE = "python_module"
55
+
56
+
57
+ class Scope(str, Enum):
58
+ """Configuration scope for MCP server installation.
59
+
60
+ - PROJECT: Project-level configuration (.claude.json, .cursor/mcp.json)
61
+ - GLOBAL: User-level configuration (~/.config/claude/mcp.json)
62
+ - BOTH: Platform supports both scopes
63
+ """
64
+
65
+ PROJECT = "project"
66
+ GLOBAL = "global"
67
+ BOTH = "both"
68
+
69
+
70
+ class ConfigFormat(str, Enum):
71
+ """Configuration file formats supported by platforms.
72
+
73
+ - JSON: Most platforms (Claude, Cursor, Auggie, Windsurf, Gemini)
74
+ - TOML: Codex uses TOML format
75
+ """
76
+
77
+ JSON = "json"
78
+ TOML = "toml"
79
+
80
+
81
+ class InstallationStrategy(str, Enum):
82
+ """Installation strategies for different platforms.
83
+
84
+ - NATIVE_CLI: Use platform's native CLI (claude mcp add)
85
+ - JSON_MANIPULATION: Direct JSON config file modification
86
+ - TOML_MANIPULATION: Direct TOML config file modification
87
+ """
88
+
89
+ NATIVE_CLI = "native_cli"
90
+ JSON_MANIPULATION = "json_manipulation"
91
+ TOML_MANIPULATION = "toml_manipulation"
92
+
93
+
94
+ # ============================================================================
95
+ # Dataclasses
96
+ # ============================================================================
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class MCPServerConfig:
101
+ """MCP server configuration for installation.
102
+
103
+ This represents the complete configuration needed to install an MCP server
104
+ on any supported platform.
105
+
106
+ Attributes:
107
+ name: Unique server identifier (e.g., "mcp-ticketer")
108
+ command: Executable command (e.g., "uv", "/usr/bin/mcp-ticketer")
109
+ args: Command arguments (e.g., ["run", "mcp-ticketer", "mcp"])
110
+ env: Environment variables (e.g., {"LINEAR_API_KEY": "..."})
111
+ description: Human-readable server description
112
+
113
+ Example:
114
+ >>> config = MCPServerConfig(
115
+ ... name="mcp-ticketer",
116
+ ... command="uv",
117
+ ... args=["run", "mcp-ticketer", "mcp"],
118
+ ... env={"LINEAR_API_KEY": "lin_api_..."}
119
+ ... )
120
+ """
121
+
122
+ name: str
123
+ command: str
124
+ args: list[str] = field(default_factory=list)
125
+ env: dict[str, str] = field(default_factory=dict)
126
+ description: str = ""
127
+
128
+
129
+ @dataclass(frozen=True)
130
+ class PlatformInfo:
131
+ """Information about a detected platform.
132
+
133
+ Contains all information needed to work with a detected AI coding tool
134
+ platform, including confidence scoring for multi-platform environments.
135
+
136
+ Attributes:
137
+ platform: Detected platform enum
138
+ confidence: Detection confidence (0.0-1.0)
139
+ - 1.0: Config exists, valid, CLI available
140
+ - 0.8: Config exists, valid, no CLI needed
141
+ - 0.6: Config exists but invalid, CLI available
142
+ - 0.4: Config exists but invalid, no CLI
143
+ - 0.0: Platform not detected
144
+ config_path: Path to platform's config file (None if not found)
145
+ cli_available: Whether platform CLI is available in PATH
146
+ scope_support: Which configuration scopes the platform supports
147
+
148
+ Example:
149
+ >>> info = PlatformInfo(
150
+ ... platform=Platform.CLAUDE_CODE,
151
+ ... confidence=1.0,
152
+ ... config_path=Path.home() / ".config/claude/mcp.json",
153
+ ... cli_available=True,
154
+ ... scope_support=Scope.BOTH
155
+ ... )
156
+ """
157
+
158
+ platform: Platform
159
+ confidence: float # 0.0-1.0
160
+ config_path: Path | None = None
161
+ cli_available: bool = False
162
+ scope_support: Scope = Scope.BOTH
163
+
164
+
165
+ @dataclass(frozen=True)
166
+ class InstallationResult:
167
+ """Result of an MCP server installation operation.
168
+
169
+ Provides comprehensive information about installation success/failure,
170
+ including error details and recovery suggestions.
171
+
172
+ Attributes:
173
+ success: Whether installation succeeded
174
+ platform: Target platform
175
+ server_name: Name of installed server
176
+ method: Installation method used
177
+ message: Human-readable status message
178
+ config_path: Path to updated config file (None on failure)
179
+ error: Exception that caused failure (None on success)
180
+
181
+ Example (success):
182
+ >>> result = InstallationResult(
183
+ ... success=True,
184
+ ... platform=Platform.CLAUDE_CODE,
185
+ ... server_name="mcp-ticketer",
186
+ ... method=InstallMethod.UV_RUN,
187
+ ... message="Successfully installed mcp-ticketer",
188
+ ... config_path=Path.home() / ".config/claude/mcp.json"
189
+ ... )
190
+
191
+ Example (failure):
192
+ >>> result = InstallationResult(
193
+ ... success=False,
194
+ ... platform=Platform.CLAUDE_CODE,
195
+ ... server_name="mcp-ticketer",
196
+ ... method=InstallMethod.UV_RUN,
197
+ ... message="Installation failed: config file not writable",
198
+ ... error=PermissionError("Permission denied")
199
+ ... )
200
+ """
201
+
202
+ success: bool
203
+ platform: Platform
204
+ server_name: str
205
+ method: InstallMethod
206
+ message: str
207
+ config_path: Path | None = None
208
+ error: Exception | None = None
209
+
210
+
211
+ # ============================================================================
212
+ # Type Aliases
213
+ # ============================================================================
214
+
215
+ # JSON-serializable dictionary type
216
+ JsonDict = dict[str, Any]
217
+
218
+ # Environment variables dictionary
219
+ EnvDict = dict[str, str]
220
+
221
+ # Command arguments list
222
+ ArgsList = list[str]