mcp-ticketer 0.1.13__py3-none-any.whl → 0.1.15__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/main.py +345 -89
- mcp_ticketer/cli/mcp_configure.py +285 -0
- mcp_ticketer/core/project_config.py +6 -6
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/METADATA +1 -1
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/RECORD +10 -9
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.1.13.dist-info → mcp_ticketer-0.1.15.dist-info}/top_level.txt +0 -0
mcp_ticketer/__version__.py
CHANGED
mcp_ticketer/cli/main.py
CHANGED
|
@@ -160,11 +160,22 @@ def get_adapter(override_adapter: Optional[str] = None, override_config: Optiona
|
|
|
160
160
|
|
|
161
161
|
@app.command()
|
|
162
162
|
def init(
|
|
163
|
-
adapter:
|
|
164
|
-
|
|
163
|
+
adapter: Optional[str] = typer.Option(
|
|
164
|
+
None,
|
|
165
165
|
"--adapter",
|
|
166
166
|
"-a",
|
|
167
|
-
help="Adapter type to use"
|
|
167
|
+
help="Adapter type to use (auto-detected from .env if not specified)"
|
|
168
|
+
),
|
|
169
|
+
project_path: Optional[str] = typer.Option(
|
|
170
|
+
None,
|
|
171
|
+
"--path",
|
|
172
|
+
help="Project path (default: current directory)"
|
|
173
|
+
),
|
|
174
|
+
global_config: bool = typer.Option(
|
|
175
|
+
False,
|
|
176
|
+
"--global",
|
|
177
|
+
"-g",
|
|
178
|
+
help="Save to global config instead of project-specific"
|
|
168
179
|
),
|
|
169
180
|
base_path: Optional[str] = typer.Option(
|
|
170
181
|
None,
|
|
@@ -213,97 +224,306 @@ def init(
|
|
|
213
224
|
help="GitHub Personal Access Token"
|
|
214
225
|
),
|
|
215
226
|
) -> None:
|
|
216
|
-
"""Initialize
|
|
227
|
+
"""Initialize mcp-ticketer for the current project.
|
|
228
|
+
|
|
229
|
+
Creates .mcp-ticketer/config.json in the current directory with
|
|
230
|
+
auto-detected or specified adapter configuration.
|
|
231
|
+
|
|
232
|
+
Examples:
|
|
233
|
+
# Auto-detect from .env.local
|
|
234
|
+
mcp-ticketer init
|
|
235
|
+
|
|
236
|
+
# Force specific adapter
|
|
237
|
+
mcp-ticketer init --adapter linear
|
|
238
|
+
|
|
239
|
+
# Initialize for different project
|
|
240
|
+
mcp-ticketer init --path /path/to/project
|
|
241
|
+
|
|
242
|
+
# Save globally (not recommended)
|
|
243
|
+
mcp-ticketer init --global
|
|
244
|
+
"""
|
|
245
|
+
from pathlib import Path
|
|
246
|
+
from ..core.project_config import ConfigResolver
|
|
247
|
+
from ..core.env_discovery import discover_config
|
|
248
|
+
|
|
249
|
+
# Determine project path
|
|
250
|
+
proj_path = Path(project_path) if project_path else Path.cwd()
|
|
251
|
+
|
|
252
|
+
# Check if already initialized (unless using --global)
|
|
253
|
+
if not global_config:
|
|
254
|
+
config_path = proj_path / ".mcp-ticketer" / "config.json"
|
|
255
|
+
|
|
256
|
+
if config_path.exists():
|
|
257
|
+
if not typer.confirm(
|
|
258
|
+
f"Configuration already exists at {config_path}. Overwrite?",
|
|
259
|
+
default=False
|
|
260
|
+
):
|
|
261
|
+
console.print("[yellow]Initialization cancelled.[/yellow]")
|
|
262
|
+
raise typer.Exit(0)
|
|
263
|
+
|
|
264
|
+
# 1. Try auto-discovery if no adapter specified
|
|
265
|
+
discovered = None
|
|
266
|
+
adapter_type = adapter
|
|
267
|
+
|
|
268
|
+
if not adapter_type:
|
|
269
|
+
console.print("[cyan]🔍 Auto-discovering configuration from .env files...[/cyan]")
|
|
270
|
+
discovered = discover_config(proj_path)
|
|
271
|
+
|
|
272
|
+
if discovered and discovered.adapters:
|
|
273
|
+
primary = discovered.get_primary_adapter()
|
|
274
|
+
if primary:
|
|
275
|
+
adapter_type = primary.adapter_type
|
|
276
|
+
console.print(f"[green]✓ Detected {adapter_type} adapter from environment files[/green]")
|
|
277
|
+
|
|
278
|
+
# Show what was discovered
|
|
279
|
+
console.print(f"\n[dim]Configuration found in: {primary.found_in}[/dim]")
|
|
280
|
+
console.print(f"[dim]Confidence: {primary.confidence:.0%}[/dim]")
|
|
281
|
+
else:
|
|
282
|
+
adapter_type = "aitrackdown" # Fallback
|
|
283
|
+
console.print("[yellow]⚠ No credentials found, defaulting to aitrackdown[/yellow]")
|
|
284
|
+
else:
|
|
285
|
+
adapter_type = "aitrackdown" # Fallback
|
|
286
|
+
console.print("[yellow]⚠ No .env files found, defaulting to aitrackdown[/yellow]")
|
|
287
|
+
|
|
288
|
+
# 2. Create configuration based on adapter type
|
|
217
289
|
config = {
|
|
218
|
-
"default_adapter":
|
|
290
|
+
"default_adapter": adapter_type,
|
|
219
291
|
"adapters": {}
|
|
220
292
|
}
|
|
221
293
|
|
|
222
|
-
|
|
294
|
+
# 3. If discovered and matches adapter_type, use discovered config
|
|
295
|
+
if discovered and adapter_type != "aitrackdown":
|
|
296
|
+
discovered_adapter = discovered.get_adapter_by_type(adapter_type)
|
|
297
|
+
if discovered_adapter:
|
|
298
|
+
config["adapters"][adapter_type] = discovered_adapter.config
|
|
299
|
+
|
|
300
|
+
# 4. Handle manual configuration for specific adapters
|
|
301
|
+
if adapter_type == "aitrackdown":
|
|
223
302
|
config["adapters"]["aitrackdown"] = {"base_path": base_path or ".aitrackdown"}
|
|
224
|
-
elif adapter == AdapterType.LINEAR:
|
|
225
|
-
# For Linear, we need team_id and optionally api_key
|
|
226
|
-
if not team_id:
|
|
227
|
-
console.print("[red]Error:[/red] --team-id is required for Linear adapter")
|
|
228
|
-
raise typer.Exit(1)
|
|
229
|
-
|
|
230
|
-
config["adapters"]["linear"] = {"team_id": team_id}
|
|
231
|
-
|
|
232
|
-
# Check for API key in environment or parameter
|
|
233
|
-
linear_api_key = api_key or os.getenv("LINEAR_API_KEY")
|
|
234
|
-
if not linear_api_key:
|
|
235
|
-
console.print("[yellow]Warning:[/yellow] No Linear API key provided.")
|
|
236
|
-
console.print("Set LINEAR_API_KEY environment variable or use --api-key option")
|
|
237
|
-
else:
|
|
238
|
-
config["adapters"]["linear"]["api_key"] = linear_api_key
|
|
239
|
-
|
|
240
|
-
elif adapter == AdapterType.JIRA:
|
|
241
|
-
# For JIRA, we need server, email, and API token
|
|
242
|
-
server = jira_server or os.getenv("JIRA_SERVER")
|
|
243
|
-
email = jira_email or os.getenv("JIRA_EMAIL")
|
|
244
|
-
token = api_key or os.getenv("JIRA_API_TOKEN")
|
|
245
|
-
project = jira_project or os.getenv("JIRA_PROJECT_KEY")
|
|
246
|
-
|
|
247
|
-
if not server:
|
|
248
|
-
console.print("[red]Error:[/red] JIRA server URL is required")
|
|
249
|
-
console.print("Use --jira-server or set JIRA_SERVER environment variable")
|
|
250
|
-
raise typer.Exit(1)
|
|
251
|
-
|
|
252
|
-
if not email:
|
|
253
|
-
console.print("[red]Error:[/red] JIRA email is required")
|
|
254
|
-
console.print("Use --jira-email or set JIRA_EMAIL environment variable")
|
|
255
|
-
raise typer.Exit(1)
|
|
256
|
-
|
|
257
|
-
if not token:
|
|
258
|
-
console.print("[red]Error:[/red] JIRA API token is required")
|
|
259
|
-
console.print("Use --api-key or set JIRA_API_TOKEN environment variable")
|
|
260
|
-
console.print("[dim]Generate token at: https://id.atlassian.com/manage/api-tokens[/dim]")
|
|
261
|
-
raise typer.Exit(1)
|
|
262
|
-
|
|
263
|
-
config["adapters"]["jira"] = {
|
|
264
|
-
"server": server,
|
|
265
|
-
"email": email,
|
|
266
|
-
"api_token": token
|
|
267
|
-
}
|
|
268
303
|
|
|
269
|
-
|
|
270
|
-
|
|
304
|
+
elif adapter_type == "linear":
|
|
305
|
+
# If not auto-discovered, build from CLI params
|
|
306
|
+
if adapter_type not in config["adapters"]:
|
|
307
|
+
linear_config = {}
|
|
308
|
+
|
|
309
|
+
# Team ID
|
|
310
|
+
if team_id:
|
|
311
|
+
linear_config["team_id"] = team_id
|
|
312
|
+
|
|
313
|
+
# API Key
|
|
314
|
+
linear_api_key = api_key or os.getenv("LINEAR_API_KEY")
|
|
315
|
+
if linear_api_key:
|
|
316
|
+
linear_config["api_key"] = linear_api_key
|
|
317
|
+
elif not discovered:
|
|
318
|
+
console.print("[yellow]Warning:[/yellow] No Linear API key provided.")
|
|
319
|
+
console.print("Set LINEAR_API_KEY environment variable or use --api-key option")
|
|
320
|
+
|
|
321
|
+
if linear_config:
|
|
322
|
+
config["adapters"]["linear"] = linear_config
|
|
323
|
+
|
|
324
|
+
elif adapter_type == "jira":
|
|
325
|
+
# If not auto-discovered, build from CLI params
|
|
326
|
+
if adapter_type not in config["adapters"]:
|
|
327
|
+
server = jira_server or os.getenv("JIRA_SERVER")
|
|
328
|
+
email = jira_email or os.getenv("JIRA_EMAIL")
|
|
329
|
+
token = api_key or os.getenv("JIRA_API_TOKEN")
|
|
330
|
+
project = jira_project or os.getenv("JIRA_PROJECT_KEY")
|
|
331
|
+
|
|
332
|
+
if not server:
|
|
333
|
+
console.print("[red]Error:[/red] JIRA server URL is required")
|
|
334
|
+
console.print("Use --jira-server or set JIRA_SERVER environment variable")
|
|
335
|
+
raise typer.Exit(1)
|
|
336
|
+
|
|
337
|
+
if not email:
|
|
338
|
+
console.print("[red]Error:[/red] JIRA email is required")
|
|
339
|
+
console.print("Use --jira-email or set JIRA_EMAIL environment variable")
|
|
340
|
+
raise typer.Exit(1)
|
|
341
|
+
|
|
342
|
+
if not token:
|
|
343
|
+
console.print("[red]Error:[/red] JIRA API token is required")
|
|
344
|
+
console.print("Use --api-key or set JIRA_API_TOKEN environment variable")
|
|
345
|
+
console.print("[dim]Generate token at: https://id.atlassian.com/manage/api-tokens[/dim]")
|
|
346
|
+
raise typer.Exit(1)
|
|
347
|
+
|
|
348
|
+
jira_config = {
|
|
349
|
+
"server": server,
|
|
350
|
+
"email": email,
|
|
351
|
+
"api_token": token
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if project:
|
|
355
|
+
jira_config["project_key"] = project
|
|
356
|
+
|
|
357
|
+
config["adapters"]["jira"] = jira_config
|
|
358
|
+
|
|
359
|
+
elif adapter_type == "github":
|
|
360
|
+
# If not auto-discovered, build from CLI params
|
|
361
|
+
if adapter_type not in config["adapters"]:
|
|
362
|
+
owner = github_owner or os.getenv("GITHUB_OWNER")
|
|
363
|
+
repo = github_repo or os.getenv("GITHUB_REPO")
|
|
364
|
+
token = github_token or os.getenv("GITHUB_TOKEN")
|
|
365
|
+
|
|
366
|
+
if not owner:
|
|
367
|
+
console.print("[red]Error:[/red] GitHub repository owner is required")
|
|
368
|
+
console.print("Use --github-owner or set GITHUB_OWNER environment variable")
|
|
369
|
+
raise typer.Exit(1)
|
|
370
|
+
|
|
371
|
+
if not repo:
|
|
372
|
+
console.print("[red]Error:[/red] GitHub repository name is required")
|
|
373
|
+
console.print("Use --github-repo or set GITHUB_REPO environment variable")
|
|
374
|
+
raise typer.Exit(1)
|
|
375
|
+
|
|
376
|
+
if not token:
|
|
377
|
+
console.print("[red]Error:[/red] GitHub Personal Access Token is required")
|
|
378
|
+
console.print("Use --github-token or set GITHUB_TOKEN environment variable")
|
|
379
|
+
console.print("[dim]Create token at: https://github.com/settings/tokens/new[/dim]")
|
|
380
|
+
console.print("[dim]Required scopes: repo (for private repos) or public_repo (for public repos)[/dim]")
|
|
381
|
+
raise typer.Exit(1)
|
|
382
|
+
|
|
383
|
+
config["adapters"]["github"] = {
|
|
384
|
+
"owner": owner,
|
|
385
|
+
"repo": repo,
|
|
386
|
+
"token": token
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# 5. Save to appropriate location
|
|
390
|
+
if global_config:
|
|
391
|
+
# Save to ~/.mcp-ticketer/config.json
|
|
392
|
+
resolver = ConfigResolver(project_path=proj_path)
|
|
393
|
+
config_file_path = resolver.GLOBAL_CONFIG_PATH
|
|
394
|
+
config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
395
|
+
|
|
396
|
+
with open(config_file_path, 'w') as f:
|
|
397
|
+
json.dump(config, f, indent=2)
|
|
398
|
+
|
|
399
|
+
console.print(f"[green]✓ Initialized with {adapter_type} adapter[/green]")
|
|
400
|
+
console.print(f"[dim]Global configuration saved to {config_file_path}[/dim]")
|
|
401
|
+
else:
|
|
402
|
+
# Save to ./.mcp-ticketer/config.json (PROJECT-SPECIFIC)
|
|
403
|
+
config_file_path = proj_path / ".mcp-ticketer" / "config.json"
|
|
404
|
+
config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
405
|
+
|
|
406
|
+
with open(config_file_path, 'w') as f:
|
|
407
|
+
json.dump(config, f, indent=2)
|
|
408
|
+
|
|
409
|
+
console.print(f"[green]✓ Initialized with {adapter_type} adapter[/green]")
|
|
410
|
+
console.print(f"[dim]Project configuration saved to {config_file_path}[/dim]")
|
|
411
|
+
|
|
412
|
+
# Add .mcp-ticketer to .gitignore if not already there
|
|
413
|
+
gitignore_path = proj_path / ".gitignore"
|
|
414
|
+
if gitignore_path.exists():
|
|
415
|
+
gitignore_content = gitignore_path.read_text()
|
|
416
|
+
if ".mcp-ticketer" not in gitignore_content:
|
|
417
|
+
with open(gitignore_path, 'a') as f:
|
|
418
|
+
f.write("\n# MCP Ticketer\n.mcp-ticketer/\n")
|
|
419
|
+
console.print("[dim]✓ Added .mcp-ticketer/ to .gitignore[/dim]")
|
|
271
420
|
else:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
421
|
+
# Create .gitignore if it doesn't exist
|
|
422
|
+
with open(gitignore_path, 'w') as f:
|
|
423
|
+
f.write("# MCP Ticketer\n.mcp-ticketer/\n")
|
|
424
|
+
console.print("[dim]✓ Created .gitignore with .mcp-ticketer/[/dim]")
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
@app.command()
|
|
428
|
+
def install(
|
|
429
|
+
adapter: Optional[str] = typer.Option(
|
|
430
|
+
None,
|
|
431
|
+
"--adapter",
|
|
432
|
+
"-a",
|
|
433
|
+
help="Adapter type to use (auto-detected from .env if not specified)"
|
|
434
|
+
),
|
|
435
|
+
project_path: Optional[str] = typer.Option(
|
|
436
|
+
None,
|
|
437
|
+
"--path",
|
|
438
|
+
help="Project path (default: current directory)"
|
|
439
|
+
),
|
|
440
|
+
global_config: bool = typer.Option(
|
|
441
|
+
False,
|
|
442
|
+
"--global",
|
|
443
|
+
"-g",
|
|
444
|
+
help="Save to global config instead of project-specific"
|
|
445
|
+
),
|
|
446
|
+
base_path: Optional[str] = typer.Option(
|
|
447
|
+
None,
|
|
448
|
+
"--base-path",
|
|
449
|
+
"-p",
|
|
450
|
+
help="Base path for ticket storage (AITrackdown only)"
|
|
451
|
+
),
|
|
452
|
+
api_key: Optional[str] = typer.Option(
|
|
453
|
+
None,
|
|
454
|
+
"--api-key",
|
|
455
|
+
help="API key for Linear or API token for JIRA"
|
|
456
|
+
),
|
|
457
|
+
team_id: Optional[str] = typer.Option(
|
|
458
|
+
None,
|
|
459
|
+
"--team-id",
|
|
460
|
+
help="Linear team ID (required for Linear adapter)"
|
|
461
|
+
),
|
|
462
|
+
jira_server: Optional[str] = typer.Option(
|
|
463
|
+
None,
|
|
464
|
+
"--jira-server",
|
|
465
|
+
help="JIRA server URL (e.g., https://company.atlassian.net)"
|
|
466
|
+
),
|
|
467
|
+
jira_email: Optional[str] = typer.Option(
|
|
468
|
+
None,
|
|
469
|
+
"--jira-email",
|
|
470
|
+
help="JIRA user email for authentication"
|
|
471
|
+
),
|
|
472
|
+
jira_project: Optional[str] = typer.Option(
|
|
473
|
+
None,
|
|
474
|
+
"--jira-project",
|
|
475
|
+
help="Default JIRA project key"
|
|
476
|
+
),
|
|
477
|
+
github_owner: Optional[str] = typer.Option(
|
|
478
|
+
None,
|
|
479
|
+
"--github-owner",
|
|
480
|
+
help="GitHub repository owner"
|
|
481
|
+
),
|
|
482
|
+
github_repo: Optional[str] = typer.Option(
|
|
483
|
+
None,
|
|
484
|
+
"--github-repo",
|
|
485
|
+
help="GitHub repository name"
|
|
486
|
+
),
|
|
487
|
+
github_token: Optional[str] = typer.Option(
|
|
488
|
+
None,
|
|
489
|
+
"--github-token",
|
|
490
|
+
help="GitHub Personal Access Token"
|
|
491
|
+
),
|
|
492
|
+
) -> None:
|
|
493
|
+
"""Initialize mcp-ticketer for the current project (alias for init).
|
|
494
|
+
|
|
495
|
+
This command is synonymous with 'init' and provides the same functionality.
|
|
496
|
+
Creates .mcp-ticketer/config.json in the current directory with
|
|
497
|
+
auto-detected or specified adapter configuration.
|
|
498
|
+
|
|
499
|
+
Examples:
|
|
500
|
+
# Auto-detect from .env.local
|
|
501
|
+
mcp-ticketer install
|
|
502
|
+
|
|
503
|
+
# Force specific adapter
|
|
504
|
+
mcp-ticketer install --adapter linear
|
|
505
|
+
|
|
506
|
+
# Initialize for different project
|
|
507
|
+
mcp-ticketer install --path /path/to/project
|
|
508
|
+
|
|
509
|
+
# Save globally (not recommended)
|
|
510
|
+
mcp-ticketer install --global
|
|
511
|
+
"""
|
|
512
|
+
# Call init with all parameters
|
|
513
|
+
init(
|
|
514
|
+
adapter=adapter,
|
|
515
|
+
project_path=project_path,
|
|
516
|
+
global_config=global_config,
|
|
517
|
+
base_path=base_path,
|
|
518
|
+
api_key=api_key,
|
|
519
|
+
team_id=team_id,
|
|
520
|
+
jira_server=jira_server,
|
|
521
|
+
jira_email=jira_email,
|
|
522
|
+
jira_project=jira_project,
|
|
523
|
+
github_owner=github_owner,
|
|
524
|
+
github_repo=github_repo,
|
|
525
|
+
github_token=github_token,
|
|
526
|
+
)
|
|
307
527
|
|
|
308
528
|
|
|
309
529
|
@app.command("set")
|
|
@@ -915,7 +1135,7 @@ def check(
|
|
|
915
1135
|
|
|
916
1136
|
|
|
917
1137
|
@app.command()
|
|
918
|
-
def
|
|
1138
|
+
def serve(
|
|
919
1139
|
adapter: Optional[AdapterType] = typer.Option(
|
|
920
1140
|
None,
|
|
921
1141
|
"--adapter",
|
|
@@ -928,7 +1148,11 @@ def mcp(
|
|
|
928
1148
|
help="Base path for AITrackdown adapter"
|
|
929
1149
|
),
|
|
930
1150
|
):
|
|
931
|
-
"""Start MCP server for JSON-RPC communication over stdio.
|
|
1151
|
+
"""Start MCP server for JSON-RPC communication over stdio.
|
|
1152
|
+
|
|
1153
|
+
This command is used by Claude Code/Desktop when connecting to the MCP server.
|
|
1154
|
+
You typically don't need to run this manually - use 'mcp-ticketer mcp' to configure.
|
|
1155
|
+
"""
|
|
932
1156
|
from ..mcp.server import MCPTicketServer
|
|
933
1157
|
|
|
934
1158
|
# Load configuration
|
|
@@ -974,6 +1198,38 @@ def mcp(
|
|
|
974
1198
|
sys.exit(1)
|
|
975
1199
|
|
|
976
1200
|
|
|
1201
|
+
@app.command()
|
|
1202
|
+
def mcp(
|
|
1203
|
+
global_config: bool = typer.Option(
|
|
1204
|
+
False,
|
|
1205
|
+
"--global",
|
|
1206
|
+
"-g",
|
|
1207
|
+
help="Configure Claude Desktop instead of project-level"
|
|
1208
|
+
),
|
|
1209
|
+
force: bool = typer.Option(
|
|
1210
|
+
False,
|
|
1211
|
+
"--force",
|
|
1212
|
+
"-f",
|
|
1213
|
+
help="Overwrite existing configuration"
|
|
1214
|
+
),
|
|
1215
|
+
):
|
|
1216
|
+
"""Configure Claude Code to use mcp-ticketer MCP server.
|
|
1217
|
+
|
|
1218
|
+
Reads configuration from .mcp-ticketer/config.json and updates
|
|
1219
|
+
Claude Code's MCP settings accordingly.
|
|
1220
|
+
|
|
1221
|
+
By default, configures project-level (.mcp/config.json).
|
|
1222
|
+
Use --global to configure Claude Desktop instead.
|
|
1223
|
+
"""
|
|
1224
|
+
from ..cli.mcp_configure import configure_claude_mcp
|
|
1225
|
+
|
|
1226
|
+
try:
|
|
1227
|
+
configure_claude_mcp(global_config=global_config, force=force)
|
|
1228
|
+
except Exception as e:
|
|
1229
|
+
console.print(f"[red]✗ Configuration failed:[/red] {e}")
|
|
1230
|
+
raise typer.Exit(1)
|
|
1231
|
+
|
|
1232
|
+
|
|
977
1233
|
def main():
|
|
978
1234
|
"""Main entry point."""
|
|
979
1235
|
app()
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"""MCP configuration for Claude Code integration."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def find_mcp_ticketer_binary() -> str:
|
|
16
|
+
"""Find the mcp-ticketer binary path.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Path to mcp-ticketer binary
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
FileNotFoundError: If binary not found
|
|
23
|
+
"""
|
|
24
|
+
# Check if running from development environment
|
|
25
|
+
import mcp_ticketer
|
|
26
|
+
package_path = Path(mcp_ticketer.__file__).parent.parent.parent
|
|
27
|
+
|
|
28
|
+
# Check for virtual environment bin
|
|
29
|
+
possible_paths = [
|
|
30
|
+
# Development paths
|
|
31
|
+
package_path / "venv" / "bin" / "mcp-ticketer",
|
|
32
|
+
package_path / ".venv" / "bin" / "mcp-ticketer",
|
|
33
|
+
package_path / "test_venv" / "bin" / "mcp-ticketer",
|
|
34
|
+
# System installation
|
|
35
|
+
Path.home() / ".local" / "bin" / "mcp-ticketer",
|
|
36
|
+
# pipx installation
|
|
37
|
+
Path.home() / ".local" / "pipx" / "venvs" / "mcp-ticketer" / "bin" / "mcp-ticketer",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
# Check PATH
|
|
41
|
+
which_result = shutil.which("mcp-ticketer")
|
|
42
|
+
if which_result:
|
|
43
|
+
return which_result
|
|
44
|
+
|
|
45
|
+
# Check possible paths
|
|
46
|
+
for path in possible_paths:
|
|
47
|
+
if path.exists():
|
|
48
|
+
return str(path.resolve())
|
|
49
|
+
|
|
50
|
+
raise FileNotFoundError(
|
|
51
|
+
"Could not find mcp-ticketer binary. Please ensure mcp-ticketer is installed.\n"
|
|
52
|
+
"Install with: pip install mcp-ticketer"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def load_project_config() -> dict:
|
|
57
|
+
"""Load mcp-ticketer project configuration.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Project configuration dict
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
FileNotFoundError: If config not found
|
|
64
|
+
ValueError: If config is invalid
|
|
65
|
+
"""
|
|
66
|
+
# Check for project-specific config first
|
|
67
|
+
project_config_path = Path.cwd() / ".mcp-ticketer" / "config.json"
|
|
68
|
+
|
|
69
|
+
if not project_config_path.exists():
|
|
70
|
+
# Check global config
|
|
71
|
+
global_config_path = Path.home() / ".mcp-ticketer" / "config.json"
|
|
72
|
+
if global_config_path.exists():
|
|
73
|
+
project_config_path = global_config_path
|
|
74
|
+
else:
|
|
75
|
+
raise FileNotFoundError(
|
|
76
|
+
"No mcp-ticketer configuration found.\n"
|
|
77
|
+
"Run 'mcp-ticketer init' to create configuration."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
with open(project_config_path, "r") as f:
|
|
81
|
+
config = json.load(f)
|
|
82
|
+
|
|
83
|
+
# Validate config
|
|
84
|
+
if "default_adapter" not in config:
|
|
85
|
+
raise ValueError("Invalid config: missing 'default_adapter'")
|
|
86
|
+
|
|
87
|
+
return config
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def find_claude_mcp_config(global_config: bool = False) -> Path:
|
|
91
|
+
"""Find or create Claude Code MCP configuration file.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
global_config: If True, use Claude Desktop config instead of project-level
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Path to MCP configuration file
|
|
98
|
+
"""
|
|
99
|
+
if global_config:
|
|
100
|
+
# Claude Desktop configuration
|
|
101
|
+
if sys.platform == "darwin": # macOS
|
|
102
|
+
config_path = Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json"
|
|
103
|
+
elif sys.platform == "win32": # Windows
|
|
104
|
+
config_path = Path(os.environ.get("APPDATA", "")) / "Claude" / "claude_desktop_config.json"
|
|
105
|
+
else: # Linux
|
|
106
|
+
config_path = Path.home() / ".config" / "Claude" / "claude_desktop_config.json"
|
|
107
|
+
else:
|
|
108
|
+
# Project-level configuration
|
|
109
|
+
config_path = Path.cwd() / ".mcp" / "config.json"
|
|
110
|
+
|
|
111
|
+
return config_path
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def load_claude_mcp_config(config_path: Path) -> dict:
|
|
115
|
+
"""Load existing Claude MCP configuration or return empty structure.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
config_path: Path to MCP config file
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
MCP configuration dict
|
|
122
|
+
"""
|
|
123
|
+
if config_path.exists():
|
|
124
|
+
with open(config_path, "r") as f:
|
|
125
|
+
return json.load(f)
|
|
126
|
+
|
|
127
|
+
# Return empty structure
|
|
128
|
+
return {"mcpServers": {}}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def save_claude_mcp_config(config_path: Path, config: dict) -> None:
|
|
132
|
+
"""Save Claude MCP configuration to file.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
config_path: Path to MCP config file
|
|
136
|
+
config: Configuration to save
|
|
137
|
+
"""
|
|
138
|
+
# Ensure directory exists
|
|
139
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
140
|
+
|
|
141
|
+
# Write with formatting
|
|
142
|
+
with open(config_path, "w") as f:
|
|
143
|
+
json.dump(config, f, indent=2)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def create_mcp_server_config(
|
|
147
|
+
binary_path: str,
|
|
148
|
+
project_config: dict,
|
|
149
|
+
cwd: Optional[str] = None
|
|
150
|
+
) -> dict:
|
|
151
|
+
"""Create MCP server configuration for mcp-ticketer.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
binary_path: Path to mcp-ticketer binary
|
|
155
|
+
project_config: Project configuration from .mcp-ticketer/config.json
|
|
156
|
+
cwd: Working directory for server (optional)
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
MCP server configuration dict
|
|
160
|
+
"""
|
|
161
|
+
config = {
|
|
162
|
+
"command": binary_path,
|
|
163
|
+
"args": ["serve"], # Use 'serve' command to start MCP server
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# Add working directory if provided
|
|
167
|
+
if cwd:
|
|
168
|
+
config["cwd"] = cwd
|
|
169
|
+
|
|
170
|
+
# Add environment variables based on adapter
|
|
171
|
+
adapter = project_config.get("default_adapter", "aitrackdown")
|
|
172
|
+
adapters_config = project_config.get("adapters", {})
|
|
173
|
+
adapter_config = adapters_config.get(adapter, {})
|
|
174
|
+
|
|
175
|
+
env_vars = {}
|
|
176
|
+
|
|
177
|
+
# Add adapter-specific environment variables
|
|
178
|
+
if adapter == "linear" and "api_key" in adapter_config:
|
|
179
|
+
env_vars["LINEAR_API_KEY"] = adapter_config["api_key"]
|
|
180
|
+
elif adapter == "github" and "token" in adapter_config:
|
|
181
|
+
env_vars["GITHUB_TOKEN"] = adapter_config["token"]
|
|
182
|
+
elif adapter == "jira":
|
|
183
|
+
if "api_token" in adapter_config:
|
|
184
|
+
env_vars["JIRA_API_TOKEN"] = adapter_config["api_token"]
|
|
185
|
+
if "email" in adapter_config:
|
|
186
|
+
env_vars["JIRA_EMAIL"] = adapter_config["email"]
|
|
187
|
+
|
|
188
|
+
if env_vars:
|
|
189
|
+
config["env"] = env_vars
|
|
190
|
+
|
|
191
|
+
return config
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def configure_claude_mcp(global_config: bool = False, force: bool = False) -> None:
|
|
195
|
+
"""Configure Claude Code to use mcp-ticketer.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
global_config: Configure Claude Desktop instead of project-level
|
|
199
|
+
force: Overwrite existing configuration
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
FileNotFoundError: If binary or project config not found
|
|
203
|
+
ValueError: If configuration is invalid
|
|
204
|
+
"""
|
|
205
|
+
# Step 1: Find mcp-ticketer binary
|
|
206
|
+
console.print("[cyan]🔍 Finding mcp-ticketer binary...[/cyan]")
|
|
207
|
+
try:
|
|
208
|
+
binary_path = find_mcp_ticketer_binary()
|
|
209
|
+
console.print(f"[green]✓[/green] Found: {binary_path}")
|
|
210
|
+
except FileNotFoundError as e:
|
|
211
|
+
console.print(f"[red]✗[/red] {e}")
|
|
212
|
+
raise
|
|
213
|
+
|
|
214
|
+
# Step 2: Load project configuration
|
|
215
|
+
console.print("\n[cyan]📖 Reading project configuration...[/cyan]")
|
|
216
|
+
try:
|
|
217
|
+
project_config = load_project_config()
|
|
218
|
+
adapter = project_config.get("default_adapter", "aitrackdown")
|
|
219
|
+
console.print(f"[green]✓[/green] Adapter: {adapter}")
|
|
220
|
+
except (FileNotFoundError, ValueError) as e:
|
|
221
|
+
console.print(f"[red]✗[/red] {e}")
|
|
222
|
+
raise
|
|
223
|
+
|
|
224
|
+
# Step 3: Find Claude MCP config location
|
|
225
|
+
config_type = "Claude Desktop" if global_config else "project-level"
|
|
226
|
+
console.print(f"\n[cyan]🔧 Configuring {config_type} MCP...[/cyan]")
|
|
227
|
+
|
|
228
|
+
mcp_config_path = find_claude_mcp_config(global_config)
|
|
229
|
+
console.print(f"[dim]Config location: {mcp_config_path}[/dim]")
|
|
230
|
+
|
|
231
|
+
# Step 4: Load existing MCP configuration
|
|
232
|
+
mcp_config = load_claude_mcp_config(mcp_config_path)
|
|
233
|
+
|
|
234
|
+
# Step 5: Check if mcp-ticketer already configured
|
|
235
|
+
if "mcp-ticketer" in mcp_config.get("mcpServers", {}):
|
|
236
|
+
if not force:
|
|
237
|
+
console.print("[yellow]⚠ mcp-ticketer is already configured[/yellow]")
|
|
238
|
+
console.print("[dim]Use --force to overwrite existing configuration[/dim]")
|
|
239
|
+
return
|
|
240
|
+
else:
|
|
241
|
+
console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
|
|
242
|
+
|
|
243
|
+
# Step 6: Create mcp-ticketer server config
|
|
244
|
+
cwd = str(Path.cwd()) if not global_config else None
|
|
245
|
+
server_config = create_mcp_server_config(
|
|
246
|
+
binary_path=binary_path,
|
|
247
|
+
project_config=project_config,
|
|
248
|
+
cwd=cwd
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Step 7: Update MCP configuration
|
|
252
|
+
if "mcpServers" not in mcp_config:
|
|
253
|
+
mcp_config["mcpServers"] = {}
|
|
254
|
+
|
|
255
|
+
mcp_config["mcpServers"]["mcp-ticketer"] = server_config
|
|
256
|
+
|
|
257
|
+
# Step 8: Save configuration
|
|
258
|
+
try:
|
|
259
|
+
save_claude_mcp_config(mcp_config_path, mcp_config)
|
|
260
|
+
console.print(f"\n[green]✓ Successfully configured mcp-ticketer[/green]")
|
|
261
|
+
console.print(f"[dim]Configuration saved to: {mcp_config_path}[/dim]")
|
|
262
|
+
|
|
263
|
+
# Print configuration details
|
|
264
|
+
console.print("\n[bold]Configuration Details:[/bold]")
|
|
265
|
+
console.print(f" Server name: mcp-ticketer")
|
|
266
|
+
console.print(f" Adapter: {adapter}")
|
|
267
|
+
console.print(f" Binary: {binary_path}")
|
|
268
|
+
if cwd:
|
|
269
|
+
console.print(f" Working directory: {cwd}")
|
|
270
|
+
if "env" in server_config:
|
|
271
|
+
console.print(f" Environment variables: {list(server_config['env'].keys())}")
|
|
272
|
+
|
|
273
|
+
# Next steps
|
|
274
|
+
console.print("\n[bold cyan]Next Steps:[/bold cyan]")
|
|
275
|
+
if global_config:
|
|
276
|
+
console.print("1. Restart Claude Desktop")
|
|
277
|
+
console.print("2. Open a conversation")
|
|
278
|
+
else:
|
|
279
|
+
console.print("1. Restart Claude Code")
|
|
280
|
+
console.print("2. Open this project in Claude Code")
|
|
281
|
+
console.print("3. mcp-ticketer tools will be available in the MCP menu")
|
|
282
|
+
|
|
283
|
+
except Exception as e:
|
|
284
|
+
console.print(f"\n[red]✗ Failed to save configuration:[/red] {e}")
|
|
285
|
+
raise
|
|
@@ -414,7 +414,7 @@ class ConfigResolver:
|
|
|
414
414
|
) -> Dict[str, Any]:
|
|
415
415
|
"""Resolve adapter configuration with hierarchical precedence.
|
|
416
416
|
|
|
417
|
-
|
|
417
|
+
Resolution order (highest to lowest priority):
|
|
418
418
|
1. CLI overrides
|
|
419
419
|
2. Environment variables (os.getenv)
|
|
420
420
|
3. Project-specific config (.mcp-ticketer/config.json)
|
|
@@ -432,7 +432,7 @@ class ConfigResolver:
|
|
|
432
432
|
global_config = self.load_global_config()
|
|
433
433
|
project_config = self.load_project_config()
|
|
434
434
|
|
|
435
|
-
# Determine which adapter to use
|
|
435
|
+
# Determine which adapter to use (check project config first)
|
|
436
436
|
if adapter_name:
|
|
437
437
|
target_adapter = adapter_name
|
|
438
438
|
elif project_config and project_config.default_adapter:
|
|
@@ -452,7 +452,7 @@ class ConfigResolver:
|
|
|
452
452
|
# Start with empty config
|
|
453
453
|
resolved_config = {"adapter": target_adapter}
|
|
454
454
|
|
|
455
|
-
# 1. Apply global adapter config
|
|
455
|
+
# 1. Apply global adapter config (LOWEST PRIORITY)
|
|
456
456
|
if target_adapter in global_config.adapters:
|
|
457
457
|
global_adapter_config = global_config.adapters[target_adapter].to_dict()
|
|
458
458
|
resolved_config.update(global_adapter_config)
|
|
@@ -473,7 +473,7 @@ class ConfigResolver:
|
|
|
473
473
|
f"Applied auto-discovered config from {discovered_adapter.found_in}"
|
|
474
474
|
)
|
|
475
475
|
|
|
476
|
-
# 3. Apply project-specific config
|
|
476
|
+
# 3. Apply project-specific config (HIGHER PRIORITY - overrides global and .env)
|
|
477
477
|
if project_config:
|
|
478
478
|
# Check if this project has specific adapter config
|
|
479
479
|
project_path_str = str(self.project_path)
|
|
@@ -486,11 +486,11 @@ class ConfigResolver:
|
|
|
486
486
|
proj_global_adapter_config = project_config.adapters[target_adapter].to_dict()
|
|
487
487
|
resolved_config.update(proj_global_adapter_config)
|
|
488
488
|
|
|
489
|
-
# 4. Apply environment variable overrides (os.getenv)
|
|
489
|
+
# 4. Apply environment variable overrides (os.getenv - HIGHER PRIORITY)
|
|
490
490
|
env_overrides = self._get_env_overrides(target_adapter)
|
|
491
491
|
resolved_config.update(env_overrides)
|
|
492
492
|
|
|
493
|
-
# 5. Apply CLI overrides
|
|
493
|
+
# 5. Apply CLI overrides (HIGHEST PRIORITY)
|
|
494
494
|
if cli_overrides:
|
|
495
495
|
resolved_config.update(cli_overrides)
|
|
496
496
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-ticketer
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
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=ayPQdFr6msypD06_G96a1H0bdFCT1m1wDtv8MZBpY4I,496
|
|
2
|
-
mcp_ticketer/__version__.py,sha256=
|
|
2
|
+
mcp_ticketer/__version__.py,sha256=OaT1sLIF9tJvQbLP2vx2vOgiGiMS2mbt4EzloZeALPo,1115
|
|
3
3
|
mcp_ticketer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
mcp_ticketer/adapters/__init__.py,sha256=K_1egvhHb5F_7yFceUx2YzPGEoc7vX-q8dMVaS4K6gw,356
|
|
5
5
|
mcp_ticketer/adapters/aitrackdown.py,sha256=gqS_N6VGLoG5itUu17ANG5SefaAITYoW-t2xL9SrY-Y,15372
|
|
@@ -12,7 +12,8 @@ mcp_ticketer/cache/memory.py,sha256=gTzv-xF7qGfiYVUjG7lnzo0ZcqgXQajMl4NAYUcaytg,
|
|
|
12
12
|
mcp_ticketer/cli/__init__.py,sha256=YeljyLtv906TqkvRuEPhmKO-Uk0CberQ9I6kx1tx2UA,88
|
|
13
13
|
mcp_ticketer/cli/configure.py,sha256=etFutvc0QpaVDMOsZiiN7wKuaT98Od1Tj9W6lsEWw5A,16351
|
|
14
14
|
mcp_ticketer/cli/discover.py,sha256=putWrGcctUH8K0fOMtr9MZA9VnWoXzbtoe7mXSkDxhg,13156
|
|
15
|
-
mcp_ticketer/cli/main.py,sha256=
|
|
15
|
+
mcp_ticketer/cli/main.py,sha256=HxvlZb4ZGxWoqOLwp2eIoS9Ie7C8LF-gShdnwolqVrE,39135
|
|
16
|
+
mcp_ticketer/cli/mcp_configure.py,sha256=1WbBdF25OvxfAGcjxtYa9xmBOGEPQu-wh_nkefmWjMQ,9352
|
|
16
17
|
mcp_ticketer/cli/migrate_config.py,sha256=iZIstnlr9vkhiW_MlnSyJOkMi4KHQqrZ6Hz1ECD_VUk,6045
|
|
17
18
|
mcp_ticketer/cli/queue_commands.py,sha256=f3pEHKZ43dBHEIoCBvdfvjfMB9_WJltps9ATwTzorY0,8160
|
|
18
19
|
mcp_ticketer/cli/utils.py,sha256=NxsS91vKA8xZnDXKU2y0Gcyc4I_ctRyJj-wT7Xd1Q_Q,18589
|
|
@@ -23,7 +24,7 @@ mcp_ticketer/core/env_discovery.py,sha256=SPoyq_y5j-3gJG5gYNVjCIIrbdzimOdDbTYySm
|
|
|
23
24
|
mcp_ticketer/core/http_client.py,sha256=RM9CEMNcuRb-FxhAijmM_FeBMgxgh1OII9HIPBdJue0,13855
|
|
24
25
|
mcp_ticketer/core/mappers.py,sha256=8I4jcqDqoQEdWlteDMpVeVF3Wo0fDCkmFPRr8oNv8gA,16933
|
|
25
26
|
mcp_ticketer/core/models.py,sha256=GhuTitY6t_QlqfEUvWT6Q2zvY7qAtx_SQyCMMn8iYkk,6473
|
|
26
|
-
mcp_ticketer/core/project_config.py,sha256=
|
|
27
|
+
mcp_ticketer/core/project_config.py,sha256=VVSeCwuESuemL-iC4fqbPrJxR4i5k5fhUpujnY7MCZA,22389
|
|
27
28
|
mcp_ticketer/core/registry.py,sha256=fwje0fnjp0YKPZ0SrVWk82SMNLs7CD0JlHQmx7SigNo,3537
|
|
28
29
|
mcp_ticketer/mcp/__init__.py,sha256=Bvzof9vBu6VwcXcIZK8RgKv6ycRV9tDlO-9TUmd8zqQ,122
|
|
29
30
|
mcp_ticketer/mcp/server.py,sha256=TDuU8ChZC2QYSRo0uGHkVReblTf--hriOjxo-pSAF_Y,34068
|
|
@@ -33,9 +34,9 @@ mcp_ticketer/queue/manager.py,sha256=79AH9oUxdBXH3lmJ3kIlFf2GQkWHL6XB6u5JqVWPq60
|
|
|
33
34
|
mcp_ticketer/queue/queue.py,sha256=z4aivQCtsH5_OUr2OfXSfnFKzugTahNnwHw0LS3ZhZc,11549
|
|
34
35
|
mcp_ticketer/queue/run_worker.py,sha256=HFoykfDpOoz8OUxWbQ2Fka_UlGrYwjPVZ-DEimGFH9o,802
|
|
35
36
|
mcp_ticketer/queue/worker.py,sha256=cVjHR_kfnGKAkiUg0HuXCnbKeKNBBEuj0XZHgIuIn4k,14017
|
|
36
|
-
mcp_ticketer-0.1.
|
|
37
|
-
mcp_ticketer-0.1.
|
|
38
|
-
mcp_ticketer-0.1.
|
|
39
|
-
mcp_ticketer-0.1.
|
|
40
|
-
mcp_ticketer-0.1.
|
|
41
|
-
mcp_ticketer-0.1.
|
|
37
|
+
mcp_ticketer-0.1.15.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
|
|
38
|
+
mcp_ticketer-0.1.15.dist-info/METADATA,sha256=VYRxHsh-APXWl3wdmdNSfiniYI84jQwFiVaZ9Y5oOBA,11211
|
|
39
|
+
mcp_ticketer-0.1.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
40
|
+
mcp_ticketer-0.1.15.dist-info/entry_points.txt,sha256=o1IxVhnHnBNG7FZzbFq-Whcs1Djbofs0qMjiUYBLx2s,60
|
|
41
|
+
mcp_ticketer-0.1.15.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
|
|
42
|
+
mcp_ticketer-0.1.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|