Metadata-Version: 2.5
Name: docsend2pdf-mcp
Version: 0.3.0
Summary: MCP server for converting DocSend documents to PDF via docsend2pdf.com
Author-email: Docsend2PDF <docsend2pdf@proton.me>
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Requires-Dist: mcp<2.0.0,>=1.0.0
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# docsend2pdf-mcp

MCP server for converting DocSend documents to PDF via docsend2pdf.com

## Installation

Requires Python 3.10+.

```bash
pip install docsend2pdf-mcp
```

## Configuration

```json
{
    "mcpServers": {
        "docsend2pdf": {
            "command": "python",
            "args": ["-m", "docsend2pdf_mcp"],
            "env": {
                "DOCSEND2PDF_DOWNLOAD_DIR": "~/Downloads/docsend_pdfs"
            }
        }
    }
}
```

## Usage

- Convert: `"Convert this DocSend to PDF: https://docsend.com/view/abc123"`
- With password: `"Convert https://docsend.com/view/xyz789 (password: mypass)"`
- With email: `"Convert https://docsend.com/view/doc456 (email: user@example.com)"`
- Custom filename: `"Save https://docsend.com/view/doc789 as report.pdf"`
- After a timeout: `"Fetch that conversion again"` (uses the reported `task_id`)

Most decks ask for an email. The agent should ask for an address you can read
before converting if you have not supplied one. The deck owner will see it.
Email remains optional for public documents. Password-protected documents need
`passcode`.

`docsend.com/view/...`, `docsend.com/v/...`, the `/view/<id>/d/<doc>` links a
Space uses for its documents, and `docsend.com` subdomains all work. A Space
link (`/view/s/...`) is forwarded to the service, which converts it when the
Space holds a single document. A gated Space takes the same `email` and
`passcode` arguments and, if DocSend emails a verification link, the same
verification step below. A Space that holds several documents, or that asks
for something the service cannot answer, is reported with a
`provide_document_link` recovery action: open the Space in DocSend and use the
individual document's link.

### Email verification

If DocSend sends a verification email, `convert_docsend` returns
`status: "email_verification_required"`, `session_id`, and `expires_at`.
Copy the link behind the **"Verify email address"** button **without opening it**,
then give it to the agent. The link is single-use. Pasting the document or
Space link instead is refused without spending anything; the session keeps
waiting for the emailed link.

The agent calls `submit_verification_link(session_id, verification_url)`. The MCP
server submits the link to the verification API, polls until the PDF is ready,
and saves it using the original custom filename, if any. Queued conversions are
also polled automatically.

Verification sessions last until expiry (normally 24 hours) and are kept in a
private file under the state directory, so restarting the client no longer
wastes the verification email. If the session expires or you already opened the
email link, start a new conversion for a fresh one.

### Collecting a conversion later

A conversion that is still running when the server gives up reports a
`task_id`. Ask the agent to fetch it rather than converting again:
`fetch_conversion(task_id)` collects the finished PDF, or says the conversion
is no longer available. The service keeps a finished result briefly, so fetch
it soon after.

### Results

Results retain the human-readable message and the `Saved to: <path>` line.
Every result also contains a fenced JSON block with `status`, `error_code`,
`retryable`, `recovery_action`, `task_id`, `session_id`, and `saved_path`.
Unavailable values are `null`. Successful conversions use `status: "completed"`;
failures use `"error"`. Verification handoffs also include `expires_at` and
the exact copying instruction.

API failures preserve `details.error_code`, `details.retryable`, and
`recovery_action` so agents can ask for missing email or credentials, restart
verification, or stop retrying a dead link. Errors remain text, not MCP
`isError` results, for compatibility with older clients.

## Features

- Password-protected documents
- Email-gated documents, including completion of email verification inside MCP
- Verification sessions that survive a client restart
- Collecting a conversion afterwards with `fetch_conversion`
- Custom filenames, sanitized to stay inside the download directory
- Rate limiting (5 req/sec), and waiting out short `Retry-After` delays
- Explicit blocking requests (`async: false`) with a versioned
  `DocSend2PDF-MCP/0.3.0` User-Agent
- Readable timeout errors that name the task to collect

## Where files are saved

PDFs go to `<Downloads>/docsend_pdfs`. The Downloads folder is the one the
account actually uses: the registry known folder on Windows, `XDG_DOWNLOAD_DIR`
on Linux, and `~/Downloads` on macOS. Set `DOCSEND2PDF_DOWNLOAD_DIR` to an
absolute path to override it; a blank value is ignored, and a relative one is
taken from your home directory. Clients must be able to read that local path.

A download never replaces an existing file unless you asked for that filename:
a second `deck.pdf` is saved as `deck (2).pdf`. If the directory cannot be
written to, the PDF is saved to a fresh private temporary folder and the reply
says so, rather than the conversion being lost. A filename you chose that is
already a symlink is refused rather than written through.

Pending verification sessions are stored under `%LOCALAPPDATA%`,
`~/Library/Application Support`, or `$XDG_STATE_HOME`. Override with
`DOCSEND2PDF_STATE_DIR`.

## Upgrading

0.3.0 keeps the existing `convert_docsend` and `submit_verification_link`
arguments, adds the `fetch_conversion` tool, and requires Python 3.10+ and
MCP 1.x. Users of `uvx docsend2pdf-mcp@latest` pick up the release on their
next client restart. Pinned pipx installations need an explicit upgrade:

```bash
pipx upgrade docsend2pdf-mcp
```

If your Downloads folder is not at `~/Downloads`, PDFs now arrive in the real
one. Set `DOCSEND2PDF_DOWNLOAD_DIR` to keep the old location.

## Development

```bash
pip install -e ".[dev]"
python -m pytest
python -m build
```

`pyproject.toml` is the only packaging file. The package is split into
`api.py` (HTTP client, polling, verification sessions), `files.py` (directory
resolution and PDF saving), `store.py` (session persistence), `server.py`
(MCP tools), and `__main__.py` (stdio entry point).

The tracked unit suite (`tests/unit`) uses mock HTTP responses, temporary
download and state directories, and no live DocSend links or email. CI runs it
on Python 3.10 through 3.13 plus macOS and Windows, alongside `mypy` and
`black --check`. The build produces both a wheel and an sdist. The sdist
includes only package sources, unit tests, and distribution metadata; anything
else in the working tree is excluded.

## License

MIT
