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

@@ -1,6 +1,6 @@
1
1
  """Version information for mcp-ticketer package."""
2
2
 
3
- __version__ = "0.4.9"
3
+ __version__ = "0.4.10"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # Package metadata
@@ -107,28 +107,44 @@ def find_claude_mcp_config(global_config: bool = False) -> Path:
107
107
  Path.home() / ".config" / "Claude" / "claude_desktop_config.json"
108
108
  )
109
109
  else:
110
- # Project-level configuration for Claude Code
111
- config_path = Path.cwd() / ".claude" / "settings.local.json"
110
+ # Claude Code configuration (project-specific)
111
+ config_path = Path.home() / ".claude.json"
112
112
 
113
113
  return config_path
114
114
 
115
115
 
116
- def load_claude_mcp_config(config_path: Path) -> dict:
116
+ def load_claude_mcp_config(config_path: Path, is_claude_code: bool = False) -> dict:
117
117
  """Load existing Claude MCP configuration or return empty structure.
118
118
 
119
119
  Args:
120
120
  config_path: Path to MCP config file
121
+ is_claude_code: If True, return Claude Code structure with projects
121
122
 
122
123
  Returns:
123
124
  MCP configuration dict
124
125
 
125
126
  """
126
127
  if config_path.exists():
127
- with open(config_path) as f:
128
- return json.load(f)
128
+ try:
129
+ with open(config_path) as f:
130
+ content = f.read().strip()
131
+ if not content:
132
+ # Empty file, return default structure
133
+ return {"projects": {}} if is_claude_code else {"mcpServers": {}}
134
+ return json.loads(content)
135
+ except json.JSONDecodeError as e:
136
+ console.print(
137
+ f"[yellow]⚠ Warning: Invalid JSON in {config_path}, creating new config[/yellow]"
138
+ )
139
+ console.print(f"[dim]Error: {e}[/dim]")
140
+ # Return default structure on parse error
141
+ return {"projects": {}} if is_claude_code else {"mcpServers": {}}
129
142
 
130
- # Return empty structure (Claude Code uses mcpServers key)
131
- return {"mcpServers": {}}
143
+ # Return empty structure based on config type
144
+ if is_claude_code:
145
+ return {"projects": {}}
146
+ else:
147
+ return {"mcpServers": {}}
132
148
 
133
149
 
134
150
  def save_claude_mcp_config(config_path: Path, config: dict) -> None:
@@ -246,11 +262,14 @@ def remove_claude_mcp(global_config: bool = False, dry_run: bool = False) -> Non
246
262
 
