OpenCTI MCP Server

  • src
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js" import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js" import { CONTENTFUL_PROMPTS } from "./prompts/contentful-prompts.js" import { handlePrompt } from "./prompts/handlers.js" import { entryHandlers } from "./handlers/entry-handlers.js" import { assetHandlers } from "./handlers/asset-handlers.js" import { spaceHandlers } from "./handlers/space-handlers.js" import { contentTypeHandlers } from "./handlers/content-type-handlers.js" import { getTools } from "./types/tools.js" import { validateEnvironment } from "./utils/validation.js" // Validate environment variables validateEnvironment() // Create MCP server const server = new Server( { name: "contentful-mcp-server", version: "1.0.0", }, { capabilities: { tools: getTools(), prompts: CONTENTFUL_PROMPTS, }, }, ) // Set up request handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: Object.values(getTools()), })) // Set up request handlers server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: Object.values(CONTENTFUL_PROMPTS), })) server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name, arguments: args } = request.params return handlePrompt(name, args) }) server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params const handler = getHandler(name) if (!handler) { throw new Error(`Unknown tool: ${name}`) } return handler(args) } catch (error) { return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, } } }) // Helper function to map tool names to handlers function getHandler(name: string) { const handlers = { // Entry operations create_entry: entryHandlers.createEntry, get_entry: entryHandlers.getEntry, update_entry: entryHandlers.updateEntry, delete_entry: entryHandlers.deleteEntry, publish_entry: entryHandlers.publishEntry, unpublish_entry: entryHandlers.unpublishEntry, search_entries: entryHandlers.searchEntries, // Asset operations upload_asset: assetHandlers.uploadAsset, get_asset: assetHandlers.getAsset, update_asset: assetHandlers.updateAsset, delete_asset: assetHandlers.deleteAsset, publish_asset: assetHandlers.publishAsset, unpublish_asset: assetHandlers.unpublishAsset, list_assets: assetHandlers.listAssets, // Space & Environment operations list_spaces: spaceHandlers.listSpaces, get_space: spaceHandlers.getSpace, list_environments: spaceHandlers.listEnvironments, create_environment: spaceHandlers.createEnvironment, delete_environment: spaceHandlers.deleteEnvironment, // Content Type operations list_content_types: contentTypeHandlers.listContentTypes, get_content_type: contentTypeHandlers.getContentType, create_content_type: contentTypeHandlers.createContentType, update_content_type: contentTypeHandlers.updateContentType, delete_content_type: contentTypeHandlers.deleteContentType, } return handlers[name as keyof typeof handlers] } // Start the server async function runServer() { const transport = new StdioServerTransport() await server.connect(transport) console.error( `Contentful MCP Server running on stdio using contentful host ${process.env.CONTENTFUL_HOST}`, ) } runServer().catch((error) => { console.error("Fatal error running server:", error) process.exit(1) })