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.
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/cli/main.py +60 -0
- mcp_ticketer/mcp/server.py +53 -20
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/METADATA +2 -2
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/RECORD +9 -9
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/entry_points.txt +0 -1
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.1.1.dist-info → mcp_ticketer-0.1.3.dist-info}/top_level.txt +0 -0
mcp_ticketer/__version__.py
CHANGED
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()
|
mcp_ticketer/mcp/server.py
CHANGED
|
@@ -41,8 +41,11 @@ class MCPTicketServer:
|
|
|
41
41
|
request_id = request.get("id")
|
|
42
42
|
|
|
43
43
|
try:
|
|
44
|
-
#
|
|
45
|
-
if method == "
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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("
|
|
448
|
-
|
|
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.
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
31
|
-
mcp_ticketer-0.1.
|
|
32
|
-
mcp_ticketer-0.1.
|
|
33
|
-
mcp_ticketer-0.1.
|
|
34
|
-
mcp_ticketer-0.1.
|
|
35
|
-
mcp_ticketer-0.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|