Skip to main content
Glama
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