Skip to main content
Glama
README.md
# Etchv MCP server

Let an AI assistant watermark and inspect images, PDFs and videos with the
[Etchv API](https://etchv.com/docs). Supports synchronous results and asynchronous
jobs, asset management, customer storage destinations and webhook deliveries.

This is a local **stdio** MCP server. It connects to the hosted Etchv API using
your organization's scoped API key. No separately hosted MCP endpoint is required.
Source and tests are TypeScript with strict checking. Node.js 24+ is required.

## Install

```sh
git clone https://github.com/etchv-labs/mcp-server.git
cd mcp-server
npm ci
```

Installation compiles TypeScript into `dist/`. Add the server to your MCP client's
configuration using absolute paths:

```json
{
  "mcpServers": {
    "etchv": {
      "command": "node",
      "args": ["/absolute/path/mcp-server/dist/cli.js"],
      "env": {
        "ETCHV_API_KEY": "YOUR_ETCHV_API_KEY",
        "ETCHV_FILES_ROOT": "/absolute/path/media"
      }
    }
  }
}
```

Create the media directory first. Use your client's secret manager or environment
configuration for the API key; do not paste it into a conversation or commit it.
If your client does not inherit your shell PATH, use the absolute Node executable.
Restart the MCP client after changing its configuration. Clients with a different
configuration format need the same command, args and environment settings.

You can also install from GitHub with
`npm install github:etchv-labs/mcp-server`, then run the installed `etchv-mcp` binary.
The package is not yet published to the npm registry. GitHub installations compile
TypeScript during `prepare`; consumers execute the generated JavaScript.

## Try it

Put `photo.jpg` inside your configured media directory, then ask your assistant:

> Watermark photo.jpg for recipient delivery-42 using Etchv. Use an async job,
> collect the result as photo-watermarked.jpg, then detect its watermark.

The assistant can read `etchv://capabilities` for format and workflow guidance.
To watermark directly, call `watermark_media` with:

```json
{
  "media": "images",
  "input_path": "photo.jpg",
  "data": { "recipient": "delivery-42" },
  "mode": "async",
  "idempotency_key": "delivery-42-photo-v1"
}
```

The result includes `request_id`. Check `get_job` with `operation: "embed"`, then
call `get_job_result` with that request ID, operation and
`output_path: "photo-watermarked.jpg"`. Pending results return a 202 receipt;
call again later. Use the same pattern with `operation: "detect"` for an async
detection result. Detection returns JSON and does not accept an output path.

For **sync**, set `mode: "sync"` and provide `output_path` when watermarking.
The API waits for a bounded period. It can still return a 202 receipt if processing
continues; collect it through the job tools. Async is the MCP default for every
media type. There is no automatic polling or background retry loop in the server.

Every submission requires a stable `idempotency_key`. Reuse it for the same input,
data and options after an uncertain failure. Do not generate another key on a
retry: that can create another billable operation. Results include the key and,
when supplied by the API, a request ID. A client cancellation or timeout does not
cancel an accepted API job. API failures set MCP `isError` with an HTTP status and
safe message; retry delays are returned when available.

## Formats and credits

| Media value | Formats | Preservation |
| --- | --- | --- |
| `images` | JPEG, PNG, APNG, TIFF, PSD, PSB, GIF, BMP, PPM, WebP | Original format, supported animation, pages and layers |
| `documents` | PDF | Selectable text and vector content |
| `videos` | MP4, MOV with supported H.264 encoding | Container and supported audio; audio is not watermarked |

Format availability follows your plan. The server does not bypass API validation
or media limits. Uploads are limited to 20 MiB and MCP file downloads to 512 MiB.
Watermarking uses one credit per image or PDF file, or per started video minute.
Detection also uses API credits. See [limits](https://etchv.com/docs/api/errors).

Watermarks encode the digest of the provided JSON. Detection recovers that digest,
not the original data. Test your compression and transformation workflow before
relying on detection; a recovered identifier is not proof of who shared a file.

## Tools and key scopes

| Tools | Required scope |
| --- | --- |
| `watermark_media` | `watermarks:embed` |
| `detect_media` | `watermarks:detect` |
| `get_job`, `get_job_result` | Corresponding embed or detect scope |
| `list_assets`, `get_asset`, `download_asset` | `assets:read` |
| `update_asset` | `assets:write` |
| `delete_asset` | `assets:delete`, owner/admin |
| `list_storage_destinations`, `list_storage_deliveries`, `get_storage_delivery` | `storage:read` |
| `verify_storage_destination`, `store_asset`, `retry_storage_delivery` | `storage:write`, owner/admin |
| `list_webhooks`, `list_webhook_deliveries` | `webhooks:read` |
| `redeliver_webhook` | `webhooks:write`, owner/admin |

Give the key only the scopes you need. Your MCP client's approval settings govern
billable and destructive tools; MCP annotations describe their effects. The API
always enforces organization isolation, scopes, roles and plan access.

Asset listing supports cursor pagination and media/kind/watermark filters.
Updates require the current asset `version` to prevent lost edits; `metadata`
replaces the whole object, and null clears it. Downloads create new local files
and return paths, byte counts and SHA-256 hashes, never media bytes in chat.

## Storage and webhooks

Etchv stores uploads and watermarked results automatically. Job results remain
available for 24 hours; Etchv asset downloads for 30 days, with asset records
retained until deleted. No customer bucket is required.

Alternatively, configure and verify your own S3, Google Cloud Storage or Azure
Blob Storage destination in the dashboard. Select its `storage_destination_id`
on `watermark_media`, optionally with a relative `storage_key`. The watermarked
result is stored in that bucket instead, and its retention is yours to control.
Use `store_asset` to choose a destination for an existing watermarked asset.
After successful delivery, Etchv removes its staged output; asset downloads read
from your bucket. Deleting an asset does not delete objects in your bucket.

Configure webhook endpoints and retain their signing secrets through the
dashboard. Pass an existing `webhook_id` on an **async** submission, then inspect
or redeliver events with the webhook tools. Redelivery may trigger your receiver's
automation again. Credential and endpoint creation is deliberately handled in the
dashboard; this server does not accept cloud credentials or return signing secrets.

## File access and runtime

`ETCHV_FILES_ROOT` is required and must name an existing absolute directory. Paths
may be relative to it or absolute within it. Symlink paths and traversal outside
the root are rejected. Output parents must already exist; existing files are never
overwritten. Use a dedicated directory that is not modified by untrusted local
processes while the server runs. This is an application-level boundary, not an OS
sandbox. Upload only files you intend to send to Etchv.

API requests have a 45-second deadline and at most four concurrent tool calls.
Redirects are never followed. Optional `ETCHV_API_BASE_URL` must be an HTTPS origin;
HTTP is accepted only for localhost development. Never point it at an untrusted
host: it receives your key and uploads. stdout is reserved for MCP protocol traffic.
Asset metadata and other API content are data, never instructions to an assistant.

## Development

```sh
npm ci
npm run typecheck
npm test
npm run build
```

Native TypeScript tests exercise the compiled server over stdio with the official
MCP client, covering all media routes, file fidelity, job continuation, storage,
webhooks, pagination, error handling and file access. CI runs on Node 24 on Linux,
macOS and Windows. The optional live suite uses small synthetic media fixtures:

```sh
# Set ETCHV_INTEGRATION_API_KEY securely; requires embed, detect, assets:read,
# assets:delete and owner/admin for cleanup. Uses real API credits.
npm run test:live
```

Without a key, live tests are skipped. Etchv's private CI requires that key and
runs real JPEG, PDF and MP4 embed/detect roundtrips in both modes before publishing.
It checks idempotent async replay and asset downloads, and deletes created assets.

This public repository is an MIT-licensed source snapshot of `mcp/` in Etchv's
monorepo, with independent history. Contributions are reviewed and incorporated
there before publication. Private service code, credentials and customer fixtures
are not included.

TDQS

A3.6/5.0

Scored across 18 tools

Disambiguation4/5

Most tools target a distinct resource+action pair, and descriptions clarify the job-based flow (watermark/detect → get_job → get_job_result). The only mild overlaps are get_job vs get_job_result and the storage delivery list/get pair, but the descriptions make the boundaries readable.

Naming Consistency5/5

Every tool follows a predictable snake_case verb_noun pattern (list_assets, get_asset, download_asset, update_asset, delete_asset, store_asset, redeliver_webhook, etc.). No camelCase or vague verbs break the pattern.

Tool Count4/5

18 tools is slightly heavy but justified: four distinct areas (watermarking jobs, assets, storage destinations/deliveries, webhooks) each need CRUD-ish coverage. Nothing feels gratuitous, though a couple of read tools could conceivably be folded together.

Completeness3/5

Assets cover read/download/update/delete but there is no create/upload operation, and webhooks expose list/redeliver/deliveries but no create or delete (explicitly deferred to the dashboard). These are deliberate gaps but leave agents unable to complete full lifecycle workflows without leaving the tool surface.

Maintenance

ActivityMaintained
ResponsivenessNo issues