247
263
  """
248
264
  # Step 1: Find Claude MCP config location
249
- config_type = "Claude Desktop" if global_config else "project-level"
265
+ config_type = "Claude Desktop" if global_config else "Claude Code"
250
266
  console.print(f"[cyan]🔍 Removing {config_type} MCP configuration...[/cyan]")
251
267
 
252
268
  mcp_config_path = find_claude_mcp_config(global_config)
253
- console.print(f"[dim]Config location: {mcp_config_path}[/dim]")
269
+ console.print(f"[dim]Primary config: {mcp_config_path}[/dim]")
270
+
271
+ # Get absolute project path for Claude Code
272
+ absolute_project_path = str(Path.cwd().resolve()) if not global_config else None
254
273
 
255
274
  # Step 2: Check if config file exists
256
275
  if not mcp_config_path.exists():
@@ -259,10 +278,22 @@ def remove_claude_mcp(global_config: bool = False, dry_run: bool = False) -> Non
259
278
  return
260
279
 
261
280
  # Step 3: Load existing MCP configuration
262
- mcp_config = load_claude_mcp_config(mcp_config_path)
281
+ is_claude_code = not global_config
282
+ mcp_config = load_claude_mcp_config(mcp_config_path, is_claude_code=is_claude_code)
263
283
 
264
284
  # Step 4: Check if mcp-ticketer is configured
265
- if "mcp-ticketer" not in mcp_config.get("mcpServers", {}):
285
+ is_configured = False
286
+ if is_claude_code:
287
+ # Check Claude Code structure: .projects[path].mcpServers["mcp-ticketer"]
288
+ if absolute_project_path:
289
+ projects = mcp_config.get("projects", {})
290
+ project_config_entry = projects.get(absolute_project_path, {})
291
+ is_configured = "mcp-ticketer" in project_config_entry.get("mcpServers", {})
292
+ else:
293
+ # Check Claude Desktop structure: .mcpServers["mcp-ticketer"]
294
+ is_configured = "mcp-ticketer" in mcp_config.get("mcpServers", {})
295
+
296
+ if not is_configured:
266
297
  console.print("[yellow]⚠ mcp-ticketer is not configured[/yellow]")
267
298
  console.print(f"[dim]No mcp-ticketer entry found in {mcp_config_path}[/dim]")
268
299
  return
@@ -272,10 +303,37 @@ def remove_claude_mcp(global_config: bool = False, dry_run: bool = False) -> Non
272
303
  console.print("\n[cyan]DRY RUN - Would remove:[/cyan]")
273
304
  console.print(" Server name: mcp-ticketer")
274
305
  console.print(f" From: {mcp_config_path}")
306
+ if absolute_project_path:
307
+ console.print(f" Project: {absolute_project_path}")
275
308
  return
276
309
 
277
310
  # Step 6: Remove mcp-ticketer from configuration
278
- del mcp_config["mcpServers"]["mcp-ticketer"]
311
+ if is_claude_code and absolute_project_path:
312
+ # Remove from Claude Code structure
313
+ del mcp_config["projects"][absolute_project_path]["mcpServers"]["mcp-ticketer"]
314
+
315
+ # Clean up empty structures
316
+ if not mcp_config["projects"][absolute_project_path]["mcpServers"]:
317
+ del mcp_config["projects"][absolute_project_path]["mcpServers"]
318
+ if not mcp_config["projects"][absolute_project_path]:
319
+ del mcp_config["projects"][absolute_project_path]
320
+
321
+ # Also remove from legacy location if it exists
322
+ legacy_config_path = Path.cwd() / ".claude" / "mcp.local.json"
323
+ if legacy_config_path.exists():
324
+ try:
325
+ legacy_config = load_claude_mcp_config(
326
+ legacy_config_path, is_claude_code=False
327
+ )
328
+ if "mcp-ticketer" in legacy_config.get("mcpServers", {}):
329
+ del legacy_config["mcpServers"]["mcp-ticketer"]
330
+ save_claude_mcp_config(legacy_config_path, legacy_config)
331
+ console.print("[dim]✓ Removed from legacy config as well[/dim]")
332
+ except Exception as e:
333
+ console.print(f"[dim]⚠ Could not remove from legacy config: {e}[/dim]")
334
+ else:
335
+ # Remove from Claude Desktop structure
336
+ del mcp_config["mcpServers"]["mcp-ticketer"]
279
337
 
280
338
  # Step 7: Save updated configuration
281
339
  try:
@@ -342,17 +400,34 @@ def configure_claude_mcp(global_config: bool = False, force: bool = False) -> No
342
400
  raise
343
401
 
344
402
  # Step 3: Find Claude MCP config location
345
- config_type = "Claude Desktop" if global_config else "project-level"
403
+ config_type = "Claude Desktop" if global_config else "Claude Code"
346
404
  console.print(f"\n[cyan]🔧 Configuring {config_type} MCP...[/cyan]")
347
405
 
348
406
  mcp_config_path = find_claude_mcp_config(global_config)
349
- console.print(f"[dim]Config location: {mcp_config_path}[/dim]")
407
+ console.print(f"[dim]Primary config: {mcp_config_path}[/dim]")
408
+
409
+ # Get absolute project path for Claude Code
410
+ absolute_project_path = str(Path.cwd().resolve()) if not global_config else None
350
411
 
351
412
  # Step 4: Load existing MCP configuration
352
- mcp_config = load_claude_mcp_config(mcp_config_path)
413
+ is_claude_code = not global_config
414
+ mcp_config = load_claude_mcp_config(mcp_config_path, is_claude_code=is_claude_code)
353
415
 
354
416
  # Step 5: Check if mcp-ticketer already configured
355
- if "mcp-ticketer" in mcp_config.get("mcpServers", {}):
417
+ already_configured = False
418
+ if is_claude_code:
419
+ # Check Claude Code structure: .projects[path].mcpServers["mcp-ticketer"]
420
+ if absolute_project_path:
421
+ projects = mcp_config.get("projects", {})
422
+ project_config_entry = projects.get(absolute_project_path, {})
423
+ already_configured = "mcp-ticketer" in project_config_entry.get(
424
+ "mcpServers", {}
425
+ )
426
+ else:
427
+ # Check Claude Desktop structure: .mcpServers["mcp-ticketer"]
428
+ already_configured = "mcp-ticketer" in mcp_config.get("mcpServers", {})
429
+
430
+ if already_configured:
356
431
  if not force:
357
432
  console.print("[yellow]⚠ mcp-ticketer is already configured[/yellow]")
358
433
  console.print("[dim]Use --force to overwrite existing configuration[/dim]")
@@ -361,18 +436,55 @@ def configure_claude_mcp(global_config: bool = False, force: bool = False) -> No
361
436
  console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
362
437
 
363
438
  # Step 6: Create mcp-ticketer server config
364
- project_path = str(Path.cwd()) if not global_config else None
365
439
  server_config = create_mcp_server_config(
366
440
  python_path=python_path,
367
441
  project_config=project_config,
368
- project_path=project_path,
442
+ project_path=absolute_project_path,
369
443
  )
370
444
 
371
- # Step 7: Update MCP configuration
372
- if "mcpServers" not in mcp_config:
373
- mcp_config["mcpServers"] = {}
374
-
375
- mcp_config["mcpServers"]["mcp-ticketer"] = server_config
445
+ # Step 7: Update MCP configuration based on platform
446
+ if is_claude_code:
447
+ # Claude Code: Write to ~/.claude.json with project-specific path
448
+ if absolute_project_path:
449
+ # Ensure projects structure exists
450
+ if "projects" not in mcp_config:
451
+ mcp_config["projects"] = {}
452
+
453
+ # Ensure project entry exists
454
+ if absolute_project_path not in mcp_config["projects"]:
455
+ mcp_config["projects"][absolute_project_path] = {}
456
+
457
+ # Ensure mcpServers for this project exists
458
+ if "mcpServers" not in mcp_config["projects"][absolute_project_path]:
459
+ mcp_config["projects"][absolute_project_path]["mcpServers"] = {}
460
+
461
+ # Add mcp-ticketer configuration
462
+ mcp_config["projects"][absolute_project_path]["mcpServers"][
463
+ "mcp-ticketer"
464
+ ] = server_config
465
+
466
+ # Also write to backward-compatible location for older Claude Code versions
467
+ legacy_config_path = Path.cwd() / ".claude" / "mcp.local.json"
468
+ console.print(f"[dim]Legacy config: {legacy_config_path}[/dim]")
469
+
470
+ try:
471
+ legacy_config = load_claude_mcp_config(
472
+ legacy_config_path, is_claude_code=False
473
+ )
474
+ if "mcpServers" not in legacy_config:
475
+ legacy_config["mcpServers"] = {}
476
+ legacy_config["mcpServers"]["mcp-ticketer"] = server_config
477
+ save_claude_mcp_config(legacy_config_path, legacy_config)
478
+ console.print("[dim]✓ Backward-compatible config also written[/dim]")
479
+ except Exception as e:
480
+ console.print(
481
+ f"[dim]⚠ Could not write legacy config (non-fatal): {e}[/dim]"
482
+ )
483
+ else:
484
+ # Claude Desktop: Write to platform-specific config
485
+ if "mcpServers" not in mcp_config:
486
+ mcp_config["mcpServers"] = {}
487
+ mcp_config["mcpServers"]["mcp-ticketer"] = server_config
376
488
 
377
489
  # Step 8: Save configuration
378
490
  try:
@@ -386,8 +498,8 @@ def configure_claude_mcp(global_config: bool = False, force: bool = False) -> No
386
498
  console.print(f" Adapter: {adapter}")
387
499
  console.print(f" Python: {python_path}")
388
500
  console.print(" Command: mcp-ticketer mcp")
389
- if project_path:
390
- console.print(f" Project path: {project_path}")
501
+ if absolute_project_path:
502
+ console.print(f" Project path: {absolute_project_path}")
391
503
  if "env" in server_config:
392
504
  console.print(
393
505
  f" Environment variables: {list(server_config['env'].keys())}"
@@ -7,9 +7,9 @@ operations via the Model Context Protocol (MCP).
7
7
  from typing import TYPE_CHECKING
8
8
 
9
9
  if TYPE_CHECKING:
10
- from .main import main
10
+ from .main import MCPTicketServer, main
11
11
 
12
- __all__ = ["main"]
12
+ __all__ = ["main", "MCPTicketServer"]
13
13
 
14
14
 
15
15
  def __getattr__(name: str):
@@ -18,4 +18,8 @@ def __getattr__(name: str):
18
18
  from .main import main
19
19
 
20
20
  return main
21
+ if name == "MCPTicketServer":
22
+ from .main import MCPTicketServer
23
+
24
+ return MCPTicketServer
21
25
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-ticketer
3
- Version: 0.4.9
3
+ Version: 0.4.10
4
4
  Summary: Universal ticket management interface for AI agents with MCP support
5
5
  Author-email: MCP Ticketer Team <support@mcp-ticketer.io>
6
6
  Maintainer-email: MCP Ticketer Team <support@mcp-ticketer.io>
@@ -1,5 +1,5 @@
1
1
  mcp_ticketer/__init__.py,sha256=Xx4WaprO5PXhVPbYi1L6tBmwmJMkYS-lMyG4ieN6QP0,717
2
- mcp_ticketer/__version__.py,sha256=TgErXAgObQmg6Q5ACy63d_W9qLAaFynoPaauS16SAi0,1117
2
+ mcp_ticketer/__version__.py,sha256=oWDc7uOVe8F1WN-3EHrCf-MWxQOm4C59Xr7bB3uDYy8,1118
3
3
  mcp_ticketer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  mcp_ticketer/adapters/__init__.py,sha256=B5DFllWn23hkhmrLykNO5uMMSdcFuuPHXyLw_jyFzuE,358
5
5
  mcp_ticketer/adapters/aitrackdown.py,sha256=cm8L7amB64ZCoGvWbnpH9zxZlXu6t-l8TWiYVSwDhlg,30320
@@ -25,7 +25,7 @@ mcp_ticketer/cli/discover.py,sha256=paG8zElIFEK6lgVD-tHWoFDTuWQ185LirFp0fVlYgB0,
25
25
  mcp_ticketer/cli/gemini_configure.py,sha256=6Czg-gJA_HrzMopKCvCLfRZeqkdR77OLV5W7W4ZG9hw,12739
26
26
  mcp_ticketer/cli/linear_commands.py,sha256=YnmqRacAfTdF0CLr4BXOxFs3uwm_hVifbGdTe6t2CfA,17273
27
27
  mcp_ticketer/cli/main.py,sha256=W36hKxZZKoojjBUYl5U5MlXLaw-qX9i0nPrmvtsndtI,89926
28
- mcp_ticketer/cli/mcp_configure.py,sha256=SfjA97OJAkYUfi9Mn-wqEt6p0xsgz_QZlATwxM_vjTo,14089
28
+ mcp_ticketer/cli/mcp_configure.py,sha256=hkr4jaZpdcqBc_K6uEGUq3z4NIUvUmdyruLLchbL3uk,19524
29
29
  mcp_ticketer/cli/migrate_config.py,sha256=MYsr_C5ZxsGg0P13etWTWNrJ_lc6ElRCkzfQADYr3DM,5956
30
30
  mcp_ticketer/cli/platform_commands.py,sha256=pTLRT2wot8dAmy1-roJWWOT0Cxu7j-06BlWDnZ9a4jY,3624
31
31
  mcp_ticketer/cli/python_detection.py,sha256=qmhi0CIDKH_AUVGkJ9jyY1zBpx1cwiQNv0vnEvMYDFQ,4272
@@ -46,7 +46,7 @@ mcp_ticketer/core/project_config.py,sha256=DmLekuMuOgNtzg-olOU4Utv00DdCH1-CXuooo
46
46
  mcp_ticketer/core/registry.py,sha256=gBeXcZ3grHl9gYFbyRp-C4IM7SD_KGTeXT_1jG8XrCc,3470
47
47
  mcp_ticketer/mcp/__init__.py,sha256=XscFBOFeIxBNgA_8yPLl6c75-YJCcIN2I9eoLEGsBdM,864
48
48
  mcp_ticketer/mcp/__main__.py,sha256=Fo_5KJOFako2gi1Z1kk5zEt2sGJW6BX6oXlYp7twYTs,1713
49
- mcp_ticketer/mcp/server/__init__.py,sha256=2ll9kLEEiKP_NtvJghHVz6TG2p7xwIUBRqlxZKWRCvU,509
49
+ mcp_ticketer/mcp/server/__init__.py,sha256=-mBqZiNloAlle9ds7jZXG2wJIRnEV0ALSQfdrMK-lVo,653
50
50
  mcp_ticketer/mcp/server/__main__.py,sha256=xE1n94M5n2tKyT6qFIOXaqRXX7L--SxmCglKUPcljG0,1711
51
51
  mcp_ticketer/mcp/server/constants.py,sha256=EBGsJtBPaTCvAm5rOMknckrXActrNIls7lRklnh1L4s,2072
52
52
  mcp_ticketer/mcp/server/dto.py,sha256=FR_OBtaxrno8AsHynPwUUW715iAoaBkrr7Ud8HZTQW8,7233
@@ -69,9 +69,9 @@ mcp_ticketer/queue/queue.py,sha256=q9HDXgnlwspamMJIeu9og7qONttXHmFZHPSaMtJDPlw,1
69
69
  mcp_ticketer/queue/run_worker.py,sha256=WhoeamL8LKZ66TM8W1PkMPwjF2w_EDFMP-mevs6C1TM,1019
70
70
  mcp_ticketer/queue/ticket_registry.py,sha256=xVg3i7Eb5rtQY-4bbw3zYY1h-C6jF1t1NZEGhObzD8g,15491
71
71
  mcp_ticketer/queue/worker.py,sha256=AJHtpJZEhGoPuCDPXSMsn9DeODelo5f__0C__3zoN08,20970
72
- mcp_ticketer-0.4.9.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
73
- mcp_ticketer-0.4.9.dist-info/METADATA,sha256=_nIoXUxM3iodpZW31n9HYkeS_LTOd0GNKwZ36k88h3w,16020
74
- mcp_ticketer-0.4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- mcp_ticketer-0.4.9.dist-info/entry_points.txt,sha256=o1IxVhnHnBNG7FZzbFq-Whcs1Djbofs0qMjiUYBLx2s,60
76
- mcp_ticketer-0.4.9.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
77
- mcp_ticketer-0.4.9.dist-info/RECORD,,
72
+ mcp_ticketer-0.4.10.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
73
+ mcp_ticketer-0.4.10.dist-info/METADATA,sha256=FhrWkaotqhB44HB3KyZzkRs3NGRReEBnvNAd2MexAu8,16021
74
+ mcp_ticketer-0.4.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ mcp_ticketer-0.4.10.dist-info/entry_points.txt,sha256=o1IxVhnHnBNG7FZzbFq-Whcs1Djbofs0qMjiUYBLx2s,60
76
+ mcp_ticketer-0.4.10.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
77
+ mcp_ticketer-0.4.10.dist-info/RECORD,,