#
tokens: 7282/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitattributes
├── .gitignore
├── dist
│   ├── index.d.ts
│   └── index.js
├── icon.png
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── index.ts
│   └── text-audio-api.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------

```
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "esModuleInterop": true,
 7 |     "outDir": "./dist",
 8 |     "rootDir": "./src",
 9 |     "strict": true,
10 |     "declaration": true
11 |   },
12 |   "include": ["src/**/*"],
13 |   "exclude": ["node_modules", "dist"]
14 | }
15 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "pollinations-mcp",
 3 |   "version": "1.0.0",
 4 |   "main": "dist/index.js",
 5 |   "type": "module",
 6 |   "scripts": {
 7 |     "build": "tsc",
 8 |     "start": "node dist/index.js",
 9 |     "test": "echo \"Error: no test specified\" && exit 1"
10 |   },
11 |   "keywords": [
12 |     "mcp",
13 |     "pollinations",
14 |     "ai",
15 |     "image",
16 |     "generation"
17 |   ],
18 |   "author": "bendusy",
19 |   "license": "ISC",
20 |   "description": "使用MCP协议连接Pollinations.ai的图像生成服务",
21 |   "dependencies": {
22 |     "@modelcontextprotocol/sdk": "^1.6.1",
23 |     "axios": "^1.8.1"
24 |   },
25 |   "devDependencies": {
26 |     "@types/node": "^22.13.9",
27 |     "typescript": "^5.8.2"
28 |   },
29 |   "repository": {
30 |     "type": "git",
31 |     "url": "https://github.com/bendusy/pollinations-mcp.git"
32 |   },
33 |   "homepage": "https://github.com/bendusy/pollinations-mcp",
34 |   "bugs": {
35 |     "url": "https://github.com/bendusy/pollinations-mcp/issues"
36 |   },
37 |   "icon": "icon.png"
38 | }
39 | 
```

