{"id":38335,"date":"2025-09-02T17:17:56","date_gmt":"2025-09-03T00:17:56","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=38335"},"modified":"2025-08-21T15:12:28","modified_gmt":"2025-08-21T22:12:28","slug":"mcp-server-interact-cloudinarys-dam","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam","title":{"rendered":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>If you\u2019ve ever wanted to let an AI assistant manage your media library, like uploading, deleting, or even fetching images for you, then you\u2019re in the right place. In this post, we\u2019ll walk you through the process of creating an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Model_Context_Protocol\">MCP (Model Context Protocol)<\/a> server that connects with <a href=\"https:\/\/cloudinary.com\/products\/dam\">Cloudinary\u2019s digital asset management (DAM)<\/a>.<\/p>\n<h2>What is MCP?<\/h2>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Model_Context_Protocol\">MCP<\/a> stands for Model Context Protocol. It\u2019s an open standard, open-source framework introduced by <a href=\"https:\/\/en.wikipedia.org\/wiki\/Anthropic\">Anthropic<\/a> to standardize the way LLMs integrate and share data with external tools (which can be APIs, databases, or services). Think of it like giving your AI assistant a secure, standardized way to use apps on your behalf.<\/p>\n<p>In our case, we want the AI to interact with Cloudinary\u2019s DAM and assist in performing certain tasks, such as uploading images, deleting outdated ones, and searching through our asset library.<\/p>\n<h2>What is Cloudinary DAM?<\/h2>\n<p><a href=\"https:\/\/cloudinary.com\/documentation\/digital_asset_management_overview\">Cloudinary\u2019s DAM<\/a> lets you manage all your media, from images and videos to documents, all from one place. You can:<\/p>\n<ul>\n<li>Upload assets (from URLs, files, or even base64 strings).<\/li>\n<li>Search assets using tags, filenames, or metadata.<\/li>\n<li>Delete or retrieve asset details.<\/li>\n<li>Organize assets in folders and with custom metadata.<\/li>\n<\/ul>\n<p>All of this is accessible through Cloudinary\u2019s APIs, which we\u2019ll use to build our MCP.<\/p>\n<h2>What We\u2019ll Build<\/h2>\n<p>We\u2019ll create an MCP server that supports the following tools:<\/p>\n<ul>\n<li>\n<strong><code>upload<\/code>.<\/strong> Upload a media asset to Cloudinary.<\/li>\n<li>\n<strong><code>delete-asset<\/code>.<\/strong> Delete a specific asset by ID or public ID.<\/li>\n<li>\n<strong><code>get-asset<\/code>.<\/strong> Fetch details for an asset.<\/li>\n<li>\n<strong><code>find-assets<\/code>.<\/strong> Search the media library using a flexible query string.<\/li>\n<li>\n<strong><code>get-usage<\/code>.<\/strong> Fetch your Cloudinary account\u2019s usage stats.<\/li>\n<\/ul>\n<h2>Prerequisites<\/h2>\n<p>Before you begin, make sure you have the following:<\/p>\n<ul>\n<li>Node.js: Version 18 or later installed.<\/li>\n<li>A (free) Cloudinary account, which you can <a href=\"https:\/\/cloudinary.com\/users\/register\">sign up for here<\/a>.<\/li>\n<li>Your Cloudinary cloud name, API Key, and API Secret from your Cloudinary dashboard.<\/li>\n<\/ul>\n<p>This post also assumes that you have a basic idea of working with Node.js and TypeScript.<\/p>\n<h2>Step 1: Set Up the Environment and Install Dependencies<\/h2>\n<p>Let\u2019s create a folder called <code>cloudinary-mcp-server<\/code>, initialize a Node.js project, and install all the dependencies we\u2019ll be using for the project.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">mkdir<\/span> <span class=\"hljs-selector-tag\">cloudinary-mcp-server<\/span> &amp;&amp; <span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">cloudinary-mcp-server<\/span>\n<span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">init<\/span> <span class=\"hljs-selector-tag\">-y<\/span>\n<span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">cloudinary<\/span> <span class=\"hljs-keyword\">@modelcontextprotocol<\/span>\/sdk dotenv\nnpm install --save-dev typescript @types\/node\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we\u2019ll create a <code>tsconfig.json<\/code> and set up a TypeScript configuration:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ tsconfig.json<\/span>\n{\n  <span class=\"hljs-attr\">\"compilerOptions\"<\/span>: {\n    <span class=\"hljs-attr\">\"target\"<\/span>: <span class=\"hljs-string\">\"ES2020\"<\/span>,\n    <span class=\"hljs-attr\">\"module\"<\/span>: <span class=\"hljs-string\">\"commonjs\"<\/span>,\n    <span class=\"hljs-attr\">\"outDir\"<\/span>: <span class=\"hljs-string\">\".\/dist\"<\/span>,\n    <span class=\"hljs-attr\">\"rootDir\"<\/span>: <span class=\"hljs-string\">\".\/src\"<\/span>,\n    <span class=\"hljs-attr\">\"strict\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"esModuleInterop\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"skipLibCheck\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"forceConsistentCasingInFileNames\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"resolveJsonModule\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"allowJs\"<\/span>: <span class=\"hljs-literal\">true<\/span>\n  },\n  <span class=\"hljs-attr\">\"include\"<\/span>: &#91;<span class=\"hljs-string\">\"src\/**\/*\"<\/span>],\n  <span class=\"hljs-attr\">\"exclude\"<\/span>: &#91;<span class=\"hljs-string\">\"node_modules\"<\/span>, <span class=\"hljs-string\">\"dist\"<\/span>]\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>And we\u2019ll update our package.json scripts:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n  <span class=\"hljs-attr\">\"scripts\"<\/span>: {\n    <span class=\"hljs-attr\">\"build\"<\/span>: <span class=\"hljs-string\">\"tsc\"<\/span>,\n    <span class=\"hljs-attr\">\"start\"<\/span>: <span class=\"hljs-string\">\"node dist\/mcp-server.js\"<\/span>,\n    <span class=\"hljs-attr\">\"dev\"<\/span>: <span class=\"hljs-string\">\"ts-node src\/mcp-server.ts\"<\/span>\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Step 2: Connect to Cloudinary<\/h2>\n<p>Let\u2019s set up our Cloudinary client:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/cloudinaryClient.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> dotenv <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'dotenv'<\/span>;\n\ndotenv.config();\n\ncloudinary.config({\n  <span class=\"hljs-attr\">cloud_name<\/span>: process.env.CLOUDINARY_CLOUD_NAME,\n  <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n  <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET\n});\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> cloudinary;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Note:<\/strong>  Make sure to manage your environment variables properly and keep them safe.<\/p>\n<p>Environment variables are typically stored in files like <code>.env<\/code> and accessed in your code using <code>process.env.VARIABLE_NAME<\/code>. These variables often contain sensitive data, such as API keys, database URLs, or secret tokens.<\/p>\n<h2>Step 3: Define Tools (API Handlers)<\/h2>\n<p>As mentioned earlier, MCP enables AI models to talk to tools, which can be APIs, databases, or services. In our case, these tools are API handlers. Each tool is a function the AI can call. Here\u2019s how we can implement the <code>upload<\/code> tool:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/upload.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinaryClient'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface UploadArgs {\n  <span class=\"hljs-attr\">source<\/span>: string;\n  folder?: string;\n  publicId?: string;\n  tags?: string;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">upload<\/span>(<span class=\"hljs-params\">{ source, folder, publicId, tags }: UploadArgs<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> cloudinary.uploader.upload(source, {\n    folder,\n    <span class=\"hljs-attr\">public_id<\/span>: publicId,\n    <span class=\"hljs-attr\">tags<\/span>: tags ? tags.split(<span class=\"hljs-string\">','<\/span>) : <span class=\"hljs-literal\">undefined<\/span>\n  });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The above exports a handler that uploads an image to Cloudinary. The method can also handle updating the image for a public ID, saving the image to a folder, and\/or tagging the image.<\/p>\n<p>Below is the implementation for the rest of the tools.<\/p>\n<p><strong>Delete Asset:<\/strong><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/delete-asset.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinaryClient'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface DeleteAssetArgs {\n  <span class=\"hljs-attr\">publicId<\/span>: string;\n  resourceType?: string;\n  type?: string;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">deleteAsset<\/span>(<span class=\"hljs-params\">{ \n  publicId, \n  resourceType = <span class=\"hljs-string\">'image'<\/span>, \n  type = <span class=\"hljs-string\">'upload'<\/span> \n}: DeleteAssetArgs<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> cloudinary.uploader.destroy(publicId, {\n    <span class=\"hljs-attr\">resource_type<\/span>: resourceType,\n    <span class=\"hljs-attr\">type<\/span>: type\n  });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Find Assets:<\/strong><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/find-assets.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinaryClient'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface FindAssetsArgs {\n  <span class=\"hljs-attr\">expression<\/span>: string;\n  maxResults?: number;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">findAssets<\/span>(<span class=\"hljs-params\">{ expression, maxResults = <span class=\"hljs-number\">10<\/span> }: FindAssetsArgs<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> cloudinary.search.expression(expression).max_results(maxResults).execute();\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Get Asset:<\/strong><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/get-asset.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinaryClient'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface GetAssetArgs {\n  <span class=\"hljs-attr\">publicId<\/span>: string;\n  resourceType?: string;\n  type?: string;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getAsset<\/span>(<span class=\"hljs-params\">{ \n  publicId, \n  resourceType = <span class=\"hljs-string\">'image'<\/span>, \n  type = <span class=\"hljs-string\">'upload'<\/span> \n}: GetAssetArgs<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> cloudinary.api.resource(publicId, {\n    <span class=\"hljs-attr\">resource_type<\/span>: resourceType,\n    <span class=\"hljs-attr\">type<\/span>: type\n  });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Get Usage:<\/strong><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/get-usage.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinaryClient'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface GetUsageArgs {\n  date?: string;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getUsage<\/span>(<span class=\"hljs-params\">{ date }: GetUsageArgs = {}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> options: Record&lt;string, any&gt; = {};\n  \n  <span class=\"hljs-keyword\">if<\/span> (date) {\n    options.date = date;\n  }\n  \n  <span class=\"hljs-keyword\">return<\/span> cloudinary.api.usage(options);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Once we have implemented all our handlers, let\u2019s create a tool registry to keep our tools centralized.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/tools\/index.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> upload <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/upload'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> findAssets <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/find-assets'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> deleteAsset <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/delete-asset'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> getAsset <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/get-asset'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> getUsage <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/get-usage'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface ToolsRegistry {\n  &#91;key: string]: ToolFunction;\n}\n\n<span class=\"hljs-keyword\">const<\/span> tools: ToolsRegistry = {\n  upload,\n  <span class=\"hljs-string\">'find-assets'<\/span>: findAssets,\n  <span class=\"hljs-string\">'delete-asset'<\/span>: deleteAsset,\n  <span class=\"hljs-string\">'get-asset'<\/span>: getAsset,\n  <span class=\"hljs-string\">'get-usage'<\/span>: getUsage\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> tools;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Step 4: Create the MCP Server<\/h2>\n<p>We\u2019ll be using <a href=\"https:\/\/github.com\/modelcontextprotocol\/typescript-sdk\">@modelcontextprotocol\/sdk<\/a> to build our MCP. <code>@modelcontextprotocol\/sdk<\/code> is a package that implements the full MCP specifications, making it a perfect tool to use.<\/p>\n<p>In the <code>src\/mcp-server.ts<\/code> file, let\u2019s create the entry point for the MCP server:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/mcp-server.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Server } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@modelcontextprotocol\/sdk\/server\/index'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Create MCP server<\/span>\n<span class=\"hljs-keyword\">const<\/span> server = <span class=\"hljs-keyword\">new<\/span> Server(\n {\n   <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'cloudinary-dam'<\/span>,\n   <span class=\"hljs-attr\">version<\/span>: <span class=\"hljs-string\">'1.0.0'<\/span>,\n },\n {\n   <span class=\"hljs-attr\">capabilities<\/span>: {\n     <span class=\"hljs-attr\">tools<\/span>: {},\n   },\n }\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The above creates an MCP server called <code>cloudinary-dam<\/code> with version <code>1.0.0<\/code>. At the moment, <code>tools<\/code> is an empty object, which is fine for now, as we need to provide more information for each tool.<\/p>\n<p>Next, we\u2019ll list out all the tools and provide more context for each tool:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/mcp-server.ts<\/span>\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n<span class=\"hljs-keyword\">import<\/span> { ListToolsRequestSchema } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@modelcontextprotocol\/sdk\/types'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-comment\">\/\/ List available tools<\/span>\nserver.setRequestHandler(ListToolsRequestSchema, <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n <span class=\"hljs-keyword\">return<\/span> {\n   <span class=\"hljs-attr\">tools<\/span>: &#91;\n     {\n       <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'upload'<\/span>,\n       <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Upload a media asset to Cloudinary'<\/span>,\n       <span class=\"hljs-attr\">inputSchema<\/span>: {\n         <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'object'<\/span>,\n         <span class=\"hljs-attr\">properties<\/span>: {\n           <span class=\"hljs-attr\">source<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'URL or base64 data of the asset to upload'<\/span> },\n           <span class=\"hljs-attr\">folder<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Folder path to store the asset in'<\/span> },\n           <span class=\"hljs-attr\">publicId<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Public ID for the asset'<\/span> },\n           <span class=\"hljs-attr\">tags<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Comma-separated list of tags'<\/span> }\n         },\n         <span class=\"hljs-attr\">required<\/span>: &#91;<span class=\"hljs-string\">'source'<\/span>]\n       }\n     },\n     {\n       <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'find-assets'<\/span>,\n       <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Search the media library using a flexible query string'<\/span>,\n       <span class=\"hljs-attr\">inputSchema<\/span>: {\n         <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'object'<\/span>,\n         <span class=\"hljs-attr\">properties<\/span>: {\n           <span class=\"hljs-attr\">expression<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Cloudinary search expression'<\/span> },\n           <span class=\"hljs-attr\">maxResults<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'number'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Maximum number of results to return'<\/span> }\n         },\n         <span class=\"hljs-attr\">required<\/span>: &#91;<span class=\"hljs-string\">'expression'<\/span>]\n       }\n     },\n     {\n       <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'delete-asset'<\/span>,\n       <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Delete a specific asset by public ID'<\/span>,\n       <span class=\"hljs-attr\">inputSchema<\/span>: {\n         <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'object'<\/span>,\n         <span class=\"hljs-attr\">properties<\/span>: {\n           <span class=\"hljs-attr\">publicId<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Public ID of the asset to delete'<\/span> },\n           <span class=\"hljs-attr\">resourceType<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Resource type (image, video, raw, etc.)'<\/span> },\n           <span class=\"hljs-attr\">type<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Delivery type (upload, private, authenticated)'<\/span> }\n         },\n         <span class=\"hljs-attr\">required<\/span>: &#91;<span class=\"hljs-string\">'publicId'<\/span>]\n       }\n     },\n     {\n       <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'get-asset'<\/span>,\n       <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Fetch details for an asset'<\/span>,\n       <span class=\"hljs-attr\">inputSchema<\/span>: {\n         <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'object'<\/span>,\n         <span class=\"hljs-attr\">properties<\/span>: {\n           <span class=\"hljs-attr\">publicId<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Public ID of the asset'<\/span> },\n           <span class=\"hljs-attr\">resourceType<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Resource type (image, video, raw, etc.)'<\/span> },\n           <span class=\"hljs-attr\">type<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Delivery type (upload, private, authenticated)'<\/span> }\n         },\n         <span class=\"hljs-attr\">required<\/span>: &#91;<span class=\"hljs-string\">'publicId'<\/span>]\n       }\n     },\n     {\n       <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'get-usage'<\/span>,\n       <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Fetch your Cloudinary account\\'s usage stats'<\/span>,\n       <span class=\"hljs-attr\">inputSchema<\/span>: {\n         <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'object'<\/span>,\n         <span class=\"hljs-attr\">properties<\/span>: {\n           <span class=\"hljs-attr\">date<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">'Date in YYYY-MM-DD format'<\/span> }\n         },\n         <span class=\"hljs-attr\">required<\/span>: &#91;]\n       }\n     }\n   ],\n };\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the above code, we list all tools, and for each tool, we provide a name (<strong>Note<\/strong>: This name should match the key we used while creating the tool registry above), a description, and the input schema.<\/p>\n<p>Next, we need to handle the tools calls.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"> <span class=\"hljs-comment\">\/\/ src\/mcp-server.ts<\/span>\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> {\n  CallToolRequestSchema,\n  ListToolsRequestSchema,\n  CallToolRequest,\n} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@modelcontextprotocol\/sdk\/types'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> tools <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/tools\/index'<\/span>;\n\n<span class=\"hljs-comment\">\/\/...<\/span>\n\n<span class=\"hljs-comment\">\/\/ Handle tool calls<\/span>\nserver.setRequestHandler(CallToolRequestSchema, <span class=\"hljs-keyword\">async<\/span> (request: CallToolRequest) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { name, <span class=\"hljs-attr\">arguments<\/span>: args } = request.params;\n\n  <span class=\"hljs-keyword\">if<\/span> (!tools&#91;name]) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Unknown tool: <span class=\"hljs-subst\">${name}<\/span>`<\/span>);\n  }\n\n  <span class=\"hljs-keyword\">try<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> tools&#91;name](args || {});\n    <span class=\"hljs-keyword\">return<\/span> {\n      <span class=\"hljs-attr\">content<\/span>: &#91;\n        {\n          <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'text'<\/span>,\n          <span class=\"hljs-attr\">text<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify(result, <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-number\">2<\/span>),\n        },\n      ],\n    };\n  } <span class=\"hljs-keyword\">catch<\/span> (error) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Tool execution failed: <span class=\"hljs-subst\">${error <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? error.message : <span class=\"hljs-string\">'Unknown error'<\/span>}<\/span>`<\/span>);\n  }\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019re registering a handler that handles the call made by the client (In this case, the AI). The AI sends the name of the tool and the relevant arguments provided to it. The backend uses the name and searches the tools registry. If it finds the tool, it calls it and returns the response as text to the client (the AI).<\/p>\n<p>Next, we add the code that starts the server:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"> <span class=\"hljs-comment\">\/\/ src\/mcp-server.ts<\/span>\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n<span class=\"hljs-keyword\">import<\/span> { StdioServerTransport } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@modelcontextprotocol\/sdk\/server\/stdio.js'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> transport = <span class=\"hljs-keyword\">new<\/span> StdioServerTransport();\n  <span class=\"hljs-keyword\">await<\/span> server.connect(transport);\n  <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Cloudinary DAM MCP server running on stdio'<\/span>);\n}\n\nmain().catch(<span class=\"hljs-function\">(<span class=\"hljs-params\">error<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Server failed to start:'<\/span>, error);\n  process.exit(<span class=\"hljs-number\">1<\/span>);\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the above code, we create a <code>StdioServerTransport<\/code>, which will read requests from <code>stdin<\/code> and write responses to <code>stdout<\/code>. And then we connect the MCP server to that transport.<\/p>\n<p>And with that, we have the full implementation of our MCP server!<\/p>\n<h2>Step 5: Connect to an MCP client<\/h2>\n<p>We can connect our MCP server to various <a href=\"https:\/\/modelcontextprotocol.io\/clients\">MCP clients<\/a> based on our needs, but for the sake of this post, we will be connecting to the <a href=\"https:\/\/claude.ai\/download\">Claude Desktop App<\/a>.<\/p>\n<p>First, we need to build the MCP server we implemented.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm run build\n<\/code><\/span><\/pre>\n<p>If you have the Claude desktop, open it and go to <strong>Settings<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1755562939\/blog-Creating_an_MCP_Server-1.png\" alt=\"Settings section with Cloudinary under Developers\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1598\" height=\"1122\"\/><\/p>\n<p>Click <strong>Developer<\/strong> -&gt; <strong>Edit config<\/strong> and add the below JSON in the <code>claude_desktop_config.json<\/code> file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n  <span class=\"hljs-attr\">\"mcpServers\"<\/span>: {\n    <span class=\"hljs-attr\">\"cloudinary\"<\/span>: {\n      <span class=\"hljs-attr\">\"command\"<\/span>: <span class=\"hljs-string\">\"node\"<\/span>,\n      <span class=\"hljs-attr\">\"args\"<\/span>: &#91;<span class=\"hljs-string\">\"\/full\/path\/to\/your\/cloudinary-mcp-server\/dist\/mcp-server.js\"<\/span>],\n      <span class=\"hljs-attr\">\"env\"<\/span>: {\n        <span class=\"hljs-attr\">\"CLOUDINARY_CLOUD_NAME\"<\/span>: <span class=\"hljs-string\">\"your-cloud-name\"<\/span>,\n        <span class=\"hljs-attr\">\"CLOUDINARY_API_KEY\"<\/span>: <span class=\"hljs-string\">\"your-api-key\"<\/span>,\n        <span class=\"hljs-attr\">\"CLOUDINARY_API_SECRET\"<\/span>: <span class=\"hljs-string\">\"your-api-secret\"<\/span>\n      }\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Important<\/strong>: Replace <code>\/full\/path\/to\/your\/cloudinary-mcp-server<\/code> with the absolute path to your project directory. Also, make sure you secure your environmental variables.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1755562939\/blog-Creating_an_MCP_Server-2.png\" alt=\"A red Failed notification next to Cloudinary. The Error says \u201cServer disconnected\u201d.\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1186\" height=\"808\"\/><\/p>\n<p>Restart Claude Desktop and you\u2019re ready to go! Now, Claude will recognize your tools, and you should see something like the image below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1755562939\/blog-Creating_an_MCP_Server-3.png\" alt=\"Inside Claude, there\u2019s a text box where you can type what you\u2019d like Claude to do. A dropdown menu includes toggles for: Disable all tools, Upload, find-assets, delete-asset, get-asset, and get-usage\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1194\" height=\"1194\"\/><\/p>\n<p>Now you can easily ask Claude to upload an asset, delete or get an asset, and it should be able to handle it!<\/p>\n<h2>Conclusion<\/h2>\n<p>We built an MCP server that connects with Cloudinary\u2019s DAM to help us handle and automate certain workflows. This is really valuable because we can extend it to do more using the Cloudinary API, such as handling transformations and automatic tagging. All we need to do is add new tools, and the AI assistant instantly gains those capabilities!<\/p>\n<p>Transform your visual media workflows today. <a href=\"https:\/\/cloudinary.com\/contact\">Contact us to learn more<\/a>.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":38380,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[336,420],"class_list":["post-38335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-ai","tag-dam"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Creating an MCP Server to Interact With Cloudinary\u2019s DAM<\/title>\n<meta name=\"description\" content=\"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating an MCP Server to Interact With Cloudinary\u2019s DAM\" \/>\n<meta property=\"og:description\" content=\"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-09-03T00:17:56+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Creating an MCP Server to Interact With Cloudinary\u2019s DAM\",\"datePublished\":\"2025-09-03T00:17:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\"},\"wordCount\":10,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA\",\"keywords\":[\"AI\",\"DAM\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\",\"url\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\",\"name\":\"Creating an MCP Server to Interact With Cloudinary\u2019s DAM\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA\",\"datePublished\":\"2025-09-03T00:17:56+00:00\",\"description\":\"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating an MCP Server to Interact With Cloudinary\u2019s DAM\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM","description":"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam","og_locale":"en_US","og_type":"article","og_title":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM","og_description":"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.","og_url":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam","og_site_name":"Cloudinary Blog","article_published_time":"2025-09-03T00:17:56+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM","datePublished":"2025-09-03T00:17:56+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam"},"wordCount":10,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","keywords":["AI","DAM"],"inLanguage":"en-US","copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam","url":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam","name":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","datePublished":"2025-09-03T00:17:56+00:00","description":"A step-by-step guide on how to create an MCP server that connects an AI assistant to Cloudinary\u2019s DAM for automated visual media management.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/mcp-server-interact-cloudinarys-dam#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Creating an MCP Server to Interact With Cloudinary\u2019s DAM"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1755643227\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog\/Creating_an_MCP_Server_to_Interact_With_Cloudinary_s_DAM-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=38335"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38335\/revisions"}],"predecessor-version":[{"id":38400,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38335\/revisions\/38400"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/38380"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=38335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=38335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=38335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}