npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

contentstack-mcp

v1.0.3

Published

Contentstack Content Management API MCP

Readme

Contentstack Content Management API MCP

This MCP provides a set of tools to interact with Contentstack's Content Management API.

Installation

NPM Package

npm install contentstack-mcp

Manual Installation

  1. Clone the repository:
git clone https://github.com/SamueleReply/contentstack-mcp.git
cd contentstack-mcp
  1. Install dependencies:
npm install
  1. Create a .env file in the root directory with your Contentstack credentials:
CONTENTSTACK_API_KEY=your_api_key
CONTENTSTACK_MANAGEMENT_TOKEN=your_management_token
CONTENTSTACK_DELIVERY_TOKEN=your_delivery_token
CONTENTSTACK_REGION=NA  # Optional, defaults to NA

MCP Server Configuration

To use this package as an MCP server in Cursor, add the following configuration to your .cursor/mcp.json file:

{
    "mcpServers": {
        "contentstack": {
            "command": "npx",
            "args": [
                "contentstack-mcp@latest"
            ],
            "env": {
                "CONTENTSTACK_API_KEY": "your_api_key",
                "CONTENTSTACK_MANAGEMENT_TOKEN": "your_management_token",
                "CONTENTSTACK_REGION": "NA",
                "CONTENTSTACK_DELIVERY_TOKEN": "your_delivery_token"
            }
        }
    }
}

Replace the environment variables with your actual Contentstack credentials.

Available MCP Tools

When configured as an MCP server, the following tools are available in Cursor:

  • contentstack_get_content_types - Get all content types
  • contentstack_get_content_type - Get a specific content type
  • contentstack_create_content_type - Create a new content type with custom schema
  • contentstack_update_content_type - Update an existing content type schema
  • contentstack_field_types_reference - Get comprehensive reference documentation for all available Contentstack field types with examples
  • mcp_list_tools - Get a list of all available MCP tools with their schemas
  • contentstack_get_entries - Get entries for a content type
  • contentstack_get_entry - Get a specific entry (supports environment and locale)
  • contentstack_create_entry - Create a new entry (supports environment and locale)
  • contentstack_update_entry - Update an entry (supports environment and locale)
  • contentstack_delete_entry - Delete an entry (supports environment and locale)
  • contentstack_get_assets - Get assets
  • contentstack_get_environments - Get all environments
  • contentstack_publish_entry - Publish an entry (supports environment and locale)
  • contentstack_unpublish_entry - Unpublish an entry (supports environment and locale)
  • contentstack_get_languages - Get all languages (locales) available in the stack
  • contentstack_localize_entry - Localize an entry to a specific locale

Region Support

The MCP supports multiple Contentstack regions. By default, it uses the North America (NA) region. You can specify a different region for each API call.

Available regions:

  • NA - North America (default)
  • EU - Europe
  • AZURE_NA - Azure North America
  • AZURE_EU - Azure Europe
  • GCP_NA - GCP North America
  • GCP_EU - GCP Europe

Available Tools

Content Types

  • getContentTypes(config) - Get all content types
  • getContentType(uid, config) - Get a specific content type
  • createContentType(data, config) - Create a new content type
  • updateContentType(uid, data, config) - Update an existing content type

Entries

  • getEntries(contentTypeUid, query, config) - Get all entries of a content type
  • getEntry(contentTypeUid, entryUid, options, config) - Get a specific entry
  • createEntry(contentTypeUid, data, options, config) - Create a new entry
  • updateEntry(contentTypeUid, entryUid, data, options, config) - Update an existing entry
  • deleteEntry(contentTypeUid, entryUid, options, config) - Delete an entry

Assets

  • getAssets(query, config) - Get all assets
  • getAsset(assetUid, config) - Get a specific asset
  • uploadAsset(data, config) - Upload a new asset

Environments

  • getEnvironments(config) - Get all environments
  • getEnvironment(uid, config) - Get a specific environment

Publishing

  • publishEntry(data, options, config) - Publish an entry
  • unpublishEntry(data, options, config) - Unpublish an entry

Languages and Localization

  • getLanguages(config) - Get all languages (locales) available in the stack
  • localizeEntry(contentTypeUid, entryUid, data, options, config) - Localize an entry to a specific locale

Environment and Locale Support

Entry operations (getEntry, createEntry, updateEntry, deleteEntry) and publishing operations (publishEntry, unpublishEntry) now support environment and locale parameters through an options object:

// Get an entry with specific environment and locale
const entry = await cs.getEntry('content_type_uid', 'entry_uid', {
    environment: 'development',
    locale: 'en-us'
});

// Create an entry with environment and locale
const newEntry = await cs.createEntry('content_type_uid', entryData, {
    environment: 'development',
    locale: 'en-us'
});

