从零实现 Cosmos.so MCP 服务器:让 AI Agent 轻松检索你的收藏与灵感 要把 Cosmos.so 里收藏的书签、图片和灵感片段直接交给 AI Agent 检索常规做法是在中间搭一个基于 Model Context ProtocolMCP的桥接服务。Unofficial Cosmos.so MCP 正是这样一类社区项目它把 Cosmos.so 的空间列表、保存条目和内容检索能力封装成 MCP 工具接入 Claude Desktop、Cline、Dify、Trae 等支持 MCP 的客户端后AI 就能按照对话指令完成“读取指定空间里的保存”“搜索和某个灵感相关的收藏”“向某个空间追加一条新收藏”这类操作而不必把数据库或 CSV 导出文件来回搬运。MCP 要解决的问题其实是 AI 应用与外部数据源之间的“接口爆炸”。如果没有统一协议每接入一个知识库就要写一套私有插件。MCP 通过 JSON-RPC 2.0 定义了一套标准的客户端-服务器通信方式服务器把数据处理能力声明为 tools客户端按名称和入参调用。站在使用者角度看配置一个 MCP 服务器和配置一个本地命令行工具很相似指定命令、参数和环境变量客户端以 stdio 子进程方式启动并维护通信。下面以 Unofficial Cosmos.so MCP 的集成思路为例从零搭建一个可运行的最小实现。先梳理协议和产品边界再准备环境然后编写服务端、接入客户端、验证结果最后整理排查路径和生产实践。代码使用 TypeScript依赖modelcontextprotocol/sdk不依赖特定云厂商。1. 理解 Unofficial Cosmos.so MCP 的定位1.1 MCP 是什么解决什么问题MCP 全称 Model Context Protocol中文常写作“模型上下文协议”。它是一个基于 JSON-RPC 2.0 的开放协议用于在 AI 客户端和外部工具服务器之间传输能力描述与调用结果。和 REST API 不同MCP 更关注“能力发现”客户端启动后会读取服务器提供的工具列表、参数模式和说明再按需调用。因此接入一个新数据源时不需要修改客户端主程序只需要新增一个 MCP 服务器配置。这个设计在 AI 编程、知识库检索、自动化办公场景中非常实用。比如模型需要查询用户收藏的网页传统做法是让模型通过代码执行环境请求某个 REST API并且要手工告诉模型 URL、鉴权方式、返回结构。使用 MCP 后模型通过读取工具描述就能知道“有一个 list_spaces 工具不需要额外参数”“有一个 search_saves 工具需要传入 spaceId 和 keyword”调用结果以结构化文本返回给模型继续理解。整个链路更规范也更容易测试。需要注意MCP 不是用来取代 REST API 的。它更多是“适配层”把已经存在的服务能力翻译成 AI 客户端能发现、能调用、能理解的结构。Unofficial Cosmos.so MCP 做的事情就是把 Cosmos.so 的数据能力翻译成 MCP 工具。1.2 Cosmos.so 为什么适合作为 AI 数据源Cosmos.so 是一个面向个人的视觉收藏与管理工具适合保存书签、灵感图片、设计参考和碎片笔记。它的核心数据结构可以粗略抽象成“空间 Space — 集合 Collection — 保存条目 Save”。用户在网页端或浏览器插件中收藏内容后后续需要反复检索。这类内容多、标签不统一、关键词不唯一的个人知识库恰恰是 AI 检索最常用的场景人工按文件夹找很慢让模型按关键词或语义过滤反而更高效。要实现这种检索普通做法是把个人知识库导出成 JSON 或 Markdown再交给 AI 客户端。但导出一来不及时二来无法反向写入。Unofficial Cosmos.so MCP 的设计目标是让 AI 客户端实时读取 Cosmos.so 数据并根据对话意图发起检索或新增操作。也就是说它不只是“把数据灌给模型”而是“让模型能按需访问数据服务”。1.3 官方与非官方集成之间怎么选很多热门工具会优先推出自己的官方 MCP 服务。如果你使用的产品已经有官方 MCP应当优先使用因为这意味着更稳定的鉴权、错误码和服务托管。非官方项目通常来自社区贡献大致有几种来源对官方公开 API 的二次封装对网页端私有接口的模拟调用对本地导出文件或数据库的直接读取官方未提供 API 时用浏览器自动化抓取页面的折中方案。“Unofficial”不一定代表质量差但使用前要确认三件事鉴权方式是否安全、接口是否可能随时变化、服务条款是否允许脚本访问。如果项目只依赖浏览器 Cookie建议只在个人电脑调试时使用不要部署到团队共享服务器。维度官方 MCP / 官方 API社区非官方集成稳定性接口有版本保障字段可能随前端改版变化鉴权通常提供短期 token可能依赖 Cookie 或私有 token使用责任官方承担可用性维护使用者自行关注条款与安全迭代速度跟随官方计划社区可快速适配新功能适配成本只需要按文档接入需要自行抓接口、维护映射2. 搭建前的环境准备2.1 需要准备的工具链要用 TypeScript 实现一个 MCP 服务器准备一台能运行 Node.js 的电脑即可。具体工具和用途如下表工具建议版本作用Node.js18 或 20 LTS运行 TypeScript 编译产物npm随 Node.js 自带安装依赖与执行脚本TypeScript5.x提供类型检查tsx最新稳定版开发时直接运行 TS 文件MCP 客户端Claude Desktop / Cline / Dify / Trae 任一验证服务能否被识别和调用安装 Node.js 后先在终端确认版本node -v npm -v如果两条命令都能正常输出版本号环境就满足要求。客户端选一个就好不需要全部安装。不同客户端的配置入口可能不同但核心都是修改一个 JSON 配置声明mcpServers列表。2.2 项目结构规划建议按单包结构组织项目避免一开始就拆 monorepo。下面这个结构足够支撑最小实现cosmos-mcp/ ├─ src/ │ ├─ server.ts # MCP 服务器入口注册工具 │ ├─ client.ts # Cosmos.so 数据接口的 HTTP 封装 │ └─ local-store.ts # 本地 JSON 模式离线演示用 ├─ data/ │ └─ saves.json # 本地模拟数据 ├─ package.json ├─ tsconfig.json └─ .env.exampleserver.ts只负责 MCP 协议相关的逻辑client.ts封装请求包括鉴权、错误处理、响应解析local-store.ts在拿不到真实接口时先跑通链路。这样分层之后后面切换数据源不用改协议层代码。2.3 凭证和接口地址怎么处理MCP 服务器运行在客户端子进程里配置文件中可以直接写环境变量。不推荐在代码里硬编码 token原因有三个token 会在 git 历史中残留不同机器调试时难以替换MCP 配置需要分享给团队时容易泄露。建议在.env.example里声明变量名再在mcpServers的env字段中注入COSMOS_BASE_URLhttps://api.example.com/v1 COSMOS_API_TOKENyour_short_lived_token COSMOS_DATA_MODElocal这里COSMOS_BASE_URL是占位值。如果项目使用的是官方公开 API以官方文档为准如果项目基于网络抓包得到的私有接口要先把接口路径、请求头和响应结构观察清楚再填入client.ts。注意不要在生产日志中输出完整 Cookie 或私有 token。调试信息里出现 Authorization 头时应先打码再截图。3. 实现最小可运行的 MCP 服务器3.1 初始化项目并安装依赖创建目录后执行mkdir cosmos-mcp cd cosmos-mcp npm init -y npm install modelcontextprotocol/sdk zod npm install -D typescript types/node tsxMCP SDK 提供McpServer类和 stdio 传输实现zod用来声明工具入参 schema。安装完成后在package.json中确认或补充type: module否则 NodeNext 模式下的 ES Module 语法会报错{ name: cosmos-mcp, type: module, scripts: { dev: tsx src/server.ts, build: tsc, start: node dist/server.js } }再写tsconfig.json{ compilerOptions: { target: ES2022, module: NodeNext, moduleResolution: NodeNext, outDir: dist, rootDir: src, strict: true, esModuleInterop: true, skipLibCheck: true }, include: [src/**/*] }这里的关键是module和moduleResolution都使用NodeNext然后 import 本地文件时必须带.js后缀。很多新手第一次跑 MCP 示例失败都是因为没有加后缀导致 TS 编译后找不到模块。3.2 编写 HTTP 客户端封装client.ts的作用是把 Cosmos.so 数据服务封装成几个返回 Promise 的函数。这样 MCP 工具层只关注参数和返回文本不关心请求细节。export interface Space { id: string; name: string; } export interface SaveItem { id: string; title: string; url?: string; notes?: string; } const BASE_URL process.env.COSMOS_BASE_URL || ; const TOKEN process.env.COSMOS_API_TOKEN || ; async function requestT(path: string, init: RequestInit {}): PromiseT { const res await fetch(${BASE_URL}${path}, { ...init, headers: { Content-Type: application/json, ...(TOKEN ? { Authorization: Bearer ${TOKEN} } : {}), ...(init.headers || {}), }, }); if (!res.ok) { const text await res.text(); throw new Error(API ${res.status}: ${text.slice(0, 200)}); } const raw await res.text(); return raw ? (JSON.parse(raw) as T) : ({} as T); } export function listSpaces() { return request{ spaces: Space[] }(/spaces); } export function searchSaves(spaceId: string, keyword: string) { return request{ saves: SaveItem[] }(/spaces/${spaceId}/saves?q${encodeURIComponent(keyword)}); } export function createSave(input: { spaceId: string; title: string; url?: string; notes?: string; }) { const { spaceId, ...body } input; return request{ save: SaveItem }(/spaces/${spaceId}/saves, { method: POST, body: JSON.stringify(body), }); }这个代码块中的接口路径是示例。真实项目中你可能要改为/v2/spaces、GraphQL 批量查询或其他路径。关键是保持request返回 JSON由工具层决定如何把结果转成文本。3.3 注册工具并启动服务器server.ts是核心文件。McpServer注册工具时工具名建议使用小写字母和下划线组合描述要写清楚用途因为模型会根据描述决定何时调用。下面示例注册三个工具list_spaces、search_saves、create_save。import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; import { listSpaces, searchSaves, createSave } from ./client.js; const server new McpServer({ name: cosmos-mcp, version: 0.1.0, }); server.registerTool( list_spaces, { description: 列出当前 Cosmos.so 账号下的所有空间 }, async () { const data await listSpaces(); return { content: [{ type: text, text: JSON.stringify(data, null, 2) }], }; } ); server.registerTool( search_saves, { description: 在指定空间内搜索保存条目支持关键词过滤, inputSchema: { spaceId: z.string().describe(空间 ID), keyword: z.string().optional().describe(搜索关键词), }, }, async ({ spaceId, keyword }) { const data await searchSaves(spaceId, keyword || ); return { content: [{ type: text, text: JSON.stringify(data, null, 2) }], }; } ); server.registerTool( create_save, { description: 向指定空间新增一条保存条目, inputSchema: { spaceId: z.string().describe(目标空间 ID), title: z.string().describe(条目标题), url: z.string().optional().describe(网页链接), notes: z.string().optional().describe(备注), }, }, async ({ spaceId, title, url, notes }) { const data await createSave({ spaceId, title, url, notes }); return { content: [{ type: text, text: JSON.stringify(data, null, 2) }], }; } ); const transport new StdioServerTransport(); await server.connect(transport);这里有两个关键点。第一MCP 工具返回值必须包含content数组数组元素是 MCP 协议定义的内容块常用的是type为text的对象。第二每个工具的inputSchema使用zod声明MCP SDK 会在客户端调用时自动校验参数不需要在函数里再手写校验。如果传入参数类型不对客户端会收到校验错误而不是业务错误。3.4 没有真实接口时先用本地 JSON 跑通社区项目如果还没确定接口版本可以先写一个本地数据源验证 MCP 链路。新建data/saves.json{ spaces: [ { id: space-1, name: 设计灵感 }, { id: space-2, name: 工程资料 } ], saves: [ { id: save-1, spaceId: space-1, title: Design System 配色参考, url: https://example.com/design-system }, { id: save-2, spaceId: space-2, title: Rust 异步编程笔记, url: https://example.com/rust-async } ] }然后在local-store.ts中读取import { readFileSync } from node:fs; export interface SaveItem { id: string; title: string; url?: string; notes?: string; } export function loadLocalData() { const raw readFileSync(new URL(../data/saves.json, import.meta.url), utf-8); return JSON.parse(raw) as { spaces: Array{ id: string; name: string }; saves: SaveItem[]; }; }接着在client.ts顶部加一个模式判断const isLocal process.env.COSMOS_DATA_MODE local;listSpaces、searchSaves、createSave内部先判断isLocal本地模式直接返回模拟数据网络模式才发起真实请求。这样在 MCP 客户端配置里把COSMOS_DATA_MODE设为local就能在离线环境验证“客户端能识别工具、能传参、能返回结果”。去掉该变量后恢复网络模式。4. 将 MCP 服务器接入客户端4.1 标准配置结构大多数支持 MCP 的客户端都使用同一套mcpServers配置格式{ mcpServers: { cosmos-mcp: { command: npx, args: [tsx, src/server.ts], env: { COSMOS_DATA_MODE: local, COSMOS_BASE_URL: https://api.example.com/v1, COSMOS_API_TOKEN: your_token_here } } } }如果是在 Claude Desktop 中配置通常把这段内容合并到claude_desktop_config.json的mcpServers里如果是在 Cline、Roo Code 这类 VSCode 插件中则在 MCP 设置面板添加服务器如果是在 Dify 或 Trae 中同样有对应 MCP 服务入口。协议层面它们是一致的差别只是配置位置和是否支持远程地址。4.2 Windows 系统上怎么创建 MCPWindows 上最常见的坑是环境变量 PATH 不一致。客户端从图形界面启动时可能读不到你在终端里配置的 npm 全局路径导致command为npx时提示“无法识别”。一种稳定做法是把command改为cmd通过/c执行命令{ mcpServers: { cosmos-mcp: { command: cmd, args: [/c, npx, tsx, C:\\Users\\you\\cosmos-mcp\\src\\server.ts], env: { COSMOS_DATA_MODE: local } } } }如果项目路径包含空格建议把整个路径放在双引号里。Windows 的 JSON 文件反斜杠需要转义写C:\\Users\\you\\...。4.3 验证配置是否生效配置完成后重启 MCP 客户端并在 MCP 面板中查看服务器状态。正常情况下应显示已连接并列出list_spaces、search_saves、create_save三个工具。如果显示错误优先看客户端日志其中通常包含 stderr 输出。直接在聊天框测试也可以。输入“看看我有哪些空间”若能返回本地 JSON 中的空间列表说明配置正确。注意如果修改了服务端代码需要重启客户端或重新加载 MCP 服务器。大多数客户端不会热加载外部 MCP 进程。5. 运行验证与调试5.1 命令行验证服务能否启动在不启动客户端的情况下可以直接验证 stdio 服务器是否能正常响应echo {jsonrpc:2.0,id:1,method:tools/list,params:{}} | npx tsx src/server.ts如果服务器正常输出会包含 JSON-RPC 响应里面带有tools数组。不过由于 SDK 运行时可能会先输出日志实际输出可能带额外内容因此这条命令主要用于快速确认进程不会立即崩溃。更可靠的验证是打开 MCP 客户端查看工具列表。5.2 对话式验证按前面配置发起对话观察三种情况“列出 cosmos 里的空间。”预期返回空间名称列表。“在空间 space-1 中搜索包含 设计 的保存。”预期返回 JSON 数组。“往空间 space-1 新增一个保存标题为 React 官方文档链接为 https://react.dev 。”如果使用本地模式数据不会真正落盘只返回模拟结果网络模式下才会写入真实账户。本地 JSON 模式下create_save返回的是模拟成功不会修改data/saves.json。这是为了避免开发时误操作真实账号。如果要验证写入再启动网络模式并使用测试空间。5.3 返回结果裁剪减少 token 消耗如果工具返回了完整数据但模型仍然理解不了常见原因是返回 JSON 太大或字段结构不直观。建议在工具内部做一次精简只返回关键字段const summary data.saves.map((s) ({ id: s.id, title: s.title, url: s.url || , })); return { content: [{ type: text, text: JSON.stringify(summary, null, 2) }], };这样做能减少 token 消耗也让模型更容易识别关键信息。返回 JSON 并不是必须的也可以返回 Markdown 列表只要文本里信息完整即可。5.4 通过日志观察工具调用MCP 服务器通常以 stdio 子进程方式运行调试时可以把工具调用信息写到 stderr。在自定义工具函数内部加一行console.error([cosmos-mcp] search_saves called, spaceId${spaceId}, keyword${keyword});注意必须使用console.error不要用console.log。因为 stdout 是 MCP 协议通道普通文本输出会污染 JSON-RPC 消息导致客户端解析失败。6. 常见问题排查6.1 排查顺序按照“配置 - 进程 - 参数 - 网络 - 日志”的顺序排查比直接改代码更高效。步骤检查点命令或位置1客户端配置路径是否正确mcpServers中command和args2服务能否单独启动直接运行npx tsx src/server.ts3依赖是否安装完整检查node_modules和package-lock.json4环境变量是否注入客户端配置文件里的env字段5网络和鉴权接口返回 401 / 403 / 4296SDK 版本是否匹配查看package.json中modelcontextprotocol/sdk版本6.2 三个高频错误错误一服务器显示 error客户端日志提示找不到 npx 或找不到源文件。原因通常是 PATH 不完整或源码路径写错。解决方式是先确认npx可执行再把command改为npx的绝对路径args也使用绝对路径。Windows 下优先使用cmd /c方案。错误二调用工具后返回 401。现象是模型能列出工具但真正执行时报 HTTP 401。原因可能是环境变量没有生效或 token 已过期。检查客户端配置文件里env字段是否完整不要依赖 shell 里的export。私有接口还要检查请求头名称某些私有接口要求 Cookie 而不是 Authorization。错误三客户端提示 content 不符合协议格式。原因通常是返回对象里content缺失或数组元素结构不对。