--------------------------------------------------------------------------------
/src/text-audio-api.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import axios from 'axios';
 2 | import * as fs from 'fs';
 3 | import * as path from 'path';
 4 | 
 5 | /**
 6 |  * Pollinations文本API实现
 7 |  */
 8 | export class PollinationsTextAudioAPI {
 9 |   private baseTextUrl = 'https://text.pollinations.ai';
10 | 
11 |   /**
12 |    * 生成文本 (GET方法)
13 |    * @param prompt 提示词
14 |    * @param options 选项
15 |    * @returns 生成的文本
16 |    */
17 |   async generateTextGet(prompt: string, options: {
18 |     model?: string;
19 |     seed?: number;
20 |     json?: boolean;
21 |     system?: string;
22 |     private?: boolean;
23 |   } = {}) {
24 |     const { model = 'openai', seed, json = false, system, private: isPrivate = false } = options;
25 |     
26 |     let url = `${this.baseTextUrl}/${encodeURIComponent(prompt)}?model=${model}`;
27 |     
28 |     if (seed !== undefined) {
29 |       url += `&seed=${seed}`;
30 |     }
31 |     
32 |     if (json) {
33 |       url += `&json=true`;
34 |     }
35 |     
36 |     if (system) {
37 |       url += `&system=${encodeURIComponent(system)}`;
38 |     }
39 |     
40 |     if (isPrivate) {
41 |       url += `&private=true`;
42 |     }
43 |     
44 |     try {
45 |       const response = await axios.get(url);
46 |       return response.data;
47 |     } catch (error) {
48 |       throw new Error(`文本生成失败: ${error instanceof Error ? error.message : String(error)}`);
49 |     }
50 |   }
51 | 
52 |   /**
53 |    * 生成文本 (POST方法)
54 |    * @param messages 消息数组
55 |    * @param options 选项
56 |    * @returns 生成的文本
57 |    */
58 |   async generateTextPost(messages: Array<{role: string, content: string | Array<{type: string, text?: string, image_url?: {url: string}}>}>, options: {
59 |     model?: string;
60 |     seed?: number;
61 |     jsonMode?: boolean;
62 |     private?: boolean;
63 |   } = {}) {
64 |     const { model = 'openai', seed, jsonMode = false, private: isPrivate = false } = options;
65 |     
66 |     try {
67 |       const response = await axios.post(`${this.baseTextUrl}/`, {
68 |         messages,
69 |         model,
70 |         seed,
71 |         jsonMode,
72 |         private: isPrivate
73 |       });
74 |       return response.data;
75 |     } catch (error) {
76 |       throw new Error(`文本生成失败: ${error instanceof Error ? error.message : String(error)}`);
77 |     }
78 |   }
79 | 
80 |   /**
81 |    * 获取可用模型列表
82 |    * @param type 模型类型 ('text')
83 |    * @returns 模型列表
84 |    */
85 |   async getAvailableModels(type: 'text' = 'text') {
86 |     try {
87 |       const url = `${this.baseTextUrl}/models`;
88 |       
89 |       const response = await axios.get(url);
90 |       return response.data;
91 |     } catch (error) {
92 |       throw new Error(`获取模型列表失败: ${error instanceof Error ? error.message : String(error)}`);
93 |     }
94 |   }
95 | } 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 | } from '@modelcontextprotocol/sdk/types.js';
 10 | import axios from 'axios';
 11 | import * as fs from 'fs';
 12 | import * as path from 'path';
 13 | 
 14 | // 简化的错误类型枚举
 15 | enum PollinationsErrorType {
 16 |   VALIDATION_ERROR = 'VALIDATION_ERROR',
 17 |   API_ERROR = 'API_ERROR',
 18 |   FILE_SYSTEM_ERROR = 'FILE_SYSTEM_ERROR'
 19 | }
 20 | 
 21 | // 简化的错误类
 22 | class PollinationsError extends Error {
 23 |   type: PollinationsErrorType;
 24 |   statusCode?: number;
 25 |   
 26 |   constructor(message: string, type: PollinationsErrorType, statusCode?: number) {
 27 |     super(message);
 28 |     this.name = 'PollinationsError';
 29 |     this.type = type;
 30 |     this.statusCode = statusCode;
 31 |   }
 32 |   
 33 |   toUserFriendlyMessage(): string {
 34 |     return `错误: ${this.message}${this.statusCode ? ` (状态码: ${this.statusCode})` : ''}`;
 35 |   }
 36 | }
 37 | 
 38 | // Pollinations文本API实现
 39 | class PollinationsTextAPI {
 40 |   private baseTextUrl = 'https://text.pollinations.ai';
 41 | 
 42 |   /**
 43 |    * 生成文本 (GET方法)
 44 |    * @param prompt 提示词
 45 |    * @param options 选项
 46 |    * @returns 生成的文本
 47 |    */
 48 |   async generateTextGet(prompt: string, options: {
 49 |     model?: string;
 50 |     seed?: number;
 51 |     json?: boolean;
 52 |     system?: string;
 53 |     private?: boolean;
 54 |   } = {}) {
 55 |     const { model = 'openai', seed, json = false, system, private: isPrivate = false } = options;
 56 |     
 57 |     let url = `${this.baseTextUrl}/${encodeURIComponent(prompt)}?model=${model}`;
 58 |     
 59 |     if (seed !== undefined) {
 60 |       url += `&seed=${seed}`;
 61 |     }
 62 |     
 63 |     if (json) {
 64 |       url += `&json=true`;
 65 |     }
 66 |     
 67 |     if (system) {
 68 |       url += `&system=${encodeURIComponent(system)}`;
 69 |     }
 70 |     
 71 |     if (isPrivate) {
 72 |       url += `&private=true`;
 73 |     }
 74 |     
 75 |     try {
 76 |       const response = await axios.get(url);
 77 |       return response.data;
 78 |     } catch (error) {
 79 |       throw new Error(`文本生成失败: ${error instanceof Error ? error.message : String(error)}`);
 80 |     }
 81 |   }
 82 | 
 83 |   /**
 84 |    * 获取可用模型列表
 85 |    * @returns 模型列表
 86 |    */
 87 |   async getAvailableModels() {
 88 |     try {
 89 |       const url = `${this.baseTextUrl}/models`;
 90 |       
 91 |       const response = await axios.get(url);
 92 |       return response.data;
 93 |     } catch (error) {
 94 |       throw new Error(`获取模型列表失败: ${error instanceof Error ? error.message : String(error)}`);
 95 |     }
 96 |   }
 97 | }
 98 | 
 99 | // Pollinations.ai 服务器实现
