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.
- mcp_ticketer/__init__.py +10 -10
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/_version_scm.py +1 -0
- mcp_ticketer/adapters/aitrackdown.py +507 -6
- mcp_ticketer/adapters/asana/adapter.py +229 -0
- mcp_ticketer/adapters/asana/mappers.py +14 -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 +47 -5
- 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/adapter.py +2730 -139
- mcp_ticketer/adapters/linear/client.py +175 -3
- mcp_ticketer/adapters/linear/mappers.py +203 -8
- mcp_ticketer/adapters/linear/queries.py +280 -3
- mcp_ticketer/adapters/linear/types.py +120 -4
- 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/cli/adapter_diagnostics.py +3 -1
- mcp_ticketer/cli/auggie_configure.py +17 -5
- mcp_ticketer/cli/codex_configure.py +97 -61
- mcp_ticketer/cli/configure.py +1288 -105
- mcp_ticketer/cli/cursor_configure.py +314 -0
- mcp_ticketer/cli/diagnostics.py +13 -12
- mcp_ticketer/cli/discover.py +5 -0
- mcp_ticketer/cli/gemini_configure.py +17 -5
- mcp_ticketer/cli/init_command.py +880 -0
- mcp_ticketer/cli/install_mcp_server.py +418 -0
- mcp_ticketer/cli/instruction_commands.py +6 -0
- mcp_ticketer/cli/main.py +267 -3175
- mcp_ticketer/cli/mcp_configure.py +821 -119
- mcp_ticketer/cli/mcp_server_commands.py +415 -0
- mcp_ticketer/cli/platform_detection.py +77 -12
- mcp_ticketer/cli/platform_installer.py +545 -0
- mcp_ticketer/cli/project_update_commands.py +350 -0
- mcp_ticketer/cli/setup_command.py +795 -0
- mcp_ticketer/cli/simple_health.py +12 -10
- mcp_ticketer/cli/ticket_commands.py +705 -103
- mcp_ticketer/cli/utils.py +113 -0
- mcp_ticketer/core/__init__.py +56 -6
- mcp_ticketer/core/adapter.py +533 -2
- mcp_ticketer/core/config.py +21 -21
- mcp_ticketer/core/exceptions.py +7 -1
- mcp_ticketer/core/label_manager.py +732 -0
- mcp_ticketer/core/mappers.py +31 -19
- mcp_ticketer/core/milestone_manager.py +252 -0
- mcp_ticketer/core/models.py +480 -0
- mcp_ticketer/core/onepassword_secrets.py +1 -1
- mcp_ticketer/core/priority_matcher.py +463 -0
- mcp_ticketer/core/project_config.py +132 -14
- mcp_ticketer/core/project_utils.py +281 -0
- mcp_ticketer/core/project_validator.py +376 -0
- mcp_ticketer/core/session_state.py +176 -0
- mcp_ticketer/core/state_matcher.py +625 -0
- mcp_ticketer/core/url_parser.py +425 -0
- mcp_ticketer/core/validators.py +69 -0
- mcp_ticketer/mcp/server/__main__.py +2 -1
- mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
- mcp_ticketer/mcp/server/main.py +106 -25
- mcp_ticketer/mcp/server/routing.py +723 -0
- mcp_ticketer/mcp/server/server_sdk.py +58 -0
- mcp_ticketer/mcp/server/tools/__init__.py +33 -11
- mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +5 -5
- mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
- mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
- mcp_ticketer/mcp/server/tools/config_tools.py +1391 -145
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +870 -460
- mcp_ticketer/mcp/server/tools/instruction_tools.py +7 -5
- 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 +3 -7
- 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 +209 -97
- mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1107 -124
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +218 -236
- mcp_ticketer/queue/queue.py +68 -0
- mcp_ticketer/queue/worker.py +1 -1
- mcp_ticketer/utils/__init__.py +5 -0
- mcp_ticketer/utils/token_utils.py +246 -0
- mcp_ticketer-2.2.13.dist-info/METADATA +1396 -0
- mcp_ticketer-2.2.13.dist-info/RECORD +158 -0
- mcp_ticketer-2.2.13.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 -1574
- mcp_ticketer/adapters/jira.py +0 -1258
- mcp_ticketer-0.12.0.dist-info/METADATA +0 -550
- mcp_ticketer-0.12.0.dist-info/RECORD +0 -91
- mcp_ticketer-0.12.0.dist-info/top_level.txt +0 -1
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.2.13.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.2.13.dist-info}/entry_points.txt +0 -0
- {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]
|