@fastcoder/vision-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -0
- package/README.zh-CN.md +210 -0
- package/build/core/api-common.d.ts +89 -0
- package/build/core/api-common.d.ts.map +1 -0
- package/build/core/api-common.js +119 -0
- package/build/core/api-common.js.map +1 -0
- package/build/core/base-image-service.d.ts +38 -0
- package/build/core/base-image-service.d.ts.map +1 -0
- package/build/core/base-image-service.js +92 -0
- package/build/core/base-image-service.js.map +1 -0
- package/build/core/chat-service.d.ts +42 -0
- package/build/core/chat-service.d.ts.map +1 -0
- package/build/core/chat-service.js +97 -0
- package/build/core/chat-service.js.map +1 -0
- package/build/core/environment.d.ts +76 -0
- package/build/core/environment.d.ts.map +1 -0
- package/build/core/environment.js +132 -0
- package/build/core/environment.js.map +1 -0
- package/build/core/error-handler.d.ts +124 -0
- package/build/core/error-handler.d.ts.map +1 -0
- package/build/core/error-handler.js +248 -0
- package/build/core/error-handler.js.map +1 -0
- package/build/core/file-service.d.ts +36 -0
- package/build/core/file-service.d.ts.map +1 -0
- package/build/core/file-service.js +141 -0
- package/build/core/file-service.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +119 -0
- package/build/index.js.map +1 -0
- package/build/prompts/data-viz.d.ts +5 -0
- package/build/prompts/data-viz.d.ts.map +1 -0
- package/build/prompts/data-viz.js +98 -0
- package/build/prompts/data-viz.js.map +1 -0
- package/build/prompts/diagram-analysis.d.ts +5 -0
- package/build/prompts/diagram-analysis.d.ts.map +1 -0
- package/build/prompts/diagram-analysis.js +102 -0
- package/build/prompts/diagram-analysis.js.map +1 -0
- package/build/prompts/error-diagnosis.d.ts +5 -0
- package/build/prompts/error-diagnosis.d.ts.map +1 -0
- package/build/prompts/error-diagnosis.js +69 -0
- package/build/prompts/error-diagnosis.js.map +1 -0
- package/build/prompts/general-image.d.ts +5 -0
- package/build/prompts/general-image.d.ts.map +1 -0
- package/build/prompts/general-image.js +45 -0
- package/build/prompts/general-image.js.map +1 -0
- package/build/prompts/index.d.ts +8 -0
- package/build/prompts/index.d.ts.map +1 -0
- package/build/prompts/index.js +8 -0
- package/build/prompts/index.js.map +1 -0
- package/build/prompts/text-extraction.d.ts +5 -0
- package/build/prompts/text-extraction.d.ts.map +1 -0
- package/build/prompts/text-extraction.js +45 -0
- package/build/prompts/text-extraction.js.map +1 -0
- package/build/prompts/ui-diff.d.ts +5 -0
- package/build/prompts/ui-diff.d.ts.map +1 -0
- package/build/prompts/ui-diff.js +190 -0
- package/build/prompts/ui-diff.js.map +1 -0
- package/build/prompts/ui-to-artifact.d.ts +10 -0
- package/build/prompts/ui-to-artifact.d.ts.map +1 -0
- package/build/prompts/ui-to-artifact.js +89 -0
- package/build/prompts/ui-to-artifact.js.map +1 -0
- package/build/tools/data-viz.d.ts +5 -0
- package/build/tools/data-viz.d.ts.map +1 -0
- package/build/tools/data-viz.js +93 -0
- package/build/tools/data-viz.js.map +1 -0
- package/build/tools/diagram-analysis.d.ts +5 -0
- package/build/tools/diagram-analysis.d.ts.map +1 -0
- package/build/tools/diagram-analysis.js +93 -0
- package/build/tools/diagram-analysis.js.map +1 -0
- package/build/tools/error-diagnosis.d.ts +5 -0
- package/build/tools/error-diagnosis.d.ts.map +1 -0
- package/build/tools/error-diagnosis.js +93 -0
- package/build/tools/error-diagnosis.js.map +1 -0
- package/build/tools/general-image.d.ts +5 -0
- package/build/tools/general-image.d.ts.map +1 -0
- package/build/tools/general-image.js +81 -0
- package/build/tools/general-image.js.map +1 -0
- package/build/tools/index.d.ts +8 -0
- package/build/tools/index.d.ts.map +1 -0
- package/build/tools/index.js +9 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/text-extraction.d.ts +5 -0
- package/build/tools/text-extraction.d.ts.map +1 -0
- package/build/tools/text-extraction.js +93 -0
- package/build/tools/text-extraction.js.map +1 -0
- package/build/tools/ui-diff.d.ts +5 -0
- package/build/tools/ui-diff.d.ts.map +1 -0
- package/build/tools/ui-diff.js +98 -0
- package/build/tools/ui-diff.js.map +1 -0
- package/build/tools/ui-to-artifact.d.ts +5 -0
- package/build/tools/ui-to-artifact.d.ts.map +1 -0
- package/build/tools/ui-to-artifact.js +117 -0
- package/build/tools/ui-to-artifact.js.map +1 -0
- package/build/types/index.d.ts +26 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +43 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/logger.d.ts +24 -0
- package/build/utils/logger.d.ts.map +1 -0
- package/build/utils/logger.js +119 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/validation.d.ts +87 -0
- package/build/utils/validation.d.ts.map +1 -0
- package/build/utils/validation.js +155 -0
- package/build/utils/validation.js.map +1 -0
- package/package.json +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Vision MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides image analysis capabilities using OpenAI API.
|
|
4
|
+
|
|
5
|
+
## Available Tools
|
|
6
|
+
|
|
7
|
+
The server provides specialized tools for different image analysis tasks:
|
|
8
|
+
|
|
9
|
+
### Image Analysis Tools
|
|
10
|
+
|
|
11
|
+
1. **`ui_to_artifact`** - Convert UI screenshots to various artifacts
|
|
12
|
+
- Generate frontend code from design mockups
|
|
13
|
+
- Create AI prompts for UI generation
|
|
14
|
+
- Extract design specification documents
|
|
15
|
+
- Generate natural language descriptions of UIs
|
|
16
|
+
|
|
17
|
+
2. **`extract_text_from_screenshot`** - OCR text extraction
|
|
18
|
+
- Extract code from screenshots (maintaining correct formatting)
|
|
19
|
+
- Extract terminal output and logs
|
|
20
|
+
- Extract documentation and text content
|
|
21
|
+
- Support programming language hints for improved accuracy
|
|
22
|
+
|
|
23
|
+
3. **`diagnose_error_screenshot`** - Error diagnosis and troubleshooting
|
|
24
|
+
- Analyze error messages and stack traces
|
|
25
|
+
- Identify root causes
|
|
26
|
+
- Provide actionable solutions
|
|
27
|
+
- Suggest prevention strategies
|
|
28
|
+
|
|
29
|
+
4. **`understand_technical_diagram`** - Technical diagram analysis
|
|
30
|
+
- Analyze architecture diagrams
|
|
31
|
+
- Understand flowcharts and UML diagrams
|
|
32
|
+
- Explain ER diagrams and sequence diagrams
|
|
33
|
+
- Identify design patterns
|
|
34
|
+
|
|
35
|
+
5. **`analyze_data_visualization`** - Data visualization insights
|
|
36
|
+
- Extract insights from charts
|
|
37
|
+
- Identify trends and patterns
|
|
38
|
+
- Detect anomalies
|
|
39
|
+
- Provide business impact analysis
|
|
40
|
+
|
|
41
|
+
6. **`ui_diff_check`** - UI comparison check (visual regression testing)
|
|
42
|
+
- Compare expected vs actual UI implementations
|
|
43
|
+
- Identify visual differences
|
|
44
|
+
- Provide detailed difference reports
|
|
45
|
+
- Prioritize issues by severity
|
|
46
|
+
|
|
47
|
+
7. **`analyze_image`** - General image analysis (fallback tool)
|
|
48
|
+
- Use when specialized tools are not applicable
|
|
49
|
+
- Flexibly understand any visual content
|
|
50
|
+
- Comprehensive image description and analysis
|
|
51
|
+
|
|
52
|
+
## Environment Variables
|
|
53
|
+
|
|
54
|
+
### OpenAI API Variables
|
|
55
|
+
- `OPENAI_API_KEY` or `VISION_MCP_API_KEY` - Your API key (required)
|
|
56
|
+
- `OPENAI_BASE_URL` or `VISION_MCP_API_URL` - API base URL (optional, default: https://api.openai.com/v1)
|
|
57
|
+
- `OPENAI_VISION_MODEL` or `VISION_MCP_MODEL` - Vision model name (optional, default: gpt-4o)
|
|
58
|
+
- `OPENAI_MODEL_TEMPERATURE` or `VISION_MCP_TEMPERATURE` - Model temperature (optional, default: 0.7)
|
|
59
|
+
- `OPENAI_MODEL_TOP_P` or `VISION_MCP_TOP_P` - Top P parameter (optional, default: 1.0)
|
|
60
|
+
- `OPENAI_MODEL_MAX_TOKENS` or `VISION_MCP_MAX_TOKENS` - Maximum tokens (optional, default: 2048)
|
|
61
|
+
- `OPENAI_TIMEOUT` or `VISION_MCP_TIMEOUT` - Request timeout in ms (optional, default: 60000)
|
|
62
|
+
- `OPENAI_RETRY_COUNT` - Retry count (optional, default: 1)
|
|
63
|
+
|
|
64
|
+
### Server Variables
|
|
65
|
+
- `SERVER_NAME` or `VISION_MCP_SERVER_NAME` - Server name (optional, default: vision-mcp-server)
|
|
66
|
+
- `SERVER_VERSION` or `VISION_MCP_SERVER_VERSION` - Server version (optional, default: 0.1.0)
|
|
67
|
+
|
|
68
|
+
Note: `VISION_MCP_*` environment variables take precedence over `OPENAI_*` variables when both are set.
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
### Install from npm
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm i @vision/mcp-server
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Local Development
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Clone or download project
|
|
82
|
+
git clone <repository-url>
|
|
83
|
+
cd vision-mcp-server
|
|
84
|
+
|
|
85
|
+
# Install dependencies
|
|
86
|
+
npm install
|
|
87
|
+
|
|
88
|
+
# Build project
|
|
89
|
+
npm run build
|
|
90
|
+
|
|
91
|
+
# Start server
|
|
92
|
+
npm start
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
### Using this MCP Server in Claude Code
|
|
98
|
+
|
|
99
|
+
```shell
|
|
100
|
+
claude mcp add vision-mcp-server --env OPENAI_API_KEY=your_api_key -- npx -y "@vision/mcp-server"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Using MCP Inspector for Testing
|
|
104
|
+
|
|
105
|
+
MCP Inspector is a powerful GUI tool for testing and debugging MCP servers.
|
|
106
|
+
|
|
107
|
+
#### Start Inspector (Build Mode)
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# First build the project
|
|
111
|
+
npm run build
|
|
112
|
+
|
|
113
|
+
# Start inspector with built version
|
|
114
|
+
npm run inspector
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Start Inspector (Development Mode)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Start inspector with tsx (watch mode enabled)
|
|
121
|
+
npm run inspector:dev
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Configure Environment Variables
|
|
125
|
+
|
|
126
|
+
Before running inspector, set your OpenAI API key:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Option 1: Set directly in terminal
|
|
130
|
+
export VISION_MCP_API_KEY="sk-your-openai-api-key"
|
|
131
|
+
|
|
132
|
+
# Option 2: Create .env file (copy from .env.example)
|
|
133
|
+
cp .env.example .env
|
|
134
|
+
# Edit .env and add your API key
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Using Inspector
|
|
138
|
+
|
|
139
|
+
1. Inspector will open in your browser (usually at http://localhost:5173)
|
|
140
|
+
2. You'll see all available tools listed on the left panel
|
|
141
|
+
3. Click on any tool to see its schema and description
|
|
142
|
+
4. Enter parameters in the form fields
|
|
143
|
+
5. Click "Call Tool" to execute
|
|
144
|
+
6. View results in the response panel
|
|
145
|
+
|
|
146
|
+
### Environment Variables Configuration
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# For OpenAI API
|
|
150
|
+
export VISION_MCP_API_KEY="sk-your-openai-key"
|
|
151
|
+
export VISION_MCP_API_URL="https://api.openai.com/v1"
|
|
152
|
+
export VISION_MCP_MODEL="gpt-4o"
|
|
153
|
+
|
|
154
|
+
# For Zhipu AI API (智谱 AI)
|
|
155
|
+
export VISION_MCP_API_KEY="your-zhipu-ai-key"
|
|
156
|
+
export VISION_MCP_API_URL="https://open.bigmodel.cn/api/paas/v4/chat/completions"
|
|
157
|
+
export VISION_MCP_MODEL="glm-4v"
|
|
158
|
+
|
|
159
|
+
# Start server
|
|
160
|
+
npm start
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Note: You can also use `OPENAI_*` environment variables if you prefer. `VISION_MCP_*` variables take precedence.
|
|
164
|
+
|
|
165
|
+
## Supported Models
|
|
166
|
+
|
|
167
|
+
- `gpt-4o` - OpenAI's latest multimodal model (recommended)
|
|
168
|
+
- `gpt-4o-mini` - Lightweight multimodal model
|
|
169
|
+
- `gpt-4-turbo` - High-performance multimodal model
|
|
170
|
+
- `gpt-4-vision-preview` - Vision preview model
|
|
171
|
+
|
|
172
|
+
## Tech Stack
|
|
173
|
+
|
|
174
|
+
- Development Language: TypeScript 5.9.2
|
|
175
|
+
- Testing Framework: Vitest
|
|
176
|
+
- Core Dependencies: @modelcontextprotocol/sdk (1.17.5), zod (3.23.8)
|
|
177
|
+
- Node.js Version: >= 18.0.0
|
|
178
|
+
|
|
179
|
+
## Architecture Design
|
|
180
|
+
|
|
181
|
+
The project uses a layered architecture design with clear structure:
|
|
182
|
+
|
|
183
|
+
- **Entry Layer**: index.ts - MCP Server startup entry
|
|
184
|
+
- **Core Services Layer** (core/):
|
|
185
|
+
- environment.ts - Environment configuration management (OpenAI format)
|
|
186
|
+
- chat-service.ts - OpenAI API invocation service
|
|
187
|
+
- file-service.ts - File operations service (image only, video methods removed)
|
|
188
|
+
- api-common.ts - API common functions (video function removed)
|
|
189
|
+
- base-image-service.ts - Image analysis base class
|
|
190
|
+
- error-handler.ts - Error handling system
|
|
191
|
+
- **Tools Layer** (tools/) - 7 image analysis tools
|
|
192
|
+
- **Prompts Layer** (prompts/) - AI prompt templates
|
|
193
|
+
- **Utilities Layer** (utils/) - Logging and validation utilities
|
|
194
|
+
- **Types Layer** (types/) - Error type definitions
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Install dependencies
|
|
200
|
+
npm install
|
|
201
|
+
|
|
202
|
+
# Development mode (with tsx watch)
|
|
203
|
+
npm run dev
|
|
204
|
+
|
|
205
|
+
# Build
|
|
206
|
+
npm run build
|
|
207
|
+
|
|
208
|
+
# Run tests
|
|
209
|
+
npm test
|
|
210
|
+
|
|
211
|
+
# Run tests with coverage report
|
|
212
|
+
npm run test:coverage
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Project Structure
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
vision-mcp-server/
|
|
219
|
+
├── src/
|
|
220
|
+
│ ├── index.ts # MCP Server entry
|
|
221
|
+
│ ├── core/
|
|
222
|
+
│ │ ├── environment.ts # Environment config service (OpenAI)
|
|
223
|
+
│ │ ├── chat-service.ts # OpenAI API invocation
|
|
224
|
+
│ │ ├── file-service.ts # File operations (no video methods)
|
|
225
|
+
│ │ ├── api-common.ts # API common functions (no video function)
|
|
226
|
+
│ │ ├── base-image-service.ts # Image analysis base class
|
|
227
|
+
│ │ └── error-handler.ts # Error handling
|
|
228
|
+
│ ├── tools/ # 7 image analysis tools
|
|
229
|
+
│ ├── prompts/ # Prompt templates
|
|
230
|
+
│ ├── types/ # Type definitions
|
|
231
|
+
│ └── utils/ # Utilities
|
|
232
|
+
├── tests/ # Vitest tests
|
|
233
|
+
├── package.json # Project configuration
|
|
234
|
+
├── tsconfig.json # TS configuration
|
|
235
|
+
├── vitest.config.ts # Vitest configuration
|
|
236
|
+
└── README.zh-CN.md # Chinese documentation
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Key Changes from Original Project
|
|
240
|
+
|
|
241
|
+
1. **Feature Removal**
|
|
242
|
+
- ✅ Removed video analysis tool (`analyze_video`)
|
|
243
|
+
- ✅ Removed all video-related code
|
|
244
|
+
- ✅ Retained 7 image analysis tools
|
|
245
|
+
|
|
246
|
+
2. **API Transformation**
|
|
247
|
+
- ✅ Transformed from Zhipu AI API to OpenAI API format
|
|
248
|
+
- ✅ Simplified environment variables (OPENAI_* replacing Z_AI_*)
|
|
249
|
+
- ✅ Removed Zhipu-specific request headers and parameters (`thinking`, `X-Title`)
|
|
250
|
+
- ✅ Improved interface compatibility
|
|
251
|
+
|
|
252
|
+
3. **Architecture Preservation**
|
|
253
|
+
- ✅ Maintained the original excellent architecture design
|
|
254
|
+
- ✅ Maintained code quality and maintainability
|
|
255
|
+
- ✅ Maintained modular design
|
|
256
|
+
|
|
257
|
+
## License
|
|
258
|
+
|
|
259
|
+
Apache-2.0
|
|
260
|
+
|
|
261
|
+
## Contributing
|
|
262
|
+
|
|
263
|
+
Issues and Pull Requests are welcome!
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Vision MCP Server
|
|
2
|
+
|
|
3
|
+
一个基于 OpenAI API 提供图像分析能力的模型上下文协议 (MCP) 服务器。
|
|
4
|
+
|
|
5
|
+
## 可用工具
|
|
6
|
+
|
|
7
|
+
该服务器提供针对不同图像分析任务的专业工具:
|
|
8
|
+
|
|
9
|
+
### 图像分析工具
|
|
10
|
+
|
|
11
|
+
1. **`ui_to_artifact`** - 将 UI 截图转换为各种产物
|
|
12
|
+
- 从设计稿生成前端代码
|
|
13
|
+
- 创建用于 UI 重建的 AI 提示词
|
|
14
|
+
- 提取设计规范文档
|
|
15
|
+
- 生成 UI 的自然语言描述
|
|
16
|
+
|
|
17
|
+
2. **`extract_text_from_screenshot`** - OCR 文字提取
|
|
18
|
+
- 从截图中提取代码(保持正确格式)
|
|
19
|
+
- 提取终端输出和日志
|
|
20
|
+
- 提取文档和文本内容
|
|
21
|
+
- 支持编程语言提示以提高准确性
|
|
22
|
+
|
|
23
|
+
3. **`diagnose_error_screenshot`** - 错误诊断和故障排查
|
|
24
|
+
- 分析错误消息和堆栈跟踪
|
|
25
|
+
- 识别根本原因
|
|
26
|
+
- 提供可操作的解决方案
|
|
27
|
+
- 建议预防策略
|
|
28
|
+
|
|
29
|
+
4. **`understand_technical_diagram`** - 技术图表分析
|
|
30
|
+
- 分析架构图
|
|
31
|
+
- 理解流程图和 UML 图
|
|
32
|
+
- 解释 ER 图和序列图
|
|
33
|
+
- 识别设计模式
|
|
34
|
+
|
|
35
|
+
5. **`analyze_data_visualization`** - 数据可视化洞察
|
|
36
|
+
- 从图表中提取洞察
|
|
37
|
+
- 识别趋势和模式
|
|
38
|
+
- 检测异常值
|
|
39
|
+
- 提供业务影响分析
|
|
40
|
+
|
|
41
|
+
6. **`ui_diff_check`** - UI 对比检查(视觉回归测试)
|
|
42
|
+
- 比较预期和实际的 UI 实现
|
|
43
|
+
- 识别视觉差异
|
|
44
|
+
- 提供详细的差异报告
|
|
45
|
+
- 按严重程度排列问题优先级
|
|
46
|
+
|
|
47
|
+
7. **`analyze_image`** - 通用图像分析(兜底工具)
|
|
48
|
+
- 当专业工具不适用时使用
|
|
49
|
+
- 灵活理解任何视觉内容
|
|
50
|
+
- 全面的图像描述和分析
|
|
51
|
+
|
|
52
|
+
## 环境变量
|
|
53
|
+
|
|
54
|
+
- `OPENAI_API_KEY` - 您的 OpenAI API 密钥(必需)
|
|
55
|
+
- `OPENAI_BASE_URL` - OpenAI API 基础 URL(可选,默认: https://api.openai.com/v1)
|
|
56
|
+
- `OPENAI_VISION_MODEL` - 视觉模型名称(可选,默认: gpt-4o)
|
|
57
|
+
- `OPENAI_MODEL_TEMPERATURE` - 模型温度(可选,默认: 0.8)
|
|
58
|
+
- `OPENAI_MODEL_TOP_P` - Top P 参数(可选,默认: 0.6)
|
|
59
|
+
- `OPENAI_MODEL_MAX_TOKENS` - 最大 tokens(可选,默认: 32768)
|
|
60
|
+
- `OPENAI_TIMEOUT` - 请求超时时间 ms(可选,默认: 300000)
|
|
61
|
+
- `OPENAI_RETRY_COUNT` - 重试次数(可选,默认: 1)
|
|
62
|
+
|
|
63
|
+
## 安装
|
|
64
|
+
|
|
65
|
+
### 从 npm 安装
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm i @vision/mcp-server
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 本地开发
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 克隆或下载项目
|
|
75
|
+
git clone <repository-url>
|
|
76
|
+
cd vision-mcp-server
|
|
77
|
+
|
|
78
|
+
# 安装依赖
|
|
79
|
+
npm install
|
|
80
|
+
|
|
81
|
+
# 编译项目
|
|
82
|
+
npm run build
|
|
83
|
+
|
|
84
|
+
# 启动服务器
|
|
85
|
+
npm start
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 使用方法
|
|
89
|
+
|
|
90
|
+
### 在 Claude Code 中使用此 MCP 服务器
|
|
91
|
+
|
|
92
|
+
```shell
|
|
93
|
+
claude mcp add vision-mcp-server --env OPENAI_API_KEY=your_api_key -- npx -y "@vision/mcp-server"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 环境变量配置
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 设置 OpenAI API Key
|
|
100
|
+
export OPENAI_API_KEY="sk-your-openai-key"
|
|
101
|
+
|
|
102
|
+
# 可选:自定义模型
|
|
103
|
+
export OPENAI_VISION_MODEL="gpt-4o"
|
|
104
|
+
|
|
105
|
+
# 可选:自定义 API 端点
|
|
106
|
+
export OPENAI_BASE_URL="https://api.openai.com/v1"
|
|
107
|
+
|
|
108
|
+
# 启动服务器
|
|
109
|
+
npm start
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 支持的模型
|
|
113
|
+
|
|
114
|
+
- `gpt-4o` - OpenAI 最新的多模态模型(推荐)
|
|
115
|
+
- `gpt-4o-mini` - 轻量级多模态模型
|
|
116
|
+
- `gpt-4-turbo` - 高性能多模态模型
|
|
117
|
+
- `gpt-4-vision-preview` - 视觉预览版模型
|
|
118
|
+
|
|
119
|
+
## 技术栈
|
|
120
|
+
|
|
121
|
+
- 开发语言:TypeScript 5.9.2
|
|
122
|
+
- 测试框架:Vitest
|
|
123
|
+
- 核心依赖:@modelcontextprotocol/sdk (1.17.5), zod (3.23.8)
|
|
124
|
+
- Node.js 版本:>= 18.0.0
|
|
125
|
+
|
|
126
|
+
## 架构设计
|
|
127
|
+
|
|
128
|
+
项目采用分层架构设计,保持清晰的结构:
|
|
129
|
+
|
|
130
|
+
- **入口层**:index.ts - MCP Server 启动入口
|
|
131
|
+
- **核心服务层**(core/):
|
|
132
|
+
- environment.ts - 环境配置管理(OpenAI 格式)
|
|
133
|
+
- chat-service.ts - OpenAI API 调用服务
|
|
134
|
+
- file-service.ts - 文件操作服务(仅支持图像)
|
|
135
|
+
- api-common.ts - API 公共函数
|
|
136
|
+
- base-image-service.ts - 图像分析基类
|
|
137
|
+
- error-handler.ts - 错误处理系统
|
|
138
|
+
- **工具层**(tools/)- 7 个图像分析工具
|
|
139
|
+
- **提示词层**(prompts/)- AI 提示词模板
|
|
140
|
+
- **工具函数层**(utils/)- 日志和验证工具
|
|
141
|
+
- **类型定义层**(types/)- 错误类型定义
|
|
142
|
+
|
|
143
|
+
## 开发
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# 安装依赖
|
|
147
|
+
npm install
|
|
148
|
+
|
|
149
|
+
# 开发模式(使用 tsx watch)
|
|
150
|
+
npm run dev
|
|
151
|
+
|
|
152
|
+
# 编译
|
|
153
|
+
npm run build
|
|
154
|
+
|
|
155
|
+
# 运行测试
|
|
156
|
+
npm test
|
|
157
|
+
|
|
158
|
+
# 运行测试并生成覆盖率报告
|
|
159
|
+
npm run test:coverage
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 项目结构
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
vision-mcp-server/
|
|
166
|
+
├── src/
|
|
167
|
+
│ ├── index.ts # MCP Server 入口
|
|
168
|
+
│ ├── core/
|
|
169
|
+
│ │ ├── environment.ts # 环境配置服务(OpenAI)
|
|
170
|
+
│ │ ├── chat-service.ts # OpenAI API 调用
|
|
171
|
+
│ │ ├── file-service.ts # 文件操作(移除视频方法)
|
|
172
|
+
│ │ ├── api-common.ts # API 公共函数(移除视频函数)
|
|
173
|
+
│ │ ├── base-image-service.ts # 图像分析基类
|
|
174
|
+
│ │ └── error-handler.ts # 错误处理
|
|
175
|
+
│ ├── tools/ # 7 个图像分析工具
|
|
176
|
+
│ ├── prompts/ # 提示词模板
|
|
177
|
+
│ ├── types/ # 类型定义
|
|
178
|
+
│ └── utils/ # 工具函数
|
|
179
|
+
├── tests/ # Vitest 测试
|
|
180
|
+
├── package.json # 项目配置
|
|
181
|
+
├── tsconfig.json # TS 配置
|
|
182
|
+
├── vitest.config.ts # Vitest 配置
|
|
183
|
+
└── README.zh-CN.md # 中文文档
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 与原项目的主要改动
|
|
187
|
+
|
|
188
|
+
1. **功能裁剪**
|
|
189
|
+
- ✅ 移除了视频分析工具(`analyze_video`)
|
|
190
|
+
- ✅ 移除了所有视频相关的代码
|
|
191
|
+
- ✅ 保留了 7 个图像分析工具
|
|
192
|
+
|
|
193
|
+
2. **接口改造**
|
|
194
|
+
- ✅ 将智谱 API 格式改造为 OpenAI API 格式
|
|
195
|
+
- ✅ 简化了环境变量配置(OPENAI_* 替代 Z_AI_*)
|
|
196
|
+
- ✅ 移除了智谱特定的请求头和参数(`thinking`, `X-Title`)
|
|
197
|
+
- ✅ 提高了接口兼容性
|
|
198
|
+
|
|
199
|
+
3. **架构保持**
|
|
200
|
+
- ✅ 保持了原有的优秀架构设计
|
|
201
|
+
- ✅ 保持了代码质量和可维护性
|
|
202
|
+
- ✅ 保持了模块化设计
|
|
203
|
+
|
|
204
|
+
## 许可证
|
|
205
|
+
|
|
206
|
+
Apache-2.0
|
|
207
|
+
|
|
208
|
+
## 贡献
|
|
209
|
+
|
|
210
|
+
欢迎提交 Issue 和 Pull Request!
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multimodal message content type
|
|
3
|
+
*/
|
|
4
|
+
export type MultimodalContent = {
|
|
5
|
+
type: 'text';
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'image_url';
|
|
9
|
+
image_url: {
|
|
10
|
+
url: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Message interface
|
|
15
|
+
*/
|
|
16
|
+
export interface Message {
|
|
17
|
+
role: string;
|
|
18
|
+
content: string | MultimodalContent[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Standard response interface
|
|
22
|
+
*/
|
|
23
|
+
export interface StandardResponse<T = unknown> {
|
|
24
|
+
success: boolean;
|
|
25
|
+
data?: T;
|
|
26
|
+
error?: string;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
context?: {
|
|
29
|
+
stack?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* MCP tool response interface
|
|
35
|
+
*/
|
|
36
|
+
export interface McpToolResponse {
|
|
37
|
+
content: Array<{
|
|
38
|
+
type: string;
|
|
39
|
+
text: string;
|
|
40
|
+
}>;
|
|
41
|
+
isError?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create multimodal message content
|
|
45
|
+
* @param content Content array including images, text, etc.
|
|
46
|
+
* @param prompt Text prompt
|
|
47
|
+
* @returns Formatted message array
|
|
48
|
+
*/
|
|
49
|
+
export declare function createMultiModalMessage(content: MultimodalContent[], prompt: string): Message[];
|
|
50
|
+
/**
|
|
51
|
+
* Create text message
|
|
52
|
+
* @param prompt Text content
|
|
53
|
+
* @returns Formatted message array
|
|
54
|
+
*/
|
|
55
|
+
export declare function createTextMessage(prompt: string): Message[];
|
|
56
|
+
/**
|
|
57
|
+
* Create image message content
|
|
58
|
+
* @param imageUrl Image URL or base64 data
|
|
59
|
+
* @returns Image content object
|
|
60
|
+
*/
|
|
61
|
+
export declare function createImageContent(imageUrl: string): MultimodalContent;
|
|
62
|
+
/**
|
|
63
|
+
* Create error response
|
|
64
|
+
* @param message Error message
|
|
65
|
+
* @param error Optional error object
|
|
66
|
+
* @returns Standardized error response
|
|
67
|
+
*/
|
|
68
|
+
export declare function createErrorResponse(message: string, error?: Error): StandardResponse;
|
|
69
|
+
/**
|
|
70
|
+
* Create success response
|
|
71
|
+
* @param data Response data
|
|
72
|
+
* @returns Standardized success response
|
|
73
|
+
*/
|
|
74
|
+
export declare function createSuccessResponse<T>(data: T): StandardResponse<T>;
|
|
75
|
+
/**
|
|
76
|
+
* Format response content to MCP format
|
|
77
|
+
* @param response API response
|
|
78
|
+
* @returns MCP tool response format
|
|
79
|
+
*/
|
|
80
|
+
export declare function formatMcpResponse(response: StandardResponse): McpToolResponse;
|
|
81
|
+
/**
|
|
82
|
+
* Create async function with retry mechanism
|
|
83
|
+
* @param fn Async function to execute
|
|
84
|
+
* @param maxRetries Maximum retry attempts
|
|
85
|
+
* @param delay Retry delay in milliseconds
|
|
86
|
+
* @returns Wrapped function
|
|
87
|
+
*/
|
|
88
|
+
export declare function withRetry<T extends unknown[]>(fn: (...args: T) => Promise<unknown>, maxRetries?: number, delay?: number): (...args: T) => Promise<unknown>;
|
|
89
|
+
//# sourceMappingURL=api-common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-common.d.ts","sourceRoot":"","sources":["../../src/core/api-common.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAAE,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,EAAE,CAOX;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAO3D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAKtE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,KAAK,GACZ,gBAAgB,CAOlB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAMrE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,eAAe,CAoB7E;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,EAC3C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,EACpC,UAAU,GAAE,MAAU,EACtB,KAAK,GAAE,MAAa,GACnB,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAmBlC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create multimodal message content
|
|
3
|
+
* @param content Content array including images, text, etc.
|
|
4
|
+
* @param prompt Text prompt
|
|
5
|
+
* @returns Formatted message array
|
|
6
|
+
*/
|
|
7
|
+
export function createMultiModalMessage(content, prompt) {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
role: 'user',
|
|
11
|
+
content: [...content, { type: 'text', text: prompt }]
|
|
12
|
+
}
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create text message
|
|
17
|
+
* @param prompt Text content
|
|
18
|
+
* @returns Formatted message array
|
|
19
|
+
*/
|
|
20
|
+
export function createTextMessage(prompt) {
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
role: 'user',
|
|
24
|
+
content: [{ type: 'text', text: prompt }]
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create image message content
|
|
30
|
+
* @param imageUrl Image URL or base64 data
|
|
31
|
+
* @returns Image content object
|
|
32
|
+
*/
|
|
33
|
+
export function createImageContent(imageUrl) {
|
|
34
|
+
return {
|
|
35
|
+
type: 'image_url',
|
|
36
|
+
image_url: { url: imageUrl }
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create error response
|
|
41
|
+
* @param message Error message
|
|
42
|
+
* @param error Optional error object
|
|
43
|
+
* @returns Standardized error response
|
|
44
|
+
*/
|
|
45
|
+
export function createErrorResponse(message, error) {
|
|
46
|
+
return {
|
|
47
|
+
success: false,
|
|
48
|
+
error: message,
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
...(error && { context: { stack: error.stack, name: error.name } })
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create success response
|
|
55
|
+
* @param data Response data
|
|
56
|
+
* @returns Standardized success response
|
|
57
|
+
*/
|
|
58
|
+
export function createSuccessResponse(data) {
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
data,
|
|
62
|
+
timestamp: Date.now()
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Format response content to MCP format
|
|
67
|
+
* @param response API response
|
|
68
|
+
* @returns MCP tool response format
|
|
69
|
+
*/
|
|
70
|
+
export function formatMcpResponse(response) {
|
|
71
|
+
if (response.success) {
|
|
72
|
+
const text = typeof response.data === 'string'
|
|
73
|
+
? response.data
|
|
74
|
+
: JSON.stringify(response.data, null, 2);
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: 'text', text }]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: `Error: ${response.error}`
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
isError: true
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create async function with retry mechanism
|
|
93
|
+
* @param fn Async function to execute
|
|
94
|
+
* @param maxRetries Maximum retry attempts
|
|
95
|
+
* @param delay Retry delay in milliseconds
|
|
96
|
+
* @returns Wrapped function
|
|
97
|
+
*/
|
|
98
|
+
export function withRetry(fn, maxRetries = 3, delay = 1000) {
|
|
99
|
+
return async (...args) => {
|
|
100
|
+
let lastError;
|
|
101
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
102
|
+
try {
|
|
103
|
+
return await fn(...args);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
lastError =
|
|
107
|
+
error instanceof Error ? error : new Error(String(error));
|
|
108
|
+
if (attempt === maxRetries) {
|
|
109
|
+
throw lastError;
|
|
110
|
+
}
|
|
111
|
+
// Exponential backoff
|
|
112
|
+
const waitTime = delay * Math.pow(2, attempt);
|
|
113
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
throw lastError;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=api-common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-common.js","sourceRoot":"","sources":["../../src/core/api-common.ts"],"names":[],"mappings":"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"}
|