diff --git a/mcp_zammad/server.py b/mcp_zammad/server.py index 4a5f5443..41063515 100644 --- a/mcp_zammad/server.py +++ b/mcp_zammad/server.py @@ -2623,7 +2623,7 @@ def _setup_prompts(self) -> None: """Register all prompts with the MCP server.""" @self.mcp.prompt() - def analyze_ticket(ticket_id: int) -> str: + def analyze_ticket(ticket_id: str) -> str: """Generate a prompt to analyze a ticket. Note: ticket_id must be the internal database ID (NOT the display number). @@ -2642,7 +2642,7 @@ def analyze_ticket(ticket_id: int) -> str: Use appropriate tools to gather any additional context about the customer or organization if needed.""" @self.mcp.prompt() - def draft_response(ticket_id: int, tone: str = "professional") -> str: + def draft_response(ticket_id: str, tone: str = "professional") -> str: """Generate a prompt to draft a response to a ticket. Note: ticket_id must be the internal database ID (NOT the display number). diff --git a/tests/test_server.py b/tests/test_server.py index e5e7e7be..dcae29cc 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -232,6 +232,28 @@ async def test_prompts(): assert "escalation_summary" in prompt_names +@pytest.mark.asyncio +@pytest.mark.parametrize( + ("name", "arguments"), + [ + ("analyze_ticket", {"ticket_id": "$1"}), + ("draft_response", {"ticket_id": "$1", "tone": "$2"}), + ("escalation_summary", {"group": "$1"}), + ], +) +async def test_prompts_render_with_non_numeric_arguments(name: str, arguments: dict[str, str]) -> None: + """Prompt arguments arrive as strings, so they must not be coerced to int. + + Clients that turn MCP prompts into slash commands render them with placeholder + values such as "$1" to discover their arguments. Annotating ticket_id as int made + FastMCP raise PromptError on those placeholders, so the prompts were unusable. + """ + result = await mcp.render_prompt(name, arguments) + + rendered = result.messages[0].content.text # type: ignore[union-attr] + assert "$1" in rendered + + @pytest.mark.asyncio async def test_initialization_failure(): """Test that initialization handles failures gracefully.""" @@ -1579,13 +1601,13 @@ def test_prompt_handlers(decorator_capturer): # Test analyze_ticket prompt assert "analyze_ticket" in test_prompts - result = test_prompts["analyze_ticket"](ticket_id=123) + result = test_prompts["analyze_ticket"](ticket_id="123") assert "analyze ticket with ID 123" in result assert "get_ticket tool" in result # Test draft_response prompt assert "draft_response" in test_prompts - result = test_prompts["draft_response"](ticket_id=123, tone="friendly") + result = test_prompts["draft_response"](ticket_id="123", tone="friendly") assert "draft a friendly response to ticket with ID 123" in result assert "add_article" in result