mcp-ticketer 0.12.0__py3-none-any.whl → 2.0.1__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 (87) hide show
  1. mcp_ticketer/__init__.py +10 -10
  2. mcp_ticketer/__version__.py +1 -1
  3. mcp_ticketer/adapters/aitrackdown.py +385 -6
  4. mcp_ticketer/adapters/asana/adapter.py +108 -0
  5. mcp_ticketer/adapters/asana/mappers.py +14 -0
  6. mcp_ticketer/adapters/github.py +525 -11
  7. mcp_ticketer/adapters/hybrid.py +47 -5
  8. mcp_ticketer/adapters/jira.py +521 -0
  9. mcp_ticketer/adapters/linear/adapter.py +1784 -101
  10. mcp_ticketer/adapters/linear/client.py +85 -3
  11. mcp_ticketer/adapters/linear/mappers.py +96 -8
  12. mcp_ticketer/adapters/linear/queries.py +168 -1
  13. mcp_ticketer/adapters/linear/types.py +80 -4
  14. mcp_ticketer/analysis/__init__.py +56 -0
  15. mcp_ticketer/analysis/dependency_graph.py +255 -0
  16. mcp_ticketer/analysis/health_assessment.py +304 -0
  17. mcp_ticketer/analysis/orphaned.py +218 -0
  18. mcp_ticketer/analysis/project_status.py +594 -0
  19. mcp_ticketer/analysis/similarity.py +224 -0
  20. mcp_ticketer/analysis/staleness.py +266 -0
  21. mcp_ticketer/automation/__init__.py +11 -0
  22. mcp_ticketer/automation/project_updates.py +378 -0
  23. mcp_ticketer/cli/adapter_diagnostics.py +3 -1
  24. mcp_ticketer/cli/auggie_configure.py +17 -5
  25. mcp_ticketer/cli/codex_configure.py +97 -61
  26. mcp_ticketer/cli/configure.py +851 -103
  27. mcp_ticketer/cli/cursor_configure.py +314 -0
  28. mcp_ticketer/cli/diagnostics.py +13 -12
  29. mcp_ticketer/cli/discover.py +5 -0
  30. mcp_ticketer/cli/gemini_configure.py +17 -5
  31. mcp_ticketer/cli/init_command.py +880 -0
  32. mcp_ticketer/cli/instruction_commands.py +6 -0
  33. mcp_ticketer/cli/main.py +233 -3151
  34. mcp_ticketer/cli/mcp_configure.py +672 -98
  35. mcp_ticketer/cli/mcp_server_commands.py +415 -0
  36. mcp_ticketer/cli/platform_detection.py +77 -12
  37. mcp_ticketer/cli/platform_installer.py +536 -0
  38. mcp_ticketer/cli/project_update_commands.py +350 -0
  39. mcp_ticketer/cli/setup_command.py +639 -0
  40. mcp_ticketer/cli/simple_health.py +12 -10
  41. mcp_ticketer/cli/ticket_commands.py +264 -24
  42. mcp_ticketer/core/__init__.py +28 -6
  43. mcp_ticketer/core/adapter.py +166 -1
  44. mcp_ticketer/core/config.py +21 -21
  45. mcp_ticketer/core/exceptions.py +7 -1
  46. mcp_ticketer/core/label_manager.py +732 -0
  47. mcp_ticketer/core/mappers.py +31 -19
  48. mcp_ticketer/core/models.py +135 -0
  49. mcp_ticketer/core/onepassword_secrets.py +1 -1
  50. mcp_ticketer/core/priority_matcher.py +463 -0
  51. mcp_ticketer/core/project_config.py +132 -14
  52. mcp_ticketer/core/session_state.py +171 -0
  53. mcp_ticketer/core/state_matcher.py +592 -0
  54. mcp_ticketer/core/url_parser.py +425 -0
  55. mcp_ticketer/core/validators.py +69 -0
  56. mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
  57. mcp_ticketer/mcp/server/main.py +106 -25
  58. mcp_ticketer/mcp/server/routing.py +655 -0
  59. mcp_ticketer/mcp/server/server_sdk.py +58 -0
  60. mcp_ticketer/mcp/server/tools/__init__.py +31 -12
  61. mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
  62. mcp_ticketer/mcp/server/tools/attachment_tools.py +6 -8
  63. mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
  64. mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
  65. mcp_ticketer/mcp/server/tools/config_tools.py +1184 -136
  66. mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
  67. mcp_ticketer/mcp/server/tools/hierarchy_tools.py +870 -460
  68. mcp_ticketer/mcp/server/tools/instruction_tools.py +7 -5
  69. mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
  70. mcp_ticketer/mcp/server/tools/pr_tools.py +3 -7
  71. mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
  72. mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
  73. mcp_ticketer/mcp/server/tools/search_tools.py +180 -97
  74. mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
  75. mcp_ticketer/mcp/server/tools/ticket_tools.py +1070 -123
  76. mcp_ticketer/mcp/server/tools/user_ticket_tools.py +218 -236
  77. mcp_ticketer/queue/worker.py +1 -1
  78. mcp_ticketer/utils/__init__.py +5 -0
  79. mcp_ticketer/utils/token_utils.py +246 -0
  80. mcp_ticketer-2.0.1.dist-info/METADATA +1366 -0
  81. mcp_ticketer-2.0.1.dist-info/RECORD +122 -0
  82. mcp_ticketer-0.12.0.dist-info/METADATA +0 -550
  83. mcp_ticketer-0.12.0.dist-info/RECORD +0 -91
  84. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/WHEEL +0 -0
  85. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/entry_points.txt +0 -0
  86. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/licenses/LICENSE +0 -0
  87. {mcp_ticketer-0.12.0.dist-info → mcp_ticketer-2.0.1.dist-info}/top_level.txt +0 -0
