npm package: @skeyelab/directus-mcp-server
Description: MCP server for managing Directus schema and content
Author: Eric Dahl
Latest version: 2.2.0

# Directus MCP Server

A Model Context Protocol (MCP) server that provides comprehensive tools for managing Directus schema and content. This server enables AI assistants and other MCP clients to interact with Directus instances programmatically.

## Installation

### From npm (once published)

```bash
npm install -g directus-mcp-server
```

### From source

```bash
git clone https://github.com/yourusername/directus-mcp.git
cd directus-mcp
npm install
npm run build
```

## Features

- **Schema Management**: Create, read, update, and delete collections, fields, and relations
- **Content Management**: Full CRUD operations on items with advanced querying
- **Type Safety**: Built with TypeScript and Zod validation
- **Official SDK**: Uses the official `@directus/sdk` for reliable API interactions
- **Flexible Authentication**: Supports both static tokens and email/password authentication

## Installation

```bash
npm install
```

## Configuration

Create a `.env` file in the root directory with your Directus configuration:

```env
# Directus Instance URL
DIRECTUS_URL=https://your-directus-instance.com

# Authentication - Use either token OR email/password
DIRECTUS_TOKEN=your_static_token_here

# Alternative: Email/Password authentication
# DIRECTUS_EMAIL=admin@example.com
# DIRECTUS_PASSWORD=your_password
```

### Authentication Options

1. **Static Token** (Recommended for production):
   - Generate a static token in Directus Admin App
   - Set `DIRECTUS_TOKEN` environment variable

2. **Email/Password**:
   - Use for development or when static tokens aren't available
   - Set `DIRECTUS_EMAIL` and `DIRECTUS_PASSWORD` environment variables

### Toolset Configuration

The Directus MCP server organizes tools into logical toolsets, similar to GitHub's MCP implementation. This allows you to control which tools are exposed to the MCP client.

**Available Toolsets:**
- `default` - Contains collections, fields, relations, and content tools (default behavior when no toolset is specified)
- `collections` - Collection management tools (list, get, create, update, delete collections)
- `fields` - Field management tools (list, create, update, delete fields)
- `relations` - Relation management tools (list, create, delete relations)
- `schema` - Schema snapshot and diff tools (get snapshot, get diff, apply diff) - NOT included in default toolset
- `content` - Content management tools (items CRUD operations)
- `flow` - Flow management tools (workflow automation) - NOT included in default toolset
- `dashboards` - Dashboard and panel management tools (list, get, create, update, delete dashboards and panels) - NOT included in default toolset
- `all` - All available tools regardless of toolset membership

**Default Behavior:**
When `MCP_TOOLSETS` is not set or empty, only tools in the `default` toolset are exposed. The `default` toolset contains collections, fields, relations, and content tools, but **not** schema, flow, or dashboard tools. Schema, flow, and dashboard tools must be explicitly requested by including `schema`, `flow`, or `dashboards` in the `MCP_TOOLSETS` environment variable.

**Configuration:**
Set the `MCP_TOOLSETS` environment variable to a comma-separated list of toolsets:

```env
# Expose only collections tools
MCP_TOOLSETS=collections

# Expose only schema snapshot/diff tools
MCP_TOOLSETS=schema

# Expose collections and fields tools
MCP_TOOLSETS=collections,fields

# Expose only dashboard and panel tools
MCP_TOOLSETS=dashboards

# Expose all schema-related toolsets
MCP_TOOLSETS=collections,fields,relations,schema

# Expose all toolsets (includes flow and dashboard tools)
MCP_TOOLSETS=default,flow,dashboards
# OR
MCP_TOOLSETS=collections,fields,relations,schema,content,flow,dashboards
# OR simply use 'all' to expose everything
MCP_TOOLSETS=all
```

**Examples:**

```json
{
  "mcpServers": {
    "directus-schema": {
      "command": "node",
      "args": ["/path/to/directus-mcp/dist/index.js"],
      "env": {
        "DIRECTUS_URL": "https://your-directus-instance.com",
        "DIRECTUS_TOKEN": "your_token",
        "MCP_TOOLSETS": "schema"
      }
    },
    "directus-content": {
      "command": "node",
      "args": ["/path/to/directus-mcp/dist/index.js"],
      "env": {
        "DIRECTUS_URL": "https://your-directus-instance.com",
        "DIRECTUS_TOKEN": "your_token",
        "MCP_TOOLSETS": "content"
      }
    }
  }
}
```

**Notes:**
- Toolset names are case-insensitive
- Invalid toolset names are ignored (with a warning)
- If all requested toolsets are invalid, the server defaults to the `default` toolset
- Collections, fields, relations, and content tools belong to both `default` and their specific toolset
- Schema, flow, and dashboard tools belong ONLY to their respective toolsets (not in `default`)

## Building

```bash
npm run build
```

## Usage

### Running the Server

```bash
npm start
```

Or use the built binary:

```bash
node dist/index.js
```

### MCP Client Configuration

Add to your MCP client configuration (e.g., Claude Desktop, Cline):

**Option 1: Using npx (recommended - no installation needed):**
```json
{
  "mcpServers": {
    "directus": {
      "command": "npx",
      "args": ["-y", "directus-mcp-server"],
      "env": {
        "DIRECTUS_URL": "https://your-directus-instance.com",
        "DIRECTUS_TOKEN": "your_static_token_here",
        "MCP_TOOLSETS": "default"
      }
    }
  }
}
```

**Option 2: Using global installation:**
```json
{
  "mcpServers": {
    "directus": {
      "command": "directus-mcp",
      "env": {
        "DIRECTUS_URL": "https://your-directus-instance.com",
        "DIRECTUS_TOKEN": "your_static_token_here",
        "MCP_TOOLSETS": "default"
      }
    }
  }
}
```

**Option 3: Using local source:**
```json
{
  "mcpServers": {
    "directus": {
      "command": "node",
      "args": ["/absolute/path/to/directus-mcp/dist/index.js"],
      "env": {
        "DIRECTUS_URL": "https://your-directus-instance.com",
        "DIRECTUS_TOKEN": "your_static_token_here",
        "MCP_TOOLSETS": "default"
      }
    }
  }
}
```

## Available Tools

### Schema Management Tools

#### `list_collections`
List all collections in the Directus instance.

**Parameters**: None

**Example**:
```json
{}
```

#### `get_collection`
Get detailed information about a specific collection.

**Parameters**:
- `collection` (string): Collection name

**Example**:
```json
{
  "collection": "articles"
}
```

#### `create_collection`
Create a new collection (database table) with optional fields. This automatically creates a proper database table, not just a folder.

**Parameters**:
- `collection` (string): Collection name
- `meta` (object, optional): Collection metadata (icon, note, singleton, etc.)
- `schema` (object, optional): Database schema configuration (automatically set if not provided)
- `fields` (array, optional): Initial fields to create

**Example**:
```json
{
  "collection": "articles",
  "meta": {
    "icon": "article",
    "note": "Blog articles collection"
  },
  "fields": [
    {
      "field": "id",
      "type": "integer",
      "schema": {
        "is_primary_key": true,
        "has_auto_increment": true
      }
    },
    {
      "field": "title",
      "type": "string",
      "meta": {
        "required": true
      }
    },
    {
      "field": "status",
      "type": "string",
      "meta": {
        "interface": "select-dropdown",
        "options": {
          "choices": [
            {"text": "Draft", "value": "draft"},
            {"text": "Published", "value": "published"}
          ]
        }
      }
    }
  ]
}
```

#### `update_collection`
Update collection metadata.

**Parameters**:
- `collection` (string): Collection name
- `meta` (object): Metadata to update

**Example**:
```json
{
  "collection": "articles",
  "meta": {
    "icon": "article",
    "note": "Updated description"
  }
}
```

#### `delete_collection`
Delete a collection and all its data.

**Parameters**:
- `collection` (string): Collection name

**Example**:
```json
{
  "collection": "articles"
}
```

#### `list_fields`
List all fields in a collection.

