npm package: @mybe/contensa-mcp
Description: MCP (Model Context Protocol) server for Contensa CMS - enables AI assistants to interact with your CMS
Latest version: 1.2.2

# Contensa MCP Server

MCP (Model Context Protocol) server for Contensa CMS. This enables AI assistants like Claude (via Cursor, Claude Desktop, etc.) to interact directly with your CMS.

## Features

- **Content Type Management**: Create, read, update, delete content types
- **Field Management**: Add, modify, remove fields from content types
- **Content Entry Management**: Create, read, update, delete, publish content entries
- **Locale Management**: Create and manage multilingual content variants with AI translation
- **Environment Management**: Create, manage, and merge/sync environments
- **Media Management**: List and manage media assets
- **AI-Powered Features**: Generate schemas and field suggestions using AI

## Installation

Install globally to use with MCP clients like Cursor or Claude Desktop:

```bash
npm install -g @mybe/contensa-mcp
```

Or use directly with npx (no installation needed):

```bash
npx @mybe/contensa-mcp
```

**For development** (if using the monorepo):

```bash
cd packages/mcp-server
npm install
npm run build
```

## Configuration

### For Cursor

Add to your Cursor MCP settings (`~/.cursor/mcp.json` or workspace `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "contensa": {
      "command": "contensa-mcp",
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

**Alternative** (if not installed globally, use npx):
```json
{
  "mcpServers": {
    "contensa": {
      "command": "npx",
      "args": ["@mybe/contensa-mcp"],
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

Or if running from the monorepo:

```json
{
  "mcpServers": {
    "contensa": {
      "command": "node",
      "args": ["/path/to/mybe-cms/packages/mcp-server/dist/cli.js"],
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

### For Claude Desktop

Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "contensa": {
      "command": "contensa-mcp",
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

**Alternative** (if not installed globally, use npx):
```json
{
  "mcpServers": {
    "contensa": {
      "command": "npx",
      "args": ["@mybe/contensa-mcp"],
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `CONTENSA_API_KEY` | Yes | Your Contensa API key (project-level authentication) |
| `CONTENSA_MCP_TOKEN` | Yes | Your Contensa MCP token (per-user authentication with scopes) |
| `CONTENSA_USER_ID` | Yes | Your user ID (required for creating/updating content) |
| `CONTENSA_PROJECT_ID` | No | Default project ID |
| `CONTENSA_BASE_URL` | No | Custom API base URL (defaults to Contensa production API or localhost in dev) |

### MCP Token and API Key - Why Both Are Required

The MCP server requires **both** `CONTENSA_MCP_TOKEN` and `CONTENSA_API_KEY` to function properly. Here's why:

**MCP Token (`X-MCP-Token` header)**:
- Per-user, per-project authentication
- Carries fine-grained scopes (e.g., `content:read`, `content:write`)
- Provides user context for operations
- Can expire and be revoked individually
- Tracks last-used timestamp for audit purposes

**API Key (`X-API-Key` header)**:
- Project-level authentication
- Provides full project access
- Required for certain backend operations
- No expiration

**How They Work Together**:
The MCP server sends both headers in every request. The backend API uses a dual authentication system (`dualAuth` middleware) with the following priority:

1. `Authorization: Bearer <session>` — Dashboard users (highest priority)
2. `X-MCP-Token: mcp_live_...` — MCP agents (per-user with scopes)
3. `X-API-Key: ck_...` — Project-level API keys (fallback)

This dual-token approach ensures:
- ✅ User-level permissions and scoping via MCP token
- ✅ Project-level access validation via API key
- ✅ Audit trail of which user performed which operations
- ✅ Fine-grained access control based on token scopes

**Getting Your Tokens**:

1. **MCP Token**:
   - Log in to your Contensa dashboard
   - Go to Settings → MCP Tokens
   - Create a new MCP token with appropriate scopes (e.g., `content:read`, `content:write`)
   - Copy the token (shown only once) - format: `mcp_live_<64 hex characters>`

2. **API Key**:
   - Log in to your Contensa dashboard
   - Go to Settings → API Keys
   - Generate a new API key for your project
   - Copy the key - format: `ck_<...>`

### API Base URL

The MCP server automatically determines the API base URL:

- **Development** (`NODE_ENV=development`): Uses `http://localhost:3001/api/v1`
- **Production**: Uses Contensa's production API endpoint

You can override the default by setting `CONTENSA_BASE_URL` for custom API endpoints or different environments:

```json
{
  "mcpServers": {
    "contensa": {
      "command": "node",
      "args": ["./packages/mcp-server/dist/cli.js"],
      "env": {
        "CONTENSA_API_KEY": "your-api-key",
        "CONTENSA_MCP_TOKEN": "mcp_live_a3f8c2d1...",
        "CONTENSA_USER_ID": "your-user-id",
        "CONTENSA_BASE_URL": "https://your-custom-api.com/api/v1"
      }
    }
  }
}
```

## Available Tools

### Project Management

| Tool | Description |
|------|-------------|
| `contensa_list_projects` | List all projects |
| `contensa_get_project` | Get project details |
| `contensa_set_active_project` | Set the active project |

### Content Type Management

| Tool | Description |
|------|-------------|
| `contensa_list_content_types` | List all content types in a project |
| `contensa_get_content_type` | Get content type details with fields |
| `contensa_create_content_type` | Create a new content type |
| `contensa_update_content_type` | Update a content type |
| `contensa_delete_content_type` | Delete a content type |

### Field Management

| Tool | Description |
|------|-------------|
| `contensa_list_fields` | List fields of a content type |
| `contensa_create_field` | Add a field to a content type |
| `contensa_update_field` | Update a field |
| `contensa_delete_field` | Delete a field |

### Content Entry Management

| Tool | Description |
|------|-------------|
| `contensa_list_content_entries` | List entries of a content type |
| `contensa_get_content_entry` | Get a content entry |
| `contensa_create_content_entry` | Create a new entry |
| `contensa_update_content_entry` | Update an entry |
| `contensa_delete_content_entry` | Delete an entry |
| `contensa_publish_content_entry` | Publish an entry |
| `contensa_unpublish_content_entry` | Unpublish an entry |

### Locale Management

| Tool | Description |
|------|-------------|
| `contensa_get_supported_locales` | Get all supported locales in the system |
| `contensa_list_locale_variants` | List all locale variants of an entry |
| `contensa_create_locale_variant` | Create a new locale variant with optional AI translation |

### Media Management

| Tool | Description |
|------|-------------|
| `contensa_list_media_assets` | List media assets |
| `contensa_get_media_asset` | Get media asset details |
| `contensa_delete_media_asset` | Delete a media asset |

### Environment Management

| Tool | Description |
|------|-------------|
| `contensa_list_environments` | List all environments for a project |
| `contensa_get_environment` | Get environment details |
| `contensa_create_environment` | Create a new environment (empty or cloned) |
| `contensa_update_environment` | Update environment details |
| `contensa_delete_environment` | Delete an environment |
| `contensa_set_active_environment` | Set the active environment for content operations |
| `contensa_merge_environment` | Merge content from one environment to another |
| `contensa_sync_environment` | Sync content between environments (in development) |

### AI Features

| Tool | Description |
|------|-------------|
| `contensa_suggest_fields` | AI-powered field suggestions |
| `contensa_generate_schema` | AI-powered schema generation |

## Usage Examples

Once configured, you can interact with your CMS through natural language:

### Example 1: Create a Blog Content Type

```
"Create a new content type called 'Blog Post' with fields for title, content, author, and published date"
```

The AI will use:
1. `contensa_create_content_type` to create "Blog Post"
2. `contensa_create_field` multiple times to add each field

### Example 2: Create Content

```
"Create a new blog post titled 'Hello World' with content 'This is my first post'"
```

The AI will use:
1. `contensa_list_content_types` to find the Blog Post type
2. `contensa_list_fields` to get the field API names
3. `contensa_create_content_entry` to create the entry with proper field names

### Example 3: Publish Content

```
"Publish all draft blog posts"
```

The AI will use:
1. `contensa_list_content_entries` with status filter
2. `contensa_publish_content_entry` for each draft

### Example 4: AI Schema Generation

```
"Generate a schema for an e-commerce product catalog"
```

The AI will use:
1. `contensa_generate_schema` to get AI suggestions
2. `contensa_create_content_type` to create the type
3. `contensa_create_field` to add each suggested field

### Example 5: Environment Merging

```
"Merge the dev environment to master"
```

The AI will use:
1. `contensa_list_environments` to find the dev and master environment IDs
2. `contensa_merge_environment` with dryRun=true to preview conflicts
3. `contensa_merge_environment` with dryRun=false to perform the merge

### Example 6: Preview Merge Conflicts

```
"Show me what conflicts would occur if I merge staging to production"
```

The AI will use:
1. `contensa_list_environments` to find environment IDs
2. `contensa_merge_environment` with dryRun=true to preview conflicts without making changes

### Example 7: Create Multilingual Content

```
"Create a French version of the blog post with ID 'post-123' and translate the content using AI"
```

The AI will use:
1. `contensa_get_content_entry` to get the original entry
2. `contensa_create_locale_variant` with translateContent=true to create and translate

### Example 8: Create Locale Variants for Referenced Content

```
"Create a Spanish version of the product 'prod-456' and also create Spanish versions of all referenced entries"
```

The AI will use:
1. `contensa_create_locale_variant` with translateReferences=true to recursively create variants

## Creating Content Entries

Creating content entries requires understanding the correct payload format and field structure.

### Required Configuration

Before creating content entries, ensure you have:

1. **API Key**: Set in `CONTENSA_API_KEY` environment variable
2. **User ID**: Set in `CONTENSA_USER_ID` environment variable (required for all write operations)
3. **Project ID**: Either set as active project or provided in each request

Example configuration:

```json
{
  "mcpServers": {
    "contensa": {
      "command": "npx",
      "args": ["@mybe/contensa-mcp"],
      "env": {
        "CONTENSA_API_KEY": "your-api-key-here",
        "CONTENSA_USER_ID": "your-user-id-here",
        "CONTENSA_PROJECT_ID": "your-default-project-id"
      }
    }
  }
}
```

### Payload Format

The `contensa_create_content_entry` tool requires:

| Parameter | Required | Description |
|-----------|----------|-------------|
| `contentTypeId` | Yes | The ID of the content type |
| `data` | Yes | Object with field values (keys must be field API names) |
| `projectId` | No* | Project ID (uses active project if not provided) |
| `userId` | No* | User ID (uses config userId if not provided) |
| `status` | No | Entry status: "draft" (default) or "published" |
| `locale` | No | Locale code (default: "en-US") |

*Required but can be set via configuration or active project/user

### Field API Names

**CRITICAL**: The `data` object keys must use **field API names**, NOT:
- ❌ Field IDs (UUIDs)
- ❌ Display names (e.g., "Title", "Description")
- ✅ API names (e.g., "title", "description", "author_name")

### Getting Field API Names

Always use `contensa_list_fields` to get the correct API names:

```javascript
// Example response from contensa_list_fields
{
  "fields": [
    {
      "id": "field-uuid-123",
      "api_name": "title",           // ← Use this as the key
      "kind": "short-text",
      "is_required": true
    },
    {
      "id": "field-uuid-456",
      "api_name": "content",         // ← Use this as the key
      "kind": "long-text",
      "is_required": true
    },
    {
      "id": "field-uuid-789",
      "api_name": "author_name",     // ← Use this as the key
      "kind": "short-text",
      "is_required": false
    }
  ]
}
```

### Example: Creating a Blog Post

**Step 1**: Get the content type and fields

```
"List all fields for the Blog Post content type"
```

Response shows:
- `title` (short-text, required)
- `content` (long-text, required)
- `author_name` (short-text, optional)
- `published_date` (date, optional)

**Step 2**: Create the entry with correct field API names

```javascript
{
  "contentTypeId": "blog-post-id",
  "data": {
    "title": "Hello World",              // ✅ Correct: using API name
    "content": "This is my first post",  // ✅ Correct: using API name
    "author_name": "John Doe"            // ✅ Correct: using API name
  },
  "status": "draft"
}
```

### Common Errors and Solutions

#### Error: "Missing required fields"

**Cause**: Required fields are not provided in the `data` object, or keys don't match field API names.

**Solution**:
1. Use `contensa_list_fields` to get all required fields
2. Ensure all required fields are in the `data` object
3. Verify keys match the `api_name` property exactly

Example error response:
```json
{
  "message": "Missing required fields",
  "missingFields": ["title", "content"]
}
```

#### Error: "Project ID is required"

**Cause**: No active project set and no `projectId` provided.

**Solution**:
1. Set active project: `contensa_set_active_project`
2. Or provide `projectId` in the request
3. Or set `CONTENSA_PROJECT_ID` in configuration

#### Error: "User ID is required"

**Cause**: No `CONTENSA_USER_ID` in configuration and no `userId` provided.

**Solution**:
1. Add `CONTENSA_USER_ID` to your MCP configuration
2. Or provide `userId` in each request

#### Error: "Invalid data format"

**Cause**: The `data` parameter is not an object or is a stringified JSON.

**Solution**:
Ensure `data` is a proper object:
```javascript
// ✅ Correct
{ "data": { "title": "Hello" } }

// ❌ Wrong
{ "data": "{\"title\": \"Hello\"}" }
```

### Handling Optional Fields

**IMPORTANT**: When creating content entries, handle optional fields correctly to avoid frontend errors:

- ✅ **Correct**: Omit optional fields entirely from the `data` object if you don't have values
- ❌ **Wrong**: Pass empty objects `{}` for optional fields (causes "Failed to construct 'URL'" errors)
- ❌ **Wrong**: Pass `null` or `undefined` for optional fields

**Example - Correct approach**:
```javascript
// User says "I'll add the image later"
{
  "contentTypeId": "blog-post-id",
  "data": {
    "title": "Hello World",
    "content": "This is my first post"
    // ✅ image field is omitted entirely
  }
}
```

**Example - Wrong approach**:
```javascript
// ❌ This causes frontend errors!
{
  "contentTypeId": "blog-post-id",
  "data": {
    "title": "Hello World",
    "content": "This is my first post",
    "image": {}  // ❌ Empty object causes "Invalid URL" errors
  }
}
```

**Why this matters**: Empty objects for media fields cause the frontend to attempt constructing URLs from invalid data, resulting in errors. The MCP server now automatically removes empty objects, `null`, and `undefined` values before sending data to the API.

### Field Value Types

Different field types expect different value formats:

| Field Type | Value Format | Example | Notes |
|------------|--------------|---------|-------|
| `short-text` | String | `"Hello World"` | Omit if optional and no value |
| `long-text` | String | `"Long content..."` | Omit if optional and no value |
| `number` | Number | `42` | Omit if optional and no value |
| `date` | ISO 8601 string | `"2024-01-15T10:30:00Z"` | Omit if optional and no value |
| `boolean` | Boolean | `true` or `false` | Omit if optional and no value |
| `list` | Array of strings | `["tag1", "tag2"]` | Empty arrays `[]` are valid |
| `media` | Media asset ID (string) | `"media-uuid-123"` | **Never use `{}`** - omit if no value |
| `reference` | Entry ID (string) | `"entry-uuid-456"` | Omit if optional and no value |
| `references-many` | Array of entry IDs | `["entry-1", "entry-2"]` | Empty arrays `[]` are valid |

### Complete Example Workflow

```
User: "Create a blog post about AI with title 'The Future of AI' and content 'AI is transforming...'"

AI Assistant:
1. Lists content types to find "Blog Post" → gets contentTypeId
2. Lists fields for Blog Post → gets field API names and requirements
3. Creates entry:
   {
     "contentTypeId": "blog-post-id",
     "data": {
       "title": "The Future of AI",
       "content": "AI is transforming..."
     },
     "status": "draft"
   }
4. Returns success with entry ID
```

### Best Practices

1. **Always get field API names first**: Use `contensa_list_fields` before creating entries
2. **Validate required fields**: Check which fields are required before submitting
3. **Use correct data types**: Match the field type's expected value format
4. **Set active project**: Use `contensa_set_active_project` to avoid repeating projectId
5. **Handle errors gracefully**: Check error messages for missing fields and retry with corrections

## Field Types

Available field types for `contensa_create_field`:

| Type | Description |
|------|-------------|
| `short-text` | Single line text |
| `long-text` | Multi-line text / rich content |
| `number` | Numeric values |
| `date` | Date/datetime values |
| `boolean` | True/false values |
| `media` | Images and files |
| `list` | Array of values |
| `reference` | Link to another content entry |
| `references-many` | Multiple links to content entries |

## Environment Merging

The MCP server supports merging content between environments (e.g., dev → staging → master).

### Merge Strategies

When merging environments, you can specify how to handle conflicts:

| Strategy | Description |
|----------|-------------|
| `skip` | Skip conflicting items (default) |
| `replace` | Replace target with source content |
| `merge` | Attempt to merge changes |
| `create-new` | Create new entries for conflicts |

### Dry Run Mode

Always preview changes before merging to production:

```
"Do a dry run merge from dev to master"
```

This will show you:
- Number of content types to be merged
- Number of entries to be merged
- Any conflicts that would occur
- Errors that would prevent the merge

### Master Environment Protection

By default, merging into the master environment requires explicit approval (`requireMasterApproval: false`). This prevents accidental overwrites of production content.

### Merge Workflow Example

1. **Preview the merge**:
   ```
   "Show me what would happen if I merge dev to master"
   ```

2. **Review conflicts** and decide on resolution strategies

3. **Execute the merge**:
   ```
   "Merge dev to master, replacing conflicts and disabling master approval"
   ```

### Sync vs Merge

- **Merge** (`contensa_merge_environment`): Fully functional, supports dry-run, conflict resolution strategies
- **Sync** (`contensa_sync_environment`): Currently in development, will support three-way merge logic

## Locale Management

The MCP server provides comprehensive support for creating and managing multilingual content.

### Supported Locales

The system supports 31 locales across multiple regions:

**Default**: `en-US` (English - United States)

**Europe**: `fr-FR`, `es-ES`, `de-DE`, `it-IT`, `pt-PT`, `nl-NL`, `sv-SE`, `pl-PL`, `ru-RU`, `en-GB`

**Americas**: `pt-BR`, `es-MX`, `es-AR`, `en-CA`, `fr-CA`

**Asia-Pacific**: `ja-JP`, `ko-KR`, `zh-CN`, `zh-TW`, `hi-IN`, `th-TH`, `vi-VN`, `id-ID`, `ms-MY`, `fil-PH`, `bn-BD`, `en-AU`

**Middle East & Africa**: `ar-SA`, `tr-TR`, `he-IL`

Use `contensa_get_supported_locales` to get the full list with locale codes, names, and flags.

### Creating Locale Variants

Locale variants allow you to create multilingual versions of your content. Each variant:
- Shares the same content structure (fields) as the original
- Has its own data in the target language
- Can optionally be AI-translated from the source locale
- Can reference the same entries or have locale-specific references

### Translation Options

When creating a locale variant, you have two key options:

#### 1. `translateContent` (default: true)

- **true**: Uses AI to translate text fields (short-text, long-text, list) to the target locale
- **false**: Copies content as-is without translation

**Note**: Reference fields are never translated - they maintain the same entry IDs across locales.

#### 2. `translateReferences` (default: false)

- **true**: Recursively creates locale variants for all referenced entries
- **false**: Only creates a variant for the main entry

**Warning**: Setting `translateReferences=true` can create many entries if you have deeply nested references. Use with caution.

### How Translation Works

The locale system uses AI-powered translation with the following behavior:

1. **Translatable Fields**: Only text-based fields are translated (short-text, long-text, number, list)
2. **Reference Fields**: Reference and references-many fields are copied as-is (same entry IDs)
3. **Retry Logic**: Translation attempts up to 2 retries on failure
4. **Fallback**: If translation fails after retries, content is copied without translation
5. **Metadata**: Translated entries are marked with `is_translated: true` in metadata

### Edge Cases and Behavior

#### Existing Variants

If a locale variant already exists for an entry, the API returns a 409 Conflict error. You cannot create duplicate locale variants.

#### Circular References

The system prevents infinite loops from circular references by tracking visited entry IDs during recursive locale creation.

#### Partial Translation

If translation fails for some fields but succeeds for others, the variant is still created with whatever translation succeeded.

#### Referenced Entry Variants

When `translateReferences=true`:
- The system checks if a locale variant already exists for each referenced entry
- If it exists, it uses the existing variant
- If not, it creates a new variant (with or without translation based on settings)
- All created entries are returned in the response

### Locale Workflow Example

1. **Check supported locales**:
   ```
   "What locales are supported?"
   ```

2. **Create a simple locale variant**:
   ```
   "Create a French version of blog post 'post-123' with AI translation"
   ```

3. **Create variant without translation**:
   ```
   "Create a German version of product 'prod-456' but don't translate the content"
   ```

4. **Create variant with referenced entries**:
   ```
   "Create a Spanish version of the homepage entry and all its referenced content"
   ```

5. **List all variants**:
   ```
   "Show me all locale variants of entry 'post-123'"
   ```

### Locale Validation

Locale codes must match the BCP-47 format (language-COUNTRY):
- ✅ Valid: `en-US`, `fr-FR`, `zh-CN`
- ❌ Invalid: `en`, `french`, `EN-us`

The client automatically validates locale codes against the supported locales list.

### Response Format

When creating a locale variant, the response includes:
- `variant`: The created locale variant entry
- `createdEntries`: Array of all entries created (if `translateReferences=true`)
- `totalCreated`: Total number of entries created (including the main variant)
- `message`: Success message

Example response:
```json
{
  "variant": { "id": "new-variant-id", "locale": "fr-FR", ... },
  "createdEntries": [
    { "id": "ref-1-fr", "title": "Referenced Entry 1" },
    { "id": "ref-2-fr", "title": "Referenced Entry 2" }
  ],
  "totalCreated": 3,
  "message": "Locale variant created successfully with references"
}
```

## Getting Your Credentials

### MCP Token (Required)

Your MCP token provides per-user authentication with fine-grained scopes:

1. Log in to your Contensa dashboard
2. Go to Settings → MCP Tokens
3. Click "Create New MCP Token"
4. Set a name (e.g., "Claude Desktop", "Cursor")
5. Select scopes based on your needs:
   - **Read-only AI assistant**: `content:read`, `schema:read`, `media:read`
   - **Content editor**: `content:read`, `content:write`, `schema:read`
   - **Full access**: All scopes (use with caution)
6. Set an expiration date (optional but recommended)
7. Click "Create Token"
8. **Copy the token immediately** - it will only be shown once
9. Add it to your MCP configuration as `CONTENSA_MCP_TOKEN`

**Token Format**: `mcp_live_<64 hex characters>`

**Security Note**: MCP tokens can be revoked individually without affecting other tokens or API keys. They also track usage for audit purposes.

### API Key (Required)

Your API key provides project-level authentication:

1. Log in to your Contensa dashboard
2. Go to Settings → API Keys
3. Generate a new API key for your project
4. Copy the key and add it to your MCP configuration as `CONTENSA_API_KEY`

**Key Format**: `ck_<...>`

### User ID (Required)

Your User ID is required for creating and updating content. To find it:

1. Log in to your Contensa dashboard
2. Go to Settings → Profile or Account Settings
3. Your User ID will be displayed in your profile information
4. Copy the User ID and add it to your MCP configuration as `CONTENSA_USER_ID`

**Note**: The User ID is a UUID that uniquely identifies your account. It's required for all write operations (creating/updating content, content types, fields, etc.).

## Development

```bash
# Install dependencies
npm install

# Build
npm run build

# Run in development
npm run dev

# Start the server
npm start
```

## Troubleshooting

### "API key is required" error

Make sure `CONTENSA_API_KEY` is set in your MCP configuration.

### Tools not showing up

1. Restart Cursor/Claude Desktop after updating the config
2. Check the MCP server logs for errors
3. Verify the path to the CLI is correct

### Permission errors

Ensure your API key has the necessary permissions for the operations you're trying to perform.

## License

MIT