Nextcloud Talk Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Nextcloud Talk Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An MCP server for Nextcloud Talk (Spreed) — 24 tools covering conversations, messages, participants, reactions, reminders, and file sharing, straight from your agent.
The established Nextcloud MCP servers (cbcoutinho, No-Smoke, hithereiamaliff) cover Notes, Calendar, Contacts, Tables, and WebDAV — but not Talk. This project fills that gap: it wraps the Talk/Spreed OCS API as MCP tools, primarily for use with Claude Desktop on macOS.
This is a monorepo with two packages under packages/:
| Package | What it is |
|---|---|
nextcloud-talk-core | The reusable, MCP-free OCS client: TalkClient, typed models, OCSClient, config, errors. On PyPI as nextcloud-talk-core — other projects (e.g. a polling bridge) depend on it directly. |
nextcloud-talk-mcp | The MCP server — a thin wrapper that exposes TalkClient as MCP tools. |
The MCP server is the focus of this README; for embedding the client in your own Python code, see nextcloud-talk-core and the snippet under Using the core directly.
Auth is via a Nextcloud app password (Basic Auth), which works even on SSO/SAML instances with two-factor authentication — the app password bypasses the identity provider server-side, so no interactive login or second factor is needed for API access.
| Tool | Kind | Description |
|---|---|---|
list_conversations() | read | List all Talk conversations (rooms) the user is part of — token, name, type, unread, lastMessage. |
read_messages(token, limit=30) | read | Read the most recent messages in a conversation. Each message includes an attachments list (shared files, with name/path/mimetype/size where available). |
wait_for_messages(token, last_known_message_id, limit=100, timeout=30) | read | Long-poll for NEW messages after a given message id; blocks up to timeout seconds (max 60). |
list_mentions(token, limit=20) | read | List users/rooms that can be @-mentioned in a conversation (autocomplete candidates). |
send_message(token, message, reply_to=None) | write | Send a message, optionally as a reply to a message id. |
edit_message(token, message_id, message) | write | Edit an existing message (needs edit-messages capability). |
delete_message(token, message_id) | destructive | Delete a message for ALL participants. Cannot be undone. |
mark_as_read(token, last_read_message=None) | write | Mark a conversation as read (optionally up to a message id). |
mark_as_unread(token) | write | Mark a conversation as unread. |
share_file_to_conversation(token, path, caption=None) | write | Share an existing Nextcloud file (WebDAV path) into a conversation. Does not upload — the file must already exist. |
| Tool | Kind | Description |
|---|---|---|
list_reactions(token, message_id, reaction=None) | read | List reactions on a message, keyed by emoji. |
add_reaction(token, message_id, reaction) | write | Add an emoji reaction to a message. |
remove_reaction(token, message_id, reaction) | write | Remove your emoji reaction from a message. |
| Tool | Kind | Description |
|---|---|---|
get_reminder(token, message_id) | read | Get the reminder set on a message (if any). |
set_reminder(token, message_id, timestamp) | write | Set a reminder; timestamp is the Unix time (seconds) it fires. |
delete_reminder(token, message_id) | write | Clear the reminder on a message. |
| Tool | Kind | Description |
|---|---|---|
create_conversation(room_type, invite=None, room_name=None, source=None) | write | Create a conversation. room_type: 1=one-to-one (set invite), 2=group, 3=public (set room_name). |
rename_conversation(token, name) | write | Rename a conversation (max 255 chars). |
set_description(token, description) | write | Set the conversation description (max 2000 chars). |
delete_conversation(token) | destructive | Permanently delete a conversation and its history for ALL participants. Cannot be undone. |
| Tool | Kind | Description |
|---|---|---|
list_participants(token) | read | List participants — attendeeId (key for the tools below), actorId, displayName, participantType, permissions. |
add_participant(token, new_participant, source="users") | write | Add a participant. source: users, groups, circles, emails, federated_users. |
remove_participant(token, attendee_id) | destructive | Remove a participant's access. |
set_participant_permissions(token, attendee_id, mode="set", can_*=...) | write | Set permissions via named boolean flags (can_publish_audio, can_post_chat, …). mode: set / add / remove. |
token always comes from list_conversations(). Conversation type codes: 1 = one-to-one, 2 = group, 3 = public, 4 = changelog, 6 = "Note to self".
Write and destructive tools require confirmation. Read-only tools carry areadOnlyHint: trueannotation; destructive ones (delete_message,delete_conversation,remove_participant) carrydestructiveHint: true. Write tools carry neither, so a well-behaved MCP client treats them as non-read-only and prompts before running them. That confirmation step is intentional — do not bypass it, especially on shared or institutional channels.
Requires Python ≥ 3.10. Both packages are on PyPI; installing the server pulls in the core automatically.
uvx nextcloud-talk-mcppipx install nextcloud-talk-mcppip install nextcloud-talk-mcpgit clone https://github.com/leiverkus/nextcloud-talk-mcp.git
cd nextcloud-talk-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -e packages/nextcloud-talk-core -e packages/nextcloud-talk-mcpTo embed the Talk client in your own Python project (no MCP), depend on just the core package:
pip install nextcloud-talk-corefrom nextcloud_talk_core import TalkClient
with TalkClient.from_env() as talk: # reads NC_URL / NC_USER / NC_APP_PASSWORD
for c in talk.list_conversations():
print(c.token, c.name, c.unread)The server reads three environment variables:
| Variable | Example | Notes |
|---|---|---|
NC_URL | https://cloud.example.com | Base URL, no trailing slash. |
NC_USER | your-username | Your Nextcloud username. |
NC_APP_PASSWORD | xxxxx-xxxxx-xxxxx-xxxxx | An app password, not your login password. |
See .env.example for a template. Missing or malformed variables produce a clear error at startup — not a traceback.
talk-mcp) and click Create new app password.On SSO/SAML instances (e.g. universities), this is the only way to use the API. The app password authenticates against Nextcloud directly, bypassing the identity provider and any two-factor prompt. Never use your actual login password.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"nextcloud-talk": {
"command": "uvx",
"args": ["nextcloud-talk-mcp"],
"env": {
"NC_URL": "https://cloud.example.com",
"NC_USER": "your-username",
"NC_APP_PASSWORD": "xxxxx-xxxxx-xxxxx-xxxxx"
}
}
}
}If you installed from source into a virtualenv, point command at that interpreter instead:
{
"mcpServers": {
"nextcloud-talk": {
"command": "/absolute/path/to/nextcloud-talk-mcp/.venv/bin/python",
"args": ["-m", "nextcloud_talk_mcp"],
"env": {
"NC_URL": "https://cloud.example.com",
"NC_USER": "your-username",
"NC_APP_PASSWORD": "xxxxx-xxxxx-xxxxx-xxxxx"
}
}
}
}Restart Claude Desktop; the tools then appear under the nextcloud-talk server.
.env is gitignored; only .env.example (placeholders) is committed.send_message) are not marked read-only, and destructive ones (delete_message, delete_conversation, remove_participant) carry destructiveHint, so MCP clients ask for confirmation first. This is by design — leave it on.Working on the server itself? See AGENTS.md for the conventions — OCS envelope handling, per-domain API versions, write/destructive annotations, the test fixture pattern, and the live-smoke discipline.
MIT © Patrick Leiverkus
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.