# 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 [](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. [](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); }); ```