一个很常见的画面:设计团队用 Cosmos.so 收藏了上千张灵感图、竞品截图和品牌规范,但当你打开 AI 编程助手,让它“从最近收藏的竞品首页灵感里提取配色方案”时,它只能干瞪眼。收藏得越多,AI 越读不到,最后所有资料被迫靠人工搬运。这个问题的本质不是模型能力不够,而是 AI 缺少一条读取 Cosmos.so 数据的标准通道。MCP(Model 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/sdk:MCP 官方 SDK。zod:用于声明工具参数的类型 schema,MCP 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_TOKEN=your_cosmos_api_token_here COSMOS_API_BASE=https://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 request<T>(path: string): Promise<T> { 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 Promise<T>; } async listSpaces(): Promise<CosmosSpace[]> { const data = await this.request<{ spaces: CosmosSpace[] }>("/spaces"); return data.spaces ?? []; } async listCards(spaceId?: string, limit = 20): Promise<CosmosCard[]> { 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): Promise<CosmosCard[]> { 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,或直接设置系统环境变量 |
| 调用工具返回 401 | API Token 无效或权限不足 | 查看返回 message 中的状态码 | 到 Cosmos 后台重新生成 Token |
| 调用工具返回 404 | API 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 加缓存与限流,避免打爆 API
AI 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 的门槛不高,真正稀缺的是对业务场景的理解,这一步想清楚案例验证就只要按本文的路径走一遍即可。