@@ -24,6 +24,7 @@ def find_codex_config() -> Path:
24
24
  No project-level or user-scoped configuration is available.
25
25
 
26
26
  Returns:
27
+ -------
27
28
  Path to Codex global config file at ~/.codex/config.toml
28
29
 
29
30
  """
@@ -36,9 +37,11 @@ def load_codex_config(config_path: Path) -> dict[str, Any]:
36
37
  """Load existing Codex configuration or return empty structure.
37
38
 
38
39
  Args:
40
+ ----
39
41
  config_path: Path to Codex config.toml file
40
42
 
41
43
  Returns:
44
+ -------
42
45
  Codex configuration dict with mcp_servers section
43
46
 
44
47
  """
@@ -61,6 +64,7 @@ def save_codex_config(config_path: Path, config: dict[str, Any]) -> None:
61
64
  """Save Codex configuration to TOML file.
62
65
 
63
66
  Args:
67
+ ----
64
68
  config_path: Path to Codex config.toml file
65
69
  config: Configuration to save
66
70
 
@@ -78,76 +82,39 @@ def create_codex_server_config(
78
82
  ) -> dict[str, Any]:
79
83
  """Create Codex MCP server configuration for mcp-ticketer.
80
84
 
85
+ Uses the CLI command (mcp-ticketer mcp) which implements proper
86
+ Content-Length framing via FastMCP SDK, required for modern MCP clients.
87
+
81
88
  Args:
89
+ ----
82
90
  python_path: Path to Python executable in mcp-ticketer venv
83
91
  project_config: Project configuration from .mcp-ticketer/config.json
84
- project_path: Project directory path (optional, not used for global config)
92
+ project_path: Project directory path (optional)
85
93
 
86
94
  Returns:
95
+ -------
87
96
  Codex MCP server configuration dict
88
97
 
89
98
  """
90
- # Use Python module invocation pattern (works regardless of where package is installed)
91
-
92
- # Get adapter configuration
93
- adapter = project_config.get("default_adapter", "aitrackdown")
94
- adapters_config = project_config.get("adapters", {})
95
- adapter_config = adapters_config.get(adapter, {})
99
+ # IMPORTANT: Use CLI command, NOT Python module invocation
100
+ # The CLI uses FastMCP SDK which implements proper Content-Length framing
101
+ # Legacy python -m mcp_ticketer.mcp.server uses line-delimited JSON (incompatible)
96
102
 
97
- # Build environment variables
98
- env_vars: dict[str, str] = {}
103
+ # Get mcp-ticketer CLI path from Python path
104
+ # If python_path is /path/to/venv/bin/python, CLI is /path/to/venv/bin/mcp-ticketer
105
+ python_dir = Path(python_path).parent
106
+ cli_path = str(python_dir / "mcp-ticketer")
99
107
 
100
- # Add PYTHONPATH for project context
108
+ # Build CLI arguments
109
+ args = ["mcp"]
101
110
  if project_path:
