MCP server for Directus 12 — items, collections, files, flows, users, and schema tools
Runs on your machine from its package; the steps are below.
At most: creates or changes data: records, files, settings.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Run
npx -y @staminna/directus-mcp-server
MCP client config
{
"mcpServers": {
"directus": {
"command": "npx",
"args": [
"-y",
"@staminna/directus-mcp-server"
]
}
}
}MCP server for Directus 12 — items, collections, files, flows, users, and schema tools. TypeScript, typed throughout.
| Statements | Branches | Functions | Lines |
|---|---|---|---|
Coverage badges are generated from coverage/coverage-summary.json by npm run badges (no external service required). Run npm run test:coverage first.
npm install -g @staminna/directus-mcp-server
git clone https://github.com/staminna/mcp-server-claude.git
cd mcp-server-claude
npm install
npm run build
| Variable | Required | Description |
|---|---|---|
DIRECTUS_URL | Yes | Your Directus instance URL (e.g., http://localhost:8065) |
DIRECTUS_TOKEN | Yes | Static API token with appropriate permissions |
DIRECTUS_PROMPTS_COLLECTION_ENABLED | No | Enable AI prompts collection (true/false) |
DIRECTUS_PROMPTS_COLLECTION | No | Collection name for AI prompts (default: ai_prompts) |
DIRECTUS_RESOURCES_ENABLED | No | Enable resources feature (true/false) |
DIRECTUS_RESOURCES_EXCLUDE_SYSTEM | No | Exclude system collections from resources (true/false) |
NODE_ENV | No | Environment mode (development/production) |
DIRECTUS_TIMEOUT | No | Request timeout in ms (default: 30000) |
DIRECTUS_RETRIES | No | Retry attempts for network errors, 5xx and 429 (default: 3) |
DIRECTUS_RETRY_DELAY | No | Base backoff delay in ms (default: 1000) |
DIRECTUS_MAX_RETRY_DELAY | No | Backoff ceiling in ms (default: 10000) |
DIRECTUS_IMPORT_MAX_FILE_SIZE | No | Client-side import size ceiling in bytes, mirroring the Directus IMPORT_MAX_FILE_SIZE (default: 50 MB) |
LOG_LEVEL | No | DEBUG/INFO/WARN/ERROR (default: INFO). Logs go to stderr; stdout is reserved for MCP |
Set these when the Directus instance uses a private CA or requires a client
certificate. Each of CA/CERT/KEY/PFX accepts either a file path or the
PEM/DER content itself.
| Variable | Description |
|---|---|
DIRECTUS_HTTPS_CA | Certificate authority |
DIRECTUS_HTTPS_CERT | Client certificate |
DIRECTUS_HTTPS_KEY | Client private key |
DIRECTUS_HTTPS_PFX | PKCS#12 bundle (alternative to cert/key) |
DIRECTUS_HTTPS_PASSPHRASE | Passphrase for the key or PFX |
DIRECTUS_HTTPS_REJECT_UNAUTHORIZED | false to accept self-signed certificates |
DIRECTUS_HTTPS_SERVERNAME | SNI server name override |
This server uses a static Directus access token (DIRECTUS_TOKEN) and runs over stdio transport. OAuth is not required, by design:
DIRECTUS_V12_BREAKING_CHANGES.md).Generate the token in Directus under User Settings → Token (use a dedicated user with least-privilege role for production).
MCP servers do not consume Anthropic API tokens themselves; only the AI client's model calls do. If you use this server inside Claude Code or Claude Desktop with a Claude Max (or Pro) subscription, the model usage is covered by the subscription — you do not need an Anthropic API key. An API key is only required when driving Claude programmatically via the Claude API (e.g. the remote MCP connector).
Cmd+, (macOS) or Ctrl+, (Windows/Linux){
"mcpServers": {
"directus": {
"command": "npx",
"args": [
"-y",
"@staminna/directus-mcp-server"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
}
}
Or if installed locally:
{
"mcpServers": {
"directus": {
"command": "node",
"args": [
"/path/to/mcp-server-claude/dist/index.js"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
}
}
Cmd+, (macOS) or Ctrl+, (Windows/Linux){
"mcpServers": {
"directus": {
"command": "npx",
"args": [
"-y",
"@staminna/directus-mcp-server"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here",
"DIRECTUS_PROMPTS_COLLECTION_ENABLED": "true",
"DIRECTUS_PROMPTS_COLLECTION": "ai_prompts",
"DIRECTUS_RESOURCES_ENABLED": "true",
"DIRECTUS_RESOURCES_EXCLUDE_SYSTEM": "true",
"NODE_ENV": "production"
}
}
}
}
Or if installed locally:
{
"mcpServers": {
"directus": {
"command": "node",
"args": [
"/path/to/mcp-server-claude/dist/index.js"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
}
}
Cmd+Q or Ctrl+Q)Locate your Claude Desktop config file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json~/.config/Claude/claude_desktop_config.jsonCreate or edit the config file:
{
"mcpServers": {
"directus": {
"command": "npx",
"args": [
"-y",
"@staminna/directus-mcp-server"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
}
}
Or if installed locally:
{
"mcpServers": {
"directus": {
"command": "node",
"args": [
"/path/to/mcp-server-claude/dist/index.js"
],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
}
}
For Claude.ai web interface with MCP support:
{
"name": "directus",
"command": "npx",
"args": ["-y", "@staminna/directus-mcp-server"],
"env": {
"DIRECTUS_URL": "http://localhost:8065",
"DIRECTUS_TOKEN": "your-directus-token-here"
}
}
Note: Claude.ai MCP support may require a Pro subscription and specific browser extensions.
| Tool | Description |
|---|---|
list_collections | List all collections; folders and inactive collections (Directus 12.4) are marked |
get_collection_schema | Get schema for a specific collection |
get_collection_items | Get items from a collection with filtering |
create_collection | Create a new collection |
delete_collection | Delete a collection (requires confirm) |
create_item | Create a new item in a collection |
update_item | Update an existing item, optionally into a draft version |
delete_items | Delete items by ids or by query (see note below) |
bulk_operations | Execute bulk create, update, delete |
| Tool | Description |
|---|---|
create_field | Create a new field in a collection |
update_field | Update an existing field |
delete_field | Delete a field from a collection |
create_relationship | Create relationships (O2O, O2M, M2O, M2M, M2A) |
analyze_collection_schema | Analyze schema with relationship mapping |
validate_collection_schema | Validate schema and relationships |
analyze_relationships | Analyze relationships across collections |
get_schema_snapshot | Read a full or partial snapshot of the data model |
diff_schema | Compare a snapshot against the live schema (merge or mirror). Directus drops request bodies over ~96 KB, so pass a partial snapshot from get_schema_snapshot with include_collections on any sizeable data model — see DIRECTUS_V12_BREAKING_CHANGES.md |
apply_schema | Apply a diff (requires confirm) |
| Tool | Description |
|---|---|
get_flows | Get all flows, optionally by folder (Directus 12.4) |
get_flow | Get a specific flow by ID |
create_flow | Create a new automation flow, optionally inside a folder |
update_flow | Update an existing flow |
delete_flow | Delete a flow |
trigger_flow | Manually trigger a flow |
get_operations | Get flow operations |
| Tool | Description |
|---|---|
get_users | Get all users with filtering |
get_user | Get a specific user by ID |
| Tool | Description |
|---|---|
get_files | Get files with filtering and pagination |
import_data | Import CSV/JSON into one collection, or several at once |
| Tool | Description |
|---|---|
diagnose_collection_access | Diagnose collection access issues |
refresh_collection_cache | Refresh collection cache |
validate_collection_creation | Validate newly created collections |
| Tool | Description |
|---|---|
search_tools | Find the tools matching a task description |
Every tool carries MCP annotations so a client can tell reads from writes before
calling: 17 are readOnlyHint: true, 6 are explicitly destructiveHint: false
(additive — creates), and 11 are destructiveHint: true (deletes, overwriting
updates, apply_schema, import_data, trigger_flow).
Note that destructiveHint defaults to true in the MCP spec, which is why
the additive tools set it to false rather than omitting it.
Following Directus 12.3.0, delete_items never falls back to deleting
everything:
ids: [...] deletes those items.query: {...} deletes everything the query matches.To delete every item in a collection, ask for it explicitly:
{ "collection": "articles", "query": { "limit": -1 }, "confirm": true }
Since Directus 12.4.0 a query resolves its targets under the token's read
permissions: read access to the primary key is required, and only items the
token can read are deleted. A token that can delete but not read deletes
nothing.
Once configured, you can interact with Directus through your AI assistant:
"List all collections in my Directus instance"
"Create a new collection called 'blog_posts' with title, content, and published fields"
"Get all items from the 'products' collection where status is 'published'"
"Create a new flow that triggers on item creation in the 'orders' collection"
"Analyze the schema of the 'users' collection including relationships"
Ensure your Directus token has the required permissions:
If using a remote Directus instance:
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run dev
# Run server
npm start
# Type check
npm run typecheck
# Lint
npm run lint
The project ships unit, integration and end-to-end suites (vitest). Coverage thresholds (95% statements/lines/functions/branches) are enforced — the test run fails below them.
# Unit + integration tests
npm test
# With coverage report (coverage/ — text, html, lcov, json-summary)
npm run test:coverage
# End-to-end: builds, then spawns the real server over stdio against a mock Directus
npm run test:e2e
# Everything
npm run test:all
# Refresh the README coverage badges from the last coverage run
npm run badges
tests/live/demo.mjs drives all 34 tools against a real instance over stdio. It is
deliberately outside npm test — it needs a credential and a reachable server, so it
is a manual gate rather than a CI one.
# Read-only + guard phases (touches nothing)
ENV_FILE=.env.mdbaudio npm run test:live
# Also create, mutate and drop a scratch mcp_demo_<stamp> collection
ENV_FILE=.env.mdbaudio npm run test:live -- --write
# Additionally exercise apply_schema, confined to that scratch collection
ENV_FILE=.env.mdbaudio npm run test:live -- --write --apply-schema
Credentials are read from ENV_FILE (default .env.mdbaudio) so they never pass through
shell history. Results are reported per tool as pass / refused-by-instance / fail, keeping
"this server is broken" separate from "this instance declined". --apply-schema diffs in
merge mode, which yields a strictly additive diff, so it can only re-create the scratch
collection — it cannot drop anything that already existed. Cleanup runs even when an
earlier phase fails.
The e2e suite uses the official MCP SDK client (StdioClientTransport) to spawn dist/index.js as a subprocess, talking to an in-process mock Directus on an ephemeral port — no real Directus instance or network access needed.
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)MIT © Jorge Domingues Nunes