Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions libs/arcade-mcp-server/arcade_mcp_server/managers/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,13 @@ async def update_prompt(
prompt: Prompt,
handler: Callable[[dict[str, str]], list[PromptMessage]] | None = None,
) -> Prompt:
# Ensure exists
# Remove the existing entry (this also verifies it exists). Removing by the
# original ``name`` rather than just upserting by ``prompt.name`` ensures a
# rename (prompt.name != name) does not leave the old entry orphaned in the
# registry. Mirrors ResourceManager.update_resource, which handles URI
# changes the same way.
try:
_ = await self.registry.get(name)
await self.registry.remove(name)
except KeyError:
raise NotFoundError(f"Prompt '{name}' not found")

Expand Down
27 changes: 27 additions & 0 deletions libs/tests/arcade_mcp_server/test_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,30 @@ async def error_prompt(args: dict[str, str]):

with pytest.raises(PromptError):
await manager.get_prompt("error_prompt", {})

@pytest.mark.asyncio
async def test_update_prompt_rename_does_not_orphan_old_entry(
self, prompt_manager, sample_prompt, prompt_function
):
"""A rename via update_prompt must not leave the old entry orphaned."""
await prompt_manager.add_prompt(sample_prompt, prompt_function)

renamed = sample_prompt.model_copy(update={"name": "greeting_v2"})
await prompt_manager.update_prompt(sample_prompt.name, renamed, prompt_function)

prompts = await prompt_manager.list_prompts()
assert len(prompts) == 1
assert prompts[0].name == "greeting_v2"
with pytest.raises(NotFoundError):
await prompt_manager.get_prompt("greeting", {"name": "Bob"})
result = await prompt_manager.get_prompt("greeting_v2", {"name": "Bob"})
assert isinstance(result, GetPromptResult)

@pytest.mark.asyncio
async def test_update_prompt_missing_raises_not_found(
self, prompt_manager, sample_prompt, prompt_function
):
"""Updating a prompt that does not exist raises NotFoundError."""
missing = sample_prompt.model_copy(update={"name": "nope"})
with pytest.raises(NotFoundError):
await prompt_manager.update_prompt("nope", missing, prompt_function)
Loading