Skip to main content
Glama

TinyPNG MCP Server

by Alvinnn1
INTRODUCE.md17.3 kB
# 保姆级教程!使用 Cursor 开发 MCP 服务器完整指南 ## 📖 项目背景 作为前端开发者,我们经常需要处理大量图片资源。无论是设计师提供的素材还是从 Figma 下载的图片,通常尺寸都较大,严重影响网页加载性能。因此,在开发过程中压缩图片是必要的优化步骤。 ### 现有方案的痛点 - **手动操作繁琐**:压缩网站需要逐个上传,限制单次处理数量 - **协作不便**:团队成员压缩后的图片缺乏同步,容易重复处理影响质量 - **技术门槛**:虽然可以通过脚本批量处理,但对有同样需求的非技术同事操作困难 本 MCP 服务器正是为了解决上述问题而开发,提供便捷的图片批量压缩解决方案。 --- ## 🛠️ 开发环境要求 | 工具 | 版本要求 | 说明 | |------|----------|------| | **Node.js** | 22.14.0+ | 推荐使用指定版本 | | **Cursor** | 1.0.0+ | 使用 Claude-4-Sonnet MAX 模式 | | **Agent Mode** | Claude-4-Sonnet | 最佳代码生成体验 | --- ## 📚 参考文档 - [MCP Node.js SDK](https://www.npmjs.com/package/@modelcontextprotocol/sdk) - [TinyPNG API SDK](https://www.npmjs.com/package/tinify) --- ## 🚀 项目搭建步骤 ### Step 1: 创建项目结构 ```bash mkdir joyme-mcp-tinify-image cd joyme-mcp-tinify-image ``` ### Step 2: 初始化 Node.js 项目 ```bash npm init ``` 按提示填写项目基础信息: - 项目名称、描述、版本号 - 作者信息、开源协议等 --- ## 🎯 开始使用 Cursor 开发 > 🎉 **从这里开始,让 Cursor 成为你的编程助手!** ### Step 3: 配置 Cursor Rules 优秀的工具配置是高效开发的基础。Rules 和 Prompts 是 Cursor 的两大核心功能。 #### 获取 Rules 的方式: - 🔍 浏览 [cursor.directory](https://cursor.directory/) 寻找适合的技术栈规则 - 🤖 直接让 Cursor 生成定制化规则 #### 这里我们使用 Prompt 让 Cursor 给我们生成 Rules: ``` 写一段rules,告诉agent精通nodejs和typescript,需要适配当前流行的javascript代码风格, 包括但不局限于文件/命名规则/eslint规则。rules需要添加参考资料 https://www.npmjs.com/package/@modelcontextprotocol/sdk 和 https://tinypng.com/developers/reference/nodejs ``` <details> <summary>💡 点击查看生成的 Rules 配置</summary> ```markdown # MCP Agent Rules - Node.js & TypeScript Expert ## Core Competencies This agent is an expert in **Node.js** and **TypeScript** development, with deep understanding of: - Modern JavaScript (ES2020+) and TypeScript features - Node.js runtime and ecosystem - Asynchronous programming patterns (async/await, Promises) - Package management with npm/yarn/pnpm - Build tools and bundlers - Testing frameworks and methodologies ## Code Style & Standards ### File Structure & Naming Conventions **File Naming:** - Use `kebab-case` for file and directory names: `user-service.ts`, `image-processor.js` - TypeScript files: `.ts` for modules, `.d.ts` for type definitions - Test files: `*.test.ts`, `*.spec.ts` - Configuration files: `*.config.js/ts` **Export/Import Conventions:** - Prefer named exports over default exports for better tree-shaking - Use barrel exports (`index.ts`) for clean module interfaces - Import ordering: external libraries → internal modules → types ### TypeScript Best Practices **Type Definitions:** - Use `interface` for object shapes, `type` for unions/intersections - Prefer `const assertions` for immutable data - Use generic constraints appropriately: `<T extends BaseType>` - Avoid `any`, prefer `unknown` or proper typing **Code Organization:** - Separate types into dedicated `types/` directory - Use module declaration merging sparingly - Implement proper error types extending `Error` **Formatting Standards:** - 2-space indentation - Single quotes for strings - Trailing commas in multiline structures - No semicolons - Line length: 100 characters **Error Handling:** - Use custom error classes - Implement proper error boundaries - Leverage `cause` property for error chaining **Functional Programming:** - Prefer immutable operations - Use array methods (`map`, `filter`, `reduce`) over loops - Implement pure functions where possible ## Package & Dependency Management **package.json Structure:** - Use semantic versioning - Separate `dependencies` from `devDependencies` - Include proper scripts for common tasks - Use `engines` field to specify Node.js version requirements **Dependencies:** - Prefer well-maintained, popular packages - Keep dependencies minimal and updated - Use exact versions for production dependencies ## Reference Resources ### Model Context Protocol (MCP) **Documentation:** https://www.npmjs.com/package/@modelcontextprotocol/sdk Key concepts to understand: - MCP server/client architecture - Protocol message handling - Resource and tool definitions - Type-safe implementations ### TinyPNG API Integration **Documentation:** https://tinypng.com/developers/reference/nodejs Essential patterns: - API key management and security - Error handling for API calls - File upload/download operations - Rate limiting and quota management ## Development Workflow **Project Setup:** 1. Initialize with `npm init` or appropriate template 2. Configure TypeScript with strict settings 3. Set up ESLint + Prettier 4. Configure testing framework (Jest/Vitest) 5. Implement CI/CD pipeline **Code Quality:** - Implement integration tests for external APIs - Use type-safe configurations - Document public APIs with JSDoc **Performance Considerations:** - Use streaming for large file operations - Implement proper caching strategies - Monitor memory usage and optimize accordingly - Use compression and bundling appropriately ## Security Best Practices - Never commit API keys or secrets - Use environment variables for configuration - Validate all inputs and sanitize outputs - Implement proper authentication/authorization - Keep dependencies updated and audit regularly This agent should consistently apply these rules while maintaining flexibility to adapt to project-specific requirements and team preferences. ``` </details> --- ### Step 4: 配置 ESLint 代码规范 良好的代码规范确保团队协作的一致性。 #### Prompt: ``` 为项目增加eslint规则/文件,符合当前代码流行趋势,例如tab=2,不使用分号, 优先单引号,只允许JSDoc风格的注释等。只需要eslint,不要prettier以及其他规则。 ``` **✅ 执行结果:** Cursor 成功创建了 `.eslintrc.json` 配置文件 --- ### Step 5: 配置编辑器自动格式化 添加 ESLint 还不够,还需要配置编辑器实现自动格式化,避免手动修改代码格式。 #### Prompt: ``` 在编辑器中保存代码时请执行eslint fix操作,禁用此项目prettier, 禁用项目formatOnSave操作。并将这些配置添加到.vscode/setting.json。 ``` **✅ 执行结果:** 现在使用 `Ctrl + S` 保存时,编辑器会自动格式化代码 --- ### Step 6: 实现核心业务逻辑 完成基础框架搭建后,开始开发具体功能。 #### 创建 MCP 服务器 **Prompt:** ``` @https://www.npmjs.com/package/@modelcontextprotocol/sdk 根据官方文档帮我实现以下需求。 in src folder, create index.ts, in this file, you will help me create an mcp server, name: joyme-mcp-tinify-image; version: 1.0.0; then start receiving messages on stdin and sending message on stdout. ``` <details> <summary>💡 点击查看生成的核心代码</summary> ```typescript /** * MCP Server for TinyPNG image optimization. * This server provides tools and resources for image compression using TinyPNG API. */ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' /** * Main function to initialize and start the MCP server. * Sets up the server with stdio transport for communication. */ async function main(): Promise<void> { /** * Create an MCP server instance with project-specific configuration. */ const server = new McpServer({ name: 'joyme-mcp-tinify-image', version: '1.0.0', }) /** * Add a basic ping tool for testing server connectivity. * This tool simply returns a pong response to verify the server is working. */ server.tool( 'ping', {}, async () => ({ content: [{ type: 'text', text: 'pong' }], }) ) /** * Create stdio transport for communication via stdin/stdout. * This allows the server to receive messages from stdin and send responses to stdout. */ const transport = new StdioServerTransport() /** * Connect the server to the transport and start listening for messages. * This establishes the MCP protocol communication channel. */ await server.connect(transport) console.error('joyme-mcp-tinify-image server started and listening on stdio') } /** * Start the server and handle any initialization errors. * Ensures proper error handling and logging for debugging. */ main().catch((error) => { console.error('Failed to start MCP server:', error) process.exit(1) }) ``` </details> > ⚠️ **注意:** 这里Cursor老毛病又犯了,首次生成的代码包含了无需的额外功能(如 `server.tool` 和 `server.resource`),最终根据实际需求进行调整。 --- ### Step 7: 实现图片压缩工具 实现项目的核心功能 - 图片批量压缩。 #### Prompt: ``` first, we require user who should provide their tinify_api_key; then create a tool named 'minify_image', the tool will accept a parameter named directoryPath which is string; then loop the every image in directory, use node fs module read the file, then use tinify@https://tinypng.com/developers/reference/nodejs to compress the current image, in the last, use fs module to cover the origin image with same name. ``` <details> <summary>💡 点击查看核心实现代码</summary> ```typescript /** * Add image minification tool. * This tool compresses all images in a specified directory using TinyPNG API. */ server.tool( 'minify_image', { tinify_api_key: z.string().describe('Your TinyPNG API key'), directoryPath: z.string().describe('Path to directory containing images to compress'), }, async ({ tinify_api_key, directoryPath }) => { try { // Validate the API key first await validateApiKey(tinify_api_key) // Check if directory exists if (!fs.existsSync(directoryPath)) { throw new Error(`Directory does not exist: ${directoryPath}`) } // Get all image files in the directory const imageFiles = await getImageFiles(directoryPath) if (imageFiles.length === 0) { return { content: [{ type: 'text', text: `No supported image files found in directory: ${directoryPath}`, }], } } // Compress each image const results: string[] = [] let successCount = 0 let errorCount = 0 for (const imagePath of imageFiles) { try { const originalSize = (await fs.promises.stat(imagePath)).size await compressImage(imagePath) const compressedSize = (await fs.promises.stat(imagePath)).size const savings = ((originalSize - compressedSize) / originalSize * 100).toFixed(1) results.push(`✅ ${path.basename(imagePath)}: ${originalSize} → ${compressedSize} bytes (${savings}% reduction)`) successCount++ } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error' results.push(`❌ ${path.basename(imagePath)}: ${errorMessage}`) errorCount++ } } // Add compression statistics results.push(`\n📊 Total compressions used this month: ${tinify.compressionCount}`) results.push(`✅ Successfully compressed: ${successCount} images`) if (errorCount > 0) { results.push(`❌ Failed to compress: ${errorCount} images`) } return { content: [{ type: 'text', text: results.join('\n'), }], } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' return { content: [{ type: 'text', text: `❌ Error: ${errorMessage}`, }], } } } ) ``` </details> #### 🔧 优化 API Key 管理 初始实现将 `tinify_api_key` 作为工具参数,这会导致用户每次调用都需要输入密钥,体验不佳且不安全。 **优化方案:** ``` tinify_api_key 应该是放在mcp.json env的参数,而不是tool中的参数。 ``` **✅ 优化结果:** API 密钥通过环境变量管理,在服务器启动时验证,提升安全性和用户体验。 --- ## 🧪 本地测试 ### Step 8: 构建项目 ```bash npm run build ``` 编译后的文件位于 `build/index.js` ### Step 9: 配置 Cursor MCP 在 Cursor 中添加自定义 MCP 服务器: **路径:** `Cursor Settings` → `MCP Tools` → `Add Custom MCP Server` **配置示例:** ```json { "mcpServers": { "joyme-mcp-tinify-image": { "command": "node", "args": [ "/Users/dengjingwen/projects/joyme-mcp-tinify-image/build/index.js" ], "env": { "TINIFY_API_KEY": "你的_TinyPNG_API_密钥" } } } } ``` > ⚠️ **重要:** `args` 中的路径必须是你本地的绝对路径 ### Step 10: 测试功能 在 Cursor 对话框中使用 Agent 模式: ``` @/images/login minify images ``` **执行结果示例:** | 图片文件 | 原始大小 | 压缩后大小 | 压缩率 | |----------|----------|------------|--------| | icon-act.png | 12.6KB | 3.5KB | 72.1% | | icon-back.png | 1.1KB | 546B | 51.3% | | icon-clear.png | 456B | 269B | 41.0% | | icon-eye-close.png | 690B | 341B | 50.6% | | icon-eye-open.png | 1.2KB | 494B | 58.5% | **📊 压缩总结:** - 处理图片总数:8 个 PNG 文件 - 最佳压缩效果:icon-act.png 减少 72.1% - 总计节省空间:10KB+ - 图片质量保持不变,显著提升加载性能 --- ## 📦 发布到 NPM ### Step 11: 完善项目文档 发布前需要补充 README.md,详细介绍项目技术栈和使用方法。 ### Step 12: 发布到NPM仓库 我们可以把包发布到公开的官网NPM,但我们选择发布到 JoyMe 私有 NPM 仓库: ```bash # 登录私有仓库 npm login --registry=http://npm.joyme.sg # 输入你的 JoyMe 账号密码(用户名不需要 @joyme.sg 后缀,例如dengjingwen) # 发布包 npm publish ``` **✅ 发布成功!** 访问 [http://npm.joyme.sg](http://npm.joyme.sg) 查看已发布的包。 [@joyme/mcp-tinify-image地址](http://npm.joyme.sg/-/web/detail/@joyme/mcp-tinify-image) --- ## 🎯 总结 通过本教程,我们成功使用 Cursor 开发了一个完整的 MCP 图片压缩服务器,主要收获: ### 技术亮点 - ✅ **MCP 协议集成** - 实现标准化的工具通信 - ✅ **TinyPNG API 集成** - 高质量图片压缩 - ✅ **TypeScript 最佳实践** - 类型安全的代码开发 - ✅ **环境变量管理** - 安全的 API 密钥处理 ### 开发体验 - 🚀 **AI 辅助开发** - Cursor 大幅提升开发效率 - 📝 **代码规范自动化** - ESLint 确保代码质量 - 🔧 **一键格式化** - 保存时自动修复代码格式 - 📚 **完整的文档** - JSDoc 注释确保代码可维护性 ### 实际价值 - 🎯 **解决实际痛点** - 批量图片压缩自动化 - 👥 **团队协作友好** - 技术和非技术人员都能使用 - ⚡ **性能优化** - 显著减少图片文件大小 - 🔒 **安全可靠** - 私有 NPM 仓库部署 ### 待开发内容 - TODO 本项目还未实现重复压缩的问题,大致解决方案是在文件内新增json文件,记录已压缩的图片。 - TODO 目前只实现了tinify的compress功能,其他resize/converting images待开发。 ## Cursor开发总结 这个项目展示了 AI 辅助开发的强大能力,让我们能够专注于业务逻辑和用户体验,而不是繁琐的代码实现细节。但是仍有许多问题 - 本文上述步骤展示的只是Cursor最理想的情况,其实很多代码细节都是经过手动调整。 - 有很多步骤其实是为了Cursor而Cursor,很多配置/初始/业务强相关代码自己去写还会更快,让Cursor去弄反而还需要多次调整。所以还是得多用,找到Cursor的甜点区,找到适合他的场景,即效率/经济性达到完美平衡。 - 大型任务应拆分成小任务让Cursor分部完成。 - “如果不知道答案,老实回答,别乱猜”,“不要实现提示词以外的功能”。Cursor真的很喜欢乱改文件!!! - 提示词精准性,一般来说, English >= 中文,当然用最适合自己的,只要能够精准描述需求。因为很多开发文档只有英文的,直接copy下来问,不要先翻译。 [Joyme MCP Tinify Image Gitlab地址](https://git.joyme.sg/liveme_fe/joyme-MCP-tinify-image) [@joyme/mcp-tinify-image NPM地址](http://npm.joyme.sg/-/web/detail/@joyme/mcp-tinify-image) 完结撒花,感谢各位阅读!

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Alvinnn1/tinify-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server