102
- env_vars["PYTHONPATH"] = project_path
103
-
104
- # Add adapter type
105
- env_vars["MCP_TICKETER_ADAPTER"] = adapter
106
-
107
- # Add adapter-specific environment variables
108
- if adapter == "aitrackdown":
109
- # Set base path for local adapter
110
- base_path = adapter_config.get("base_path", ".aitrackdown")
111
- if project_path:
112
- # Use absolute path if project_path is provided
113
- env_vars["MCP_TICKETER_BASE_PATH"] = str(Path(project_path) / base_path)
114
- else:
115
- env_vars["MCP_TICKETER_BASE_PATH"] = base_path
116
-
117
- elif adapter == "linear":
118
- if "api_key" in adapter_config:
119
- env_vars["LINEAR_API_KEY"] = adapter_config["api_key"]
120
- if "team_id" in adapter_config:
121
- env_vars["LINEAR_TEAM_ID"] = adapter_config["team_id"]
122
-
123
- elif adapter == "github":
124
- if "token" in adapter_config:
125
- env_vars["GITHUB_TOKEN"] = adapter_config["token"]
126
- if "owner" in adapter_config:
127
- env_vars["GITHUB_OWNER"] = adapter_config["owner"]
128
- if "repo" in adapter_config:
129
- env_vars["GITHUB_REPO"] = adapter_config["repo"]
130
-
131
- elif adapter == "jira":
132
- if "api_token" in adapter_config:
133
- env_vars["JIRA_API_TOKEN"] = adapter_config["api_token"]
134
- if "email" in adapter_config:
135
- env_vars["JIRA_EMAIL"] = adapter_config["email"]
136
- if "server" in adapter_config:
137
- env_vars["JIRA_SERVER"] = adapter_config["server"]
138
- if "project_key" in adapter_config:
139
- env_vars["JIRA_PROJECT_KEY"] = adapter_config["project_key"]
140
-
141
- # Use Python module invocation pattern
142
- args = ["-m", "mcp_ticketer.mcp.server"]
143
- if project_path:
144
- args.append(project_path)
111
+ args.extend(["--path", project_path])
145
112
 
146
113
  # Create server configuration with Codex-specific structure
114
+ # No environment variables needed - config loaded from .mcp-ticketer/config.json
147
115
  config: dict[str, Any] = {
148
- "command": python_path,
116
+ "command": cli_path,
149
117
  "args": args,
150
- "env": env_vars,
151
118
  }
152
119
 
153
120
  return config
@@ -157,10 +124,12 @@ def _test_configuration(adapter: str, project_config: dict) -> bool:
157
124
  """Test the configuration by validating adapter credentials.
158
125
 
159
126
  Args:
127
+ ----
160
128
  adapter: Adapter type (linear, github, jira, aitrackdown)
161
129
  project_config: Project configuration dict
162
130
 
163
131
  Returns:
132
+ -------
164
133
  True if validation passed, False otherwise
165
134
 
166
135
  """
@@ -222,6 +191,37 @@ def _test_configuration(adapter: str, project_config: dict) -> bool:
222
191
  return False
223
192
 
224
193
 
194
+ def detect_legacy_config(config_path: Path) -> tuple[bool, dict[str, Any] | None]:
195
+ """Detect if existing config uses legacy Python module invocation.
196
+
197
+ Args:
198
+ ----
199
+ config_path: Path to Codex config.toml file
200
+
201
+ Returns:
202
+ -------
203
+ Tuple of (is_legacy, server_config):
204
+ - is_legacy: True if config uses 'python -m mcp_ticketer.mcp.server'
205
+ - server_config: The legacy server config dict, or None if not legacy
206
+
207
+ """
208
+ if not config_path.exists():
209
+ return False, None
210
+
211
+ codex_config = load_codex_config(config_path)
212
+ mcp_servers = codex_config.get("mcp_servers", {})
213
+
214
+ if "mcp-ticketer" in mcp_servers:
215
+ server_config = mcp_servers["mcp-ticketer"]
216
+ args = server_config.get("args", [])
217
+
218
+ # Check for legacy pattern: ["-m", "mcp_ticketer.mcp.server", ...]
219
+ if len(args) >= 2 and args[0] == "-m" and "mcp_ticketer.mcp.server" in args[1]:
220
+ return True, server_config
221
+
222
+ return False, None
223
+
224
+
225
225
  def remove_codex_mcp(dry_run: bool = False) -> None:
226
226
  """Remove mcp-ticketer from Codex CLI configuration.
227
227
 
@@ -229,6 +229,7 @@ def remove_codex_mcp(dry_run: bool = False) -> None:
229
229
  This will remove mcp-ticketer from the global configuration.
230
230
 
231
231
  Args:
232
+ ----
232
233
  dry_run: Show what would be removed without making changes
233
234
 
234
235
  """
