Skip to main content
Glama
dominik1001

carddav-mcp

by dominik1001
README.md
# carddav-mcp

<div align="center">

šŸ“‡ A CardDAV Model Context Protocol (MCP) server to expose contacts and address books as tools for AI assistants.

[![Release](https://github.com/dominik1001/carddav-mcp/actions/workflows/release.yml/badge.svg)](https://github.com/dominik1001/carddav-mcp/actions/workflows/release.yml)
[![npm version](https://badge.fury.io/js/carddav-mcp.svg)](https://www.npmjs.com/package/carddav-mcp)
[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/)
[![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io)
[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)

</div>

## ✨ Features

- Connect to CardDAV servers
- List address books
- List contacts in an address book
- Get the full details of a single contact
- Create contacts (vCard)
- Update contacts — partial updates that preserve vCard properties written by other clients
- Delete contacts by UID

## Setup

```
{
  "mcpServers": {
    ...,
    "contacts": {
      "command": "npx",
      "args": [
        "carddav-mcp"
      ],
      "env": {
        "CARDDAV_BASE_URL": "<CardDAV server URL>",
        "CARDDAV_USERNAME": "<CardDAV username>",
        "CARDDAV_PASSWORD": "<CardDAV password>"
      }
    }
  }
}
```

## Development

### Quick Start

Run the MCP server in development mode with auto-reload:
```bash
npm run dev
```

This will run the TypeScript code directly with watch mode and automatically load environment variables from `.env`.

### Manual Build

Alternatively, you can compile TypeScript to JavaScript and run it:

1. Compile:
```bash
npx tsc
```

2. Run:
```bash
node dist/index.js
```

## Available Tools

<!-- TOOLS:START - generated by scripts/gen-tool-docs.ts -->
### list-address-books

List all address books returning both name and URL

Parameters: none

Returns:
- List of all available address books

### list-contacts

List all contacts in the address book specified by its URL. Returns a summary per contact; use get-contact for full details.

Parameters:
- `addressBookUrl`: string

Returns:
- A list of contacts, each containing `uid`, `fn` (formatted name), `emails`, and `phones`

### get-contact

Get the full details of a single contact in the address book specified by its URL

Parameters:
- `uid`: string — Unique identifier of the contact to fetch (obtained from list-contacts)
- `addressBookUrl`: string

Returns:
- The contact's parsed fields (`uid`, `fn`, `name`, `emails`, `phones`, and optionally `org`, `title`, `note`) plus the raw vCard in `vcard`

### create-contact

Creates a contact (vCard) in the address book specified by its URL. If `name` is omitted, structured name parts are derived from `fn`.

Parameters:
- `addressBookUrl`: string
- `fn`: string — Formatted display name of the contact
- `name`: object (optional) — Structured name parts (family, given, middle, ...)
  - `family`: string (optional)
  - `given`: string (optional)
  - `middle`: string (optional)
  - `prefix`: string (optional)
  - `suffix`: string (optional)
- `emails`: array of string (optional)
- `phones`: array of string (optional)
- `org`: string (optional) — Organization / company
- `title`: string (optional) — Job title or role
- `note`: string (optional)

Returns:
- The unique ID of the created contact

### update-contact

Updates an existing contact in the address book specified by its URL. Only provided fields are changed; `emails` and `phones` replace the full list (pass an empty array to clear them, or an empty string to clear `org`, `title`, or `note`). Other vCard properties are preserved.

Parameters:
- `uid`: string — Unique identifier of the contact to update (obtained from list-contacts)
- `addressBookUrl`: string
- `fn`: string (optional)
- `name`: object (optional)
  - `family`: string (optional)
  - `given`: string (optional)
  - `middle`: string (optional)
  - `prefix`: string (optional)
  - `suffix`: string (optional)
- `emails`: array of string (optional)
- `phones`: array of string (optional)
- `org`: string (optional)
- `title`: string (optional)
- `note`: string (optional)

Returns:
- The unique ID of the updated contact

### delete-contact

Deletes a contact in the address book specified by its URL

Parameters:
- `uid`: string — Unique identifier of the contact to delete (obtained from list-contacts)
- `addressBookUrl`: string

Returns:
- Confirmation message when the contact is successfully deleted
<!-- TOOLS:END -->

## Smoke Tests

Two complementary end-to-end checks against a real CardDAV server (both read credentials from `.env`):

- `npm run smoke` — deterministic SDK harness (`scripts/smoke.ts`). Spawns the built server over stdio via the MCP client SDK and asserts the create → list → get → update → delete contact round-trip.
- `npm run smoke:agent` — agent-ergonomics harness (`scripts/smoke-agent.sh`). Drives the server via `claude -p` with a JSON output schema, validating that tool names, descriptions, schemas, and error messages are usable by an LLM.

## License

[MIT](https://choosealicense.com/licenses/mit/)