nextcloud-mcp
by raychao-oao
README.md
# nextcloud-mcp
A remote [MCP](https://modelcontextprotocol.io) server that exposes a Nextcloud account as MCP tools: files (WebDAV), calendars (CalDAV), share links (OCS Share API), and Talk chat (proxy-read).
Need admin operations (create/disable users, quotas, groups) instead? See the sibling package, [`admin/`](admin/README.md) — it's a separate server with its own tiered authorization model, not part of this one.
## Scope
User-level only: every tool call acts with the permissions of one Nextcloud account (an [App Password](https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#app-passwords), never the main account password), scoped exactly like that account logging into the Nextcloud web UI. There is no authorization model here beyond "whatever this account can already do" — for anything that needs per-caller permission tiers or targets other people's accounts, use [`nextcloud-admin-mcp`](admin/README.md).
## Design
- **Remote, not local.** One deployment, always current with the MCP spec, no per-user install to keep updated.
- **Stateless.** No MCP protocol-level session — every request is self-contained, matching the [2026-07-28 MCP spec](https://modelcontextprotocol.io/specification/2026-07-28) and Nextcloud's own stateless WebDAV/CalDAV/OCS APIs.
- **Multi-tenant.** One deployment serves any Nextcloud instance — the instance URL and credentials are per-request, not baked into the server.
- **Auth via connection-layer headers, not tool arguments.** The Nextcloud App Password never enters the LLM's context — the MCP client attaches it when it opens the connection, exactly like a local MCP server reading credentials from an env var.
## For AI agents / MCP clients: connecting
Every request to `POST /mcp` must carry:
- `Authorization: Basic <base64(username:app-password)>` — standard HTTP Basic Auth. `username`/`app-password` are the Nextcloud account this request acts as (generate the App Password under the account's own Nextcloud Settings → Security → "Create new app password").
- `X-Nextcloud-Url: https://your-nextcloud-instance.example` — the base URL of the caller's Nextcloud instance.
No `initialize` handshake is required — `tools/list` and `tools/call` work directly per-request.
Example `mcpServers` entry (Claude Code / any HTTP-transport MCP client):
```json
{
"mcpServers": {
"nextcloud-mcp": {
"type": "http",
"url": "https://your-deployment.example/mcp",
"headers": {
"Authorization": "Basic <base64(username:app-password)>",
"X-Nextcloud-Url": "https://your-nextcloud-instance.example"
}
}
}
}
```
## Tools
| Category | Tool | Description |
|---|---|---|
| Files (WebDAV) | `list_directory` | List files/folders at a path |
| | `read_file` | Read a text file's content |
| | `write_file` | Create or overwrite a file (`text` or `base64` encoding) |
| | `delete_entry` | Delete a file or folder |
| | `create_folder` | Create a folder |
| | `move_entry` | Move/rename a file or folder |
| | `copy_entry` | Copy a file or folder |
| Calendar (CalDAV) | `list_calendars` | List the account's calendars |
| | `list_events` | List events in a date range |
| | `get_event` | Get a single event |
| | `create_event` | Create an event |
| | `update_event` | Update an event (only the fields given; others are preserved) |
| | `delete_event` | Delete an event |
| Shares (OCS Share API) | `list_shares` | List a file/folder's shares |
| | `create_share` | Create a share (public link or user share) |
| | `update_share` | Update a share's password/expiration/permissions |
| | `delete_share` | Delete a share |
| Talk (proxy-read) | `list_conversations` | List the account's Talk conversations |
| | `list_messages` | List messages (`recent` or `since_last_read` mode) |
| | `get_message` | Get a single message |
| | `send_message` | Send a message (text, mentions, replies) |
## Development
```bash
npm install
npm run build
npm test
PORT=3939 node dist/index.js
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues