#
tokens: 2472/50000 6/6 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

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

# Files

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

```
1 | CONTENTFUL_SPACE_ID=YOURSPCE_ID
2 | CONTENTFUL_ACCESS_TOKEN=YOUR_CONTENTFUL_TOKEN
3 | CONTENTFUL_ENVIRONMENT=YOUR_ENVIRONMENT
4 | CONTENTFUL_PREVIEW_ACCESS_TOKEN=YOURACCESS_TOKEN
```

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

```
 1 | # Dependency directories
 2 | node_modules/
 3 | dist/
 4 | 
 5 | # Environment variables
 6 | .env
 7 | .env.local
 8 | .env.*.local
 9 | 
10 | # Build files
11 | build/
12 | 
13 | # Logs
14 | logs
15 | *.log
16 | npm-debug.log*
17 | 
18 | # Editor directories and files
19 | .idea/
20 | .vscode/
21 | *.swp
22 | *.swo
23 | 
24 | # Operating System Files
25 | .DS_Store
26 | Thumbs.db
```

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

```markdown
 1 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/tejedamiguel6-mcp-server-contenful-badge.png)](https://mseep.ai/app/tejedamiguel6-mcp-server-contenful)
 2 | 
 3 | # Contentful MCP Server
 4 | 
 5 | 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.
 6 | [![Verified on MseeP](https://mseep.ai/badge.svg)](https://mseep.ai/app/5fafc920-b065-43ab-946a-bbc57aadebe0)
 7 | 
 8 | ## Features
 9 | 
10 | - Fetch all content types from your Contentful space
11 | - Retrieve entries for specific content types
12 | - Structured responses for easy consumption by AI assistants
13 | 
14 | ## Prerequisites
15 | 
16 | - Node.js (v16 or higher)
17 | - A Contentful account with API keys
18 | - Claude Desktop (to use the MCP server with Claude)
19 | 
20 | ## Installation
21 | 
22 | 1. Clone this repository:
23 |    ```bash
24 |    git clone https://github.com/yourusername/contentful-mcp-server.git
25 |    cd contentful-mcp-server
26 | 
27 | 2.Install dependencies:
28 |  npm install
29 | 
30 | Create a .env file in the root directory with your Contentful credentials:
31 | 4. CONTENTFUL_SPACE_ID=your_space_id
32 | CONTENTFUL_ACCESS_TOKEN=your_access_token
33 | CONTENTFUL_ENVIRONMENT=develop
34 | CONTENTFUL_PREVIEW_ACCESS_TOKEN=your_preview_token
35 | 
36 | 
37 | npm run build
38 | 
39 | 
40 | Or configure a build script in your package.json:
41 | "scripts": {
42 |   "build": "tsc",
43 |   "start": "node dist/index.js"
44 | }
45 | 
46 | ##Configuration for Claude Desktop
47 | ```
48 | {
49 |   "mcpServers": {
50 |     "contentful": {
51 |       "command": "node",
52 |       "args": [
53 |         "/absolute/path/to/contentful-mcp-server/dist/index.js"
54 |       ]
55 |     }
56 |   }
57 | }
58 | ```
59 | 
```

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

```json
 1 | {
 2 |     "compilerOptions": {
 3 |       "target": "ES2022",
 4 |       "module": "Node16",
 5 |       "moduleResolution": "Node16",
 6 |       "outDir": "./build",
 7 |       "rootDir": "./src",
 8 |       "strict": true,
 9 |       "esModuleInterop": true,
10 |       "skipLibCheck": true,
11 |       "forceConsistentCasingInFileNames": true
12 |     },
13 |     "include": ["src/**/*"],
14 |     "exclude": ["node_modules"]
15 |   }
```

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

```json
 1 | {
 2 |   "name": "contentful-mcp-server",
 3 |   "version": "1.0.0",
 4 |   "main": "index.js",
 5 |   "type": "module",
 6 |   "scripts": {
 7 |     "start": "ts-node --esm src/index.ts",
 8 |     "dev": "ts-node-esm src/index.ts",
 9 |     "build": "tsc",
10 |     "test": "echo \"Error: no test specified\" && exit 1"
11 |   },
12 |   "keywords": [],
13 |   "author": "",
14 |   "license": "ISC",
15 |   "description": "",
16 |   "dependencies": {
17 |     "@modelcontextprotocol/sdk": "^1.7.0",
18 |     "dotenv": "^16.4.7",
19 |     "zod": "^3.24.2"
20 |   },
21 |   "devDependencies": {
22 |     "@types/node": "^22.13.10",
23 |     "ts-node": "^10.9.2",
24 |     "typescript": "^5.8.2"
25 |   }
26 | }
27 | 
```

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

```typescript
  1 | import * as dotenv from "dotenv";
  2 | import path from "path";
  3 | import { fileURLToPath } from "url";
  4 | 
  5 | const __filename = fileURLToPath(import.meta.url);
  6 | const __dirname = path.dirname(__filename);
  7 | 
  8 | // Load .env file from project root
  9 | dotenv.config({ path: path.resolve(__dirname, "../.env") });
 10 | 
 11 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
 12 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 13 | import { z } from "zod";
 14 | 
 15 | const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID;
 16 | const CONTENTFUL_ACCESS_TOKEN = process.env.CONTENTFUL_ACCESS_TOKEN;
 17 | const CONTENTFUL_ENVIRONMENT = process.env.CONTENTFUL_ENVIRONMENT;
 18 | 
 19 | // Validate required environment variables
 20 | if (
 21 |   !CONTENTFUL_SPACE_ID ||
 22 |   !CONTENTFUL_ACCESS_TOKEN ||
 23 |   !CONTENTFUL_ENVIRONMENT
 24 | ) {
 25 |   console.error(
 26 |     "Missing required environment variables. Please check your .env file."
 27 |   );
 28 |   process.exit(1);
 29 | }
 30 | 
 31 | const server = new McpServer({
 32 |   name: "Contentful Tools",
 33 |   version: "1.0.0",
 34 | });
 35 | 
 36 | server.tool("get-content-types", "get content types", {}, async () => {
 37 |   const restEndpoint = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/${CONTENTFUL_ENVIRONMENT}/content_types`;
 38 |   try {
 39 |     const response = await fetch(restEndpoint, {
 40 |       headers: {
 41 |         Authorization: `Bearer ${CONTENTFUL_ACCESS_TOKEN}`,
 42 |       },
 43 |     });
 44 | 
 45 |     if (!response.ok) {
 46 |       throw new Error(`http error! status ${response.status}`);
 47 |     }
 48 |     const data = await response.json();
 49 | 
 50 |     return {
 51 |       content: [
 52 |         {
 53 |           type: "text",
 54 |           text: JSON.stringify(
 55 |             data.items.map((item: any) => ({
 56 |               id: item.sys.id,
 57 |               name: item.name,
 58 |             })),
 59 |             null,
 60 |             2
 61 |           ),
 62 |         },
 63 |       ],
 64 |     };
 65 |   } catch (error: any) {
 66 |     console.error("Error fetching content types:", error);
 67 |     return {
 68 |       content: [
 69 |         {
 70 |           type: "text",
 71 |           text: `Error: ${error.message}`,
 72 |         },
 73 |       ],
 74 |     };
 75 |   }
 76 | });
 77 | 
 78 | server.tool(
 79 |   "get-entries",
 80 |   "Get entries for a specific content type",
 81 |   {
 82 |     contentType: z.string(),
 83 |   },
 84 |   async (parameters) => {
 85 |     const { contentType } = parameters;
 86 |     const entriesEndpoint = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/${CONTENTFUL_ENVIRONMENT}/entries?content_type=${contentType}&limit=10`;
 87 | 
 88 |     try {
 89 |       const response = await fetch(entriesEndpoint, {
 90 |         headers: {
 91 |           Authorization: `Bearer ${CONTENTFUL_ACCESS_TOKEN}`,
 92 |         },
 93 |       });
 94 | 
 95 |       if (!response.ok) {
 96 |         throw new Error(`HTTP error! Status: ${response.status}`);
 97 |       }
 98 | 
 99 |       const data = await response.json();
100 | 
101 |       return {
102 |         content: [
103 |           {
104 |             type: "text",
105 |             text: JSON.stringify(data, null, 2),
106 |           },
107 |         ],
108 |       };
109 |     } catch (error: any) {
110 |       console.error("Error fetching entries:", error);
111 |       return {
112 |         content: [
113 |           {
114 |             type: "text",
115 |             text: `Error: ${error.message}`,
116 |           },
117 |         ],
118 |       };
119 |     }
120 |   }
121 | );
122 | 
123 | // Start the server
124 | async function main() {
125 |   const transport = new StdioServerTransport();
126 |   await server.connect(transport);
127 |   console.error(
128 |     `CONTENTFUL MCP Server running on stdio - Connected to space: ${CONTENTFUL_SPACE_ID}`
129 |   );
130 | }
131 | 
132 | main().catch((error) => {
133 |   console.error("Fatal error in main():", error);
134 |   process.exit(1);
135 | });
136 | 
```