Nextcloud MCP Server


Experimental — This repository is fully maintained by AI (Claude). It serves as an experiment in autonomous AI-driven open-source development.
An MCP (Model Context Protocol) server that exposes Nextcloud APIs as tools for AI assistants. Connect any MCP-compatible client (Claude Desktop, Claude Code, etc.) to your Nextcloud instance and let AI manage your files, calendar, contacts, conversations, and more.
Quick Start
pip install nc-mcp-server
Set environment variables and connect:
export NEXTCLOUD_URL=https://your-nextcloud.example.com
export NEXTCLOUD_USER=your-username
export NEXTCLOUD_PASSWORD=your-app-password
nc-mcp-server
A 223rd tool, upload_file_from_path, is registered only when the operator sets NEXTCLOUD_MCP_UPLOAD_ROOT. See Files for details.
| Category | Tools | Protocol |
|---|
| Files | list, read, search, upload (text / binary / from path), copy, move, delete | WebDAV |
| File Sharing | list, get, create, update, delete shares; accept, decline and leave shares from others | OCS |
| Trashbin | list, restore, delete item, empty trash | WebDAV |
| File Versions | list, restore versions | WebDAV |
| File Comments | list, add, edit, delete comments | WebDAV |
| File Reminders | get, set, remove per-file reminders | OCS |
| System Tags | list, create, assign, unassign, delete tags | WebDAV |
| Users | get current, list, get, create, update, enable/disable, delete users | OCS |
| Groups | list groups and members, create, delete groups | OCS |
| User Status | get, set, clear status | OCS |
| Notifications | list, dismiss one, dismiss all | OCS |
| Activity | activity feed with filters, search by file, time and user, daily counts | OCS |
| Talk | conversations, messages, threads, participants, edits, reactions, read state, shared items, pins, reminders, personal settings and tags, participant and conversation management | OCS |
| Talk Polls | get, create, vote, close polls | OCS |
| Announcements | list, create, delete announcements | OCS |
| Calendar | list calendars, CRUD events | CalDAV |
| Contacts | list address books, CRUD contacts | CardDAV |
| Tasks | list lists, CRUD tasks, complete | CalDAV |
| Mail | accounts, mailboxes, messages, send, move, flags, tags | OCS + REST |
| Collectives | list, pages, create, edit, move and copy, search, tags, attachments, public links, trash, restore | OCS |
| Forms | CRUD forms, questions, options, shares, submissions + export | OCS |
| Circles (Teams) | list, CRUD, members (add/remove/promote), join/leave, search | OCS |
| Cospend | shared expense tracking — projects, members, bills | OCS |
| Unified Search | list providers, search across apps | OCS |
| App Management | list, info, enable, disable apps | OCS |
| Flow | list, create, update, delete automation rules; list what they can be built from | OCS |
Security: Permission Model
Every tool has a required permission level. You control what the AI is allowed to do:
| Level | What it can do | Environment variable |
|---|
read (default) | List files, read files, get users, view notifications | NEXTCLOUD_MCP_PERMISSIONS=read |
write | Everything in read + upload files, send messages, create events | NEXTCLOUD_MCP_PERMISSIONS=write |
destructive | Everything in write + delete files, remove shares, empty trash | NEXTCLOUD_MCP_PERMISSIONS=destructive |
If a tool is called without sufficient permission, it returns a clear error explaining what permission is needed — no silent failures, no accidental deletions.
Installation
pip install nc-mcp-server
Or with pipx / uvx for isolated installation:
pipx install nc-mcp-server
# or
uvx nc-mcp-server
Or from source:
git clone https://github.com/cloud-py-api/nc_mcp_server.git
cd nc_mcp_server
pip install -e .
Configuration
Set these environment variables:
# Required
export NEXTCLOUD_URL=https://your-nextcloud.example.com
export NEXTCLOUD_USER=your-username
export NEXTCLOUD_PASSWORD=your-app-password # Use an app password, not your main password!
# Optional
export NEXTCLOUD_MCP_PERMISSIONS=read # read (default), write, or destructive
export NEXTCLOUD_MCP_RETRY_MAX=3 # max retries on 429/503 (default: 3, 0 to disable)
export NEXTCLOUD_MCP_UPLOAD_ROOT= # unset (default). If set to an absolute directory,
# enables upload_file_from_path, restricted to files
# inside that directory (symlinks resolved).
Getting an App Password
- Log into your Nextcloud instance
- Go to Settings > Security
- Under "Devices & sessions", create a new app password
- Use this password for
NEXTCLOUD_PASSWORD
Since Nextcloud 34.0.1 an app-password session never counts as password-confirmed, so with an app password the admin tools Nextcloud guards with password confirmation (create_user, update_user, set_user_enabled, delete_user, create_group, delete_group, enable_app, disable_app) fail with "Password confirmation is required". To use them, allow the MCP server's IP address in config.php (Nextcloud 34.0.3 and newer), e.g. 'allowed_no_password_confirmation_ranges' => ['192.0.2.10/32']. With the account's login password they work without that: when Nextcloud asks for a confirmation, the server repeats the request as a fresh login. Accounts with two-factor authentication cannot log in with their password here, so they need an app password and the exemption.
Usage
With Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"nextcloud": {
"command": "nc-mcp-server",
"env": {
"NEXTCLOUD_URL": "https://your-nextcloud.example.com",
"NEXTCLOUD_USER": "your-username",
"NEXTCLOUD_PASSWORD": "your-app-password",
"NEXTCLOUD_MCP_PERMISSIONS": "read"
}
}
}
}
With Claude Code
claude mcp add nextcloud \
-e NEXTCLOUD_URL=https://your-nextcloud.example.com \
-e NEXTCLOUD_USER=your-username \
-e NEXTCLOUD_PASSWORD=your-app-password \
-e NEXTCLOUD_MCP_PERMISSIONS=read \
-- nc-mcp-server
As HTTP Server (for containers/remote)
nc-mcp-server --transport http
# Listens on http://0.0.0.0:8100 by default
Stdio Mode (default)
nc-mcp-server
# Communicates via stdin/stdout — used by MCP clients like Claude Desktop
Files
| Tool | Permission | Description |
|---|
list_directory | read | List files and folders in a directory |
get_file | read | Read a file's content (returns images as MCP ImageContent) |
search_files | read | Search files by name, MIME type, or path pattern |
upload_file | write | Upload or overwrite a text file |
upload_file_binary | write | Upload or overwrite a binary file (images, PDFs, archives) from base64-encoded content |
upload_file_from_path | write | Stream a local file from the server's filesystem — only registered when NEXTCLOUD_MCP_UPLOAD_ROOT is set |
create_directory | write | Create a new directory |
copy_file | write | Copy a file or directory |
move_file | destructive | Move or rename a file |
delete_file | destructive | Delete a file or directory (moves to trash) |
upload_file_from_path is off by default because it gives the AI read access to the local filesystem. To enable it, set NEXTCLOUD_MCP_UPLOAD_ROOT to an absolute directory — only files resolving inside that directory (after symlink resolution) can be uploaded. This is the right choice when you need to upload multi-GB files that would blow past the size limit of an inline base64 tool call; the body is streamed in chunks rather than loaded into memory.
File Sharing
| Tool | Permission | Description |
|---|
list_shares | read | List shares for a file/folder, all your shares, or the shares others gave you (federated included) |
get_share | read | Get details of a specific share |
list_pending_shares | read | List shares offered to you that wait to be accepted, from this server and federated |
create_share | write | Share a file/folder (user, group, public link, email) |
update_share | write | Update share permissions, expiration, password, etc. |
accept_share | write | Accept a pending share |
delete_share | destructive | Remove a share, or leave one you received |
decline_share | destructive | Decline a pending share |
Trashbin
| Tool | Permission | Description |
|---|
list_trash | read | List deleted files in the trash bin |
restore_trash_item | write | Restore a file from trash to its original location |
delete_trash_item | destructive | Permanently delete a single item from trash |
empty_trash | destructive | Permanently delete all items in trash |
File Versions
| Tool | Permission | Description |
|---|
list_versions | read | List version history of a file |
restore_version | write | Restore a previous version of a file |
| Tool | Permission | Description |
|---|
list_comments | read | List comments on a file |
add_comment | write | Add a comment to a file |
edit_comment | write | Edit an existing comment |
delete_comment | destructive | Delete a comment |
File Reminders
| Tool | Permission | Description |
|---|
get_file_reminder | read | Get the reminder set on a file (null if none) |
set_file_reminder | write | Set or replace a reminder due date (ISO 8601, must be in the future) |
remove_file_reminder | destructive | Remove the reminder from a file |
| Tool | Permission | Description |
|---|
list_tags | read | List all available tags |
get_file_tags | read | Get tags assigned to a file |
create_tag | write | Create a new tag |
assign_tag | write | Assign a tag to a file |
unassign_tag | destructive | Remove a tag from a file |
delete_tag | destructive | Delete a tag |
Users
| Tool | Permission | Description |
|---|
get_current_user | read | Get current authenticated user info |
list_users | read | List or search users |
get_user | read | Get specific user details |
create_user | write | Create a new user (admin only) |
update_user | write | Change display name, email, password, quota, language, manager, groups and sub-admin groups in one call (Nextcloud 34+) |
set_user_enabled | write | Enable or disable a user account (admin or sub-admin); disabling needs destructive |
delete_user | destructive | Delete a user (admin only) |
update_user has Nextcloud validate every field before applying any of them. Users can change their own display name, email, language and password with it; Nextcloud 34 and 35 only accept the underlying call from admins and sub-admins, so for a regular user's own account the tool sets those fields one at a time instead, without that all-or-nothing check. Passing password, groups or subadmin_groups needs the destructive level, as does disabling an account with set_user_enabled.
Groups
| Tool | Permission | Description |
|---|
list_groups | read | List or search groups with member counts (admin) |
list_group_members | read | List the users in a group (admins, the group's sub-admins and members) |
create_group | write | Create a group (admin only) |
delete_group | destructive | Delete a group (admin only) |
User Status
| Tool | Permission | Description |
|---|
get_user_status | read | Get a user's status (online, away, dnd, etc.) |
set_user_status | write | Set your status and custom message |
clear_user_status | destructive | Clear your status |
Notifications
| Tool | Permission | Description |
|---|
list_notifications | read | List all notifications |
dismiss_notification | write | Dismiss a single notification |
dismiss_all_notifications | write | Dismiss all notifications |
Activity
| Tool | Permission | Description |
|---|
get_activity | read | View recent activity with filtering, sorting, and pagination; search by file path, time range and user (Nextcloud 35) |
list_activity_filters | read | List the activity filters this server offers |
get_activity_counts | read | Count activities per day over the last days (Nextcloud 35) |
Talk
| Tool | Permission | Description |
|---|
list_conversations | read | List all Talk conversations |
get_conversation | read | Get conversation details |
get_messages | read | Get messages from a conversation, or from one thread |
get_participants | read | List participants in a conversation |
list_threads | read | List the most recently active threads in a conversation |
get_thread | read | Get a thread's title, reply count and first/last message |
list_subscribed_threads | read | List the threads you follow across all conversations |
get_message_context | read | Get the messages before and after one message |
get_reactions | read | List who reacted to a message, and with what |
list_shared_items | read | List files, media, polls, locations and more shared in a conversation |
search_mentions | read | Find who can be mentioned, with the text to put in a message |
list_message_reminders | read | List your upcoming message reminders |
list_conversation_tags | read | List your personal conversation tags |
list_conversation_presets | read | List the presets create_conversation can start from |
send_message | write | Send a message; can start a thread or post into one |
create_conversation | write | Create a one-to-one, group or public conversation, optionally from a preset |
update_conversation | write | Rename, describe, lock (read-only) or open (public) a conversation (moderators); making it private needs destructive; owners can preserve it (Talk 25+) |
add_participant | write | Add a user, group, team, email guest or federated user (moderators) |
set_participant_role | write | Make a participant owner (Talk 25+), moderator or user |
rename_thread | write | Rename a thread |
set_thread_notification_level | write | Set your notification level for a thread |
edit_message | write | Edit a message (own ones, or any as a moderator of a group conversation; within 24 hours) |
add_reaction | write | React to a message with an emoji |
mark_conversation_read | write | Mark a conversation read, fully or up to a message |
mark_conversation_unread | write | Mark the last message unread again |
set_conversation_preferences | write | Your own settings: favorite, archived, important, sensitive, message and call notifications |
pin_message | write | Pin a message for everyone, optionally until a time (moderators) |
set_message_reminder | write | Get a notification about a message later |
create_conversation_tag | write | Create a personal conversation tag |
rename_conversation_tag | write | Rename a conversation tag |
set_conversation_tags | write | Set which of your tags a conversation has |
delete_message | destructive | Delete a message |
leave_conversation | destructive | Leave a conversation |
remove_participant | destructive | Remove someone from a conversation (moderators) |
delete_conversation | destructive | Delete a conversation for everyone (moderators; one-to-one ones can only be left) |
remove_reaction | destructive | Take back your reaction to a message |
unpin_message | destructive | Unpin a message for everyone, or hide it only for you |
remove_message_reminder | destructive | Cancel a message reminder |
delete_conversation_tag | destructive | Delete a conversation tag |
The thread tools need a Talk version that advertises the threads capability (Talk 22, which ships with Nextcloud 32, and newer), so every Nextcloud release supported here has them. A thread ID is the message ID of the thread's first message.
Messages read back with their mentions and shared objects filled in ("@Jane Doe", "report.pdf") instead of the placeholders Talk stores ({mention-user1}, {file}).
Talk Polls
| Tool | Permission | Description |
|---|
get_poll | read | Get poll details and results |
create_poll | write | Create a poll in a conversation |
vote_poll | write | Vote on a poll |
close_poll | write | Close a poll |
Announcements
| Tool | Permission | Description |
|---|
list_announcements | read | List announcements |
create_announcement | write | Create an announcement |
delete_announcement | destructive | Delete an announcement |
Calendar
| Tool | Permission | Description |
|---|
list_calendars | read | List user's calendars |
get_events | read | Get events from a calendar (with date filtering) |
get_event | read | Get a single event by UID |
create_event | write | Create a calendar event |
update_event | write | Update an event (partial updates supported) |
delete_event | destructive | Delete a calendar event |
| Tool | Permission | Description |
|---|
list_addressbooks | read | List user's address books |
get_contacts | read | Get contacts with pagination |
get_contact | read | Get a single contact by UID |
create_contact | write | Create a contact (multi-value email/phone supported) |
update_contact | write | Update a contact (ETag concurrency control) |
delete_contact | destructive | Delete a contact |
Tasks
| Tool | Permission | Description |
|---|
list_task_lists | read | List task lists (CalDAV VTODO collections) |
get_tasks | read | List tasks in a list (with status/completed filters) |
get_task | read | Get a single task by UID |
create_task | write | Create a task (due date, priority, categories, etc.) |
update_task | write | Update a task (partial updates supported) |
complete_task | write | Mark a task as completed |
delete_task | destructive | Delete a task |
Mail
| Tool | Permission | Description |
|---|
list_mail_accounts | read | List mail accounts |
list_mailboxes | read | List mailboxes (folders) for an account |
list_mail_messages | read | List messages in a mailbox |
get_mail_message | read | Get full message content |
send_mail | write | Send an email |
move_mail_message | write | Move a message to another mailbox of the same account (its ID changes) |
set_mail_message_flags | write | Mark as read/unread, starred, answered |
create_mail_tag | write | Create a tag, or get the existing one with the same label |
add_mail_message_tag | write | Tag a message |
remove_mail_message_tag | write | Remove a tag from a message |
Collectives
| Tool | Permission | Description |
|---|
list_collectives | read | List all collectives |
get_collective_pages | read | List pages in a collective |
get_collective_page | read | Get a page's content |
search_collective_pages | read | Search the text of a collective's pages |
list_recent_collective_pages | read | List the most recently changed pages across collectives |
list_collective_tags | read | List a collective's page tags |
list_collective_page_attachments | read | List the files attached to a page |
list_collective_shares | read | List your public links to a collective and its pages |
create_collective | write | Create a new collective |
create_collective_page | write | Create a page in a collective, optionally with its text |
update_collective_page | write | Change a page's text, title or emoji |
move_collective_page | write | Move or copy a page under another page, also into another collective |
create_collective_tag | write | Create a page tag |
update_collective_tag | write | Rename a tag or change its color |
set_collective_page_tags | write | Set which tags a page has |
share_collective | write | Create a public link to a collective or one page, optionally editable and with a password |
update_collective_share | write | Change a public link's editing and password |
trash_collective | destructive | Move a collective to trash |
delete_collective | destructive | Permanently delete a trashed collective, optionally with its team (and, when told, the team's folder) |
trash_collective_page | destructive | Move a page to trash |
delete_collective_page | destructive | Permanently delete a trashed page |
delete_collective_tag | destructive | Delete a tag, taking it off its pages |
delete_collective_share | destructive | Remove a public link |
restore_collective | write | Restore a collective from trash |
restore_collective_page | write | Restore a page from trash |
| Tool | Permission | Description |
|---|
list_forms | read | List forms (filter by ownership: "owned" or "shared"; omit to merge both) |
get_form | read | Get a form with questions, options, shares |
list_questions | read | List questions on a form |
get_question | read | Get a single question |
list_submissions | read | List submissions (owner only), with pagination and text filter |
get_submission | read | Get a single submission with answers |
create_form | write | Create an empty form or clone from an existing form |
update_form | write | Update form properties (title, access, state, maxSubmissions, etc.) |
create_question | write | Add a question (short, long, multiple, dropdown, date, file, grid, …) |
update_question | write | Update question properties |
reorder_questions | write | Reorder all questions on a form |
create_options | write | Add answer options to a choice question |
update_option | write | Update option text |
reorder_options | write | Reorder options within a question |
create_form_share | write | Share a form with user, group, circle, or link |
update_form_share | write | Update share permissions |
submit_form | write | Submit answers to a form |
update_submission | write | Edit an existing submission (requires allowEditSubmissions) |
export_submissions | write | Export submissions as a spreadsheet to a Nextcloud folder |
delete_form | destructive | Delete a form and all its content |
delete_question | destructive | Delete a question |
delete_option | destructive | Delete an option |
delete_form_share | destructive | Revoke a share |
delete_submission | destructive | Delete one submission |
delete_all_submissions | destructive | Delete every submission on a form |
Circles (Teams)
| Tool | Permission | Description |
|---|
list_circles | read | List circles the current user can see |
get_circle | read | Get a single circle including the current user's membership |
list_circle_members | read | List members of a circle |
search_circles | read | Search circles and candidate members (users/groups/mail) by term |
create_circle | write | Create a circle; caller becomes owner. Optionally with a team folder (Nextcloud 35 + Team folders app) |
update_circle_name | write | Rename a circle |
update_circle_description | write | Update description |
update_circle_config | write | Update config bitmask (VISIBLE, OPEN, INVITE, HIDDEN, etc.) |
add_circle_member | write | Add a user, group, email, or nested circle as a member |
update_circle_member_level | write | Promote/demote a member (member/moderator/admin/owner) |
join_circle | write | Join an open circle |
leave_circle | destructive | Leave a circle. The owner's leave passes ownership to any other member (pending invitations count), or destroys the circle when no one else is left; refuses to lose a team folder unless told |
delete_circle | destructive | Delete a circle; refuses to delete its team folder and files unless told |
remove_circle_member | destructive | Kick a member |
Cospend
Shared expense tracking ("who paid for what"). Requires the Cospend app to be installed and enabled. All routes are OCS at /ocs/v2.php/apps/cospend/api/v1/.
| Tool | Permission | Description |
|---|
list_cospend_projects | read | List projects the user can access |
get_cospend_project | read | Get full project info (members, balance, shares, settings) |
get_cospend_project_statistics | read | Per-member spending stats (paid/spent/balance) with filters |
get_cospend_project_settlement | read | Suggested reimbursement transactions to settle a project |
list_cospend_members | read | List members of a project |
list_cospend_bills | read | List bills with filters (payer, category, search, pagination) |
get_cospend_bill | read | Get a single bill |
create_cospend_project | write | Create a project (caller becomes ADMIN) |
update_cospend_project | write | Update project name, currency, sort, archive, etc. |
create_cospend_member | write | Add a member (free-form name or linked to a Nextcloud user) |
update_cospend_member | write | Update name/weight/color/activated/userid |
create_cospend_bill | write | Create a bill (defaults date to today if neither date nor timestamp set) |
update_cospend_bill | write | Update any bill field |
delete_cospend_project | destructive | Delete a project and all its data |
delete_cospend_member | destructive | Delete (or soft-disable if member has bills) |
delete_cospend_bill | destructive | Delete a bill (default: trash; pass move_to_trash=False to purge) |
Unified Search
| Tool | Permission | Description |
|---|
list_search_providers | read | List available search providers (files, mail, talk, etc.) |
unified_search | read | Search across one or more providers with pagination |
App Management
| Tool | Permission | Description |
|---|
list_apps | read | List installed apps |
get_app_info | read | Get detailed app information |
enable_app | write | Enable an app (admin only) |
disable_app | destructive | Disable an app (admin only) |
Flow
| Tool | Permission | Description |
|---|
list_flows | read | List Flow rules of the user or (admin) global scope |
get_flow_options | read | List the operations, entities, events and checks a rule can use, with operators and value formats for the built-in checks |
create_flow | write | Create a rule; global rules need destructive |
update_flow | write | Change a rule's name, checks, settings or events; global rules need destructive |
delete_flow | destructive | Delete a rule |
The available operations depend on the installed apps (Talk adds "Write to conversation", for example), and Nextcloud has no API that lists them, so get_flow_options reads them from the Flow settings page. Global rules act on every user's files, which is why they need the destructive level. Rules that would run a command or command-line arguments of the agent's choosing on the server (the workflow_script app's operation, or workflow_ocr with custom ocrmypdf arguments) are refused at any level.
Development
# Clone and install
git clone https://github.com/cloud-py-api/nc_mcp_server.git
cd nc_mcp_server
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest # Unit tests
pytest tests/integration/ -v # Integration tests (needs running Nextcloud)
# Lint & type check
ruff check . && ruff format --check .
pyright
Integration Tests
Integration tests run against a real Nextcloud instance. Set the environment variables and run:
export NEXTCLOUD_URL=http://localhost:8080
export NEXTCLOUD_USER=admin
export NEXTCLOUD_PASSWORD=admin
pytest tests/integration/ -v
CI runs the integration tests against Nextcloud 34 and 35 using the official Docker images.
About This Project
This project is an experiment in AI-autonomous open-source development. The entire codebase — including this README — is written and maintained by Claude (Anthropic's AI assistant). Human oversight is limited to:
- High-level design decisions
- Code review of pull requests
- Resolving architectural questions
The goal is to explore how far autonomous AI development can go in building production-quality, well-tested software.