mcp-ticketer 0.1.1__py3-none-any.whl → 0.1.3__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.1.1"
3
+ __version__ = "0.1.3"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # Package metadata
mcp_ticketer/cli/main.py CHANGED
@@ -803,6 +803,66 @@ def check(
803
803
  console.print(f"\nRetry Count: {item.retry_count}")
804
804
 
805
805
 
806
+ @app.command()
807
+ def mcp(
808
+ adapter: Optional[AdapterType] = typer.Option(
809
+ None,
810
+ "--adapter",
811
+ "-a",
812
+ help="Override default adapter type"
813
+ ),
814
+ base_path: Optional[str] = typer.Option(
815
+ None,
816
+ "--base-path",
817
+ help="Base path for AITrackdown adapter"
818
+ ),
819
+ ):
820
+ """Start MCP server for JSON-RPC communication over stdio."""
821
+ from ..mcp.server import MCPTicketServer
822
+
823
+ # Load configuration
824
+ config = load_config()
825
+
826
+ # Determine adapter type
827
+ adapter_type = adapter.value if adapter else config.get("default_adapter", "aitrackdown")
828
+
829
+ # Get adapter configuration
830
+ adapters_config = config.get("adapters", {})
831
+ adapter_config = adapters_config.get(adapter_type, {})
832
+
833
+ # Override with command line options if provided
834
+ if base_path and adapter_type == "aitrackdown":
835
+ adapter_config["base_path"] = base_path
836
+
837
+ # Fallback to legacy config format
838
+ if not adapter_config and "config" in config:
839
+ adapter_config = config["config"]
840
+
841
+ # MCP server uses stdio for JSON-RPC, so we can't print to stdout
842
+ # Only print to stderr to avoid interfering with the protocol
843
+ import sys
844
+ if sys.stderr.isatty():
845
+ # Only print if stderr is a terminal (not redirected)
846
+ console.file = sys.stderr
847
+ console.print(f"[green]Starting MCP server[/green] with {adapter_type} adapter")
848
+ console.print("[dim]Server running on stdio. Send JSON-RPC requests via stdin.[/dim]")
849
+
850
+ # Create and run server
851
+ try:
852
+ server = MCPTicketServer(adapter_type, adapter_config)
853
+ asyncio.run(server.run())
854
+ except KeyboardInterrupt:
855
+ # Also send this to stderr
856
+ if sys.stderr.isatty():
857
+ console.print("\n[yellow]Server stopped by user[/yellow]")
858
+ if 'server' in locals():
859
+ asyncio.run(server.stop())
860
+ except Exception as e:
861
+ # Log error to stderr
862
+ sys.stderr.write(f"MCP server error: {e}\n")
863
+ sys.exit(1)
864
+
865
+
806
866
  def main():
807
867
  """Main entry point."""
808
868
  app()
@@ -41,8 +41,11 @@ class MCPTicketServer:
41
41
  request_id = request.get("id")
42
42
 
43
43
  try:
44
- # Route to appropriate handler
45
- if method == "ticket/create":
44
+ # Handle MCP protocol methods
45
+ if method == "initialize":
46
+ result = await self._handle_initialize(params)
47
+ # Route to ticket operation handlers
48
+ elif method == "ticket/create":
46
49
  result = await self._handle_create(params)
47
50
  elif method == "ticket/read":
48
51
  result = await self._handle_read(params)
@@ -293,6 +296,28 @@ class MCPTicketServer:
293
296
 
294
297
  return response
295
298
 
299
+ async def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
300
+ """Handle initialize request from MCP client.
301
+
302
+ Args:
303
+ params: Initialize parameters
304
+
305
+ Returns:
306
+ Server capabilities
307
+ """
308
+ return {
309
+ "protocolVersion": "1.0.0",
310
+ "serverInfo": {
311
+ "name": "mcp-ticketer",
312
+ "version": "0.1.3"
313
+ },
314
+ "capabilities": {
315
+ "tools": {
316
+ "listChanged": False
317
+ }
318
+ }
319
+ }
320
+
296
321
  async def _handle_tools_list(self) -> Dict[str, Any]:
297
322
  """List available MCP tools."""
298
323
  return {
@@ -378,28 +403,22 @@ class MCPTicketServer:
378
403
  async def run(self) -> None:
379
404
  """Run the MCP server, reading from stdin and writing to stdout."""
380
405
  self.running = True
381
- reader = asyncio.StreamReader()
382
- protocol = asyncio.StreamReaderProtocol(reader)
383
- await asyncio.get_event_loop().connect_read_pipe(lambda: protocol, sys.stdin)
384
406
 
385
- # Send initialization
386
- init_message = {
387
- "jsonrpc": "2.0",
388
- "method": "initialized",
389
- "params": {
390
- "name": "mcp-ticketer",
391
- "version": "0.1.0",
392
- "capabilities": ["tickets", "comments", "search"]
393
- }
394
- }
395
- sys.stdout.write(json.dumps(init_message) + "\n")
396
- sys.stdout.flush()
407
+ try:
408
+ reader = asyncio.StreamReader()
409
+ protocol = asyncio.StreamReaderProtocol(reader)
410
+ await asyncio.get_event_loop().connect_read_pipe(lambda: protocol, sys.stdin)
411
+ except Exception as e:
412
+ sys.stderr.write(f"Failed to connect to stdin: {str(e)}\n")
413
+ return
397
414
 
398
415
  # Main message loop
399
416
  while self.running:
400
417
  try:
401
418
  line = await reader.readline()
402
419
  if not line:
420
+ # EOF reached, exit gracefully
421
+ sys.stderr.write("EOF reached, shutting down server\n")
403
422
  break
404
423
 
405
424
  # Parse JSON-RPC request
@@ -422,6 +441,11 @@ class MCPTicketServer:
422
441
  sys.stdout.flush()
423
442
 
424
443
  except KeyboardInterrupt:
444
+ sys.stderr.write("Received interrupt signal\n")
445
+ break
446
+
447
+ except BrokenPipeError:
448
+ sys.stderr.write("Connection closed by client\n")
425
449
  break
426
450
 
427
451
  except Exception as e:
@@ -435,7 +459,11 @@ class MCPTicketServer:
435
459
 
436
460
 
437
461
  async def main():
438
- """Main entry point for MCP server."""
462
+ """Main entry point for MCP server - kept for backward compatibility.
463
+
464
+ This function is maintained in case it's being called directly,
465
+ but the preferred way is now through the CLI: `mcp-ticketer mcp`
466
+ """
439
467
  # Load configuration
440
468
  import json
441
469
  from pathlib import Path
@@ -444,8 +472,13 @@ async def main():
444
472
  if config_file.exists():
445
473
  with open(config_file, "r") as f:
446
474
  config = json.load(f)
447
- adapter_type = config.get("adapter", "aitrackdown")
448
- adapter_config = config.get("config", {})
475
+ adapter_type = config.get("default_adapter", "aitrackdown")
476
+ # Get adapter-specific config
477
+ adapters_config = config.get("adapters", {})
478
+ adapter_config = adapters_config.get(adapter_type, {})
479
+ # Fallback to legacy config format
480
+ if not adapter_config and "config" in config:
481
+ adapter_config = config["config"]
449
482
  else:
450
483
  adapter_type = "aitrackdown"
451
484
  adapter_config = {"base_path": ".aitrackdown"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-ticketer
3
- Version: 0.1.1
3
+ Version: 0.1.3
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>
@@ -251,7 +251,7 @@ cd mcp-ticketerer
251
251
 
252
252
  # Create virtual environment
253
253
  python -m venv venv
254
- source venv/bin/activate # On Windows: venv\Scripts\activate
254
+ source .venv/bin/activate # On Windows: venv\Scripts\activate
255
255
 
256
256
  # Install in development mode with all dependencies
257
257
  pip install -e ".[dev,test,docs]"
@@ -1,5 +1,5 @@
1
1
  mcp_ticketer/__init__.py,sha256=ayPQdFr6msypD06_G96a1H0bdFCT1m1wDtv8MZBpY4I,496
2
- mcp_ticketer/__version__.py,sha256=qSqPXA3OEKZmdvDrsW7qILCtjGikygqmeWhMrBtY1qY,1114
2
+ mcp_ticketer/__version__.py,sha256=EIH_Cx5rmGZz5D32cuf-HOcrHTYFFBDYsHASv82EjfY,1114
3
3
  mcp_ticketer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  mcp_ticketer/adapters/__init__.py,sha256=_QRLaX38EUsL-kMvJITY0lYHvrq_ip9Qw4Q1YLavJSo,283
5
5
  mcp_ticketer/adapters/aitrackdown.py,sha256=ICNimTtF6rPajuVoVEpmdw2TfjYjnWvao8prUwukNn0,15210
@@ -9,7 +9,7 @@ mcp_ticketer/adapters/linear.py,sha256=PYqR30h223un50_Z-0lepPyIasK2uVHyL11mfPqtW
9
9
  mcp_ticketer/cache/__init__.py,sha256=MSi3GLXancfP2-edPC9TFAJk7r0j6H5-XmpMHnkGPbI,137
10
10
  mcp_ticketer/cache/memory.py,sha256=gTzv-xF7qGfiYVUjG7lnzo0ZcqgXQajMl4NAYUcaytg,5133
11
11
  mcp_ticketer/cli/__init__.py,sha256=YeljyLtv906TqkvRuEPhmKO-Uk0CberQ9I6kx1tx2UA,88
12
- mcp_ticketer/cli/main.py,sha256=j8rLLKIB1CtwN9ayrCw8CP35_18BqPdj1LfUeIWuCe0,25775
12
+ mcp_ticketer/cli/main.py,sha256=sGQhyaPZhCZpHM5-1aqaW3KJTfkSv2LteIKlXdavkSQ,27774
13
13
  mcp_ticketer/cli/queue_commands.py,sha256=f3pEHKZ43dBHEIoCBvdfvjfMB9_WJltps9ATwTzorY0,8160
14
14
  mcp_ticketer/cli/utils.py,sha256=NxsS91vKA8xZnDXKU2y0Gcyc4I_ctRyJj-wT7Xd1Q_Q,18589
15
15
  mcp_ticketer/core/__init__.py,sha256=NA-rDvwuAOZ9sUZVYJOWp8bR6mOBG8w_5lpWTT75JNI,318
@@ -20,16 +20,16 @@ mcp_ticketer/core/mappers.py,sha256=8I4jcqDqoQEdWlteDMpVeVF3Wo0fDCkmFPRr8oNv8gA,
20
20
  mcp_ticketer/core/models.py,sha256=K-bLuU_DNNVgjHnVFzAIbSa0kJwT2I3Hj24sCklwIYo,4374
21
21
  mcp_ticketer/core/registry.py,sha256=fwje0fnjp0YKPZ0SrVWk82SMNLs7CD0JlHQmx7SigNo,3537
22
22
  mcp_ticketer/mcp/__init__.py,sha256=Bvzof9vBu6VwcXcIZK8RgKv6ycRV9tDlO-9TUmd8zqQ,122
23
- mcp_ticketer/mcp/server.py,sha256=iWdXGYxtONY7P5YB8RJ-WwbJEaxSIGWIyCY5YOR8qU8,15669
23
+ mcp_ticketer/mcp/server.py,sha256=1zfcgTRlTnlOCkAA8wT6JvkSYexpvKWnzkizjG8tgWw,16910
24
24
  mcp_ticketer/queue/__init__.py,sha256=xHBoUwor8ZdO8bIHc7nP25EsAp5Si5Co4g_8ybb7fes,230
25
25
  mcp_ticketer/queue/__main__.py,sha256=kQd6iOCKbbFqpRdbIRavuI4_G7-oE898JE4a0yLEYPE,108
26
26
  mcp_ticketer/queue/manager.py,sha256=79AH9oUxdBXH3lmJ3kIlFf2GQkWHL6XB6u5JqVWPq60,7571
27
27
  mcp_ticketer/queue/queue.py,sha256=UgbIChWPiyI7BJNQ9DYA92D2jVMMtmVWBzotI5ML51A,11394
28
28
  mcp_ticketer/queue/run_worker.py,sha256=HFoykfDpOoz8OUxWbQ2Fka_UlGrYwjPVZ-DEimGFH9o,802
29
29
  mcp_ticketer/queue/worker.py,sha256=cVjHR_kfnGKAkiUg0HuXCnbKeKNBBEuj0XZHgIuIn4k,14017
30
- mcp_ticketer-0.1.1.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
31
- mcp_ticketer-0.1.1.dist-info/METADATA,sha256=F55wT1Fco4HeDuvZkCpZldAvLC_WSvhdpTb-eBBw5-s,11176
32
- mcp_ticketer-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
- mcp_ticketer-0.1.1.dist-info/entry_points.txt,sha256=2V70xrJlC0xiIfRRD5yX8hxhh0mX_ZpkjtmOVrztAEU,111
34
- mcp_ticketer-0.1.1.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
35
- mcp_ticketer-0.1.1.dist-info/RECORD,,
30
+ mcp_ticketer-0.1.3.dist-info/licenses/LICENSE,sha256=KOVrunjtILSzY-2N8Lqa3-Q8dMaZIG4LrlLTr9UqL08,1073
31
+ mcp_ticketer-0.1.3.dist-info/METADATA,sha256=ZTvef2hIblRp6-hp1iYiJCMzCyFCmU1V2xMZfJ0DNVY,11177
32
+ mcp_ticketer-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ mcp_ticketer-0.1.3.dist-info/entry_points.txt,sha256=o1IxVhnHnBNG7FZzbFq-Whcs1Djbofs0qMjiUYBLx2s,60
34
+ mcp_ticketer-0.1.3.dist-info/top_level.txt,sha256=WnAG4SOT1Vm9tIwl70AbGG_nA217YyV3aWFhxLH2rxw,13
35
+ mcp_ticketer-0.1.3.dist-info/RECORD,,
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  mcp-ticketer = mcp_ticketer.cli.main:main
3
- mcp-ticketer-server = mcp_ticketer.mcp.server:main