@lutery/vision-mcp 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.
Files changed (122) hide show
  1. package/README.md +428 -0
  2. package/dist/adapters/base-adapter.d.ts +69 -0
  3. package/dist/adapters/base-adapter.d.ts.map +1 -0
  4. package/dist/adapters/base-adapter.js +143 -0
  5. package/dist/adapters/base-adapter.js.map +1 -0
  6. package/dist/adapters/claude-adapter.d.ts +38 -0
  7. package/dist/adapters/claude-adapter.d.ts.map +1 -0
  8. package/dist/adapters/claude-adapter.js +251 -0
  9. package/dist/adapters/claude-adapter.js.map +1 -0
  10. package/dist/adapters/glm-adapter.d.ts +15 -0
  11. package/dist/adapters/glm-adapter.d.ts.map +1 -0
  12. package/dist/adapters/glm-adapter.js +131 -0
  13. package/dist/adapters/glm-adapter.js.map +1 -0
  14. package/dist/adapters/modelscope-adapter.d.ts +20 -0
  15. package/dist/adapters/modelscope-adapter.d.ts.map +1 -0
  16. package/dist/adapters/modelscope-adapter.js +142 -0
  17. package/dist/adapters/modelscope-adapter.js.map +1 -0
  18. package/dist/adapters/openai-adapter.d.ts +20 -0
  19. package/dist/adapters/openai-adapter.d.ts.map +1 -0
  20. package/dist/adapters/openai-adapter.js +194 -0
  21. package/dist/adapters/openai-adapter.js.map +1 -0
  22. package/dist/adapters/siliconflow-adapter.d.ts +21 -0
  23. package/dist/adapters/siliconflow-adapter.d.ts.map +1 -0
  24. package/dist/adapters/siliconflow-adapter.js +145 -0
  25. package/dist/adapters/siliconflow-adapter.js.map +1 -0
  26. package/dist/config/model-config.d.ts +39 -0
  27. package/dist/config/model-config.d.ts.map +1 -0
  28. package/dist/config/model-config.js +115 -0
  29. package/dist/config/model-config.js.map +1 -0
  30. package/dist/index.d.ts +17 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +186 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/prompts/system.d.ts +75 -0
  35. package/dist/prompts/system.d.ts.map +1 -0
  36. package/dist/prompts/system.js +272 -0
  37. package/dist/prompts/system.js.map +1 -0
  38. package/dist/providers/provider-registry.d.ts +58 -0
  39. package/dist/providers/provider-registry.d.ts.map +1 -0
  40. package/dist/providers/provider-registry.js +173 -0
  41. package/dist/providers/provider-registry.js.map +1 -0
  42. package/dist/src/adapters/base-adapter.d.ts +59 -0
  43. package/dist/src/adapters/base-adapter.d.ts.map +1 -0
  44. package/dist/src/adapters/base-adapter.js +83 -0
  45. package/dist/src/adapters/base-adapter.js.map +1 -0
  46. package/dist/src/adapters/glm-adapter.d.ts +15 -0
  47. package/dist/src/adapters/glm-adapter.d.ts.map +1 -0
  48. package/dist/src/adapters/glm-adapter.js +116 -0
  49. package/dist/src/adapters/glm-adapter.js.map +1 -0
  50. package/dist/src/adapters/siliconflow-adapter.d.ts +21 -0
  51. package/dist/src/adapters/siliconflow-adapter.d.ts.map +1 -0
  52. package/dist/src/adapters/siliconflow-adapter.js +130 -0
  53. package/dist/src/adapters/siliconflow-adapter.js.map +1 -0
  54. package/dist/src/config/model-config.d.ts +40 -0
  55. package/dist/src/config/model-config.d.ts.map +1 -0
  56. package/dist/src/config/model-config.js +126 -0
  57. package/dist/src/config/model-config.js.map +1 -0
  58. package/dist/src/index.d.ts +17 -0
  59. package/dist/src/index.d.ts.map +1 -0
  60. package/dist/src/index.js +188 -0
  61. package/dist/src/index.js.map +1 -0
  62. package/dist/src/prompts/system.d.ts +75 -0
  63. package/dist/src/prompts/system.d.ts.map +1 -0
  64. package/dist/src/prompts/system.js +272 -0
  65. package/dist/src/prompts/system.js.map +1 -0
  66. package/dist/src/tools/vision-tool.d.ts +91 -0
  67. package/dist/src/tools/vision-tool.d.ts.map +1 -0
  68. package/dist/src/tools/vision-tool.js +171 -0
  69. package/dist/src/tools/vision-tool.js.map +1 -0
  70. package/dist/src/utils/errors.d.ts +65 -0
  71. package/dist/src/utils/errors.d.ts.map +1 -0
  72. package/dist/src/utils/errors.js +146 -0
  73. package/dist/src/utils/errors.js.map +1 -0
  74. package/dist/src/utils/image-input.d.ts +45 -0
  75. package/dist/src/utils/image-input.d.ts.map +1 -0
  76. package/dist/src/utils/image-input.js +226 -0
  77. package/dist/src/utils/image-input.js.map +1 -0
  78. package/dist/src/utils/logger.d.ts +63 -0
  79. package/dist/src/utils/logger.d.ts.map +1 -0
  80. package/dist/src/utils/logger.js +157 -0
  81. package/dist/src/utils/logger.js.map +1 -0
  82. package/dist/test/integration.test.d.ts +10 -0
  83. package/dist/test/integration.test.d.ts.map +1 -0
  84. package/dist/test/integration.test.js +270 -0
  85. package/dist/test/integration.test.js.map +1 -0
  86. package/dist/test/test-utils.d.ts +45 -0
  87. package/dist/test/test-utils.d.ts.map +1 -0
  88. package/dist/test/test-utils.js +107 -0
  89. package/dist/test/test-utils.js.map +1 -0
  90. package/dist/test/vision-tool.test.d.ts +9 -0
  91. package/dist/test/vision-tool.test.d.ts.map +1 -0
  92. package/dist/test/vision-tool.test.js +167 -0
  93. package/dist/test/vision-tool.test.js.map +1 -0
  94. package/dist/tools/vision-tool.d.ts +91 -0
  95. package/dist/tools/vision-tool.d.ts.map +1 -0
  96. package/dist/tools/vision-tool.js +167 -0
  97. package/dist/tools/vision-tool.js.map +1 -0
  98. package/dist/utils/data-url-parser.d.ts +27 -0
  99. package/dist/utils/data-url-parser.d.ts.map +1 -0
  100. package/dist/utils/data-url-parser.js +53 -0
  101. package/dist/utils/data-url-parser.js.map +1 -0
  102. package/dist/utils/errors.d.ts +65 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +146 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/image-input.d.ts +45 -0
  107. package/dist/utils/image-input.d.ts.map +1 -0
  108. package/dist/utils/image-input.js +238 -0
  109. package/dist/utils/image-input.js.map +1 -0
  110. package/dist/utils/logger.d.ts +63 -0
  111. package/dist/utils/logger.d.ts.map +1 -0
  112. package/dist/utils/logger.js +157 -0
  113. package/dist/utils/logger.js.map +1 -0
  114. package/dist/utils/thinking-extractors.d.ts +34 -0
  115. package/dist/utils/thinking-extractors.d.ts.map +1 -0
  116. package/dist/utils/thinking-extractors.js +83 -0
  117. package/dist/utils/thinking-extractors.js.map +1 -0
  118. package/dist/utils/thinking-filter.d.ts +32 -0
  119. package/dist/utils/thinking-filter.d.ts.map +1 -0
  120. package/dist/utils/thinking-filter.js +147 -0
  121. package/dist/utils/thinking-filter.js.map +1 -0
  122. package/package.json +41 -0
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Thinking/Reasoning Content Filter
3
+ *
4
+ * @description Filters thinking/reasoning content from model responses to prevent
5
+ * exposing internal reasoning to MCP clients. Supports multiple models and response formats.
6
+ *
7
+ * Architecture Decision: Keep thinking enabled at model level but strip reasoning
8
+ * content before returning to MCP client.
9
+ */
10
+ import { logger } from './logger.js';
11
+ import { extractGLMThinking, extractOpenAIThinking, extractClaudeThinking } from './thinking-extractors.js';
12
+ /**
13
+ * Thinking content patterns to filter from text
14
+ * These patterns match common thinking/reasoning content markers used by various models
15
+ */
16
+ const THINKING_PATTERNS = [
17
+ // HTML-style thinking tags
18
+ /<thinking>[\s\S]*?<\/thinking>/gi,
19
+ // Analysis tags
20
+ /<<analysis>>[\s\S]*?<<analysis>>/gi,
21
+ // Reasoning patterns (match from Reasoning:/Thoughts:/Analysis: to end of line)
22
+ /^\s*(Reasoning|Thoughts|Analysis):.*$/gim,
23
+ // Markdown thinking sections
24
+ /```(?:thinking|reasoning)[\s\S]*?```/gi,
25
+ // Inline thinking markers
26
+ /\[thinking\][\s\S]*?\[\/thinking\]/gi,
27
+ // Match leftover thinking markers to ensure they don't appear
28
+ /(<thinking>|<\/thinking>|<<analysis>>)/gi,
29
+ // Optional: Add more patterns as new models are discovered
30
+ ];
31
+ /**
32
+ * Registry of thinking extractors by model type
33
+ * Uses imported extractor functions to avoid circular dependencies
34
+ */
35
+ export const THINKING_EXTRACTORS = {
36
+ 'glm-4.6v': extractGLMThinking,
37
+ 'glm-4v': extractGLMThinking,
38
+ 'siliconflow': extractOpenAIThinking,
39
+ 'openai': extractOpenAIThinking,
40
+ 'claude': extractClaudeThinking,
41
+ // Add more model extractors as needed
42
+ };
43
+ /**
44
+ * Strips thinking content from text using pattern matching
45
+ * @param text - The text to clean
46
+ * @returns Cleaned text with thinking content removed
47
+ */
48
+ function stripThinkingPatterns(text) {
49
+ if (!text || typeof text !== 'string') {
50
+ return '';
51
+ }
52
+ let cleaned = text;
53
+ let removedCount = 0;
54
+ // Apply each pattern to remove thinking content
55
+ for (const pattern of THINKING_PATTERNS) {
56
+ let beforeLength = cleaned.length;
57
+ cleaned = cleaned.replace(pattern, '');
58
+ // Loop to replace all occurrences of the pattern
59
+ while (cleaned.length < beforeLength) {
60
+ removedCount++;
61
+ beforeLength = cleaned.length;
62
+ cleaned = cleaned.replace(pattern, '');
63
+ }
64
+ }
65
+ // Log if we removed thinking content
66
+ if (removedCount > 0) {
67
+ logger.debug(`Stripped thinking patterns from content`, {
68
+ patternsRemoved: removedCount,
69
+ sizeReduction: text.length - cleaned.length
70
+ });
71
+ }
72
+ // Clean up extra whitespace
73
+ return cleaned.trim().replace(/\n\s*\n\s*\n/g, '\n\n');
74
+ }
75
+ /**
76
+ * Strips thinking content from model response envelope
77
+ * @param envelope - Response envelope that may contain thinking content
78
+ * @returns Cleaned content string with all thinking content removed
79
+ */
80
+ export function stripThinking(envelope) {
81
+ const { content, reasoning, thinking } = envelope;
82
+ // Start with the main content
83
+ let cleaned = content || '';
84
+ // If there's explicit reasoning/thinking content, ignore it
85
+ // We NEVER return thinking content to the client
86
+ if (reasoning || thinking) {
87
+ logger.debug('Ignoring explicit thinking/reasoning field', {
88
+ hasReasoning: !!reasoning,
89
+ hasThinking: !!thinking,
90
+ reasoningLength: reasoning?.length || 0,
91
+ thinkingLength: thinking?.length || 0
92
+ });
93
+ }
94
+ // Strip any thinking patterns from the content itself
95
+ cleaned = stripThinkingPatterns(cleaned);
96
+ // If after cleaning the content is very short and we have reasoning,
97
+ // this might indicate the model only returned thinking content
98
+ // In this case, we return empty string, not the thinking content
99
+ if (cleaned.length < 10 && (reasoning || thinking)) {
100
+ logger.warn('Model response appears to contain only thinking content', {
101
+ contentLength: content?.length || 0,
102
+ reasoningLength: reasoning?.length || 0,
103
+ thinkingLength: thinking?.length || 0
104
+ });
105
+ return '';
106
+ }
107
+ return cleaned;
108
+ }
109
+ /**
110
+ * Filters thinking content from raw model response
111
+ * This is the main entry point for filtering thinking content
112
+ *
113
+ * @param rawResponse - The raw response from the model API
114
+ * @param modelType - The type of model (e.g., 'glm-4.6v', 'siliconflow')
115
+ * @returns Cleaned content string with thinking content removed
116
+ */
117
+ export function filterThinkingContent(rawResponse, modelType) {
118
+ // modelType is now required - validate it
119
+ if (!modelType) {
120
+ logger.error('modelType is required for thinking filter but was not provided');
121
+ throw new Error('modelType is required for thinking filter');
122
+ }
123
+ try {
124
+ // Use local extractor map to avoid circular dependency with provider-registry
125
+ const extractor = THINKING_EXTRACTORS[modelType.toLowerCase()] || extractOpenAIThinking;
126
+ if (!THINKING_EXTRACTORS[modelType.toLowerCase()]) {
127
+ logger.warn(`No extractor found for model type: ${modelType}, using generic extraction`);
128
+ }
129
+ // 提取 thinking content
130
+ const envelope = extractor(rawResponse);
131
+ return stripThinking(envelope);
132
+ }
133
+ catch (error) {
134
+ logger.error('Failed to filter thinking content', { error, modelType });
135
+ // Fallback: try to extract content directly from response
136
+ try {
137
+ // @ts-ignore
138
+ const content = rawResponse?.choices?.[0]?.message?.content || '';
139
+ return stripThinkingPatterns(content);
140
+ }
141
+ catch (fallbackError) {
142
+ logger.error('Fallback content extraction also failed', { error: fallbackError });
143
+ return '';
144
+ }
145
+ }
146
+ }
147
+ //# sourceMappingURL=thinking-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-filter.js","sourceRoot":"","sources":["../../src/utils/thinking-filter.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@lutery/vision-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP Server providing vision capabilities for LLMs via GLM-4.6V, SiliconFlow, and ModelScope",
5
+ "type": "module",
6
+ "bin": {
7
+ "vision-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc -p tsconfig.json",
14
+ "prepublishOnly": "npm run build",
15
+ "test": "npm run build && node -r dotenv/config test/simple-test.js",
16
+ "test:complex": "npm run build && node -r dotenv/config test/run-tests.js",
17
+ "test:unit": "node test/thinking-filter.test.js && node test/data-url-parser.test.js && node test/thinking-extractors.test.js && node test/claude-adapter.test.js",
18
+ "test:integration": "npm run build && node -r dotenv/config test/simple-test.js"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "vision",
23
+ "llm",
24
+ "glm-4.6v",
25
+ "siliconflow"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.0.4",
31
+ "zod": "^3.22.4",
32
+ "dotenv": "^16.4.7"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "^5.6.0",
36
+ "@types/node": "^20.17.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ }
41
+ }