#
tokens: 1748/50000 6/6 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .env.example
├── .gitignore
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
CONTENTFUL_SPACE_ID=YOURSPCE_ID
CONTENTFUL_ACCESS_TOKEN=YOUR_CONTENTFUL_TOKEN
CONTENTFUL_ENVIRONMENT=YOUR_ENVIRONMENT
CONTENTFUL_PREVIEW_ACCESS_TOKEN=YOURACCESS_TOKEN
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependency directories
node_modules/
dist/

# Environment variables
.env
.env.local
.env.*.local

# Build files
build/

# Logs
logs
*.log
npm-debug.log*

# Editor directories and files
.idea/
.vscode/
*.swp
*.swo

# Operating System Files
.DS_Store
Thumbs.db
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/tejedamiguel6-mcp-server-contenful-badge.png)](https://mseep.ai/app/tejedamiguel6-mcp-server-contenful)

# Contentful MCP Server

A Model Context Protocol (MCP) server that allows Claude to interact with Contentful CMS data directly. This integration enables Claude to fetch content types and entries from your Contentful space.
[![Verified on MseeP](https://mseep.ai/badge.svg)](https://mseep.ai/app/5fafc920-b065-43ab-946a-bbc57aadebe0)

## Features

- Fetch all content types from your Contentful space
- Retrieve entries for specific content types
- Structured responses for easy consumption by AI assistants

## Prerequisites

- Node.js (v16 or higher)
- A Contentful account with API keys
- Claude Desktop (to use the MCP server with Claude)

## Installation

1. Clone this repository:
   ```bash
   git clone https://github.com/yourusername/contentful-mcp-server.git
   cd contentful-mcp-server

2.Install dependencies:
 npm install

Create a .env file in the root directory with your Contentful credentials:
4. CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_access_token
CONTENTFUL_ENVIRONMENT=develop
CONTENTFUL_PREVIEW_ACCESS_TOKEN=your_preview_token


npm run build


Or configure a build script in your package.json:
"scripts": {
  "build": "tsc",
  "start": "node dist/index.js"
}

##Configuration for Claude Desktop
```
{
  "mcpServers": {
    "contentful": {
      "command": "node",
      "args": [
        "/absolute/path/to/contentful-mcp-server/dist/index.js"
      ]
    }
  }
}
```

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
    "compilerOptions": {
      "target": "ES2022",
      "module": "Node16",
      "moduleResolution": "Node16",
      "outDir": "./build",
      "rootDir": "./src",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
  }
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "contentful-mcp-server",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "ts-node --esm src/index.ts",
    "dev": "ts-node-esm src/index.ts",
    "build": "tsc",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.7.0",
    "dotenv": "^16.4.7",
    "zod": "^3.24.2"
  },
  "devDependencies": {
    "@types/node": "^22.13.10",
    "ts-node": "^10.9.2",
    "typescript": "^5.8.2"
  }
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import * as dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Load .env file from project root
dotenv.config({ path: path.resolve(__dirname, "../.env") });

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID;
const CONTENTFUL_ACCESS_TOKEN = process.env.CONTENTFUL_ACCESS_TOKEN;
const CONTENTFUL_ENVIRONMENT = process.env.CONTENTFUL_ENVIRONMENT;

// Validate required environment variables
if (
  !CONTENTFUL_SPACE_ID ||
  !CONTENTFUL_ACCESS_TOKEN ||
  !CONTENTFUL_ENVIRONMENT
) {
  console.error(
    "Missing required environment variables. Please check your .env file."
  );
  process.exit(1);
}

const server = new McpServer({
  name: "Contentful Tools",
  version: "1.0.0",
});

server.tool("get-content-types", "get content types", {}, async () => {
  const restEndpoint = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/${CONTENTFUL_ENVIRONMENT}/content_types`;
  try {
    const response = await fetch(restEndpoint, {
      headers: {
        Authorization: `Bearer ${CONTENTFUL_ACCESS_TOKEN}`,
      },
    });

    if (!response.ok) {
      throw new Error(`http error! status ${response.status}`);
    }
    const data = await response.json();

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(
            data.items.map((item: any) => ({
              id: item.sys.id,
              name: item.name,
            })),
            null,
            2
          ),
        },
      ],
    };
  } catch (error: any) {
    console.error("Error fetching content types:", error);
    return {
      content: [
        {
          type: "text",
          text: `Error: ${error.message}`,
        },
      ],
    };
  }
});

server.tool(
  "get-entries",
  "Get entries for a specific content type",
  {
    contentType: z.string(),
  },
  async (parameters) => {
    const { contentType } = parameters;
    const entriesEndpoint = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/${CONTENTFUL_ENVIRONMENT}/entries?content_type=${contentType}&limit=10`;

    try {
      const response = await fetch(entriesEndpoint, {
        headers: {
          Authorization: `Bearer ${CONTENTFUL_ACCESS_TOKEN}`,
        },
      });

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }

      const data = await response.json();

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(data, null, 2),
          },
        ],
      };
    } catch (error: any) {
      console.error("Error fetching entries:", error);
      return {
        content: [
          {
            type: "text",
            text: `Error: ${error.message}`,
          },
        ],
      };
    }
  }
);

// Start the server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error(
    `CONTENTFUL MCP Server running on stdio - Connected to space: ${CONTENTFUL_SPACE_ID}`
  );
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

```