darktable-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@darktable-mcpAdjust exposure +0.5 on all underexposed photos"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Darktable MCP Server
A Model Context Protocol (MCP) server that exposes darktable operations to MCP clients (Claude Desktop, Claude Code, etc.). The AI lives in the client; this server drives darktable.
Tools
Library operations (require darktable-mcp install-plugin and an open darktable session):
view_photos(filter?, rating_min?, limit?)— Browse the library by filename substring and minimum rating. Returns id, filename, absolute file path, and rating per match — the path drops straight intoexport_images'sphoto_ids.rate_photos(photo_ids, rating)— Apply -1..5 star ratings (-1 = reject, 0 = unrated).import_batch(source_path, recursive?)— Register a folder as a film roll.recursive=trueis honoured in Lua by walking the tree and importing each directory, so it works regardless of darktable'srecurse_directoriespreference.recursive=falsecannot stop darktable recursing, so the response says so (recursive_honoured: false) rather than claiming a mode it did not deliver. If darktable's background scan has not settled when the plugin answers, the count is reported as a floor, not a total.list_styles()— Enumerate installed darktable styles (presets), returning name + description per entry.apply_preset(photo_ids, preset_name)— Apply a named darktable style to one or more photos. Uselist_stylesfirst to discover exact names.
Camera ingest (headless):
import_from_camera(destination?, camera_port?, timeout_seconds?)— Detect a camera via libgphoto2 and copy photos to a local directory. Auto-merges hybrid setups (one card on PTP, the other mounted as USB Mass-Storage) into a single import — Nikon DSLRs in particular show up that way and the previous behavior silently halved the import.Files land one subdirectory per camera folder or card, prefixed with the camera's identity — never flat:
<destination>/Nikon_D850_sn_30014567_store_00010001_DCIM_100NCD80/DSC_0001.NEF <destination>/Nikon_D850_sn_30014567_store_00020001_DCIM_100NCD80/DSC_0001.NEF # same name, different photo <destination>/Canon_EOS_R6_EOS_DIGITAL_100EOSR6/IMG_0001.CR3 <destination>/.import.logCamera filenames repeat across folders, across the two cards of a dual-slot body, and across bodies importing into the same destination — and the default destination
~/Pictures/import-YYYY-MM-DD/is shared by every import on the same day. The old flat layout combined with gphoto2's--skip-existingsilently dropped those duplicates; correctness no longer rests on that flag, which now only ever sees files the same run just wrote into its own private staging directory. Import the destination recursively.The serial number is read once per camera via
gphoto2 --get-config serialnumberand omitted when the camera doesn't report one. On both paths a file that would collide with a different photo already on disk is written alongside it asIMG_0001-2.CR3and reported — never overwritten; sameness is judged on size plus the first and last 8 KB, and is only ever used to authorise a skip.Two bodies of the same model that report no serial share a destination subdirectory, and both bodies' photos are kept there. The PTP path downloads into a private staging area and, before skipping files the destination appears to already hold, re-checks a bounded sample of them against the bytes on disk — a second body fails that check and its folder is fetched in full. Re-running stays cheap: a body with a serial transfers nothing it already delivered, and one without transfers at most 3 files per folder. Any file the card lists that doesn't reach the destination is reported by name.
Residual limit: that sample is bounded at 3 files per folder, so a second body whose sampled files are byte-identical to the first body's — in a folder holding more than 3 candidates — is still taken to be the same body. Folders with 3 or fewer candidates are checked exhaustively.
timeout_secondsis an overall budget for one camera, shared across all its folders — not a per-folder timeout. Skipped files are counted and reported, and a post-flight shortfall (fewer files on disk than the camera said it held) is surfaced as a prominent!! INCOMPLETE IMPORTblock, because that is the moment before someone formats the card.
Vision-rating workflow (headless, file-based — no library required, needs [vision] extra):
extract_previews(source_dir, output_dir?, max_dim?, thumb_dim?, overwrite?, max_workers?)— Pull auto-rotated JPEG previews + small thumbs out of raws (NEF/CR2/ARW/DNG/...), with an EXIF summary per file. Per-file details (paths, EXIF, errors) land in<output_dir>/.extract_previews.jsonl; the tool response keeps only counts and the side-file path so 700+ NEFs don't overflow the agent's context. The scan is recursive and the output tree mirrors the source tree, so same-named raws in different subdirectories get distinct previews — read the path from each item rather than assuming<output_dir>/<stem>.jpg. Decoding runs on a thread pool (max_workers, defaultmin(8, cpu_count)).apply_ratings_batch(source_dir, ratings, log?, force?)— Write XMPxmp:Ratingsidecars for a{stem: rating}batch + an append-onlyratings.jsonllog. Keys may be a bare stem or a source-relative path; a bare stem that matches raws in more than one subdirectory is rejected as ambiguous rather than resolved by guesswork.open_in_darktable(source_dir, rating?, rating_min?, rating_max?)— Launch the GUI on a folder. Auto-registers as a film roll; pre-applies any rating filter (exact, ≥, ≤, or inner range) viadt.gui.libs.collect.filter.
Behaviour worth knowing
Existing XMP sidecars are patched, never replaced. apply_ratings_batch rewrites only the rating value and leaves every other byte intact, so darktable edit history survives. A sidecar with no recognisable rating is skipped with an error instead of being overwritten. force=True opts into wholesale replacement and discards edit history — it exists for the "reset these sidecars" case and nothing else.
Ratings for photos darktable already knows need one manual step. darktable prefers its own library.db over the sidecar for images already in the library, so writing a sidecar changes nothing on screen. When this is detected the summary warns and names the affected files; run selected image(s) → read sidecar files in the lighttable to pull them in.
open_in_darktable no longer claims a launch it didn't get. An already-open darktable is the normal state when the bridge-backed library tools are in use, and it holds the lock on library.db. What darktable then does is platform-dependent, and neither branch is a launch:
behaviour | reported as | |
Linux (session D-Bus present) | hands the folder to the running instance, child exits 0 |
|
macOS (no session D-Bus) | handoff fails on a GLib assertion and the child hangs forever |
|
The tool used to report a phantom pid in both cases. Detection reads what darktable says, not whether the process is alive — on macOS it stays alive indefinitely, so liveness proves nothing. Verified against darktable 5.6.0.
Export:
export_images(photo_ids, output_path, format, quality?, max_width?, max_height?)— Export to JPEG/PNG/TIFF viadarktable-cli. Runs in an isolated config dir under$XDG_CACHE_HOME/darktable-mcp/cli-config/, so exports work even when the GUI is open (nodatabase is lockedrace against the user's~/.config/darktable/library.db). Files export in parallel, and the output isstated afterwards — darktable-cli can exit 0 without writing anything, which used to be reported as success. Per-file results land in<output_path>/.export_images.jsonl; the tool response is bounded — counts, side-file path, and the first error if any.Output names are de-collided: two inputs with the same stem from different folders no longer overwrite each other, so read the real path from the
outputfield rather than assuming<stem>.<format>. Note darktable-cli picks the extension itself —jpegwrites.jpgandtiffwrites.tif. Each parallel worker gets its own config dir, because concurrentdarktable-cliprocesses sharing one contend for the samelibrary.dband one of them silently writes nothing.Sidecar caveat: because the config dir is isolated from the GUI's, exports read develop settings from XMP sidecars only. If darktable's write sidecar file for each image preference is off, files export without their edits and darktable-cli still reports success.
Related MCP server: rawtherapee-mcp-server
Design rules
Use only the official darktable APIs: darktable-cli for export, the Lua API for everything else. No direct library.db reads or writes. Tools that return data to the AI must be headless; the GUI may launch only when the tool's purpose is to show the human something.
Why some tools are parked
darktable-cli doesn't load the user's library and darktable --lua brings up the full GUI, so there's no headless one-shot path for library reads/writes. Iteration 2 (spec: docs/superpowers/specs/2026-04-27-ipc-bridge-mvp-design.md) shipped a long-running Lua plugin loaded into the user's interactive darktable session, with a file-based JSON RPC bridge. The library tools (view_photos, rate_photos, import_batch, list_styles, apply_preset) all ride on it.
adjust_exposure was retired during iteration 3 — see docs/superpowers/specs/2026-04-28-iter3-design.md. The darktable Lua API in 9.6.0 exposes neither image.modules nor image.history, and dt.gui.action requires an active darkroom view (single-image, GUI-driven). The realistic future paths (pre-created .dtstyle exposure presets + apply_preset, or darktable-cli --style for export-only) are workable but not "set +N EV from Lua" tools.
Installation
Not on PyPI yet — install from the repository:
pip install 'git+https://github.com/w1ne/darktable-mcp'
# Optional: vision-rating workflow extras
pip install 'darktable-mcp[vision] @ git+https://github.com/w1ne/darktable-mcp'
# Install the Lua plugin into ~/.config/darktable/, then restart darktable
darktable-mcp install-pluginYou also need darktable (with darktable-cli) on PATH. The [vision] extra pulls in rawpy, Pillow, and pyexiv2, which need system libraw and libexiv2.
Configuration
Add to your Claude Desktop config:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"darktable": {
"command": "darktable-mcp"
}
}
}Vision-rating workflow
When darktable's library doesn't yet know about your shoot — typically straight off a card — you can rate by vision before any import:
extract_previewswrites auto-rotated JPEGs and an EXIF summary so the client can iterate efficiently.The client reads previews, decides ratings, and calls
apply_ratings_batchto write XMP sidecars next to the raws.open_in_darktablelaunches the GUI with the folder as a film roll, lighttable filtered to the rating range you want.
No SQLite poking, no half-imported state, no GUI launch until step 3.
Requirements
Python 3.10+ (the floor comes from
mcp, which requires 3.10)darktable 4.0+ (with
darktable-clionPATH)An MCP-compatible client (Claude Desktop, Claude Code, etc.)
Linux, or macOS for the parts that don't need
gphoto2. The plugin installer writes to~/.config/darktable/, which is where darktable keeps its config on Linux and macOS but not on Windows —import_from_cameraalso needsgphoto2, which has no Windows build.
The MCP SDK is pinned to mcp>=2,<3. Tools are registered through the mcp 2.x low-level Server(on_list_tools=…, on_call_tool=…) handlers; the 1.x decorators this server used before do not exist in 2.x, so mcp 1.x cannot run this code.
The low-level API is deliberate. The high-level MCPServer derives each inputSchema from the handler signature, which cannot express additionalProperties: {type: integer, minimum: -1, maximum: 5} — the rating bounds on apply_ratings_batch silently disappear — and it injects a title into every property. The tool schemas here are handwritten and pinned by a golden-snapshot test, because their descriptions are what the calling model reads to decide behaviour.
Contributing
Contributions welcome. Any change that reads or writes library.db directly will be rejected.
License
MIT — see LICENSE.
Available Tools
10 toolsapply_presetA
Apply a darktable style (preset) to one or more photos. The preset_name must exactly match a style name from list_styles. Returns counts of applied and missed photos. Requires darktable to be running with the darktable-mcp Lua plugin installed.
| Name | Required | Description | Default |
|---|---|---|---|
| photo_ids | Yes | Photo IDs (from view_photos) | |
| preset_name | Yes | Style name (must match exactly; see list_styles) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses that the operation applies a style to multiple photos and returns applied/missed counts, implying a batch mutation. No annotations exist, so it carries more burden; however, it does not state side effects like whether an existing style is overwritten, but the return counts provide useful behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action, and includes necessary operational preconditions. Slightly more than minimal but each sentence adds value; no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers what it does, the exact-match source, required runtime, and return counts. With no annotations and no output schema, this is reasonably complete for a batch operation, though it doesn't mention error cases or whether partial failures occur; still adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the description reinforces the exact-match constraint already in the schema. It adds nuance that preset_name must match a style name from list_styles, clarifying the enum-like source beyond the schema, which benefits selection.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (apply), the resource (darktable style/preset), the target (one or more photos) and the requ�rement of an exact style name, distinguishing it from sibling import/export/rate tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly requires the preset_name to come from list_styles and notes darktable must be running with the plugin, giving clear preconditions. It does not enumerate when-not-to-use, but the exact-match instruction and mention of list_styles effectively routes the agent to the correct sibling tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
apply_ratings_batchA
Write XMP sidecars (xmp:Rating) for a batch of {stem: rating} pairs. Each sidecar sits next to its raw file at .xmp and is picked up automatically by darktable on import. Rating range: -1 (reject), 0 (unrated), 1-5 (stars). Each rating is also appended to /ratings.jsonl for replay/audit. An existing sidecar is never replaced: only its rating value is rewritten, so darktable edit history survives. A sidecar with no recognisable rating is skipped with an error rather than overwritten.
| Name | Required | Description | Default |
|---|---|---|---|
| log | No | Append entries to ratings.jsonl | |
| force | No | Destructive: replace an existing sidecar wholesale instead of patching its rating. This discards any darktable edit history in that file. Only use when the user has explicitly asked to reset the sidecars. | |
| ratings | Yes | Map of file stem (e.g. 'DSC_1234') to rating int in [-1, 5]. When the same stem occurs in more than one subdirectory the bare stem is rejected as ambiguous — use a source-relative path instead (e.g. 'store_00010001_DCIM_100NCD80/DSC_1234'). | |
| source_dir | Yes | Directory holding the raw files |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the behavioral disclosure burden. It explains sidecar placement, darktable auto-import, the audit log, the 'never replace existing sidecar' behavior, and the error handling for unrecognizable sidecars. It also highlights the destructive force option via the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and efficiently conveys side effects, error behavior, and integration details in five concise sentences. No sentence is redundant or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description covers the essential invocation context: file locations, side effects, rating semantics, audit logging, and safety behavior. It does not explicitly describe the function's return value or success/failure response, but the described side effects make the tool's behavior highly predictable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all four parameters with 100% coverage. The description adds value by explaining the rating scale semantics (-1 reject, 0 unrated, 1-5 stars), sidecar naming, and the purpose of the ratings.jsonl log, going beyond the schema's basic type and range constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action ('Write XMP sidecars') on a specific resource ('a batch of {stem: rating} pairs'). It makes the tool's purpose unambiguous, though it does not explicitly differentiate it from the sibling rate_photos tool by name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies this tool is for batch-rating operations by writing XMP sidecars that darktable picks up automatically. However, it does not explicitly state when to prefer this over siblings like rate_photos, or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_imagesA
Export photos to JPEG/PNG/TIFF via darktable-cli. Pass absolute file paths in photo_ids — the path field from view_photos drops in directly. Output names are de-collided: two sources sharing a stem (e.g. DSC_0001.NEF from two folders) get suffixed names rather than overwriting each other, so do not assume the written file is .. Read the real path from the output field of the .export_images.jsonl side file.
| Name | Required | Description | Default |
|---|---|---|---|
| format | Yes | ||
| quality | No | ||
| max_width | No | Constrain the output width in pixels; aspect ratio is preserved. Omit for full resolution. | |
| photo_ids | Yes | Absolute paths to source images | |
| max_height | No | Constrain the output height in pixels; aspect ratio is preserved. Omit for full resolution. | |
| output_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full behavioral disclosure. It reveals that output filenames are de-collided to avoid overwrites, that the actual written file may not match the expected stem, and that the real path must be read from the .export_images.jsonl side file. This materially changes how an agent should invoke and inspect results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences with no filler. The purpose is front-loaded, and each sentence adds necessary operational detail—input format expectations, name-collision behavior, and how to recover the real output path. The side-file sentence is long but justified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with six parameters, no annotations, and no output schema, the description covers the key workflow: inputs from view_photos, output naming hazards, and the side file to read. The main gaps are the exact semantics of output_path (directory vs file prefix) and when the side file is produced, but the description is largely complete for successful use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50%, and the description compensates for the undocumented output_path by explaining de-collision and the side file's output field. It also adds meaning to photo_ids by linking directly to view_photos.path. It does not clarify whether output_path is a directory or base filename, and format/quality semantics are only lightly implied.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Export photos'), the output formats (JPEG/PNG/TIFF), and the mechanism ('via darktable-cli'). This distinguishes it from siblings like view_photos or extract_previews, so an agent can identify what this tool does without needing to inspect the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete usage context: pass the path field from view_photos directly into photo_ids, and use this tool when exporting photos to the listed formats. It does not explicitly name sibling alternatives or say 'do not use X', but the integration instruction provides enough context for correct selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extract_previewsA
Extract auto-rotated JPEG previews from a directory of raw files (NEF/CR2/ARW/DNG/etc) for vision-based rating. Each preview is rotated upright via EXIF orientation and resized to max_dim (default 1024). A smaller thumb_dim (default 384) is also written for token-efficient first-pass culling. Returns a list of items with preview paths plus an EXIF summary (ISO, shutter, focal, aperture, datetime) per file. The scan is recursive, and the output tree mirrors the source tree, so raws with the same filename in different subdirectories get distinct previews. Read the preview path from each item rather than assuming /.jpg.
| Name | Required | Description | Default |
|---|---|---|---|
| max_dim | No | Longest-edge for the standard preview | |
| overwrite | No | Re-extract even if preview exists | |
| thumb_dim | No | Thumb longest-edge; 0 to skip | |
| output_dir | No | Where to write JPEGs. Default: <source_dir>/.previews/ | |
| source_dir | Yes | Directory containing raw files | |
| max_workers | No | Parallel decode workers. Default: min(8, cpu_count). Lower it if the machine is memory-constrained. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so thoroughly: it discloses EXIF-based auto-rotation, resizing to max_dim and thumb_dim, recursive scanning, mirrored output tree, handling of duplicate filenames, and the instruction not to assume output paths. This gives the agent a reliable mental model of what will happen.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is several sentences long but each sentence adds a useful detail about behavior, output, or path resolution. It is front-loaded with the core purpose and avoids filler, though it slightly repeats default values already present in the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations and no output schema, the description covers the essential return information: a list of items with preview paths and per-file EXIF summaries. It could be more explicit about the exact output item field names or error conditions, but an agent has enough context to invoke the tool and consume its results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter. The description adds some operational context, such as thumbnails being 'for token-efficient first-pass culling' and the mirroring behavior, but it does not materially enrich parameter semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action on a specific resource: 'Extract auto-rotated JPEG previews from a directory of raw files'. It also clarifies the downstream purpose ('for vision-based rating') and distinguishes itself from siblings like view_photos, rate_photos, and export_images by focusing on preview generation rather than viewing, rating, or exporting.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: when raw files need upright JPEG previews for rating workflows. It does not explicitly name alternatives or state when not to use this tool, but the use case is specific enough that an agent can infer appropriate selection among the listed siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
import_batchA
Register a folder as a film roll in the user's darktable library. Useful when you've copied photos from a card or external drive and want darktable to know about them. Returns the count of newly-imported photos. Requires darktable to be running with the darktable-mcp Lua plugin installed.
| Name | Required | Description | Default |
|---|---|---|---|
| recursive | No | Recurse into subdirectories (default true) | |
| source_path | Yes | Absolute path to the folder of photos to import |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It adds meaningful context: the tool returns the count of newly-imported photos, and requires darktable to be running with the darktable-mcp Lua plugin installed. However, it does not disclose side effects such as how existing film rolls or duplicates are handled, or whether files are referenced in place or copied.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, tightly packed and front-loaded with the core purpose before usage context, return value, and prerequisite. Every sentence earns its place; there is no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-parameter tool with a fully documented schema and no output schema, the description covers the essentials: purpose, when to use it, the return value (count), and a key prerequisite (running darktable with the Lua plugin). Minor gaps like duplicate handling and explicit side effects keep it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both parameters (source_path, recursive) with descriptions and defaults. The description reinforces the path semantics ('folder of photos') but adds no new parameter-level detail. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Register a folder as a film roll in the user's darktable library.' This clearly identifies what the tool does and distinguishes it from the sibling import_from_camera by specifying a local-folder source ('copied photos from a card or external drive') rather than camera import.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear when-to-use scenario: 'Useful when you've copied photos from a card or external drive and want darktable to know about them.' It does not explicitly name alternatives or provide exclusions, but the stated context is sufficient for an agent to select this tool over import_from_camera in most cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
import_from_cameraA
Use when a camera or memory card is physically connected. Detects the camera via libgphoto2 and copies all photos to a local directory, then returns the destination path. Copying alone does not put the photos in the library: follow up with import_batch on that destination path to register them as a film roll. Files are written one subdirectory per camera folder or card, prefixed with the camera's identity (e.g. /Nikon_D850_sn_30014567_store_00010001_DCIM_100NCD80/DSC_0001.NEF), because camera filenames repeat across folders, across the two cards of a dual-slot body, and across bodies importing into the same destination. Import the destination recursively. A file that would collide with a different photo already on disk is kept alongside it as -2., never overwritten. This holds for two bodies of the same model that report no serial number and therefore share a subdirectory: before skipping files a destination appears to already hold, such a camera is asked for a small sample of them and the bytes are compared, so a second body's photos are kept rather than dropped. Re-running is cheap: a body with a serial number transfers nothing it already delivered. Any file the card lists that does not reach the destination is reported by name. Cost: this tool runs to completion synchronously and does not return early. A full card can take many minutes, up to the 1 hour default timeout, which is longer than most MCP clients wait for a single request. Progress is observable while it runs by tailing the .import.log file in the destination directory.
| Name | Required | Description | Default |
|---|---|---|---|
| camera_port | No | gphoto2 port string (e.g. 'usb:002,002'). Required when multiple cameras are connected. | |
| destination | No | Target directory for copied files. Default: ~/Pictures/import-YYYY-MM-DD/ | |
| timeout_seconds | No | Overall time budget for the transfer from one camera, shared across all of its folders (not per folder). Default: 3600 (1 hour). On timeout, re-run the tool to resume — already-copied files are skipped. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it does so thoroughly: it explains libgphoto2 detection, non-overwriting collision behavior, filename/subdirectory conventions, serial-number edge cases, timeout/resume semantics, and observable progress via .import.log. These are genuine behavioral disclosures beyond what a schema could infer.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but information-dense, with the primary use condition front-loaded and every sentence serving a distinct purpose. Slight structural awkwardness in the later edge-case sentences and an embedded user directive ('Import the destination recursively.') keep it from a perfect score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and meaningful side effects, the description is remarkably complete: it states the return value, the follow-up workflow, collision handling, timeout behavior, progress observability, and naming rationale. An agent has enough context to invoke it correctly and debug its behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters are already documented in the input schema. The description adds some operational context around destination subdirectories and timeout recovery, but it does not materially extend parameter meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('copies all photos to a local directory'), identifies the physical-camera context, and explicitly separates this from the library-registration step performed by import_batch. The tool's scope is unambiguous and clearly distinguished from its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It opens with the exact condition for use ('Use when a camera or memory card is physically connected') and explicitly instructs to follow up with import_batch on the returned destination path. This provides both when-to-use and when-not-to-stop guidance, with the alternative tool named directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_stylesA
List all darktable styles (presets) installed on the user's system. Returns name and description for each. Required discovery step before calling apply_preset, since style names must match exactly. Requires darktable to be running with the darktable-mcp Lua plugin installed.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations available, the description carries the burden and discloses the key behavioral context: it returns only name/description per style and requires darktable to be running with the darktable-mcp Lua plugin installed. It doesn't detail error cases or explicitly state read-only behavior, but 'list' plus the return description makes the non-destructive nature reasonably clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, each earning its place: the action, the return content, the prerequisite relationship to apply_preset, and the runtime requirement. The most important information is front-loaded and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter listing tool with no output schema, the description covers the purpose, the returned data shape, the dependency on apply_preset, and the external runtime prerequisite. Nothing essential for invoking it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no parameters, so there is nothing for the description to add about parameters. The 0-parameter baseline of 4 applies; the description instead usefully explains what the output contains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List all darktable styles (presets) installed on the user's system.' It also states the returned fields (name and description), which makes the tool's function unambiguous and distinct from sibling tools like apply_preset.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when this tool is required: 'Required discovery step before calling apply_preset, since style names must match exactly.' This provides clear sequencing and identifies the relevant sibling, so an agent knows to call this before apply_preset and why.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_in_darktableA
Launch the darktable GUI on a folder. The folder is registered as a film roll on first launch and XMP sidecars are picked up automatically. The lighttable opens already filtered via the official darktable.gui.libs.collect.filter Lua API for any rating spec: exact rating=N, rating_min=N (>=), rating_max=N (<=), arbitrary rating_min..rating_max inner ranges, or no filter at all.
| Name | Required | Description | Default |
|---|---|---|---|
| rating | No | Filter to exactly this rating (-1=reject, 0=unrated, 1-5=stars) | |
| rating_max | No | Upper bound of a rating range | |
| rating_min | No | Lower bound of a rating range | |
| source_dir | Yes | Folder containing the raw files | |
| darktable_path | No | darktable executable (default: 'darktable' on PATH) | darktable |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it delivers meaningful behavior: first-launch film roll registration, automatic XMP sidecar pickup, and filter application via a named Lua API. It does not disclose whether the GUI launch blocks until exit or what happens if the darktable executable is missing, but it covers the most important side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main purpose and side effects are front-loaded, followed by a compact specification of every supported rating form. The text is dense but each clause contributes; only the internal Lua API reference is mildly incidental to actual invocation, and the overall length is justified by the complexity of the filtering behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter, no-output-schema tool with no annotations, the description covers the purpose, the non-obvious rating filter combinations, and key side effects. It does not discuss the darktable_path parameter or process return behavior, but those are low-stakes: darktable_path has a schema default, and a GUI launcher does not require detailed return documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real value by explaining how the rating parameters combine: exact rating=N, rating_min=N, rating_max=N, arbitrary inner ranges, or no filter. This gives the agent semantic guidance beyond the individual integer descriptions in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Launch'), a clear resource ('the darktable GUI on a folder'), and the distinguishing behavior: it is the tool that opens an interactive GUI rather than performing batch operations like export_images or apply_preset. It also differentiates itself by naming the exact outcome: film roll registration and an already-filtered lighttable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The context is clear: use this when the user wants to open the interactive darktable GUI on a folder, optionally with rating filters. It does not explicitly name or contrast with sibling tools such as view_photos or rate_photos, so it stops short of a 5, but the launch-GUI framing makes the intended usage obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rate_photosB
Apply a star rating to one or more photos in the user's darktable library. Requires darktable to be running with the darktable-mcp Lua plugin installed.
| Name | Required | Description | Default |
|---|---|---|---|
| rating | Yes | Star rating: -1=reject, 0=unrated, 1-5=stars | |
| photo_ids | Yes | List of photo IDs (from view_photos) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It reveals only the runtime prerequisite and does not state whether an existing rating is overwritten, whether the operation is reversible, what happens if darktable is not running, or error behavior. For a mutation tool with zero annotation coverage, this is a significant gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The action is front-loaded, and the prerequisite sentence earns its place by warning the agent about a hard runtime requirement. Nothing redundant or extraneous.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 2-parameter tool with fully documented schema, the description covers the core action and the critical prerequisite. However, it lacks differentiation from the near-duplicate sibling 'apply_ratings_batch', and with no annotations or output schema, a bit more behavioral context would make it fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both 'photo_ids' and 'rating' fully documented in the input schema (including the rating scale -1/0/1-5). The description adds no meaningful parameter meaning beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Apply a star rating to one or more photos in the user's darktable library.' This is clear and unambiguous. However, it does not distinguish itself from the sibling tool 'apply_ratings_batch', which appears to perform a nearly identical operation, so it misses the sibling-differentiation mark for a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a runtime prerequisite (darktable running with the darktable-mcp Lua plugin installed) but gives no guidance on when to use this tool versus alternatives like 'apply_ratings_batch'. There is no mention of exclusions, precedence, or which tool fits a given scenario, so an agent gets no tool-selection help.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
view_photosA
Browse photos in the user's darktable library. Filter by filename substring, minimum star rating, or both. Returns id, filename, absolute file path, and rating per match — the path can be passed straight into export_images. Requires darktable to be running with the darktable-mcp Lua plugin installed (see darktable-mcp install-plugin).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of photos to return | |
| filter | No | Substring filter on filename (case-insensitive) | |
| rating_min | No | Minimum star rating to include |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses the exact return fields, the fact that the returned path is directly usable by export_images, and the runtime prerequisite. It does not mention sorting, pagination, or read-only guarantees, but those are minor for a simple browse operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose, a useful integration note, and the prerequisite. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description compensates by listing return fields. It also states the necessary runtime prerequisite and the relationship to export_images. The only omissions are minor behavioral details like sort order and error behavior when the plugin is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the description need only add value over the schema. It adds the fact that filter and rating_min can be combined ('or both'), but otherwise restates the schema's descriptions. This is a slight but not substantial addition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Browse photos in the user's darktable library'), names the core filtering capabilities, and states the returned fields. This clearly separates it from siblings like rate_photos, import_batch, or export_images, and even points downstream to export_images.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the operation context (browsing/filtering before export) and the requirement that darktable be running with the plugin installed. It does not explicitly enumerate alternatives or when-not-to-use, but the export_images reference and filter description give clear usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
10 tool updates
v0.1.0- First observed
apply_preset - First observed
apply_ratings_batch - First observed
export_images - First observed
extract_previews - First observed
import_batch - First observed
import_from_camera - First observed
list_styles - First observed
open_in_darktable - First observed
rate_photos - First observed
view_photos
TDQS
Most tools map cleanly to a distinct resource+action (import, browse, rate, style, export, preview, GUI launch). The one genuine overlap is rate_photos vs apply_ratings_batch — both write star ratings, one via the running darktable library and one via XMP sidecars for pre-import files — and view_photos vs extract_previews both surface photos, though the rich descriptions clarify the library-browsing vs file-preview distinction.
All tools are snake_case and verb-first, following a readable verb_noun convention (view_photos, list_styles, export_images, extract_previews). Minor deviations: import_from_camera and open_in_darktable use prepositional phrases, and the 'batch' suffix appears in both import_batch and apply_ratings_batch with slightly different grammatical roles, but the overall pattern stays predictable.
Ten tools is well-scoped for the domain: two import paths, library browsing, two rating mechanisms, style discovery/application, preview extraction, export, and GUI launch. Each tool occupies a distinct step in the photo-management workflow and none feels like filler.
The end-to-end pipeline is covered: copy from camera → register film roll → browse → rate → apply style → export, plus an alternative XMP-sidecar rating path that darktable picks up on launch. Missing operations like metadata editing, style creation, photo deletion, and richer library search (tags, dates) are workable gaps rather than dead ends.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Edit your Overleaf LaTeX projects from Claude and ChatGPT; every change is a real Git commit.
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Turn Claude into a creative studio: DNA-locked characters, images, video, voiceover — 55 tools.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI agents to control Adobe Lightroom Classic on macOS for professional photo editing and catalog management. It allows users to inspect photos, apply develop settings, and automate workflows through a secure local bridge without direct catalog database manipulation.592MIT
- AlicenseAqualityDmaintenanceEnables AI-assisted RAW photo development via RawTherapee CLI, with a visual feedback loop that allows the LLM to see and iteratively edit images.493MIT

CoreViz MCPofficial
AlicenseNot gradedqualityDmaintenanceExposes a visual library with semantic search, tagging, editing, and management of photos as tools for AI agents like Claude Code.3048MIT- AlicenseNot gradedqualityDmaintenanceEnables AI assistants like Claude to control the Scribus desktop publishing app for document creation, editing, and export via its Python Scripter API, supporting both headless and interactive modes with ~125 tools.1MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/w1ne/darktable-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server