☰
Pollinations MCP Server 开发指南:薄代理设计、无状态 HTTP 与工具扩展实战
2026/10/14 20:47:03 网站建设 项目流程
  • AI 应用
  • 媒体生成
  • 后端
  • 前端

【免费下载链接】pollinations

Your Friendly Open-Source Gen-AI Platform

项目地址:https://gitcode.com/gh_mirrors/po/pollinations
点击查看免费下载

Pollinations 是一个开源多模型生成式 AI 平台(Your Friendly Open-Source Gen-AI Platform),其官方 MCP(Model Context Protocol)服务器将 Pollinations 的文本、图像、视频、音频、3D 与账户能力封装为一组 Agent 工具,供 Claude Desktop、Cursor 等宿主通过 Streamable HTTP 调用。本文以仓库内 Agent Guidelines for MCP Server Development 为核心骨架,结合 packages/mcp 的源码实现、测试用例 与 部署 Worker,系统讲解该服务器的五大设计原则、代码结构、无状态 HTTP 纪律、工具注册流程、模型校验模式与测试方法。读完本文,你将掌握如何在既有架构约束下安全地为 Pollinations MCP Server 新增一个工具,并理解其"薄代理 + 实时注册表校验 + 请求级鉴权"的实现原理。

一、设计原则:为什么 MCP Server 要做得"薄"

AGENTS.md开篇给出了五条设计原则,它们是整个代码库的灵魂,也是审查任何新增代码时的第一检查项。

1. 薄代理(Thin Proxy)

API 调用全部经由gen.pollinations.ai网关转发,生成的媒体复用 API 已返回的公开 URL作为 MCP resource link,不做下载再上传。媒体 URL 有两个来源:

  • 图像 API 的 JSON 响应(data[0].url字段);
  • 二进制响应(视频、音频、3D)的Link响应头(rel="enclosure")。

对应的实现位于 coreUtils.js 的 fetchMediaLink:请求发出后读取响应头Link中^<([^>]+)>; rel="enclosure"$捕获组,得到公开文件 URL,随即response.body?.cancel()释放连接,绝不把二进制数据拉进内存:

const mediaUrl = response.headers .get("Link") ?.match(/^<([^>]+)>; rel="enclosure"$/)?.[1]; await response.body?.cancel(); if (!mediaUrl) throw new Error("Media generation returned no public file URL");

同时,服务端禁止直接调用其他服务主机,必须走网关的 rewrite 路由:/account/*、/image/*、/text/*、/audio/*、/v1/*。这一约束在 coreUtils.js 的 buildUrl 中落地:所有请求都基于单一API_BASE_URL(默认https://gen.pollinations.ai,可由环境变量POLLINATIONS_BASE_URL覆盖)拼接路径,天然杜绝了向任意第三方主机发请求的写法。

2. 无硬编码模型/音色枚举

MCP Server不内置任何模型名或音色名的枚举,而是通过 utils/models.js 实时拉取注册表校验。工具参数 schema 一律写成z.string(),并在描述中提示"使用listModels获取实时列表"。原因很直接:Pollinations 是活的多模型网关,模型随时可能上下架、新增别名,硬编码会让工具在模型变更后立刻失准。

3. 不转换响应数据

API 响应原样透传,仅在需要 MCP content block 时才做重塑(例如把生成的媒体 URL 包装成 resource link)。这条原则保证了 MCP 返回内容与网关真实数据一致,避免二次加工引入偏差。

4. 最小工具面(Minimal Tool Surface)

每个工具都会成为 LLM 推理的额外上下文,也是"选错工具"的一个机会。因此只在宿主(Claude Desktop、Cursor 等)内真正有用的工具才会被加入。当前 server 注册了 17 个工具(见下文工具全览),每个都对应一个明确的 API 能力域。

5. 无状态 HTTP(Stateless HTTP Only)

Bearer token 从请求上下文读取,不引入进程内状态、认证工具、会话或 stdio 入口。这是整个服务可部署为 Cloudflare Worker、可水平扩展的前提。

二、代码结构:按服务域组织的模块化布局

AGENTS.md给出了标准目录结构,仓库实际布局与之一致:

packages/mcp/ src/ server.js # server factory、工具注册、SERVER_INSTRUCTIONS services/ imageService.js # generateImage, generateVideo textService.js # generateText audioService.js # generateAudio, transcribeAudio embeddingService.js # createEmbeddings model3dService.js # generate3D discoveryService.js # listModels, getModelStatus accountService.js # getBalance, getUsage, getEarnings, listQuests, listKeys, createKey, revokeKey(走 /account/*) utils/ authUtils.js # 请求级 bearer 鉴权 coreUtils.js # fetch 封装、URL 构建、错误映射 models.js # 注册表拉取 + 校验器 test/ accountService.test.js audioService.test.js coreUtils.test.js discoveryService.test.js textService.test.js AGENTS.md README.md package.json

各文件职责要点:

  • server.js:导出createMcpHandler与buildServer()。buildServer创建McpServer实例,声明SERVER_VERSION(当前为 2.5.1,见 package.json),把来自 7 个 service 的工具数组全部 spread 进tools,再通过server.registerTool(name, { description, inputSchema: z.object(inputSchema) }, handler)逐个注册(server.js L70-L77)。SERVER_INSTRUCTIONS作为注入给 LLM 的系统级指令,包含鉴权方式、模型发现与生成约定、账户权限要求、API Endpoint 四部分,其中 Endpoint 由validateApiBaseUrl()动态生成。
  • utils/:authUtils.js负责从context.http.authInfo.token解析密钥并拼装Authorization: Bearer ...头;coreUtils.js提供buildUrl、fetchWithAuth、fetchJsonWithAuth、fetchMediaLink、createMCPResponse、createTextContent、parseApiError;models.js提供按模态分组的注册表获取与校验函数。
  • apps/mcp/worker.js:托管在 Cloudflare 的 Streamable HTTP Worker,导入packages/mcp/src/server.js的工厂,负责 bearer token 解析、健康检查、批量请求拒绝等 HTTP 边界职责。

三、无状态 HTTP 纪律:凭据只属于一个请求

AGENTS.md强调:"The public server uses Streamable HTTP without MCP sessions. Credentials belong to one request and must never be stored in module state."

这在两层代码中体现为硬约束:

第一层:工具层。authUtils.js 每次调用都从请求上下文取密钥:

function resolveApiKey(context) { return context?.http?.authInfo?.token || null; }

requireApiKey(context)在无密钥时抛出提示信息,getAuthHeaders(context)在存在密钥时才附加Authorization头。密钥从不写入模块级变量、不缓存、不进会话。

第二层:HTTP 边界层。apps/mcp/worker.js 在fetch入口解析Authorization: Bearer <token>,未携带则直接返回 401(带WWW-Authenticate头);通过后将 token 作为authInfo.token传入 MCP handler:

return mcpHandler.fetch(request, { authInfo: { token, clientId: "pollinations-api-key", scopes: [], }, });

同时 Worker 使用legacy: "stateless"模式(worker.js L6-L9),并拒绝 JSON 数组形式的批量请求(返回 400invalid_request),进一步强化"一次请求一次鉴权"的纪律。/health端点返回stateless: true便于探活确认。

四、添加一个工具:五步标准流程

AGENTS.md给出新增工具的标准步骤,结合源码可将每一步落到具体位置:

  1. 在相关 service 文件中添加 handler(新域则新建 service 文件)。handler 签名统一为async (params, context) => { ... },内部先requireApiKey(context),再校验模型(如需要),最后通过fetchJsonWithAuth/fetchMediaLink调用网关并组装 MCP 响应。
  2. 在工具数组中导出[name, description, zodShape, handler]四元组。例如 imageService.js 的 imageTools:name是工具名,description是给 LLM 看的能力说明(含"先用 listModels"的提示语),zodShape是 zod schema 对象,handler是执行函数。
  3. 在 src/server.js 导入数组并 spread 进tools。工具顺序即注册顺序,buildServer会将其逐一注册。
  4. 在SERVER_INSTRUCTIONS中补一行说明(server.js L26-L54),确保注入给 LLM 的指引与工具面同步。
  5. 更新 README.md 的工具表格,记录工具名、用途与对应 API 路由,保持文档与实现一致。

服务端的工具四元组会被z.object(inputSchema)包装成 MCP 输入 schema;description会被 MCP 协议暴露给宿主 LLM,因此描述的质量直接影响 Agent 的工具选择准确率——这也是"最小工具面"原则的延伸:宁缺毋滥。

五、校验模式剖析:注册表实时校验 + 模糊建议

AGENTS.md给出了标准的校验写法:

import { validateImageModel } from "../utils/models.js"; const result = await validateImageModel(model); if (!result.valid) { throw new Error(`${result.error} Use listModels for the live registry.`); }

底层实现在 models.js 的 validateAgainstRegistry,流程如下:

  1. 若模型名为空,直接返回{ valid: true }(未指定模型时走网关默认值);
  2. 拉取对应模态的实时注册表(/image/models、/text/models、/video/models、/audio/models、/embeddings/models、/3d/models,全部经 MODEL_PATHS 映射);
  3. 按m.name === modelName || m.aliases?.includes(modelName)匹配规范名或别名;
  4. 未命中时,对名称做双向子串匹配,最多给出 3 个建议名,并附带availableCount供错误提示使用。

各模态的校验入口validateImageModel、validateTextModel、validateVideoModel、validateEmbeddingModel、validateModel3d均由该函数参数化生成。实际错误信息比模板更友好,例如 imageService.js L16-L22:

throw new Error( `${validation.error} Did you mean: ${validation.suggestions.join(", ")}? ` + "Use listModels with type=image to see all available models.", );

这套机制保证:模型名拼写错误、模型下线、新增模型都能得到实时、可操作的反馈,而不会出现"模型不存在但工具仍按旧枚举放行"的过期行为。

六、工具全览:17 个工具的能力域与 API 路由

结合 README.md 工具表 与各 service 源码,当前工具面如下:

工具用途API 路由
generateText文本生成、搜索、多模态输入与工具调用/v1/chat/completions
generateImage生成或编辑图像/v1/images/generations
generateVideo生成视频/video/{prompt}
generateAudio生成语音、音乐或音效/audio/{text}
transcribeAudio转写公开 HTTPS 音频 URL/v1/audio/transcriptions
generate3D生成 GLB 3D 模型/3d/{prompt}
createEmbeddings创建文本或多模态嵌入/v1/embeddings
listModels搜索并列出实时模型、能力、音色与定价模型注册表路由
getModelStatus查看近期请求、错误与延迟/models/status
getBalance查询剩余 Pollen 余额(需account:usage)/account/balance
getUsage请求历史或按日汇总(需account:usage)/account/usage、/account/usage/daily
getEarningsBYOP 应用与社区模型的开发者收益(需account:usage)/account/earnings
listQuests任务奖励与领取状态(需account:usage)/account/quests
listKeys列出 API 密钥(需account:keys)/account/keys
createKey创建 secret 或 publishable 应用密钥(需account:keys)POST /account/keys
revokeKey按 id 吊销密钥(需account:keys)DELETE /account/keys/{id}

几个值得深入的点:

  • 生成类工具的典型返回:图像返回resource_link(uri为image.url,mimeType为image.media_type)+ 结构化文本元数据;视频/音频/3D 通过fetchMediaLink拿到content-type与公开 URL 后同样组装resource_link。媒体以链接形式返回,不占用模型上下文窗口,且"任何持有链接者都可访问,过期文件返回 404"(README 原话)。
  • generateText是能力最重的工具:textService.js 的 schema 覆盖 messages(6 种角色)、温度/采样参数(temperature0-2、top_p0-1、三类惩罚系数)、response_format(text/json_object/json_schema 结构化输出)、reasoning_effort、tools/tool_choice/parallel_tool_calls、modalities/audio语音输出、logprobs/logit_bias、legacy 的functions/function_call等;响应侧按assistantMessage拆分 content、reasoning_content、tool_calls、function_call、audio(含转录文本)与citations,最后附上model、finish_reason、usage元数据。
  • 账户类工具:权限由 API 端强制(读类需account:usage,密钥类需account:keys),错误信息原样透传(accountService.js L10-L11);createKey返回完整密钥仅此一次,工具描述明确要求"展示给用户且不得存储"(accountService.js L179)。getUsage支持daily=true切换汇总口径,days上限 90、limit默认 20(accountService.js L50-L60)。
  • listModels的过滤参数:type(all/text/image/video/audio/embedding/3d)、community(仅社区/仅官方模型)、agent(仅 Agent)、query(名称/别名/标题/描述/发布者全词匹配)、capabilities(如tool_calling、reasoning、web_search)、limit(上限 500),服务端在 Gen 侧过滤,客户端只传筛选条件(discoveryService.js L10-L16)。

七、错误映射与安全细节

coreUtils.js 的 parseApiError 把网关的 HTTP 错误翻译成对 LLM 友好的中文/英文提示:

  • 400:命中 "content moderation"/"safety"/"blocked" 时提示内容被安全过滤器拦截;命中 "invalid model" 时提示用listModels查看可用模型;
  • 401:提示发送有效 API 密钥(bearer token)及其获取入口;
  • 403:优先透传 API 返回的原始错误消息(如"密钥无权使用该模型"),无消息时才用兜底文案;
  • 404 / 429 / 5xx / 502-504:分别给出资源不存在、限流(并提示 publishablepk_密钥可升级 secretsk_密钥以提升限额)、服务器错误与临时不可用提示。

coreUtils.test.js 对该映射有针对性覆盖:403 场景分别验证了"网关权限错误消息原样保留(含编辑密钥链接)"、"非权限消息透传"、"staging 白名单限制消息透传"与"空 body 兜底文案"四种分支。

在音频转写上还有一层 SSRF 防护:audioService.js 的 publicAudioUrl 强制source为无凭据的公开 HTTPS URL,拒绝localhost、.localhost域名与 IP 地址;同时因 Workers 拒绝redirect: "error",采用redirect: "manual"并显式拒绝 3xx 重定向(audioService.js L45-L62),防止代理访问内网地址。

八、测试体系

AGENTS.md给出两级测试:

  • npm run test(在 packages/mcp 内执行):聚焦工具 handler 的单元测试。脚本定义于 package.json(node --test test/*.test.js),覆盖coreUtils、textService、audioService、discoveryService、accountService。运行环境要求 Node.js 20+(package.json engines)。
  • npm run test(在 apps/mcp 内执行):Streamable HTTP Worker 层的测试(worker.test.js),覆盖鉴权、路由、批量请求拒绝等 HTTP 边界行为。

新增工具时,应同时在对应 service 的测试文件中补充 handler 级用例,保证工具注册 schema、错误分支与响应组装都有可验证的依据。

九、连接与使用方式

Streamable HTTP 客户端可连接至网关暴露的端点(路径见 README 与SERVER_INSTRUCTIONS),每次请求携带 Pollinations API 密钥:

Authorization: Bearer YOUR_KEY

密钥的 Pollen 钱包、权限与预算即被用于该请求的计费与鉴权。所有模型、音色、能力与定价均来自实时注册表,因此在选定模型或音色前应先用listModels查询。生成的媒体以 MCP resource link 形式返回,无需下载与回传。

十、小结

packages/mcp/AGENTS.md用极简的篇幅定义了 Pollinations MCP Server 的全部架构约束,而这些约束在源码中均有一一对应的强制实现:

  • 薄代理→buildUrl单网关拼接 +fetchMediaLink复用公开 URL;
  • 无硬编码枚举→models.js注册表拉取与validateAgainstRegistry模糊建议;
  • 不转换响应→ 除 resource link 包装外原样透传;
  • 最小工具面→ 17 个工具全部有明确 API 路由对应;
  • 无状态 HTTP→authUtils.js请求级取 token +worker.js的legacy: "stateless"与批量请求拒绝。

这套设计让服务器既能在 Cloudflare Worker 上无状态水平扩展,又能保持对多模态模型生态的实时感知。对于希望为 Pollinations 贡献新工具(或在其上构建自定义 MCP 工具集)的开发者,按"四、添加一个工具"的五步流程操作,再以第八节的测试体系验证,即可安全合入。

延伸阅读:进一步了解工具能力说明与 API 路由对应关系可读 packages/mcp/README.md;模型校验与注册表映射可读 packages/mcp/src/utils/models.js;HTTP 边界实现可读 apps/mcp/worker.js 与 apps/mcp/worker.test.js。

  • AI 应用
  • 媒体生成
  • 后端
  • 前端

【免费下载链接】pollinations

Your Friendly Open-Source Gen-AI Platform

项目地址:https://gitcode.com/gh_mirrors/po/pollinations
点击查看免费下载
上一篇:如何快速优化Windows系统:3步完成智能清理与性能提升终极指南
下一篇:Windows Cleaner终极指南:简单三步告别C盘爆红,让电脑重获新生

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询