feat(talk): add MCP integration for Nextcloud Talk (spreed)
Adds 6 MCP tools so an LLM can read a user's Talk conversations and post messages on their behalf, addressing the "read my chats and reply" use case from issue #720: - talk_list_conversations - talk_get_conversation - talk_get_messages - talk_list_participants - talk_send_message (auto-attaches a referenceId for retry dedup) - talk_mark_as_read Edit/delete messages, reactions, threads, and call/session ops are intentionally out of scope for this first PR. The TalkClient also exposes create_conversation/delete_conversation for the integration test fixture; these are not registered as MCP tools. A post-installation hook enables spreed in the docker dev env so the integration suite has a real Talk backend to talk to. Closes #720 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a9c5759869
commit
69814f30e3
+43
-3
@@ -38,7 +38,8 @@ DEFAULT_FULL_SCOPES = (
|
||||
"deck.read deck.write "
|
||||
"tables.read tables.write "
|
||||
"files.read files.write "
|
||||
"sharing.read sharing.write"
|
||||
"sharing.read sharing.write "
|
||||
"talk.read talk.write"
|
||||
)
|
||||
|
||||
# Read-only scopes (all read scopes across apps) - should match DEFAULT_FULL_SCOPES read portion
|
||||
@@ -52,7 +53,8 @@ DEFAULT_READ_SCOPES = (
|
||||
"deck.read "
|
||||
"tables.read "
|
||||
"files.read "
|
||||
"sharing.read"
|
||||
"sharing.read "
|
||||
"talk.read"
|
||||
)
|
||||
|
||||
# Write-only scopes (all write scopes across apps) - should match DEFAULT_FULL_SCOPES write portion
|
||||
@@ -66,7 +68,8 @@ DEFAULT_WRITE_SCOPES = (
|
||||
"deck.write "
|
||||
"tables.write "
|
||||
"files.write "
|
||||
"sharing.write"
|
||||
"sharing.write "
|
||||
"talk.write"
|
||||
)
|
||||
|
||||
|
||||
@@ -916,6 +919,43 @@ async def temporary_board_with_card(
|
||||
logger.error(f"Unexpected error deleting temporary card {card.id}: {e}")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def temporary_conversation(nc_client: NextcloudClient):
|
||||
"""Create a temporary Talk conversation and clean it up after the test.
|
||||
|
||||
Yields a dict with the room ``token``, ``id``, and ``name``.
|
||||
"""
|
||||
unique_suffix = uuid.uuid4().hex[:8]
|
||||
room_name = f"MCP Test Room {unique_suffix}"
|
||||
token = None
|
||||
|
||||
logger.info(f"Creating temporary Talk conversation: {room_name}")
|
||||
try:
|
||||
room = await nc_client.talk.create_conversation(room_name=room_name)
|
||||
token = room.token
|
||||
logger.info(f"Temporary Talk conversation created (token={token})")
|
||||
yield {"token": token, "id": room.id, "name": room_name}
|
||||
|
||||
finally:
|
||||
if token:
|
||||
logger.info(f"Cleaning up temporary Talk conversation token={token}")
|
||||
try:
|
||||
await nc_client.talk.delete_conversation(token)
|
||||
logger.info(f"Successfully deleted Talk conversation token={token}")
|
||||
except HTTPStatusError as e:
|
||||
if e.response.status_code not in [404, 403]:
|
||||
logger.error(f"HTTP error deleting Talk conversation {token}: {e}")
|
||||
else:
|
||||
logger.warning(
|
||||
f"Talk conversation {token} already deleted or access denied "
|
||||
f"({e.response.status_code})."
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Unexpected error deleting Talk conversation {token}: {e}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def shared_test_calendar_name():
|
||||
"""Unique calendar name for the entire test session."""
|
||||
|
||||
Reference in New Issue
Block a user