100 | class PollinationsServer {
101 |   private server: Server;
102 |   private baseUrl = 'https://image.pollinations.ai';
103 |   private textAPI: PollinationsTextAPI;
104 | 
105 |   constructor() {
106 |     this.server = new Server(
107 |       {
108 |         name: 'pollinations-mcp-server',
109 |         version: '0.1.0',
110 |       },
111 |       {
112 |         capabilities: {
113 |           tools: {},
114 |         },
115 |       }
116 |     );
117 | 
118 |     // 初始化文本API
119 |     this.textAPI = new PollinationsTextAPI();
120 |     
121 |     // 设置工具处理器
122 |     this.setupToolHandlers();
123 |     
124 |     // 错误处理
125 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
126 |     process.on('SIGINT', async () => {
127 |       await this.server.close();
128 |       process.exit(0);
129 |     });
130 |   }
131 | 
132 |   // 错误处理方法
133 |   private handleValidationError(message: string): PollinationsError {
134 |     return new PollinationsError(message, PollinationsErrorType.VALIDATION_ERROR, 400);
135 |   }
136 |   
137 |   private handleApiError(error: any): PollinationsError {
138 |     if (axios.isAxiosError(error)) {
139 |       const statusCode = error.response?.status || 0;
140 |       const message = error.response?.data?.message || error.message;
141 |       return new PollinationsError(`API错误: ${message}`, PollinationsErrorType.API_ERROR, statusCode);
142 |     }
143 |     return new PollinationsError(`未知错误: ${error.message || error}`, PollinationsErrorType.API_ERROR, 0);
144 |   }
145 |   
146 |   private handleFileSystemError(error: any, operation: string): PollinationsError {
147 |     return new PollinationsError(`文件操作失败 (${operation}): ${error.message || error}`, PollinationsErrorType.FILE_SYSTEM_ERROR);
148 |   }
149 | 
150 |   // 设置MCP工具处理器
151 |   private setupToolHandlers() {
152 |     // 列出可用工具
153 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
154 |       tools: [
155 |         {
156 |           name: 'generate_image',
157 |           description: '使用Pollinations.ai生成图像',
158 |           inputSchema: {
159 |             type: 'object',
160 |             properties: {
161 |               prompt: {
162 |                 type: 'string',
163 |                 description: '图像描述提示词',
164 |               },
165 |               width: {
166 |                 type: 'number',
167 |                 description: '图像宽度(像素)',
168 |                 default: 1024,
169 |               },
170 |               height: {
171 |                 type: 'number',
172 |                 description: '图像高度(像素)',
173 |                 default: 1024,
174 |               },
175 |               seed: {
176 |                 type: 'number',
177 |                 description: '随机种子值(用于生成一致的图像)',
178 |               },
179 |               model: {
180 |                 type: 'string',
181 |                 description: '要使用的模型(如flux、variation等)',
182 |                 default: 'flux',
183 |               },
184 |               nologo: {
185 |                 type: 'boolean',
186 |                 description: '设置为true可去除水印',
187 |                 default: true,
188 |               },
189 |               enhance: {
190 |                 type: 'boolean',
191 |                 description: '提高图像质量(应用增强滤镜)',
192 |                 default: false,
193 |               },
194 |               safe: {
195 |                 type: 'boolean',
196 |                 description: '启用安全过滤(过滤不适内容)',
197 |                 default: false,
198 |               },
199 |               private: {
200 |                 type: 'boolean',
201 |                 description: '设置为true可使图像私有',
202 |                 default: false,
203 |               },
204 |             },
205 |             required: ['prompt'],
206 |           },
207 |         },
208 |         {
209 |           name: 'download_image',
210 |           description: '下载Pollinations.ai生成的图像到本地文件',
211 |           inputSchema: {
212 |             type: 'object',
213 |             properties: {
214 |               url: {
215 |                 type: 'string',
216 |                 description: '要下载的图像URL',
217 |               },
218 |               output_path: {
219 |                 type: 'string',
220 |                 description: '保存图像的路径(包括文件名)',
221 |                 default: 'image.jpg',
222 |               },
223 |             },
224 |             required: ['url'],
225 |           },
226 |         },
227 |         {
228 |           name: 'generate_text',
229 |           description: '使用Pollinations.ai生成文本',
230 |           inputSchema: {
231 |             type: 'object',
232 |             properties: {
233 |               prompt: {
234 |                 type: 'string',
235 |                 description: '文本提示词',
236 |               },
237 |               model: {
238 |                 type: 'string',
239 |                 description: '要使用的模型(如openai、mistral等)',
240 |                 default: 'openai',
241 |               },
242 |               seed: {
243 |                 type: 'number',
244 |                 description: '随机种子值(用于生成一致的结果)',
245 |               },
246 |               system: {
247 |                 type: 'string',
248 |                 description: '系统提示词(设置AI行为)',
249 |               },
250 |               json: {
251 |                 type: 'boolean',
252 |                 description: '是否返回JSON格式的响应',
253 |                 default: false,
254 |               },
255 |               private: {
256 |                 type: 'boolean',
257 |                 description: '设置为true可使响应私有',
258 |                 default: false,
259 |               },
260 |             },
261 |             required: ['prompt'],
262 |           },
263 |         },
264 |       ],
265 |     }));
266 |     
267 |     // 处理工具调用
268 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
269 |       switch (request.params.name) {
270 |         case 'generate_image':
271 |           return this.handleGenerateImage(request.params.arguments);
272 |         case 'download_image':
273 |           return this.handleDownloadImage(request.params.arguments);
274 |         case 'generate_text':
275 |           return this.handleGenerateText(request.params.arguments);
276 |         default:
277 |           throw new McpError(
278 |             ErrorCode.MethodNotFound,
279 |             `未知工具: ${request.params.name}`
280 |           );
281 |       }
282 |     });
283 |   }
284 | 
285 |   // 处理生成图像请求
286 |   private async handleGenerateImage(args: any) {
287 |     try {
288 |       if (!this.isValidGenerateImageArgs(args)) {
289 |         throw this.handleValidationError('无效的图像生成参数');
290 |       }
291 | 
292 |       const { 
293 |         prompt, 
294 |         width = 1024, 
295 |         height = 1024, 
296 |         seed, 
297 |         model = 'flux', 
298 |         nologo = true,
299 |         enhance = false,
300 |         safe = false,
301 |         private: isPrivate = false
302 |       } = args;
303 |       
304 |       // 检查提示词是否为英文
305 |       const isMainlyEnglish = this.isMainlyEnglish(prompt);
306 |       const isConcise = prompt.length <= 200;
307 |       
308 |       let promptFeedback = '';
309 |       
310 |       if (!isMainlyEnglish) {
311 |         promptFeedback += '提示:Pollinations.ai对英文提示词的理解更好,建议使用英文编写提示词。\n';
312 |       }
313 |       
314 |       if (!isConcise) {
315 |         promptFeedback += '提示:提示词过长可能影响生成效果,建议保持简短精确(建议不超过200字符)。\n';
316 |       }
317 |       
318 |       // 构建Pollinations URL(使用官方路径格式)
319 |       let imageUrl = `${this.baseUrl}/prompt/${encodeURIComponent(prompt)}?width=${width}&height=${height}`;
320 |       
321 |       if (seed !== undefined) {
322 |         imageUrl += `&seed=${seed}`;
323 |       }
324 |       
325 |       if (model) {
326 |         imageUrl += `&model=${model}`;
327 |       }
328 | 
329 |       if (nologo) {
330 |         imageUrl += `&nologo=true`;
331 |       }
332 | 
333 |       // 添加新参数支持
334 |       if (enhance) {
335 |         imageUrl += `&enhance=true`;
336 |       }
337 | 
338 |       if (safe) {
339 |         imageUrl += `&safe=true`;
340 |       }
341 | 
342 |       if (isPrivate) {
343 |         imageUrl += `&private=true`;
344 |       }
345 | 
346 |       // 验证URL是否有效
347 |       try {
348 |         // 发送HEAD请求检查URL是否可访问(不下载完整图像)
349 |         await axios.head(imageUrl);
350 |       } catch (error) {
351 |         // 处理API错误
352 |         const pollinationsError = this.handleApiError(error);
353 |         
354 |         // 特殊处理安全过滤错误
355 |         if (pollinationsError.statusCode === 400 && safe) {
356 |           throw new PollinationsError(
357 |             '内容被安全过滤拦截,请修改提示词后重试',
358 |             PollinationsErrorType.VALIDATION_ERROR,
359 |             400
360 |           );
361 |         }
362 |         
363 |         throw pollinationsError;
364 |       }
365 | 
366 |       const response = {
367 |         content: [
368 |           {
369 |             type: 'text',
370 |             text: JSON.stringify({
371 |               url: imageUrl,
372 |               prompt,
373 |               width,
374 |               height,
375 |               seed,
376 |               model,
377 |               nologo,
378 |               enhance,
379 |               safe,
380 |               private: isPrivate
381 |             }, null, 2),
382 |           },
383 |         ],
384 |       };
385 |       
386 |       // 如果有提示反馈,添加到响应中
387 |       if (promptFeedback) {
388 |         response.content.unshift({
389 |           type: 'text',
390 |           text: promptFeedback
391 |         });
392 |       }
393 |       
394 |       return response;
395 |     } catch (error) {
396 |       // 处理所有错误
397 |       let pollinationsError: PollinationsError;
398 |       
399 |       if (error instanceof PollinationsError) {
400 |         pollinationsError = error;
401 |       } else {
402 |         pollinationsError = this.handleApiError(error);
403 |       }
404 |       
405 |       return {
406 |         content: [
407 |           {
408 |             type: 'text',
409 |             text: pollinationsError.toUserFriendlyMessage(),
410 |           },
411 |         ],
412 |         isError: true,
413 |       };
414 |     }
415 |   }
416 | 
417 |   // 检查文本是否主要为英文
418 |   private isMainlyEnglish(text: string): boolean {
419 |     // 英文字符(包括空格和标点)的正则表达式
420 |     const englishRegex = /^[A-Za-z0-9\s.,;:'"!?()-]+$/;
421 |     
422 |     // 如果完全匹配英文字符,返回true
423 |     if (englishRegex.test(text)) {
424 |       return true;
425 |     }
426 |     
427 |     // 否则计算非英文字符的比例
428 |     const nonEnglishChars = text.split('').filter(char => !char.match(/[A-Za-z0-9\s.,;:'"!?()-]/)).length;
429 |     const totalChars = text.length;
430 |     
431 |     // 如果非英文字符少于20%,仍然视为主要是英文
432 |     return (nonEnglishChars / totalChars) < 0.2;
433 |   }
434 | 
435 |   // 处理下载图像请求
436 |   private async handleDownloadImage(args: any) {
437 |     try {
438 |       if (!this.isValidDownloadImageArgs(args)) {
439 |         throw this.handleValidationError('无效的图像下载参数');
440 |       }
441 | 
442 |       // 获取参数
443 |       let { url, output_path = 'image.jpg' } = args;
444 |       
445 |       // 使用相对路径保存图像到当前工作目录
446 |       output_path = path.resolve(process.cwd(), output_path);
447 |       console.error(`图像将保存到: ${output_path}`);
448 | 
449 |       try {
450 |         // 确保输出目录存在
451 |         const dirname = path.dirname(output_path);
452 |         if (!fs.existsSync(dirname)) {
453 |           console.error(`创建目录: ${dirname}`);
454 |           fs.mkdirSync(dirname, { recursive: true });
455 |         }
456 |       } catch (fsError) {
457 |         throw this.handleFileSystemError(fsError, '创建目录');
458 |       }
459 | 
460 |       // 下载图像
461 |       console.error(`开始下载图像: ${url}`);
462 |       let response;
463 |       try {
464 |         response = await axios.get(url, { responseType: 'arraybuffer' });
465 |       } catch (downloadError) {
466 |         throw this.handleApiError(downloadError);
467 |       }
468 |       
469 |       // 写入文件
470 |       try {
471 |         console.error(`写入文件: ${output_path}`);
472 |         fs.writeFileSync(output_path, Buffer.from(response.data, 'binary'));
473 |       } catch (writeError) {
474 |         throw this.handleFileSystemError(writeError, '写入文件');
475 |       }
476 |       
477 |       // 验证文件是否写入成功
478 |       try {
479 |         if (fs.existsSync(output_path)) {
480 |           const fileSize = fs.statSync(output_path).size;
481 |           console.error(`文件成功写入: ${output_path}, 大小: ${fileSize} 字节`);
482 |           
483 |           return {
484 |             content: [
485 |               {
486 |                 type: 'text',
487 |                 text: JSON.stringify({
488 |                   success: true,
489 |                   message: `图像已下载到 ${output_path}`,
490 |                   size: fileSize,
491 |                   path: output_path
492 |                 }, null, 2),
493 |               },
494 |             ],
495 |           };
496 |         } else {
497 |           throw new PollinationsError(
498 |             `文件写入失败: ${output_path}`,
499 |             PollinationsErrorType.FILE_SYSTEM_ERROR
500 |           );
501 |         }
502 |       } catch (verifyError) {
503 |         if (verifyError instanceof PollinationsError) {
504 |           throw verifyError;
505 |         } else {
506 |           throw this.handleFileSystemError(verifyError, '验证文件');
507 |         }
508 |       }
509 |     } catch (error) {
510 |       // 处理所有错误
511 |       let pollinationsError: PollinationsError;
512 |       
513 |       if (error instanceof PollinationsError) {
514 |         pollinationsError = error;
515 |       } else {
516 |         pollinationsError = this.handleApiError(error);
517 |       }
518 |       
519 |       return {
520 |         content: [
521 |           {
522 |             type: 'text',
523 |             text: pollinationsError.toUserFriendlyMessage(),
524 |           },
525 |         ],
526 |         isError: true,
527 |       };
528 |     }
529 |   }
530 | 
531 |   // 验证生成图像参数
532 |   private isValidGenerateImageArgs(args: any): args is {
533 |     prompt: string;
534 |     width?: number;
535 |     height?: number;
536 |     seed?: number;
537 |     model?: string;
538 |     nologo?: boolean;
539 |     enhance?: boolean;
540 |     safe?: boolean;
541 |     private?: boolean;
542 |   } {
543 |     return (
544 |       typeof args === 'object' &&
545 |       args !== null &&
546 |       typeof args.prompt === 'string' &&
547 |       (args.width === undefined || typeof args.width === 'number') &&
548 |       (args.height === undefined || typeof args.height === 'number') &&
549 |       (args.seed === undefined || typeof args.seed === 'number') &&
550 |       (args.model === undefined || typeof args.model === 'string') &&
551 |       (args.nologo === undefined || typeof args.nologo === 'boolean') &&
552 |       (args.enhance === undefined || typeof args.enhance === 'boolean') &&
553 |       (args.safe === undefined || typeof args.safe === 'boolean') &&
554 |       (args.private === undefined || typeof args.private === 'boolean')
555 |     );
556 |   }
557 | 
558 |   // 验证下载图像参数
559 |   private isValidDownloadImageArgs(args: any): args is {
560 |     url: string;
561 |     output_path?: string;
562 |   } {
563 |     return (
564 |       typeof args === 'object' &&
565 |       args !== null &&
566 |       typeof args.url === 'string' &&
567 |       (args.output_path === undefined || typeof args.output_path === 'string')
568 |     );
569 |   }
570 | 
571 |   // 处理生成文本请求
572 |   private async handleGenerateText(args: any) {
573 |     try {
574 |       if (!this.isValidGenerateTextArgs(args)) {
575 |         throw this.handleValidationError('无效的文本生成参数');
576 |       }
577 | 
578 |       const { prompt, model = 'openai', seed, system, json = false, private: isPrivate = false } = args;
579 | 
580 |       const result = await this.textAPI.generateTextGet(prompt, {
581 |         model,
582 |         seed,
583 |         json,
584 |         system,
585 |         private: isPrivate
586 |       });
587 | 
588 |       return {
589 |         content: [
590 |           {
591 |             type: 'text',
592 |             text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
593 |           },
594 |         ],
595 |       };
596 |     } catch (error) {
597 |       // 处理所有错误
598 |       let pollinationsError: PollinationsError;
599 |       
600 |       if (error instanceof PollinationsError) {
601 |         pollinationsError = error;
602 |       } else {
603 |         pollinationsError = this.handleApiError(error);
604 |       }
605 |       
606 |       return {
607 |         content: [
608 |           {
609 |             type: 'text',
610 |             text: pollinationsError.toUserFriendlyMessage(),
611 |           },
612 |         ],
613 |         isError: true,
614 |       };
615 |     }
616 |   }
617 | 
618 |   // 验证生成文本参数
619 |   private isValidGenerateTextArgs(args: any): args is {
620 |     prompt: string;
621 |     model?: string;
622 |     seed?: number;
623 |     system?: string;
624 |     json?: boolean;
625 |     private?: boolean;
626 |   } {
627 |     return (
628 |       typeof args === 'object' &&
629 |       args !== null &&
630 |       typeof args.prompt === 'string' &&
631 |       (args.model === undefined || typeof args.model === 'string') &&
632 |       (args.seed === undefined || typeof args.seed === 'number') &&
633 |       (args.system === undefined || typeof args.system === 'string') &&
634 |       (args.json === undefined || typeof args.json === 'boolean') &&
635 |       (args.private === undefined || typeof args.private === 'boolean')
636 |     );
637 |   }
638 | 
639 |   // 运行服务器
640 |   async run() {
641 |     const transport = new StdioServerTransport();
642 |     await this.server.connect(transport);
643 |     console.error('Pollinations MCP服务器正在通过stdio运行');
644 |   }
645 | }
646 | 
647 | // 创建并运行服务器
648 | const server = new PollinationsServer();
649 | server.run().catch(console.error);
650 | 
```