**Parameters**:
- `collection` (string): Collection name

**Example**:
```json
{
  "collection": "articles"
}
```

#### `create_field`
Add a new field to a collection.

**Parameters**:
- `collection` (string): Collection name
- `field` (string): Field name
- `type` (string): Field type (string, integer, text, boolean, json, uuid, timestamp, etc.)
- `meta` (object, optional): Field metadata
- `schema` (object, optional): Database schema configuration

**Example**:
```json
{
  "collection": "articles",
  "field": "author",
  "type": "uuid",
  "meta": {
    "interface": "select-dropdown-m2o",
    "required": true,
    "special": ["m2o"]
  }
}
```

#### `update_field`
Update field properties.

**Parameters**:
- `collection` (string): Collection name
- `field` (string): Field name
- `type` (string, optional): Field type
- `meta` (object, optional): Metadata to update
- `schema` (object, optional): Schema to update

**Example**:
```json
{
  "collection": "articles",
  "field": "title",
  "meta": {
    "note": "Article title (required)"
  }
}
```

#### `delete_field`
Remove a field from a collection.

**Parameters**:
- `collection` (string): Collection name
- `field` (string): Field name

**Example**:
```json
{
  "collection": "articles",
  "field": "old_field"
}
```

#### `list_relations`
List all relations in the Directus instance.

**Parameters**: None

**Example**:
```json
{}
```

#### `create_relation`
Create a relation between collections.

**Parameters**:
- `collection` (string): Many collection (with foreign key)
- `field` (string): Field name in many collection
- `related_collection` (string, optional): One collection
- `meta` (object, optional): Relation metadata
- `schema` (object, optional): Database relation configuration

**Example (Many-to-One)**:
```json
{
  "collection": "articles",
  "field": "author",
  "related_collection": "users",
  "schema": {
    "on_delete": "SET NULL"
  }
}
```

**Example (One-to-Many)**:
```json
{
  "collection": "articles",
  "field": "author",
  "related_collection": "users",
  "meta": {
    "one_field": "articles"
  }
}
```

#### `delete_relation`
Delete a relation.

**Parameters**:
- `collection` (string): Collection name
- `field` (string): Field name

**Example**:
```json
{
  "collection": "articles",
  "field": "author"
}
```

### Content Management Tools

#### `query_items`
Query items with filtering, sorting, and pagination.

**Parameters**:
- `collection` (string): Collection name
- `fields` (array, optional): Fields to return
- `filter` (object, optional): Filter criteria
- `search` (string, optional): Search query
- `sort` (array, optional): Sort fields (prefix with `-` for descending)
- `limit` (number, optional): Maximum items to return
- `offset` (number, optional): Items to skip
- `page` (number, optional): Page number
- `aggregate` (object, optional): Aggregation functions
- `groupBy` (array, optional): Group by fields
- `deep` (object, optional): Deep relational queries

**Filter Operators**: `_eq`, `_neq`, `_lt`, `_lte`, `_gt`, `_gte`, `_in`, `_nin`, `_null`, `_nnull`, `_contains`, `_ncontains`, `_starts_with`, `_nstarts_with`, `_ends_with`, `_nends_with`, `_between`, `_nbetween`

**Example**:
```json
{
  "collection": "articles",
  "filter": {
    "status": {"_eq": "published"},
    "date_created": {"_gte": "2024-01-01"}
  },
  "sort": ["-date_created"],
  "limit": 10
}
```

#### `get_item`
Get a single item by ID.

**Parameters**:
- `collection` (string): Collection name
- `id` (string|number): Item ID
- `fields` (array, optional): Fields to return
- `deep` (object, optional): Deep relational queries

**Example**:
```json
{
  "collection": "articles",
  "id": 1,
  "fields": ["id", "title", "status", "author.first_name"]
}
```

#### `create_item`
Create a new item.

**Parameters**:
- `collection` (string): Collection name
- `data` (object): Item data

**Example**:
```json
{
  "collection": "articles",
  "data": {
    "title": "My New Article",
    "status": "draft",
    "body": "Article content here...",
    "author": "user-uuid-here"
  }
}
```

