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.
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/cli/mcp_configure.py +137 -25
- mcp_ticketer/mcp/server/__init__.py +6 -2
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/METADATA +1 -1
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/RECORD +9 -9
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.9.dist-info → mcp_ticketer-0.4.10.dist-info}/top_level.txt +0 -0
mcp_ticketer/__version__.py
CHANGED
|
@@ -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
|
-
#
|
|
111
|
-
config_path = Path.
|
|
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
|
-
|
|
128
|
-
|
|
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
|
|
131
|
-
|
|
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 "
|
|
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]
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 "
|
|
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]
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
442
|
+
project_path=absolute_project_path,
|
|
369
443
|
)
|
|
370
444
|
|
|
371
|
-
# Step 7: Update MCP configuration
|
|
372
|
-
if
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
|
390
|
-
console.print(f" 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.
|
|
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=
|
|
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=
|
|
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
|
|
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.
|
|
73
|
-
mcp_ticketer-0.4.
|
|
74
|
-
mcp_ticketer-0.4.
|
|
75
|
-
mcp_ticketer-0.4.
|
|
76
|
-
mcp_ticketer-0.4.
|
|
77
|
-
mcp_ticketer-0.4.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|