Expose a Nextcloud/WebDAV repository to Model Context Protocol (MCP) clients (Claude Desktop, IDE plug-ins, etc.) so agents can browse folders, filter directories, and stream files directly into their workflows.
- Lists directories/files from any Nextcloud-compatible WebDAV endpoint (personal accounts or public share links).
- Publishes MCP resources so agents can click through folders and fetch files without hand‑crafting URLs.
- Ships three MCP tools (
list_webdav_directory,list_webdav_directories_only,read_webdav_file) plus matching resource templates. - Supports credentialed access, public shares, file-size limits, and configurable directory depth.
- Runnable with Docker or plain Node.js (TypeScript project compiled to
build/index.js).
- Node.js 18+ (for local runs; the compiled server relies on the built-in
fetchimplementation). - npm (ships with Node) for building TypeScript.
- Docker 24+ (optional) if you prefer containerized deployment.
- Claude Desktop 0.5+ or another MCP-compatible host.
-
Build the image
docker build -t webdav-mcp-server:latest . -
Wire it into Claude Desktop
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Windows:%APPDATA%\Claude\claude_desktop_config.json{ "mcpServers": { "webdav": { "command": "docker", "args": [ "run", "-i", "--rm", "-e", "NEXTCLOUD_BASE_URL=https://nextcloud.example.com", "-e", "NEXTCLOUD_USERNAME=files-user", "-e", "WEBDAV_USERNAME=files-login", "-e", "WEBDAV_PASSWORD=files-password", "webdav-mcp-server:latest" ] } } } -
Restart Claude Desktop so the server is loaded. You should see
WebDAV MCP Server running on stdioin the Claude logs or container output.
npm install # install dependencies
npm run build # compile TypeScript → build/index.js
npm start # equivalent to node build/index.jsPoint Claude Desktop at the compiled entry point:
{
"mcpServers": {
"webdav": {
"command": "node",
"args": [
"/absolute/path/to/webdav-mcp-server/build/index.js"
],
"env": {
"NEXTCLOUD_BASE_URL": "https://nextcloud.example.com",
"NEXTCLOUD_USERNAME": "files-user",
"WEBDAV_USERNAME": "files-login",
"WEBDAV_PASSWORD": "files-password"
}
}
}
}| Variable | Purpose | Default |
|---|---|---|
NEXTCLOUD_BASE_URL |
Base URL (https://nextcloud.example.com). |
https://glacier.nurral.com (placeholder) |
NEXTCLOUD_USERNAME |
User whose files are exposed. | your-username |
WEBDAV_URL |
Override the full DAV endpoint. Also accepts public share links (https://…/s/<token>). |
${NEXTCLOUD_BASE_URL}/remote.php/dav/files/${NEXTCLOUD_USERNAME} |
WEBDAV_USERNAME |
Login/username or share token sent via HTTP Basic auth. | Auto-detected from WEBDAV_URL share tokens, otherwise required. |
WEBDAV_PASSWORD |
Password for private accounts or password-protected shares. | Empty string |
WEBDAV_MAX_FILE_BYTES |
Max bytes returned from resources/read / read_webdav_file. |
10_485_760 (10 MB) |
MAX_DIRECTORY_RESOURCES |
How many entries resources/list exposes from the root directory. |
25 |
When you pass a share URL such as https://nextcloud.example.com/s/abc123, the server rewrites it to https://nextcloud.example.com/public.php/webdav and infers abc123 as the username. Provide the share password via WEBDAV_PASSWORD if required, otherwise leave it blank:
{
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "WEBDAV_URL=https://nextcloud.example.com/s/abc123",
"-e", "WEBDAV_PASSWORD=",
"webdav-mcp-server:latest"
]
}| Tool | Description | Key params |
|---|---|---|
list_webdav_directory |
Returns every child entry (files + directories) for the requested path. | path (default /) |
list_webdav_directories_only |
Same as above but filters to folders. Useful for drilling down quickly. | path |
read_webdav_file |
Streams a file via text or base64 blob depending on MIME type. | path or resourceUri |
Each tool response includes path + resourceUri fields so you can pivot into resources/read.
resources/listalways exposes the root directory plus up toMAX_DIRECTORY_RESOURCEStop-level children, each represented aswebdav-directory://…orwebdav-file://….resources/readaccepts those URIs (or even a rawhttps://WebDAV URL) and enforces theWEBDAV_MAX_FILE_BYTESlimit.resources/templates/listpublishes:webdav-file– supply/Documents/report.mdetc.webdav-directory– supply/Projects,/etc.
The templates emit ready-to-read URIs so you never need to manually encode DAV paths.
Downloads larger than WEBDAV_MAX_FILE_BYTES are rejected before they reach the MCP client. Adjust the env var when you trust the source and understand the cost of transferring bigger blobs.
- Manual smoke test inside Docker:
Expect
docker run -i --rm webdav-mcp-server:latest
WebDAV MCP Server running on stdio. - Outside Docker, run
npm startand connect via Claude’s “Test Connection” button or watch stdio logs. - Sanity-check connectivity with curl if necessary:
curl -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -X PROPFIND "$WEBDAV_URL" -H "Depth: 1"
- Server missing from Claude: Confirm the config file path, rebuild the Docker image, and fully restart Claude Desktop. Inspect
~/Library/Logs/Claude(macOS) for MCP loading errors. - 401 / authentication failures: Ensure you supplied
WEBDAV_USERNAME/WEBDAV_PASSWORD. Public shares still require HTTP Basic with the token as the username—even if the password is blank. - Endpoint unreachable: Try
curl -X PROPFINDagainst the DAV URL to confirm reachability and TLS trust. SetNODE_TLS_REJECT_UNAUTHORIZED=0temporarily if you must accept a self-signed cert (only for debugging). - Large downloads truncated: Increase
WEBDAV_MAX_FILE_BYTESor fetch files piecemeal.
MIT