@@ -299,9 +300,11 @@ def configure_codex_mcp(force: bool = False) -> None:
299
300
  After configuration, you must restart Codex CLI for changes to take effect.
300
301
 
301
302
  Args:
303
+ ----
302
304
  force: Overwrite existing configuration
303
305
 
304
306
  Raises:
307
+ ------
305
308
  FileNotFoundError: If Python executable or project config not found
306
309
  ValueError: If configuration is invalid
307
310
 
@@ -338,6 +341,26 @@ def configure_codex_mcp(force: bool = False) -> None:
338
341
  codex_config_path = find_codex_config()
339
342
  console.print(f"[dim]Config location: {codex_config_path}[/dim]")
340
343
 
344
+ # Step 3.5: Check for legacy configuration (DETECTION & MIGRATION)
345
+ is_legacy, legacy_config = detect_legacy_config(codex_config_path)
346
+ if is_legacy:
347
+ console.print("\n[yellow]⚠ LEGACY CONFIGURATION DETECTED[/yellow]")
348
+ console.print(
349
+ "[yellow]Your current configuration uses the legacy line-delimited JSON server:[/yellow]"
350
+ )
351
+ console.print(f"[dim] Command: {legacy_config.get('command')}[/dim]")
352
+ console.print(f"[dim] Args: {legacy_config.get('args')}[/dim]")
353
+ console.print(
354
+ "\n[red]This legacy server is incompatible with modern MCP clients (Codex, Claude Desktop/Code).[/red]"
355
+ )
356
+ console.print(
357
+ "[red]The legacy server uses line-delimited JSON instead of Content-Length framing.[/red]"
358
+ )
359
+ console.print(
360
+ "\n[cyan]✨ Automatically migrating to modern FastMCP-based server...[/cyan]"
361
+ )
362
+ force = True # Auto-enable force mode for migration
363
+
341
364
  # Step 4: Load existing Codex configuration
342
365
  codex_config = load_codex_config(codex_config_path)
343
366
 
@@ -350,7 +373,9 @@ def configure_codex_mcp(force: bool = False) -> None:
350
373
  console.print("[dim]Use --force to overwrite existing configuration[/dim]")
351
374
  return
352
375
  else:
353
- console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
376
+ if not is_legacy:
377
+ console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
378
+ # If is_legacy, we already printed migration message above
354
379
 
355
380
  # Step 6: Create mcp-ticketer server config
356
381
  # For global config, include current working directory for context
@@ -378,13 +403,11 @@ def configure_codex_mcp(force: bool = False) -> None:
378
403
  console.print(" Server name: mcp-ticketer")
379
404
  console.print(f" Adapter: {adapter}")
380
405
  console.print(f" Python: {python_path}")
381
- console.print(" Command: python -m mcp_ticketer.mcp.server")
406
+ console.print(f" Command: {server_config.get('command')}")
407
+ console.print(f" Args: {server_config.get('args')}")
408
+ console.print(" Protocol: Content-Length framing (FastMCP SDK)")
382
409
  console.print(" Scope: global (Codex only supports global config)")
383
410
  console.print(f" Project path: {project_path}")
384
- if "env" in server_config:
385
- console.print(
386
- f" Environment variables: {list(server_config['env'].keys())}"
387
- )
388
411
 
389
412
  # Step 9: Test configuration
390
413
  console.print("\n[cyan]🧪 Testing configuration...[/cyan]")
@@ -396,6 +419,19 @@ def configure_codex_mcp(force: bool = False) -> None:
396
419
  "Please check your credentials and settings.[/yellow]"
397
420
  )
398
421
 
422
+ # Migration success message (if legacy config was detected)
423
+ if is_legacy:
424
+ console.print("\n[green]✅ Migration Complete![/green]")
425
+ console.print(
426
+ "[green]Your configuration has been upgraded from legacy line-delimited JSON[/green]"
427
+ )
428
+ console.print(
429
+ "[green]to modern Content-Length framing (FastMCP SDK).[/green]"
430
+ )
431
+ console.print(
432
+ "\n[cyan]This fixes MCP connection issues with Codex and other modern clients.[/cyan]"
433
+ )
434
+
399
435
  # Next steps
400
436
  console.print("\n[bold cyan]Next Steps:[/bold cyan]")
401
437
  console.print("1. [bold]Restart Codex CLI[/bold] (required for changes)")