相关新闻

最新新闻

Python实数模拟器:从数学概念到可视化教学工具的实现

Python实数模拟器:从数学概念到可视化教学工具的实现

1. 项目概述:为什么我们需要一个“实数模拟器”?在数学教学或者编程初学者的世界里,“实数”这个概念既基础又抽象。我们经常在课本上看到它,知道它包含了有理数和无理数,知道它和数轴上的点一一对应。但当你真正想用代…

2026/8/28 2:59:30
从蓝桥杯国赛到实战:基于51单片机的门禁系统设计与状态机编程

从蓝桥杯国赛到实战:基于51单片机的门禁系统设计与状态机编程

1. 项目概述:从“国赛真题”到“实战系统”的跨越看到“蓝桥杯单片机第三届国赛门禁系统”这个标题,很多参加过蓝桥杯的朋友估计会心一笑,脑子里立刻浮现出那块熟悉的CT107D开发板,还有那些让人又爱又恨的LED、数码管和矩阵键盘。…

2026/8/28 2:59:30
Matlab实战入门:从环境部署到核心函数精讲与项目应用

Matlab实战入门:从环境部署到核心函数精讲与项目应用

1. 从“安装”到“跑通”:一个工程师的Matlab入门心路如果你刚拿到Matlab的安装包,或者正准备开始学习,大概率会和我当初一样,面对一堆教程和选项感到无从下手。Matlab远不止是一个“高级计算器”,它是一个庞大的工程生…

2026/8/28 2:59:30
开源大模型将迎收费时代?开发者如何应对“大用户”商业授权风险

开源大模型将迎收费时代?开发者如何应对“大用户”商业授权风险

如果有一天,你所在团队辛苦调优并接入生产环境的开源大模型,到了下一个版本突然宣布“大用户要收费”,你会怎么办?这已经不是假设。最近行业里流传着一条消息:阿里巴巴计划对其下一代开源 AI 模型的大规模商业用户收费…

2026/8/28 2:59:30
自托管Uptime监控工具Overcheck:部署、API与多用户权限实践

自托管Uptime监控工具Overcheck:部署、API与多用户权限实践

在实际的运维和开发工作中,网站是否可用、接口是否超时、证书是否即将过期,往往不是靠用户反馈才知道的,而是靠主动探测提前发现的。Overcheck正是一个面向这一类需求的自托管 uptime monitoring 工具,它把“定时探测、状态展示、…

2026/8/28 2:59:30
AI Agent在物流行业落地:从数据治理到人工兜底的工程化路径

AI Agent在物流行业落地:从数据治理到人工兜底的工程化路径

如果要在物流行业落地 AI Agent,我最常见到的开场是这样的:一个物流公司的 IT 负责人,在内部技术分享里看到了一个智能体 Demo——它能在对话框里帮你查订单、推荐车辆、汇总异常。他当场觉得“这个能省掉调度员一半的重复劳动”,…

2026/8/28 2:54:30