cloudmindmaps-mcp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jan Rezab / CloudMindMaps
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # CloudMindMaps MCP Server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/cloudmindmaps-mcp.svg)](https://www.npmjs.com/package/cloudmindmaps-mcp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+
6
+ Let Claude — and any other [Model Context Protocol](https://modelcontextprotocol.io) client — create, browse, and read mind maps directly on **[cloudmindmaps.app](https://cloudmindmaps.app)**. Maps use the open FreeMind/Freeplane `.mm` format, so anything you make here also opens in those desktop apps.
7
+
8
+ Just ask:
9
+
10
+ > *"Turn these meeting notes into a mind map."*
11
+ > *"Make a mind map of the pros and cons of microservices."*
12
+ > *"List my mind maps and show me the roadmap one."*
13
+
14
+ Claude structures the ideas, this server saves the map, and you get a shareable link.
15
+
16
+ ## Tools
17
+
18
+ | Tool | What it does |
19
+ |---|---|
20
+ | **`create_mindmap_from_outline`** | **Recommended.** The AI supplies a nested outline; the server generates valid `.mm` XML (IDs, balanced branches, escaping) and saves it. |
21
+ | `create_mindmap` | Create a map from raw CloudMindMaps `.mm` XML (for power users who need clouds, edges, connectors, rich HTML nodes). |
22
+ | `list_mindmaps` | List maps you own or that are shared with you. |
23
+ | `get_mindmap` | Read a map's details and full `.mm` XML by ID. |
24
+
25
+ Plus a prompt, **`convert_to_mindmap`**, that turns any pasted content into a well-structured map in one step.
26
+
27
+ ## Quick start
28
+
29
+ ### 1. Get your CloudMindMaps API key
30
+
31
+ Sign in at [cloudmindmaps.app](https://cloudmindmaps.app), open your browser console, and run:
32
+
33
+ ```js
34
+ const token = await firebase.auth().currentUser.getIdToken();
35
+ const res = await fetch("https://cloudmindmaps.app/api/keys", {
36
+ method: "POST",
37
+ headers: { Authorization: `Bearer ${token}` },
38
+ });
39
+ console.log("Your API key:", (await res.json()).key);
40
+ ```
41
+
42
+ Copy the key — it's shown only once. Re-running the command regenerates it (and revokes the old one).
43
+
44
+ ### 2. Add the server to your MCP client
45
+
46
+ No install needed — `npx` fetches and runs it. Just add the config below and drop in your key.
47
+
48
+ **Claude Desktop** — edit `claude_desktop_config.json` (Settings → Developer → Edit Config):
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "cloudmindmaps": {
54
+ "command": "npx",
55
+ "args": ["-y", "cloudmindmaps-mcp"],
56
+ "env": { "CLOUDMINDMAPS_API_KEY": "YOUR_API_KEY_HERE" }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ **Claude Code** (CLI):
63
+
64
+ ```bash
65
+ claude mcp add cloudmindmaps --env CLOUDMINDMAPS_API_KEY=YOUR_API_KEY_HERE -- npx -y cloudmindmaps-mcp
66
+ ```
67
+
68
+ **Cursor / other MCP clients** — same shape: command `npx`, args `["-y", "cloudmindmaps-mcp"]`, env `CLOUDMINDMAPS_API_KEY`.
69
+
70
+ ### 3. Restart your client
71
+
72
+ You'll see the four tools appear. Ask Claude to make a mind map and it will reply with a link to open on cloudmindmaps.app.
73
+
74
+ ## Configuration
75
+
76
+ | Env var | Required | Default | Description |
77
+ |---|---|---|---|
78
+ | `CLOUDMINDMAPS_API_KEY` | ✅ | — | Your API key from step 1. |
79
+ | `CLOUDMINDMAPS_API_URL` | — | `https://cloudmindmaps.app` | Override for self-hosted / staging. |
80
+ | `CLOUDMINDMAPS_TIMEOUT_MS` | — | `30000` | Per-request timeout in milliseconds. |
81
+
82
+ ## Running from source (development)
83
+
84
+ ```bash
85
+ cd mcp-server
86
+ npm install
87
+ CLOUDMINDMAPS_API_KEY=YOUR_KEY node index.js
88
+ ```
89
+
90
+ Then point your client at `node /absolute/path/to/mcp-server/index.js` instead of `npx`.
91
+
92
+ ## Revoking your key
93
+
94
+ ```js
95
+ const token = await firebase.auth().currentUser.getIdToken();
96
+ await fetch("https://cloudmindmaps.app/api/keys", {
97
+ method: "DELETE",
98
+ headers: { Authorization: `Bearer ${token}` },
99
+ });
100
+ ```
101
+
102
+ ## Links
103
+
104
+ - Web app: https://cloudmindmaps.app
105
+ - Setup guide: https://cloudmindmaps.app/mcp
106
+ - `.mm` format spec: https://cloudmindmaps.app/prompt-convert-to-mm.md
107
+
108
+ ## License
109
+
110
+ MIT © Jan Rezab / CloudMindMaps
package/index.js ADDED
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+
6
+ const VERSION = "1.1.0";
7
+ const API_URL = (process.env.CLOUDMINDMAPS_API_URL || "https://cloudmindmaps.app").replace(/\/+$/, "");
8
+ const API_KEY = process.env.CLOUDMINDMAPS_API_KEY || "";
9
+ const REQUEST_TIMEOUT_MS = Number(process.env.CLOUDMINDMAPS_TIMEOUT_MS || 30000);
10
+
11
+ // -------------------------------------------------------------------------
12
+ // API client
13
+ // -------------------------------------------------------------------------
14
+
15
+ async function apiRequest(method, path, body) {
16
+ if (!API_KEY) {
17
+ throw new Error(
18
+ "No API key configured. Set CLOUDMINDMAPS_API_KEY in your MCP client config. " +
19
+ "Get a key at https://cloudmindmaps.app (see the MCP setup guide)."
20
+ );
21
+ }
22
+
23
+ const controller = new AbortController();
24
+ const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
25
+ try {
26
+ const res = await fetch(`${API_URL}${path}`, {
27
+ method,
28
+ headers: {
29
+ "X-API-Key": API_KEY,
30
+ "Content-Type": "application/json",
31
+ "User-Agent": `cloudmindmaps-mcp/${VERSION}`,
32
+ },
33
+ body: body ? JSON.stringify(body) : undefined,
34
+ signal: controller.signal,
35
+ });
36
+ if (!res.ok) {
37
+ const text = await res.text().catch(() => "");
38
+ if (res.status === 401 || res.status === 403) {
39
+ throw new Error(
40
+ "Authentication failed (invalid or revoked API key). Regenerate a key at https://cloudmindmaps.app and update CLOUDMINDMAPS_API_KEY."
41
+ );
42
+ }
43
+ throw new Error(`CloudMindMaps API ${method} ${path} failed (${res.status})${text ? `: ${text}` : ""}`);
44
+ }
45
+ return res.json();
46
+ } catch (err) {
47
+ if (err.name === "AbortError") {
48
+ throw new Error(`Request to CloudMindMaps timed out after ${REQUEST_TIMEOUT_MS}ms.`);
49
+ }
50
+ throw err;
51
+ } finally {
52
+ clearTimeout(timer);
53
+ }
54
+ }
55
+
56
+ const ok = (text) => ({ content: [{ type: "text", text }] });
57
+ const fail = (text) => ({ isError: true, content: [{ type: "text", text }] });
58
+
59
+ // -------------------------------------------------------------------------
60
+ // .mm XML builder — turns a nested outline into valid CloudMindMaps XML
61
+ // -------------------------------------------------------------------------
62
+
63
+ function escapeXml(s) {
64
+ return String(s)
65
+ .replace(/&/g, "&")
66
+ .replace(/</g, "&lt;")
67
+ .replace(/>/g, "&gt;")
68
+ .replace(/"/g, "&quot;")
69
+ .replace(/'/g, "&apos;");
70
+ }
71
+
72
+ function outlineToXml(root) {
73
+ let counter = 0;
74
+ const nextId = () => `ID_${counter++}`;
75
+
76
+ const renderNode = (node, position, depth) => {
77
+ const attrs = [`ID="${nextId()}"`, `TEXT="${escapeXml(node.text)}"`];
78
+ if (position) attrs.push(`POSITION="${position}"`);
79
+ if (node.color) attrs.push(`COLOR="${escapeXml(node.color)}"`);
80
+ if (node.background) attrs.push(`BACKGROUND_COLOR="${escapeXml(node.background)}"`);
81
+ if (node.link) attrs.push(`LINK="${escapeXml(node.link)}"`);
82
+
83
+ const inner = [];
84
+ if (node.bold || node.size) {
85
+ const fontAttrs = [`NAME="SansSerif"`];
86
+ if (node.size) fontAttrs.push(`SIZE="${Number(node.size)}"`);
87
+ if (node.bold) fontAttrs.push(`BOLD="true"`);
88
+ inner.push(`<font ${fontAttrs.join(" ")}/>`);
89
+ }
90
+ if (node.icon) inner.push(`<icon BUILTIN="${escapeXml(node.icon)}"/>`);
91
+ if (node.note) {
92
+ inner.push(
93
+ `<richcontent TYPE="NOTE"><html><body><p>${escapeXml(node.note)}</p></body></html></richcontent>`
94
+ );
95
+ }
96
+
97
+ const children = Array.isArray(node.children) ? node.children : [];
98
+ const pad = " ".repeat(depth);
99
+ if (inner.length === 0 && children.length === 0) {
100
+ return `${pad}<node ${attrs.join(" ")}/>`;
101
+ }
102
+
103
+ const parts = [`${pad}<node ${attrs.join(" ")}>`];
104
+ for (const el of inner) parts.push(`${pad} ${el}`);
105
+ children.forEach((child, i) => {
106
+ // Only the root's direct children carry a POSITION; balance them left/right.
107
+ const childPos = depth === 0 ? (i % 2 === 0 ? "right" : "left") : null;
108
+ parts.push(renderNode(child, childPos, depth + 1));
109
+ });
110
+ parts.push(`${pad}</node>`);
111
+ return parts.join("\n");
112
+ };
113
+
114
+ return `<map version="1.0.0">\n<!-- CloudMindMaps .mm format -->\n${renderNode(root, null, 0)}\n</map>`;
115
+ }
116
+
117
+ // -------------------------------------------------------------------------
118
+ // Server
119
+ // -------------------------------------------------------------------------
120
+
121
+ const server = new McpServer({
122
+ name: "cloudmindmaps",
123
+ version: VERSION,
124
+ });
125
+
126
+ // A recursive outline node schema.
127
+ const OutlineNode = z.lazy(() =>
128
+ z
129
+ .object({
130
+ text: z.string().describe("The node's label."),
131
+ note: z.string().optional().describe("Optional longer note attached to the node."),
132
+ icon: z
133
+ .string()
134
+ .optional()
135
+ .describe(
136
+ "Optional built-in icon name, e.g. idea, yes, no, star, flag, warning, info, question, button_ok, full-1..full-9."
137
+ ),
138
+ color: z.string().optional().describe('Optional text color as hex, e.g. "#6366f1".'),
139
+ background: z.string().optional().describe('Optional node background color as hex, e.g. "#fef08a".'),
140
+ link: z.string().optional().describe("Optional hyperlink URL for the node."),
141
+ bold: z.boolean().optional().describe("Render the node text bold."),
142
+ size: z.number().optional().describe("Font size in points (default 14)."),
143
+ children: z.array(OutlineNode).optional().describe("Child nodes (unlimited depth)."),
144
+ })
145
+ .describe("A mind map node. The top-level node is the map's central topic.")
146
+ );
147
+
148
+ // --- create_mindmap_from_outline (recommended) ---
149
+ server.registerTool(
150
+ "create_mindmap_from_outline",
151
+ {
152
+ title: "Create mind map from an outline",
153
+ description: `Create a mind map on CloudMindMaps from a simple nested outline. THIS IS THE RECOMMENDED WAY to create maps — you provide the structure as nested objects and the server generates valid .mm XML for you (correct IDs, balanced left/right branches, XML escaping). Use this whenever you're turning notes, documents, ideas, or a plan into a mind map.
154
+
155
+ Provide 'root' as the central topic with nested 'children'. Guidelines for a readable map:
156
+ - Give the root a short, punchy central topic.
157
+ - Aim for 2-6 top-level branches; the server auto-balances them left and right.
158
+ - Keep it 3-4 levels deep. Split further rather than writing long node text.
159
+ - Use 'icon' sparingly for emphasis (e.g. "idea", "warning", "yes"), and 'note' for detail that shouldn't clutter the node label.
160
+
161
+ Returns the map's shareable URL on cloudmindmaps.app.`,
162
+ inputSchema: {
163
+ title: z.string().describe("Title of the mind map (used for the file/name, not shown as a node)."),
164
+ root: OutlineNode.describe("The central topic node, with nested children forming the map."),
165
+ },
166
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
167
+ },
168
+ async ({ title, root }) => {
169
+ try {
170
+ const xml = outlineToXml(root);
171
+ const result = await apiRequest("POST", "/api/mindmaps", { title, xml });
172
+ return ok(`Mind map created ✅\n\nTitle: ${result.title}\nID: ${result.id}\nOpen it: ${result.url}`);
173
+ } catch (err) {
174
+ return fail(err.message);
175
+ }
176
+ }
177
+ );
178
+
179
+ // --- create_mindmap (raw XML, power users) ---
180
+ server.registerTool(
181
+ "create_mindmap",
182
+ {
183
+ title: "Create mind map from raw .mm XML",
184
+ description: `Create a mind map on CloudMindMaps from raw CloudMindMaps XML (.mm format). Prefer create_mindmap_from_outline unless you specifically need XML features not exposed by the outline (clouds, edge styling, arrowlink connectors, richcontent HTML nodes).
185
+
186
+ Minimal XML shape:
187
+ <map version="1.0.0">
188
+ <node ID="ID_0" TEXT="Root Topic">
189
+ <node ID="ID_1" TEXT="Branch A" POSITION="right">
190
+ <node ID="ID_2" TEXT="Detail"/>
191
+ </node>
192
+ <node ID="ID_3" TEXT="Branch B" POSITION="left"/>
193
+ </node>
194
+ </map>
195
+
196
+ Rules:
197
+ - Exactly one root <node> inside <map>. Root has no POSITION.
198
+ - Only the root's direct children take POSITION="left" or "right".
199
+ - Every node needs a unique ID (ID_0, ID_1, ...).
200
+ - Escape XML entities in TEXT (&amp; &lt; &gt; &quot; &apos;).
201
+ - Optional sub-elements: <font>, <edge>, <icon BUILTIN="...">, <cloud>, <richcontent>, <arrowlink>.`,
202
+ inputSchema: {
203
+ title: z.string().describe("Title of the mind map."),
204
+ xml: z.string().describe("Valid CloudMindMaps .mm XML content."),
205
+ },
206
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
207
+ },
208
+ async ({ title, xml }) => {
209
+ try {
210
+ const result = await apiRequest("POST", "/api/mindmaps", { title, xml });
211
+ return ok(`Mind map created ✅\n\nTitle: ${result.title}\nID: ${result.id}\nOpen it: ${result.url}`);
212
+ } catch (err) {
213
+ return fail(err.message);
214
+ }
215
+ }
216
+ );
217
+
218
+ // --- list_mindmaps ---
219
+ server.registerTool(
220
+ "list_mindmaps",
221
+ {
222
+ title: "List my mind maps",
223
+ description: "List all mind maps owned by or shared with the authenticated CloudMindMaps user.",
224
+ inputSchema: {},
225
+ annotations: { readOnlyHint: true, openWorldHint: true },
226
+ },
227
+ async () => {
228
+ try {
229
+ const result = await apiRequest("GET", "/api/mindmaps");
230
+ const maps = result.mindmaps || [];
231
+ if (maps.length === 0) return ok("No mind maps found.");
232
+ const lines = maps.map((m) => `- ${m.title} (id: ${m.id}, role: ${m.role}, url: ${m.url})`);
233
+ return ok(`Found ${maps.length} mind map(s):\n\n${lines.join("\n")}`);
234
+ } catch (err) {
235
+ return fail(err.message);
236
+ }
237
+ }
238
+ );
239
+
240
+ // --- get_mindmap ---
241
+ server.registerTool(
242
+ "get_mindmap",
243
+ {
244
+ title: "Get a mind map's content",
245
+ description: "Fetch the full details and .mm XML content of a mind map by its ID.",
246
+ inputSchema: {
247
+ id: z.string().describe("The mind map ID (16-character string)."),
248
+ },
249
+ annotations: { readOnlyHint: true, openWorldHint: true },
250
+ },
251
+ async ({ id }) => {
252
+ try {
253
+ const r = await apiRequest("GET", `/api/mindmaps/${encodeURIComponent(id)}`);
254
+ return ok(
255
+ `Title: ${r.title}\nID: ${r.id}\nRole: ${r.role}\nURL: ${r.url}\nPublic: ${r.is_public}\n\nXML:\n${r.xml}`
256
+ );
257
+ } catch (err) {
258
+ return fail(err.message);
259
+ }
260
+ }
261
+ );
262
+
263
+ // -------------------------------------------------------------------------
264
+ // Prompt: guide the model to turn any content into a great mind map
265
+ // -------------------------------------------------------------------------
266
+
267
+ server.registerPrompt(
268
+ "convert_to_mindmap",
269
+ {
270
+ title: "Convert content into a mind map",
271
+ description:
272
+ "Turn notes, a document, a list, or an idea into a well-structured CloudMindMaps mind map and save it.",
273
+ argsSchema: {
274
+ content: z.string().describe("The text/notes/document to turn into a mind map."),
275
+ title: z.string().optional().describe("Optional title for the mind map."),
276
+ },
277
+ },
278
+ ({ content, title }) => ({
279
+ messages: [
280
+ {
281
+ role: "user",
282
+ content: {
283
+ type: "text",
284
+ text: `Turn the following content into a clear, well-structured mind map and save it to CloudMindMaps using the create_mindmap_from_outline tool.
285
+
286
+ Structuring guidelines:
287
+ - Choose a short central topic${title ? ` (suggested title: "${title}")` : ""}.
288
+ - Group related ideas into 2-6 top-level branches.
289
+ - Nest details 3-4 levels deep; prefer more nodes over long labels.
290
+ - Preserve the meaning and hierarchy of the source; don't invent facts.
291
+ - Use an 'icon' or 'note' only where it genuinely adds clarity.
292
+ After saving, give me the shareable link.
293
+
294
+ CONTENT:
295
+ ${content}`,
296
+ },
297
+ },
298
+ ],
299
+ })
300
+ );
301
+
302
+ // -------------------------------------------------------------------------
303
+ // Boot
304
+ // -------------------------------------------------------------------------
305
+
306
+ async function main() {
307
+ const transport = new StdioServerTransport();
308
+ await server.connect(transport);
309
+ console.error(`CloudMindMaps MCP server v${VERSION} running on stdio (API: ${API_URL})`);
310
+ if (!API_KEY) {
311
+ console.error("⚠️ CLOUDMINDMAPS_API_KEY not set — tools will return an auth error until you configure it.");
312
+ }
313
+ }
314
+
315
+ main().catch((err) => {
316
+ console.error("Fatal error:", err);
317
+ process.exit(1);
318
+ });
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "cloudmindmaps-mcp",
3
+ "version": "1.1.0",
4
+ "description": "Model Context Protocol (MCP) server that lets Claude and other AI assistants create, list, and read mind maps on CloudMindMaps (FreeMind/Freeplane .mm format).",
5
+ "mcpName": "app.cloudmindmaps/mindmaps",
6
+ "main": "index.js",
7
+ "type": "module",
8
+ "bin": {
9
+ "cloudmindmaps-mcp": "index.js"
10
+ },
11
+ "files": [
12
+ "index.js",
13
+ "README.md",
14
+ "server.json"
15
+ ],
16
+ "scripts": {
17
+ "start": "node index.js"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "modelcontextprotocol",
23
+ "mindmap",
24
+ "mind-map",
25
+ "mindmapping",
26
+ "freemind",
27
+ "freeplane",
28
+ "mm",
29
+ "claude",
30
+ "cloudmindmaps",
31
+ "ai"
32
+ ],
33
+ "author": "Jan Rezab",
34
+ "license": "MIT",
35
+ "homepage": "https://cloudmindmaps.app/mcp",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/jan-rezab/cloudmindmaps.git",
39
+ "directory": "mcp-server"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/jan-rezab/cloudmindmaps/issues"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "@modelcontextprotocol/sdk": "^1.29.0",
49
+ "zod": "^3.24.0"
50
+ }
51
+ }
package/server.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.json",
3
+ "name": "app.cloudmindmaps/mindmaps",
4
+ "description": "Create, list, and read mind maps on CloudMindMaps (FreeMind/Freeplane .mm format) directly from Claude and other AI assistants.",
5
+ "version": "1.1.0",
6
+ "repository": {
7
+ "url": "https://github.com/jan-rezab/cloudmindmaps",
8
+ "source": "github",
9
+ "subfolder": "mcp-server"
10
+ },
11
+ "websiteUrl": "https://cloudmindmaps.app/mcp",
12
+ "packages": [
13
+ {
14
+ "registryType": "npm",
15
+ "registryBaseUrl": "https://registry.npmjs.org",
16
+ "identifier": "cloudmindmaps-mcp",
17
+ "version": "1.1.0",
18
+ "transport": {
19
+ "type": "stdio"
20
+ },
21
+ "environmentVariables": [
22
+ {
23
+ "name": "CLOUDMINDMAPS_API_KEY",
24
+ "description": "Your CloudMindMaps API key. Generate one while signed in at https://cloudmindmaps.app (see the MCP setup guide).",
25
+ "isRequired": true,
26
+ "isSecret": true
27
+ },
28
+ {
29
+ "name": "CLOUDMINDMAPS_API_URL",
30
+ "description": "Base URL of the CloudMindMaps API. Defaults to https://cloudmindmaps.app.",
31
+ "isRequired": false,
32
+ "default": "https://cloudmindmaps.app"
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }