尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从零搭建 Unofficial Cosmos MCP:让 AI 直接查询你的设计灵感库

从零搭建 Unofficial Cosmos MCP:让 AI 直接查询你的设计灵感库 一个很常见的画面设计团队用 Cosmos.so 收藏了上千张灵感图、竞品截图和品牌规范但当你打开 AI 编程助手让它“从最近收藏的竞品首页灵感里提取配色方案”时它只能干瞪眼。收藏得越多AI 越读不到最后所有资料被迫靠人工搬运。这个问题的本质不是模型能力不够而是 AI 缺少一条读取 Cosmos.so 数据的标准通道。MCPModel Context Protocol就是来补这条通道的。本文要讲的是在 Cosmos.so 还没有官方成熟 MCP Server 的时候如何用社区方案自己搭一个 Unofficial Cosmos.so MCP把设计灵感库变成 AI 可以直接查询的资源。我的核心判断是这类“非官方 MCP”的工程难度不在协议本身MCP 并不会让一个没有 API 的产品突然开放数据它真正的价值是把已有的 HTTP API 包装成 AI 能理解、能调用、能组合成任务的工具层。读完本文你能跑通一个只读的 Cosmos MCP Server并把这套方法迁移到 Figma、Notion 以及任意一个有 API 的 SaaS 工具上。如果你正在做设计系统工程、提示词工程或者好奇“AI Agent 如何接外部数据”这篇文章值得收藏。1. 为什么要关注 Cosmos.so 的 MCP 能力1.1 Cosmos.so 到底是什么Cosmos.so 常被团队用作设计灵感管理和品牌知识库你可以把它理解为“面向设计师和创意团队的高质量收藏夹”。它和普通书签工具的核心差异在于它会抓取网页截图、提炼元数据、保留视觉效果并且按空间Space、卡片Card、标签Tag组织内容。设计团队会把竞品页面、灵感参考、品牌案例、设计标注全部沉淀进去形成团队的视觉语料库。但问题也随之而来这些语料库平时只有人在看。AI 编程助手、AI 写作助手无法直接登录 Cosmos.so 去检索更没法理解“用户收藏里的视觉风格”。过去想解决这个问题只能靠人工把卡片导出、整理成文本、再粘贴给 AI。一次两次还能忍团队大了之后这种人工搬运完全不可持续。1.2 MCP 解决的是 AI 与数据之间的“翻译”问题MCP 是 Anthropic 提出的开放协议它定义了一套标准通信方式让 AI 模型可以调用外部工具、读取外部资源。你可以把它理解成 AI 世界的 USB-C任何一个支持 MCP 的客户端都能通过同一套协议连接任意一个 MCP Server。MCP Server 的工作流程可以简化为三步客户端Claude Desktop、Cline、Dify 等启动时发现 Server 提供的工具列表。模型根据用户问题判断需要调用哪个工具。Server 收到调用请求后执行真实操作比如请求 Cosmos API把结果返回给模型。所以MCP 的本质不是数据源而是“适配层”。只要 Cosmos.so 提供了公开 API我们就完全可以自己写一个 Unofficial MCP Server把 Cosmos 的空间、卡片、搜索能力暴露给 AI。1.3 官方缺失与社区补位从材料来看Cosmos.so 官方对 MCP 的支持还在演进阶段社区出现 Unofficial Cosmos.so MCP 是一个典型的“官方能力未覆盖、社区先补位”过程。这其实是好事它让我们提前验证了 AI 与设计知识库结合的场景。同时也要清楚非官方实现的质量取决于背后 API 的稳定性和权限边界。如果 Cosmos 调整了接口社区 Server 需要同步更新这是使用非官方项目时必须接受的成本。2. MCP 与 Cosmos.so 的核心概念拆解为了后面动手时不迷糊先把几个关键概念讲清楚。2.1 MCP 的三个要素Host宿主运行 AI 模型的客户端比如 Claude Desktop、Cline、Cursor、Dify。Server服务端本文要写的程序负责连接外部数据源并提供工具。Protocol协议JSON-RPC 2.0 消息格式加上一组标准方法比如tools/list、tools/call。MCP 的模型并不复杂真正复杂的永远是“你向 AI 暴露什么工具、工具描述写得好不好”。如果工具命名含糊AI 就不知道该什么时候调用如果参数 schema 描述不清AI 就会传错参数。这个判断适用于所有 MCP 项目。2.2 Cosmos.so 的核心对象在 Cosmos 数据模型里我们最关心三类对象对象含义对 AI 的价值Space空间/收藏库类似于项目分组让 AI 知道从哪个分类里找资料Card卡片对应一条书签、灵感、链接或笔记是 AI 最终要读取的内容单元Tag/Collection标签或集合描述卡片的属性可以作为过滤条件提高检索精度非官方 MCP 要做的就是把这些对象映射成 MCP Tools。2.3 官方 MCP、非官方 MCP、直接用 API 的差别方案接入成本能力边界风险官方 MCP Server最低配置即用由官方控制通常稳定功能同步官方节奏非官方 MCP Server中等需要写适配层取决于公开 API 和你的想象力API 变动可能导致不可用直接在代码里调用 API高每次任务都写一遍灵活但 AI 无法自主发现重复劳动且不通用我的建议是先用非官方 MCP Server 验证工作流如果 AI 与 Cosmos 的结合确实成为团队刚需再推动官方支持或自己维护一个内部稳定版本。3. 环境准备与前置条件动手之前先确认四件事。3.1 运行环境操作系统Windows / macOS / Linux 均可本文命令以通用为主。Node.js 版本建议 18 及以上。MCP TypeScript SDK 和 fetch API 在 18 下更稳定。JavaScript 包管理器npm 或 pnpm 均可。3.2 MCP SDK 与依赖以 TypeScript 为例我们需要几个关键依赖modelcontextprotocol/sdkMCP 官方 SDK。zod用于声明工具参数的类型 schemaMCP SDK 会把它转成 JSON Schema 给 AI。dotenv读取本地环境变量避免把 API Token 写进代码。tsx在开发阶段直接运行 TypeScript 文件。版本号不建议写死以你安装时的最新稳定版为准。本文示例基于 SDK 0.6 之后的 API 风格如果版本更新导致方法签名变化以官方类型声明为准。3.3 Cosmos.so 账号与 API Token非官方 MCP 的核心是调用 Cosmos.so 的 HTTP API因此你至少需要一个能访问数据接口的 Token。具体申请方式以 Cosmos 官方文档为准申请到之后把 Token 放到本地环境变量里不要提交到 Git。如果当前账号没有 API 权限也可以用 Mock 数据先跑通 MCP 流程把“协议适配”和“真实数据接入”两步拆开验证。3.4 MCP 客户端建议准备两个MCP Inspector官方调试工具用来单独验证 Server 是否工作。Claude Desktop 或 Cline用来测试真实 AI 对话链路。4. 核心设计思路与目录结构4.1 设计原则先做只读再考虑写操作最稳妥的 Unofficial Cosmos.so MCP 第一版只做读操作。理由有三点读操作风险低不会误删用户数据。设计场景里AI 主要需要“找资料”“读详情”写入需求并不紧急。非官方 API 可能不支持写入强行适配反而增加维护成本。因此第一版工具集定义如下list_spaces列出当前用户的所有 Cosmos 空间。get_cards读取某个空间下的卡片可按数量限制。search_cards搜索卡片支持关键词、标题等过滤。这三个工具足以支撑“了解用户有哪些灵感库”“从灵感库中找相关案例”“按主题搜索收藏”三类高频问题。4.2 架构与目录结构整个链路是AI 客户端 (Claude/Cline/Dify) ↓ MCP (JSON-RPC over stdio) MCP Server (本项目的 TypeScript 程序) ↓ HTTPS Cosmos.so API项目目录可以这样组织cosmos-mcp/ ├── package.json ├── tsconfig.json ├── .env ├── src/ │ ├── index.ts # MCP Server 入口 │ ├── cosmosApi.ts # Cosmos API 客户端封装 │ └── tools.ts # 工具定义可选拆分 └── test/ └── api.test.ts # 接口测试第一版不必过度拆分但index.ts和cosmosApi.ts一定要分开。这样以后换 API 版本或增加工具时逻辑不会全堆在一起。5. 完整代码实现下面按步骤实现一个可运行的最小版本。5.1 初始化项目和安装依赖mkdir cosmos-mcp cd cosmos-mcp npm init -y npm install modelcontextprotocol/sdk zod dotenv npm install -D typescript tsx types/node安装完成后创建tsconfig.json{ compilerOptions: { target: ES2022, module: NodeNext, moduleResolution: NodeNext, strict: true, outDir: dist, rootDir: src, skipLibCheck: true }, include: [src] }这里需要注意使用NodeNext模块规范时导入本地文件需要写.js后缀这是 TypeScript 对 ESM 的要求很多新手会在这里报错。5.2 配置环境变量创建.env文件COSMOS_API_TOKENyour_cosmos_api_token_here COSMOS_API_BASEhttps://api.cosmos.so/v0COSMOS_API_BASE的默认地址只是示例请以你申请到的 API 文档为准。Cosmos API 的端点可能随官方版本调整不确定时先查文档。5.3 封装 Cosmos API 客户端新建src/cosmosApi.ts。这个模块只负责 HTTP 请求和类型定义不依赖 MCP 的任何概念方便单独测试。// 文件路径src/cosmosApi.ts import dotenv from dotenv; dotenv.config(); const COSMOS_API_BASE process.env.COSMOS_API_BASE ?? https://api.cosmos.so/v0; export interface CosmosSpace { id: string; name: string; description?: string; } export interface CosmosCard { id: string; title: string; url?: string; note?: string; spaceId?: string; createdAt?: string; } export class CosmosApiClient { constructor(private readonly apiToken: string) {} private async requestT(path: string): PromiseT { const res await fetch(${COSMOS_API_BASE}${path}, { headers: { Authorization: Bearer ${this.apiToken}, Content-Type: application/json, }, }); if (!res.ok) { const detail await res.text(); throw new Error(Cosmos API 请求失败: ${res.status} ${detail.slice(0, 200)}); } return res.json() as PromiseT; } async listSpaces(): PromiseCosmosSpace[] { const data await this.request{ spaces: CosmosSpace[] }(/spaces); return data.spaces ?? []; } async listCards(spaceId?: string, limit 20): PromiseCosmosCard[] { const query new URLSearchParams({ limit: String(limit) }); if (spaceId) { query.set(spaceId, spaceId); } const data await this.request{ cards: CosmosCard[] }( /cards?${query.toString()} ); return data.cards ?? []; } async searchCards(queryText: string): PromiseCosmosCard[] { const query new URLSearchParams({ q: queryText }); const data await this.request{ cards: CosmosCard[] }( /search?${query.toString()} ); return data.cards ?? []; } }这段代码的核心逻辑有三个通过Authorization: Bearer传 Token避免每次调用手动拼接。把 HTTP 错误统一包装成可读错误信息方便 MCP 端回传给模型。所有方法都返回结构化的 TypeScript 类型后续就算 Cosmos 返回字段有调整也只需要改这里。这里真正容易踩坑的地方是Cosmos 返回的数据结构可能不是{ spaces: [...] }而是其他嵌套结构。如果你在真实调用时发现拿不到数据先打印一次原始 JSON再调整类型定义不要盲目照抄。5.4 实现 MCP Server 入口新建src/index.ts把 API 客户端映射成 MCP Tools。// 文件路径src/index.ts import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; import { CosmosApiClient } from ./cosmosApi.js; const apiToken process.env.COSMOS_API_TOKEN; if (!apiToken) { console.error(缺少 COSMOS_API_TOKEN 环境变量); process.exit(1); } const client new CosmosApiClient(apiToken); const server new McpServer({ name: cosmos-mcp, version: 0.1.0, }); server.tool( list_spaces, 列出当前用户的所有 Cosmos 空间收藏库, {}, async () { try { const spaces await client.listSpaces(); return { content: [{ type: text, text: JSON.stringify(spaces, null, 2) }], }; } catch (err) { return { content: [{ type: text, text: list_spaces 调用失败: ${(err as Error).message} }], isError: true, }; } } ); server.tool( get_cards, 读取某个空间下的卡片用于查看该收藏库里的具体灵感链接、笔记和标题, { spaceId: z.string().optional().describe(空间 ID来自 list_spaces 的返回结果), limit: z.number().optional().default(20).describe(最大返回卡片数默认 20), }, async ({ spaceId, limit }) { try { const cards await client.listCards(spaceId, limit); return { content: [{ type: text, text: JSON.stringify(cards, null, 2) }], }; } catch (err) { return { content: [{ type: text, text: get_cards 调用失败: ${(err as Error).message} }], isError: true, }; } } ); server.tool( search_cards, 在 Cosmos 收藏库中搜索卡片关键词可以是设计术语、品牌名、颜色、页面类型等, { query: z.string().describe(搜索关键词), }, async ({ query }) { try { const cards await client.searchCards(query); return { content: [{ type: text, text: JSON.stringify(cards, null, 2) }], }; } catch (err) { return { content: [{ type: text, text: search_cards 调用失败: ${(err as Error).message} }], isError: true, }; } } ); const transport new StdioServerTransport(); await server.connect(transport); console.error(Cosmos MCP Server 已启动);这段代码有几点值得说明工具的description是给 AI 看的必须写清楚“什么时候该用这个工具”不要只写“查询卡片”三个字。每个 handler 都做了错误捕获并把错误转成isError: true的响应。否则 AI 收到一个异常崩溃整个会话都会受影响。工具返回值统一使用content: [{ type: text, text: JSON.stringify(...) }]这是 MCP 的标准文本返回格式。5.5 增加调试脚本在package.json中增加{ scripts: { dev: tsx src/index.ts, build: tsc, start: node dist/index.js } }启动调试npm run dev如果没有报错并输出Cosmos MCP Server 已启动说明 Server 已经在标准输入输出上等待 MCP 客户端连接。此时用一个普通终端运行会一直挂起这是正常现象因为它在等 MCP 客户端通过 stdio 发消息。5.6 接入 MCP 客户端以 Claude Desktop 为例在客户端配置文件中增加一条 MCP Server{ mcpServers: { cosmos: { command: npx, args: [tsx, /absolute/path/to/cosmos-mcp/src/index.ts], env: { COSMOS_API_TOKEN: your_cosmos_api_token_here } } } }如果是 Windows 且npx路径有问题可以改用{ mcpServers: { cosmos: { command: cmd, args: [/c, npx, tsx, D:\\path\\to\\cosmos-mcp\\src\\index.ts], env: { COSMOS_API_TOKEN: your_cosmos_api_token_here } } } }注意配置文件里的路径必须是绝对路径不能使用~或相对路径。配置完成后需要完全重启客户端MCP 工具列表才会重新加载。6. 运行结果与效果验证6.1 用 MCP Inspector 验证不直接打开 AI 客户端先用官方的 MCP Inspector 验证 Server 是否正常npx modelcontextprotocol/inspector tsx src/index.ts启动后页面会显示 MCP Server 暴露的工具列表。点击list_spaces应该能看到 Cosmos API 返回的空间数据如果list_spaces报错就不用继续测后面的工具了。预期结果有两种成功返回一个 JSON 数组包含空间 ID 和名称。失败返回isError: true并且在 text 里能看到具体的 HTTP 状态码。6.2 在 AI 客户端中验证在 Claude Desktop 中重启后可以问这样一句话列出我的 Cosmos 空间然后读取第一个空间里的前 5 张卡片告诉我它们大致是什么主题。正常情况下AI 会先调用list_spaces获取空间再调用get_cards读取卡片最后根据返回的标题和 URL 做总结。观察这个过程能判断两件事工具是否被 AI 正确理解和使用。API 返回的数据是否足够让 AI 回答问题。6.3 如何判断成功一个非官方 MCP 是否算成功不只看“工具被调用了”还要看模型能否把多个工具串起来完成任务。比如“先找空间再查卡片再搜索某个关键词”是一个多步链路。如果链路能走通说明工具描述和参数 schema 设计是合格的。6.4 失败时先看哪看 MCP Server 的 stderr 输出是否有报错。看 AI 客户端日志是工具没被发现还是调用时报错。看 Cosmos API 的返回状态401 是 token 问题404 是接口路径问题。7. 常见问题与排查思路问题现象可能原因排查方式解决方案启动后没有任何输出MCP Server 被普通终端启动而不是 MCP 客户端确认是否通过客户端配置启动使用 MCP Inspector 测试或接入客户端配置连接时报错Missing COSMOS_API_TOKEN环境变量未配置或文件名不是.env检查项目根目录是否有.env确认变量名拼写在客户端配置里显式传入env或直接设置系统环境变量调用工具返回 401API Token 无效或权限不足查看返回 message 中的状态码到 Cosmos 后台重新生成 Token调用工具返回 404API Base URL 或路径与真实接口不符打印完整请求地址对照官方文档修改COSMOS_API_BASE或 API 路径AI 不知道什么时候使用工具工具描述写得太泛阅读工具描述检查是否有明确场景词重写 description例如“当用户提到灵感库或收藏时使用”AI 传入参数格式错误参数 schema 描述不清晰查看客户端请求中的参数在 z.string().describe() 中补充示例值返回数据太大导致上下文过长一次返回卡片过多卡片内容太长观察 AI 是否截断或忽略部分数据降低 limit 默认值或在返回前只保留关键字段Windows 下 npx 启动失败Path 配置或命令解析问题在命令行单独运行配置中的 command 测试改成cmd /c npx形式或使用 tsx 的绝对路径8. 最佳实践与工程化建议8.1 工具命名与描述要遵循“场景优先”不要用getData1、search2这类命名。工具名最好能直接反映业务语义比如list_spaces、get_cards、search_cards。描述里要包含触发场景例如“搜索词可以是品牌名、颜色、设计风格、页面类型”这种提示能显著提升 AI 的调用准确率。8.2 不要暴露多余数据和敏感字段非官方 MCP 在默认情况下会返回完整字段但没必要全部给 AI。比如卡片里如果包含收藏人 ID、内部备注、创建时间等AI 往往用不上反而浪费上下文。更稳妥的做法是在 API 客户端层做字段裁剪只保留 title、url、spaceId、note 等关键字段。对于团队级数据还要考虑权限边界只给 AI 暴露它确实需要读取的部分避免把整个团队知识库无差别交给模型。8.3 加缓存与限流避免打爆 APIAI Agent 的调用习惯和人类不同它可能会在短时间内连续调用同一个工具多次。如果你们的 Cosmos 账号有 API 配额限制建议在 MCP Server 内做两层保护对空间列表这类低频数据做 30 秒到 1 分钟的内存缓存。对搜索接口做简单的并发队列或最小调用间隔。8.4 日志要区分“协议日志”和“业务日志”MCP Server 的 stdout 是协议通道不能乱打印日志否则会破坏 JSON-RPC 通信。调试日志应该输出到 stderr 或文件。这也是为什么上面的示例里console.error是安全的而console.log要谨慎使用。8.5 版本兼容与升级策略非官方项目最容易受 API 变动影响。建议把 Cosmos API 调用集中在cosmosApi.ts一个文件。任何字段解析都做兜底data.spaces ?? []。每次升级依赖前先跑一遍 MCP Inspector 的工具调用测试。8.6 合规与安全提醒调用第三方 API 时务必遵守 Cosmos.so 的服务条款和 API 使用政策。不要在公开仓库里提交 Token不要抓取超出自己权限的数据如果用于公司内部先确认是否允许通过非官方方式访问。对于不能确定的行为保持保守宁可只读不要盲目写入。9. 总结与后续学习方向通过上面的实现你应该已经得到了一个完整可运行的 Unofficial Cosmos.so MCP Server。它虽然只是社区方案但已经打通了“设计灵感库”和“AI 助手”之间最关键的链路。现在再让 AI 从收藏中提取配色、总结竞品首页、对比不同灵感类型已经不需要人工复制粘贴了。下一步可以从几个方向继续深入增加写入能力如果 Cosmos API 支持创建卡片可以新增create_card工具让 AI 直接往指定空间收藏内容。部署为远程 MCP Server把 stdio 传输换成 Streamable HTTP团队里多人共用同一个 Server。接入更多客户端在 Dify、Cline、Cursor 中测试观察不同宿主下的工具调用表现差异。扩展数据源用同样的模式去接 Figma、Notion、蓝湖把你团队的工具站全部变成 AI 的可读数据源。最后提醒一点非官方工具的价值是“快速验证”而不是“长期依赖”。如果你验证出 AI 与 Cosmos 的结合确实能提升团队效率就值得推动官方支持或内部维护一个稳定版本把它正式纳入工具链。MCP 的门槛不高真正稀缺的是对业务场景的理解这一步想清楚案例验证就只要按本文的路径走一遍即可。
返回列表