// Update an entry with environment and locale
const updatedEntry = await cs.updateEntry('content_type_uid', 'entry_uid', updateData, {
    environment: 'development',
    locale: 'en-us'
});

// Delete an entry with environment and locale
await cs.deleteEntry('content_type_uid', 'entry_uid', {
    environment: 'development',
    locale: 'en-us'
});

// Publish an entry with environment and locale
const publishResult = await cs.publishEntry({
    entry: {
        uid: 'entry_uid',
        content_type: 'content_type_uid',
        version: 1
    },
    environments: ['development']
}, {
    environment: 'development',
    locale: 'en-us'
});

// Unpublish an entry with environment and locale
const unpublishResult = await cs.unpublishEntry({
    entry: {
        uid: 'entry_uid',
        content_type: 'content_type_uid'
    },
    environments: ['development']
}, {
    environment: 'development',
    locale: 'en-us'
});

The options parameter supports:

  • environment: Target environment name
  • locale: Target locale code (e.g., 'en-us', 'fr-fr')
  • Any other query parameters supported by the Contentstack API

Field Types Reference Tool

The contentstack_field_types_reference tool provides comprehensive documentation and examples for all available Contentstack field types. This is especially useful when creating or updating content types.

Usage

Get all field types:

// Via MCP tool
const allFieldTypes = await mcpClient.callTool('contentstack_field_types_reference', {});

// Response includes: overview, text, json, number, boolean, isodate, file, link, reference, group, blocks, global_field, extension

Get specific field type:

// Via MCP tool
const textFieldInfo = await mcpClient.callTool('contentstack_field_types_reference', {
    fieldType: 'text'
});

// Returns detailed information about text fields including all variants:
// - Single Line Textbox
// - Multi Line Textbox
// - Rich Text Editor (HTML)
// - Markdown
// - Select Dropdown

Content Type Reuse Strategy ⚡

IMPORTANT: Before creating new content types or fields, always check what already exists!

Best Practices for Reusing Content Types

  1. Check First: Use contentstack_get_content_types to see existing content types
  2. Use References: Connect content types with reference fields instead of duplicating structures
  3. Global Fields: Reuse common field groups (SEO, social sharing) across multiple content types
  4. Avoid Duplication: If you need "author" info, check if an "author" content type exists - reference it instead of creating duplicate fields

When to Use References vs Groups

| Use Reference Field | Use Group Field | |---------------------|-----------------| | Entity needs independent management (authors, categories) | Data is tightly coupled to parent (address in contact form) | | Needs to be shared across multiple entries | Only used within this specific content type | | Has its own workflow and permissions | Simple nested data structure | | Example: Blog → Author (reference) | Example: Person → Address (group) |

Available Field Types

| Field Type | Description | Use Cases | Reuse Notes | |------------|-------------|-----------|-------------| | text | Text content with multiple variants | Titles, descriptions, content, select dropdowns | - | | number | Numeric values | Prices, quantities, ratings | - | | boolean | True/false toggle | Feature flags, published status | - | | isodate | Date and time | Publication dates, event dates | - | | file | Media assets | Images, videos, documents | - | | link | URL with title | External links, CTAs | - | | reference | Entry references | Related content, categories | Use to reuse existing content types | | json | JSON Rich Text Editor | Structured rich text content | - | | group | Nested field groups | Address details, coordinates | Use only for tightly coupled data | | blocks | Modular content blocks | Page sections, flexible layouts | - | | global_field | Reusable field groups | SEO metadata, social sharing | Check if global fields exist first | | extension | Custom field extensions | Custom widgets, integrations | - |

Key Field Properties

All fields share these common properties:

  • display_name - Human-readable label (NOT "title")
  • uid - Unique identifier in snake_case
  • data_type - Field type (NOT "type")
  • mandatory - Boolean for required fields (NOT "required")
  • unique - Boolean for unique values
  • multiple - Boolean for multiple values
  • non_localizable - Boolean for shared values across locales
  • field_metadata - Field-specific configuration

Example: Creating a Content Type with Various Field Types

const complexContentType = await cs.createContentType({
    content_type: {
        title: "Blog Post",
        uid: "blog_post",
        schema: [
            // Text - Single Line
            {
                data_type: "text",
                display_name: "Title",
                uid: "title",
                mandatory: true,
                unique: true
            },
            // Text - Multi Line
            {
                data_type: "text",
                display_name: "Excerpt",
                uid: "excerpt",
                field_metadata: {
                    multiline: true
                }
            },
            // JSON RTE
            {
                data_type: "json",
                display_name: "Content",
                uid: "content",
                field_metadata: {
                    allow_json_rte: true,
                    rich_text_type: "advanced"
                },
                reference_to: ["sys_assets"]
            },
            // Select Dropdown
            {
                data_type: "text",
                display_name: "Status",
                uid: "status",
                display_type: "dropdown",
                enum: {
                    advanced: false,
                    choices: [
                        { value: "draft" },
                        { value: "published" }
                    ]
                }
            },
            // Number
            {
                data_type: "number",
                display_name: "Read Time (minutes)",
                uid: "read_time"
            },
            // Boolean
            {
                data_type: "boolean",
                display_name: "Featured",
                uid: "featured",
                field_metadata: {
                    default_value: false
                }
            },
            // Date
            {
                data_type: "isodate",
                display_name: "Publish Date",
                uid: "publish_date"
            },
            // File/Asset
            {
                data_type: "file",
                display_name: "Featured Image",
                uid: "featured_image"
            },
            // Reference
            {
                data_type: "reference",
                display_name: "Related Posts",
                uid: "related_posts",
                reference_to: ["blog_post"],
                field_metadata: {
                    ref_multiple: true
                },
                multiple: true
            },
            // Group
            {
                data_type: "group",
                display_name: "Author Info",
                uid: "author_info",
                schema: [
                    {
                        data_type: "text",
                        display_name: "Author Name",
                        uid: "author_name"
                    },
                    {
                        data_type: "text",
                        display_name: "Bio",
                        uid: "bio",
                        field_metadata: {
                            multiline: true
                        }
                    }
                ]
            }
        ]
    }
});

Content Type Management

Creating Content Types

You can create content types with various field types including text, number, select fields, JSON RTE, custom asset fields, and taxonomy fields.

Basic Content Type Example

const newContentType = await cs.createContentType({
    content_type: {
        title: "Blog Post",
        uid: "blog_post",
        description: "Blog posts for the website",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true,
                field_metadata: {
                    _default: true
                }
            },
            {
                display_name: "Content",
                uid: "content",
                data_type: "text",
                field_metadata: {
                    multiline: true
                }
            },
            {
                display_name: "Publish Date",
                uid: "publish_date",
                data_type: "isodate",
                mandatory: true
            }
        ]
    }
});

Content Type with Select Field (Simple Values)

const contentTypeWithSelect = await cs.createContentType({
    content_type: {
        title: "Product",
        uid: "product",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                display_name: "Priority",
                uid: "priority",
                data_type: "text",
                field_metadata: {
                    description: "Product priority level"
                },
                enum: {
                    advanced: false,
                    choices: [
                        { value: "1" },
                        { value: "2" },
                        { value: "3" }
                    ]
                }
            }
        ]
    }
});

Content Type with Select Field (Key-Value Pairs)

const contentTypeWithAdvancedSelect = await cs.createContentType({
    content_type: {
        title: "Location",
        uid: "location",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                display_name: "Region",
                uid: "region",
                data_type: "text",
                enum: {
                    advanced: true,
                    choices: [
                        { key: "New York", value: "NY" },
                        { key: "India", value: "IN" },
                        { key: "Australia", value: "AUS" }
                    ]
                }
            }
        ]
    }
});

Content Type with JSON RTE (Rich Text Editor)

const contentTypeWithRTE = await cs.createContentType({
    content_type: {
        title: "Article",
        uid: "article",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                data_type: "json",
                display_name: "JSON RTE Content",
                uid: "json_rte_content",
                field_metadata: {
                    allow_json_rte: true,
                    rich_text_type: "advanced",
                    description: "Rich text content with embedded entries",
                    default_value: ""
                },
                reference_to: [
                    "blog_post",
                    "product"
                ],
                non_localizable: false,
                multiple: false,
                mandatory: false,
                unique: false
            }
        ]
    }
});

Content Type with Custom Asset Field

const contentTypeWithAsset = await cs.createContentType({
    content_type: {
        title: "Media Gallery",
        uid: "media_gallery",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                display_name: "Gallery Images",
                uid: "gallery_images",
                data_type: "file",
                multiple: true,
                mandatory: false
            }
        ]
    }
});

Content Type with Taxonomy Fields

const contentTypeWithTaxonomy = await cs.createContentType({
    content_type: {
        title: "Categorized Content",
        uid: "categorized_content",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                uid: "taxonomies",
                taxonomies: [
                    {
                        taxonomy_uid: "taxonomy_1",
                        max_terms: 5,
                        mandatory: true,
                        non_localizable: false
                    },
                    {
                        taxonomy_uid: "taxonomy_2",
                        max_terms: 10,
                        mandatory: false,
                        non_localizable: false
                    }
                ],
                multiple: true
            }
        ]
    }
});

Content Type with Field Visibility Rules

