New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@tekmidian/devonthink-mcp

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tekmidian/devonthink-mcp

DEVONthink MCP server for Claude Code. Zero-config setup with automatic Claude configuration.

latest
Source
npmnpm
Version
2.0.2
Version published
Maintainers
1
Created
Source

devonthink-mcp

DEVONthink MCP server for Claude Code. Zero-config setup — one command and you're done.

Extends mcp-server-devonthink with additional tools for smart groups, smart rules, EML header parsing, and column layout management.

Quick start

npx @tekmidian/devonthink-mcp setup

The wizard checks prerequisites, configures ~/.claude.json, and enables the server. Restart Claude Code and DEVONthink tools are immediately available.

What it provides

With this server running, Claude Code can:

  • Search and browse all open DEVONthink databases
  • Read document content (PDFs, Markdown, plain text, HTML, rich text)
  • Create, update, and delete records
  • Add and remove tags, classify documents, manage metadata
  • Move, replicate, and duplicate records across groups
  • Cross-reference emails with archived documents
  • Ask AI about documents (DEVONthink's built-in AI)
  • List and navigate database groups
  • List smart groups — enumerate all smart groups (not accessible via AppleScript)
  • List smart rules — enumerate all smart rules (not accessible via AppleScript)
  • Parse EML headers — extract Message-ID, In-Reply-To, References, Subject, etc.
  • Read/copy column layouts — inspect and copy view column configurations

Requirements

  • macOS (DEVONthink is macOS-only)
  • DEVONthink 3 or 4 installed and running
  • Node.js >= 18
  • Claude Code

Installation

Option 1: npx (no install required)

npx @tekmidian/devonthink-mcp setup

Option 2: Global install

npm install -g @tekmidian/devonthink-mcp
devonthink-mcp setup

Option 3: Clone and build

git clone https://github.com/mnott/devonthink-mcp ~/dev/ai/devonthink-mcp
cd ~/dev/ai/devonthink-mcp
npm install
npm run build
node dist/index.js setup

Manual configuration

If you prefer to configure Claude Code manually, add this to the mcpServers section of ~/.claude.json:

"devonthink": {
  "type": "stdio",
  "command": "npx",
  "args": ["-y", "@tekmidian/devonthink-mcp", "serve"],
  "env": {}
}

Or if you have it installed locally:

"devonthink": {
  "type": "stdio",
  "command": "node",
  "args": ["/path/to/devonthink-mcp/dist/index.js", "serve"],
  "env": {}
}

Restart Claude Code after editing ~/.claude.json.

Usage

Once configured, Claude Code has access to all DEVONthink tools automatically. DEVONthink must be running with at least one database open.

Example prompts:

  • "Search my DEVONthink databases for notes about the Q3 budget"
  • "Find the email from John about the contract and show me related documents"
  • "Create a new markdown note in my Inbox with today's meeting notes"
  • "List all documents tagged 'todo' in my Ablegen database"
  • "Read the content of the PDF I imported yesterday"
  • "List my smart groups"
  • "Parse the headers from this .eml file to find its thread ID"

Custom tools

These five tools extend the upstream mcp-server-devonthink capabilities. They are not part of the original package.

Key limitation: Smart groups and smart rules are not accessible via the DEVONthink AppleScript scripting dictionary. The list_smart_groups and list_smart_rules tools are the only programmatic way to enumerate them. They work by reading the plist files directly.

list_smart_groups

Parses ~/Library/Application Support/DEVONthink/SmartGroups.plist and returns all smart groups with their name, UUID, sync date, and UseUUIDKey flag.

Parameters: none

Returns:

FieldTypeDescription
successbooleanWhether the operation succeeded
smartGroupsarrayList of smart group entries
totalCountnumberTotal number of smart groups found

Each entry in smartGroups:

FieldTypeDescription
namestringDisplay name of the smart group
uuidstringUUID from the sync.UUID field — use this with the search tool
syncDatestring | nullLast sync date (ISO 8601)
useUuidKeyboolean | nullWhether DEVONthink uses UUID as the key internally

Example:

list_smart_groups
{
  "success": true,
  "totalCount": 4,
  "smartGroups": [
    {
      "name": "Jobs - To Review",
      "uuid": "4A469368-94FD-46D3-9A62-ED7C24D822D8",
      "syncDate": "2024-11-15T10:23:00Z",
      "useUuidKey": true
    }
  ]
}

Use the uuid with the search tool's groupUuid parameter to query the contents of that smart group.

list_smart_rules

Parses ~/Library/Application Support/DEVONthink/SmartRules.plist and returns all smart rules with name, UUID, enabled state, execution metadata, and sync date.

Parameters: none

Returns:

FieldTypeDescription
successbooleanWhether the operation succeeded
smartRulesarrayList of smart rule entries
totalCountnumberTotal number of smart rules found

Each entry in smartRules:

FieldTypeDescription
namestringDisplay name of the smart rule
uuidstringUUID from the sync.UUID field
enabledboolean | nullWhether the rule is currently enabled
indexOffsetnumber | nullOrder index within the rules list
lastExecutionnumber | nullCFAbsoluteTime timestamp of last execution
syncDatestring | nullLast sync date (ISO 8601)
useUuidKeyboolean | nullWhether DEVONthink uses UUID as the key internally

Example:

list_smart_rules
{
  "success": true,
  "totalCount": 2,
  "smartRules": [
    {
      "name": "Auto-tag Invoices",
      "uuid": "B1234567-ABCD-EF01-2345-67890ABCDEF0",
      "enabled": true,
      "indexOffset": 0,
      "lastExecution": 756000000,
      "syncDate": "2024-12-01T08:00:00Z",
      "useUuidKey": false
    }
  ]
}

parse_eml_headers

Reads an RFC 2822 .eml file and extracts the MIME headers needed for email thread correlation.

Handles CRLF and LF line endings, folded headers (continuation lines), and RFC 2047 encoded words in Subject, From, and To fields.

Only reads the first 64 KB of the file since headers are always at the start.

Parameters:

ParameterTypeRequiredDescription
filePathstringyesAbsolute path to the .eml file

Returns:

FieldTypeDescription
successbooleanWhether parsing succeeded
filePathstringThe path that was read
messageIdstring | nullThe Message-ID header value
inReplyTostring | nullThe In-Reply-To header value
referencesstring[]Array of message IDs parsed from the References header
subjectstring | nullDecoded subject line
fromstring | nullSender address(es)
tostring | nullRecipient address(es)
ccstring | nullCC address(es)
datestring | nullDate string from the header

Example:

{
  "filePath": "/path/to/email.eml"
}
{
  "success": true,
  "filePath": "/path/to/email.eml",
  "messageId": "<abc123@mail.example.com>",
  "inReplyTo": "<xyz789@mail.example.com>",
  "references": [
    "<original@mail.example.com>",
    "<xyz789@mail.example.com>"
  ],
  "subject": "Re: Contract renewal discussion",
  "from": "Jane Smith <jane@example.com>",
  "to": "John Doe <john@example.com>",
  "cc": null,
  "date": "Mon, 15 Jan 2024 14:32:00 +0100"
}

get_column_layout

Reads the column layout for a named smart group or smart rule from ~/Library/Preferences/com.devon-technologies.think.plist.

Returns the ordered visible columns, all table view columns (visible and hidden), and column widths. Supports partial name matching — if only one partial match exists, it is used automatically.

DEVONthink stores layouts under three related plist keys per smart group: the visible column order, all columns, and column widths.

Parameters:

ParameterTypeRequiredDescription
namestringyesDisplay name of the smart group or smart rule
uuidstringnoUUID of the smart group (fallback if name lookup fails — DEVONthink sometimes stores layouts under the UUID)

Returns:

FieldTypeDescription
successbooleanWhether a layout was found
namestringThe name that was searched
resolvedKeystringThe actual plist key used (may be UUID if name was not found directly)
columnsstring[] | nullVisible columns in display order
tableViewColumnsstring[] | nullAll column identifiers (visible + hidden)
widthsobject | nullMap of column identifier to width (float)
keysFoundstring[]Which of the three plist keys were present

On failure, the response includes exampleNames (a list of names with saved layouts) and partialMatches when multiple fuzzy matches are found.

Example:

{
  "name": "Jobs - To Review"
}
{
  "success": true,
  "name": "Jobs - To Review",
  "resolvedKey": "Jobs - To Review",
  "columns": ["name", "date", "from", "subject"],
  "tableViewColumns": ["name", "date", "from", "subject", "tags", "size"],
  "widths": { "name": 280.0, "date": 120.0, "from": 180.0, "subject": 320.0 },
  "keysFound": [
    "ListColumnsHorizontal-Jobs - To Review",
    "TableView Columns ListColumnsHorizontal-Jobs - To Review",
    "TableView Column Widths ListColumnsHorizontal-Jobs - To Review"
  ]
}

copy_column_layout

Copies the column layout (visible columns, all columns, and column widths) from one smart group or smart rule to another. All three layout keys are written atomically using Python's plistlib so the binary plist format is preserved correctly.

Supports partial name matching for both source and target. DEVONthink must be restarted (or the smart group window closed and reopened) for the change to take effect.

Parameters:

ParameterTypeRequiredDescription
sourceNamestringyesName of the source smart group or smart rule (must have a saved layout)
targetNamestringyesName of the target smart group or smart rule
sourceUuidstringnoUUID fallback for the source (used if name lookup fails)
targetUuidstringnoUUID of the target — if supplied, the layout is written under the UUID key

Returns:

FieldTypeDescription
successbooleanWhether the copy succeeded
sourceNamestringThe source name provided
targetNamestringThe target name provided
resolvedSourceKeystringThe plist key used for the source
resolvedTargetKeystringThe plist key used for the target
keysCopiedstring[]The plist keys that were written
messagestringHuman-readable summary including the column names that were copied

Example:

{
  "sourceName": "Archivieren - Jobs",
  "targetName": "Jobs - To Review"
}
{
  "success": true,
  "sourceName": "Archivieren - Jobs",
  "targetName": "Jobs - To Review",
  "resolvedSourceKey": "Archivieren - Jobs",
  "resolvedTargetKey": "Jobs - To Review",
  "keysCopied": [
    "ListColumnsHorizontal-Jobs - To Review",
    "TableView Columns ListColumnsHorizontal-Jobs - To Review",
    "TableView Column Widths ListColumnsHorizontal-Jobs - To Review"
  ],
  "message": "Copied column layout from \"Archivieren - Jobs\" to \"Jobs - To Review\". Columns: [name, date, from, subject]. Restart DEVONthink or close/reopen the smart group window for the change to take effect."
}

Workflows

Smart group discovery and content querying

Smart groups are virtual views defined by search criteria — they have no physical location in the database. Because they are not part of the AppleScript scripting dictionary, you cannot list them through normal MCP or JXA calls. Use this two-step pattern instead:

Step 1: Enumerate all smart groups to find the UUID of the one you want.

list_smart_groups

Response includes each smart group's name and uuid.

Step 2: Query the contents of that smart group using the search tool with groupUuid.

search
  query: ""
  groupUuid: "4A469368-94FD-46D3-9A62-ED7C24D822D8"

This returns all records that match the smart group's criteria. The search tool sorts by relevance by default; add a sortBy parameter if you need date ordering.

Important: list_group_content with a smart group UUID returns email Message-IDs in the uuid field (not DEVONthink record UUIDs). Use search with groupUuid instead — it returns proper records with dates and correct UUIDs that work with get_record_properties and get_record_content.

Email thread correlation

To link a live Gmail thread back to its archived copy in DEVONthink, use a three-tier matching strategy:

Tier 1 — Thread ID match (highest precision)

Get the file path for the archived record:

get_record_properties
  uuid: <record_uuid>

Extract the path field, then parse the EML headers:

parse_eml_headers
  filePath: "/path/to/archived/email.eml"

Use the messageId, inReplyTo, and references values to correlate precisely with Gmail thread headers.

Tier 2 — Subject and sender match

search
  query: "kind:email subject:\"Contract renewal\" from:jane@example.com"

Strip Re:, Fwd:, AW:, WG: prefixes before searching.

Tier 3 — Subject only (broadest)

search
  query: "kind:email subject:\"Contract renewal\""

Always try Tier 1 first when the EML path is available. Report which tier matched so confidence is clear.

Column layout management

When you create a new smart group and want it to display the same columns as an existing one:

Step 1: Read the layout of the source smart group to see what columns it uses.

get_column_layout
  name: "Archivieren - Jobs"

Step 2: Copy that layout to the new smart group.

copy_column_layout
  sourceName: "Archivieren - Jobs"
  targetName: "New Smart Group"

If DEVONthink stores layouts by UUID rather than display name, supply the UUID as a fallback:

copy_column_layout
  sourceName: "Archivieren - Jobs"
  targetName: "New Smart Group"
  targetUuid: "4A469368-94FD-46D3-9A62-ED7C24D822D8"

Close and reopen the smart group window (or restart DEVONthink) after copying for the change to take effect.

DEVONthink search syntax

The upstream search tool supports these operators:

OperatorExampleDescription
kind:kind:emailFilter by record type
name:name:"offer letter"Match filename or subject
subject:subject:"interview"Email subject field
from:from:recruiter@co.comSender address
to:to:user@example.comRecipient address
text:text:"stock options"Full-text content search
tags:tags:jobsTagged records
date:date:2024-01-01~Date range (~ = after)
Quotes"exact phrase"Exact phrase match
AND/ORfrom:x OR from:yBoolean operators

Combining operators:

kind:email from:@company.com subject:"compensation" date:2023-01-01~2024-12-31

How it works

devonthink-mcp runs as an in-process MCP server built on @modelcontextprotocol/sdk. It imports all upstream tool objects from mcp-server-devonthink and adds the five custom tools, then serves them through a single unified ListTools / CallTool handler.

The upstream tools communicate with DEVONthink via JXA (JavaScript for Automation) over the macOS Scripting Bridge. The custom tools use plutil, PlistBuddy, and Python's plistlib to read DEVONthink preference and data files directly.

Troubleshooting

"DEVONthink not found" Make sure DEVONthink 3 or 4 is installed in /Applications and running.

"No databases found" Open at least one DEVONthink database before using the MCP tools.

Tools not appearing in Claude Code

  • Verify ~/.claude.json has the devonthink entry
  • Restart Claude Code (not just a new session — fully quit and reopen)
  • Check that DEVONthink is running

AppleScript errors Grant Claude Code (or Terminal) Automation permissions in System Settings > Privacy & Security > Automation.

list_smart_groups returns no results or error The plist format varies between DEVONthink versions. If the tool cannot parse the structure, use plutil -p ~/Library/Application\ Support/DEVONthink/SmartGroups.plist to inspect the raw format and report an issue.

get_column_layout returns "no layout found" The smart group does not yet have a custom column layout saved — it uses DEVONthink defaults. Use copy_column_layout to copy a layout from another smart group that already has one configured.

Credits

The core DEVONthink MCP implementation is by dvcrn. This package adds setup tooling, packaging, and the custom extensions above.

License

MIT

Keywords

mcp

FAQs

Package last updated on 23 Feb 2026

Related posts