#### `update_item`
Update an existing item.

**Parameters**:
- `collection` (string): Collection name
- `id` (string|number): Item ID
- `data` (object): Fields to update

**Example**:
```json
{
  "collection": "articles",
  "id": 1,
  "data": {
    "status": "published"
  }
}
```

#### `delete_item`
Delete an item.

**Parameters**:
- `collection` (string): Collection name
- `id` (string|number): Item ID

**Example**:
```json
{
  "collection": "articles",
  "id": 1
}
```

#### `bulk_create_items`
Create multiple items at once.

**Parameters**:
- `collection` (string): Collection name
- `items` (array): Array of item data objects

**Example**:
```json
{
  "collection": "articles",
  "items": [
    {"title": "Article 1", "status": "draft"},
    {"title": "Article 2", "status": "draft"}
  ]
}
```

#### `bulk_update_items`
Update multiple items at once.

**Parameters**:
- `collection` (string): Collection name
- `items` (array): Array of items with id and fields to update

**Example**:
```json
{
  "collection": "articles",
  "items": [
    {"id": 1, "status": "published"},
    {"id": 2, "status": "published"}
  ]
}
```

#### `bulk_delete_items`
Delete multiple items at once.

**Parameters**:
- `collection` (string): Collection name
- `ids` (array): Array of item IDs

**Example**:
```json
{
  "collection": "articles",
  "ids": [1, 2, 3]
}
```

## Common Use Cases

### Setting up a new content model

1. Create a collection with `create_collection`
2. Add fields with `create_field`
3. Create relations with `create_relation`
4. Start adding content with `create_item`

### Querying content with relations

```json
{
  "collection": "articles",
  "fields": ["*", "author.first_name", "author.last_name"],
  "filter": {"status": {"_eq": "published"}},
  "sort": ["-date_created"],
  "limit": 10
}
```

### Bulk operations

Use `bulk_create_items`, `bulk_update_items`, or `bulk_delete_items` for efficient batch operations.

## Development

```bash
# Watch mode for development
npm run dev

# Build for production
npm run build
```

## Tool Authoring

This project provides utilities to streamline MCP tool development and reduce code duplication:

### Tool Helpers

Use `createTool` for tools that return data, and `createActionTool` for tools that perform actions:

```typescript
import { createTool, createActionTool } from './tools/tool-helpers.js';

// Data-returning tool
const myTool = createTool({
  name: 'my_tool',
  description: 'Description of what the tool does',
  inputSchema: MySchema,
  toolsets: ['default', 'my-category'],
  handler: async (client, args) => client.someMethod(args)
});

// Action tool (returns success message)
const myActionTool = createActionTool({
  name: 'delete_something',
  description: 'Delete something',
  inputSchema: DeleteSchema,
  toolsets: ['default'],
  handler: async (client, args) => client.deleteMethod(args.id),
  successMessage: (args) => `Successfully deleted item ${args.id}`
});
```

### Shared Validators

Common Zod schemas are available in `src/tools/validators.ts`:

- `CollectionNameSchema` - For collection names
- `ItemIdSchema` - For item IDs (string | number)
- `FieldsSchema` - For field arrays
- `FilterSchema` - For Directus filter objects
- Query parameter schemas (`SortSchema`, `LimitSchema`, etc.)
- Flow-related schemas (`FlowTriggerSchema`, `FlowStatusSchema`, etc.)

Example usage:

```typescript
import { CollectionNameSchema, ItemIdSchema } from './tools/validators.js';

const MyToolSchema = z.object({
  collection: CollectionNameSchema,
  id: ItemIdSchema,
  // ... other fields
});
```

### Directus Client Resource Factory

The client uses a resource factory pattern for consistent CRUD operations. When adding new Directus resources, define them in the client constructor using `createResourceMethods()`.

## Error Handling

All tools include error handling and will return descriptive error messages for:
- Authentication failures
- Invalid parameters
- API errors
- Network issues
- Validation errors

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.