const contentTypeWithRules = await cs.createContentType({
    content_type: {
        title: "Conditional Form",
        uid: "conditional_form",
        schema: [
            {
                display_name: "Title",
                uid: "title",
                data_type: "text",
                mandatory: true,
                unique: true
            },
            {
                display_name: "Show Details",
                uid: "show_details",
                data_type: "boolean",
                mandatory: false
            },
            {
                display_name: "Details",
                uid: "details",
                data_type: "text",
                mandatory: false
            }
        ],
        field_rules: [
            {
                conditions: [
                    {
                        operand_field: "show_details",
                        operator: "equals",
                        value: true
                    }
                ],
                match_type: "all",
                actions: [
                    {
                        action: "show",
                        target_field: "details"
                    }
                ]
            }
        ]
    }
});

Updating Content Types

To update a content type, you must provide the complete schema including all existing fields plus any new fields:

// First, get the existing content type
const existingContentType = await cs.getContentType('blog_post');

// Modify the schema (add a new field, for example)
existingContentType.content_type.schema.push({
    display_name: "Author",
    uid: "author",
    data_type: "text",
    mandatory: false
});

// Update the content type
const updatedContentType = await cs.updateContentType('blog_post', {
    content_type: existingContentType.content_type
});

Field Visibility Rule Operators by Data Type

When creating field visibility rules, use these operators based on the operand field's data type:

  • Text: matches, does_not_match, starts_with, ends_with, contains
  • Number: equals, not_equals, less_than, greater_than, less_than_or_equals, greater_than_or_equals
  • Date: equals, not_equals, before_date, after_date (use ISO format)
  • Boolean: is, is_not
  • Select: is, is_not
  • Reference: is, is_not

Usage Example

As a Node.js Library

const contentstack = require('contentstack-cursor-mcp');

// Initialize with default configuration from .env
const cs = contentstack.initialize();

// Or initialize with custom configuration
const csCustom = contentstack.initialize({
    region: 'EU',
    apiKey: 'your_api_key',
    managementToken: 'your_management_token',
    deliveryToken: 'your_delivery_token'
});

// Get all content types
async function example() {
    try {
        const contentTypes = await cs.getContentTypes();
        console.log(contentTypes);
    } catch (error) {
        console.error(error);
    }
}

// Get entries with query parameters
async function getEntriesExample() {
    try {
        const entries = await cs.getEntries('content_type_uid', {
            limit: 10,
            skip: 0,
            environment: 'production'
        });
        console.log(entries);
    } catch (error) {
        console.error(error);
    }
}

// Get entry with environment and locale
async function getEntryWithOptions() {
    try {
        const entry = await cs.getEntry('content_type_uid', 'entry_uid', {
            environment: 'development',
            locale: 'en-us',
            include_schema: true
        });
        console.log(entry);
    } catch (error) {
        console.error(error);
    }
}

// Get all available languages/locales
async function getLanguagesExample() {
    try {
        const languages = await cs.getLanguages();
        console.log('Available languages:', languages);
    } catch (error) {
        console.error(error);
    }
}

// Localize an entry to a specific locale
async function localizeEntryExample() {
    try {
        const localizedEntry = await cs.localizeEntry('content_type_uid', 'entry_uid', {
            entry: {
                title: 'Titre localisé',
                description: 'Description en français'
            }
        }, {
            locale: 'fr-fr'
        });
        console.log('Localized entry:', localizedEntry);
    } catch (error) {
        console.error(error);
    }
}

As an MCP Server in Cursor

Once configured in your .cursor/mcp.json, you can use the Contentstack tools directly in Cursor by asking questions like:

  • "Get all content types from Contentstack"
  • "Show me entries for the 'blog_post' content type"
  • "Get the entry with UID 'xyz123' from content type 'product' in the development environment"
  • "Create a new blog post entry with title 'My New Post'"
  • "Create a new content type called 'Product' with fields for title, description, price, and category"
  • "Update the 'blog_post' content type to add an 'author' field"
  • "Add field visibility rules to the 'contact_form' content type"
  • "Create a content type with a select field for product categories"
  • "Get all available languages in the stack"
  • "Localize the entry 'xyz123' from content type 'blog_post' to French locale"

Configuration

Each API call accepts an optional configuration object with the following properties:

  • region: Contentstack region (NA, EU, AZURE_NA, AZURE_EU, GCP_NA, GCP_EU)
  • apiKey: Contentstack API Key
  • managementToken: Contentstack Management Token
  • deliveryToken: Contentstack Delivery Token

Error Handling

All API calls are wrapped in try-catch blocks and will throw errors with meaningful messages if something goes wrong. The error message will include the specific error message from the Contentstack API if available.

Testing

Run the test suite to verify your configuration:

npm test

This will test various API endpoints and verify that your credentials and configuration are working correctly.

Contributing

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

License

This project is licensed under the MIT License - see the LICENSE file for details.