cos-mcp 1.0.7 → 1.0.8
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 +22 -1
- package/dist/__tests__/utils.test.js +23 -0
- package/dist/__tests__/utils.test.js.map +1 -0
- package/dist/index.js +49 -36
- package/dist/index.js.map +1 -1
- package/dist/server.js +91 -79
- package/dist/server.js.map +1 -1
- package/dist/services/ci/ai.service.js +24 -20
- package/dist/services/ci/ai.service.js.map +1 -1
- package/dist/services/ci/doc.service.js +25 -28
- package/dist/services/ci/doc.service.js.map +1 -1
- package/dist/services/ci/mateInsight.service.js +7 -7
- package/dist/services/ci/mateInsight.service.js.map +1 -1
- package/dist/services/ci/media.service.js +22 -20
- package/dist/services/ci/media.service.js.map +1 -1
- package/dist/services/ci/pic.service.js +13 -12
- package/dist/services/ci/pic.service.js.map +1 -1
- package/dist/services/cos/cos.service.js +23 -21
- package/dist/services/cos/cos.service.js.map +1 -1
- package/dist/services/utils.js +3 -14
- package/dist/services/utils.js.map +1 -1
- package/package.json +16 -3
package/README.md
CHANGED
|
@@ -60,6 +60,24 @@
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
```
|
|
64
|
+
也可以简单配置
|
|
65
|
+
```
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"cos-mcp": {
|
|
69
|
+
"command": "npx",
|
|
70
|
+
"args": [
|
|
71
|
+
"cos-mcp",
|
|
72
|
+
"--Region=yourRegion",
|
|
73
|
+
"--Bucket=yourBucket",
|
|
74
|
+
"--SecretId=yourSecretId",
|
|
75
|
+
"--SecretKey=yourSecretKey",
|
|
76
|
+
"--DatasetName=yourDatasetname",
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
63
81
|
```
|
|
64
82
|
|
|
65
83
|
## 使用npm安装
|
|
@@ -69,6 +87,9 @@ npm install -g cos-mcp
|
|
|
69
87
|
|
|
70
88
|
// 运行开启sse模式
|
|
71
89
|
cos-mcp --cos-config='{"Region":"yourRegion","Bucket":"BucketName-APPID","SecretId":"yourSecretId","SecretKey":"yourSecretKey","DatasetName":"datasetName"}' --port=3001 --connectType=sse
|
|
90
|
+
// 也可以简单配置
|
|
91
|
+
cos-mcp --Region=yourRegion --Bucket=yourBucket --SecretId=yourSecretId --SecretKey=yourSecretKey --DatasetName=yourDatasetname --port=3001 --connectType=sse
|
|
92
|
+
|
|
72
93
|
|
|
73
94
|
// 参数说明:
|
|
74
95
|
// connectType 代表连接方式,可以是stdio (本地) 或 sse (远程)
|
|
@@ -97,7 +118,7 @@ cos-mcp --cos-config='{"Region":"yourRegion","Bucket":"BucketName-APPID","Secret
|
|
|
97
118
|
---
|
|
98
119
|
⚠️请注意!
|
|
99
120
|
|
|
100
|
-
1. 如果全局安装后直接使用cos-mcp
|
|
121
|
+
1. 如果全局安装后直接使用cos-mcp不行,可能是全局变量有问题,可以使用拆分变量或使用 npx的方式来启动
|
|
101
122
|
|
|
102
123
|
```
|
|
103
124
|
npm install -g cos-mcp
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { generateOutPutFileId, generateCode } from '../services/utils.js';
|
|
2
|
+
describe('utils.ts functions', () => {
|
|
3
|
+
describe('generateOutPutFileId function', () => {
|
|
4
|
+
it('should generate a valid output file ID', () => {
|
|
5
|
+
const objectKey = 'example.txt';
|
|
6
|
+
const result = generateOutPutFileId(objectKey);
|
|
7
|
+
expect(result).toContain('example');
|
|
8
|
+
expect(result).toMatch(/\d{8}_example/); // 日期格式验证
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
describe('generateCode function', () => {
|
|
12
|
+
it('should generate a code of specified length', () => {
|
|
13
|
+
const length = 8;
|
|
14
|
+
const code = generateCode(length);
|
|
15
|
+
expect(code).toHaveLength(length);
|
|
16
|
+
});
|
|
17
|
+
it('should generate a secure random code', () => {
|
|
18
|
+
const code = generateCode(6, true);
|
|
19
|
+
expect(code).toMatch(/^[A-Za-z0-9]+$/);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=utils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE1E,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC7C,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,SAAS,GAAG,aAAa,CAAC;YAChC,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,MAAM,GAAG,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { StdioServerTransport } from
|
|
3
|
-
import { createCosMcpServer, startWithSSE } from
|
|
4
|
-
import { config } from
|
|
5
|
-
import { resolve } from
|
|
6
|
-
import yargs from
|
|
7
|
-
import { hideBin } from
|
|
8
|
-
import { z } from
|
|
9
|
-
import { maskSecret } from
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createCosMcpServer, startWithSSE } from './server.js';
|
|
4
|
+
import { config } from 'dotenv';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import yargs from 'yargs';
|
|
7
|
+
import { hideBin } from 'yargs/helpers';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { maskSecret } from './server.js';
|
|
10
10
|
// COS配置验证Schema
|
|
11
11
|
export const cosConfigSchema = z.object({
|
|
12
12
|
Region: z.string(),
|
|
13
13
|
SecretId: z.string(),
|
|
14
14
|
SecretKey: z.string(),
|
|
15
15
|
Bucket: z.string(),
|
|
16
|
-
DatasetName: z.string().optional()
|
|
16
|
+
DatasetName: z.string().optional(),
|
|
17
17
|
});
|
|
18
18
|
// 加载当前工作目录中的.env文件
|
|
19
|
-
config({ path: resolve(process.cwd(),
|
|
19
|
+
config({ path: resolve(process.cwd(), '.env') });
|
|
20
20
|
function getConfig() {
|
|
21
21
|
const argv = yargs(hideBin(process.argv))
|
|
22
22
|
.options({
|
|
23
|
-
|
|
24
|
-
type:
|
|
25
|
-
description:
|
|
23
|
+
'cos-config': {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'COS配置的JSON',
|
|
26
26
|
},
|
|
27
27
|
port: {
|
|
28
|
-
type:
|
|
29
|
-
description:
|
|
28
|
+
type: 'number',
|
|
29
|
+
description: 'server运行端口',
|
|
30
30
|
},
|
|
31
31
|
connectType: {
|
|
32
|
-
type:
|
|
33
|
-
description:
|
|
34
|
-
choices: [
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: '连接类型',
|
|
34
|
+
choices: ['stdio', 'sse'],
|
|
35
35
|
},
|
|
36
36
|
})
|
|
37
37
|
.help()
|
|
38
|
-
.version(
|
|
38
|
+
.version('0.0.1')
|
|
39
39
|
.parseSync();
|
|
40
40
|
// 首先从命令行中获取
|
|
41
41
|
let config = {
|
|
42
|
+
connectType: 'stdio',
|
|
42
43
|
port: 3001,
|
|
43
44
|
cosConfig: {
|
|
44
|
-
Region:
|
|
45
|
-
SecretId:
|
|
46
|
-
SecretKey:
|
|
47
|
-
Bucket:
|
|
48
|
-
DatasetName:
|
|
45
|
+
Region: '',
|
|
46
|
+
SecretId: '',
|
|
47
|
+
SecretKey: '',
|
|
48
|
+
Bucket: '',
|
|
49
|
+
DatasetName: '',
|
|
49
50
|
},
|
|
50
|
-
connectType: "stdio",
|
|
51
51
|
};
|
|
52
52
|
// 必要参数
|
|
53
53
|
// SecretId SecretKey bucket region connectType
|
|
@@ -64,29 +64,42 @@ function getConfig() {
|
|
|
64
64
|
else if (process.env.connectType) {
|
|
65
65
|
config.connectType = process.env.connectType;
|
|
66
66
|
}
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
// 从获取cos配置, 复杂获取
|
|
68
|
+
if (argv['cos-config']) {
|
|
69
|
+
config.cosConfig = JSON.parse(argv['cos-config']);
|
|
69
70
|
}
|
|
70
71
|
else if (process.env.cosConfig) {
|
|
71
72
|
config.cosConfig = JSON.parse(process.env.cosConfig);
|
|
72
73
|
}
|
|
74
|
+
// 从环境变量中获取cos配置, 简单获取
|
|
75
|
+
['Region', 'SecretId', 'SecretKey', 'Bucket', 'DatasetName'].forEach((item) => {
|
|
76
|
+
if (argv[item]) {
|
|
77
|
+
config.cosConfig[item] = argv[item];
|
|
78
|
+
}
|
|
79
|
+
else if (process.env[item]) {
|
|
80
|
+
config.cosConfig[item] = process.env[item];
|
|
81
|
+
}
|
|
82
|
+
});
|
|
73
83
|
// 验证配置
|
|
74
|
-
if (!config.cosConfig.SecretId ||
|
|
75
|
-
|
|
84
|
+
if (!config.cosConfig.SecretId ||
|
|
85
|
+
!config.cosConfig.SecretKey ||
|
|
86
|
+
!config.cosConfig.Bucket ||
|
|
87
|
+
!config.cosConfig.Region) {
|
|
88
|
+
console.error('COS配置不全。请使用cos-config参数指定COS配置');
|
|
76
89
|
}
|
|
77
|
-
if (config.connectType !==
|
|
78
|
-
console.log(
|
|
90
|
+
if (config.connectType !== 'stdio') {
|
|
91
|
+
console.log('\nCOS配置信息:');
|
|
79
92
|
console.log(`- 端口: ${config.port}`);
|
|
80
93
|
console.log(`- 运行模式: ${config.connectType}`);
|
|
81
|
-
console.log(
|
|
94
|
+
console.log('- cos配置:');
|
|
82
95
|
Object.keys(config.cosConfig).forEach((key) => {
|
|
83
96
|
let value = config.cosConfig[key];
|
|
84
|
-
if (key ===
|
|
97
|
+
if (key === 'SecretId' || key === 'SecretKey') {
|
|
85
98
|
value = maskSecret(value);
|
|
86
99
|
}
|
|
87
100
|
console.log(` - ${key}: ${value}`);
|
|
88
101
|
});
|
|
89
|
-
console.log(
|
|
102
|
+
console.log('\n');
|
|
90
103
|
}
|
|
91
104
|
return config;
|
|
92
105
|
}
|
|
@@ -94,7 +107,7 @@ async function startCOServer() {
|
|
|
94
107
|
const config = getConfig();
|
|
95
108
|
// 创建COS MCP
|
|
96
109
|
const server = createCosMcpServer(config);
|
|
97
|
-
if (config.connectType ===
|
|
110
|
+
if (config.connectType === 'stdio') {
|
|
98
111
|
// 使用stdio:标准输入输出进行通信
|
|
99
112
|
const transport = new StdioServerTransport();
|
|
100
113
|
await server.connect(transport);
|
|
@@ -104,7 +117,7 @@ async function startCOServer() {
|
|
|
104
117
|
startWithSSE(server, config.port || 3001);
|
|
105
118
|
}
|
|
106
119
|
startCOServer().catch((error) => {
|
|
107
|
-
console.error(
|
|
120
|
+
console.error('启动失败', error);
|
|
108
121
|
process.exit(1);
|
|
109
122
|
});
|
|
110
123
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import express from
|
|
2
|
-
import { SSEServerTransport } from
|
|
3
|
-
import { McpServer } from
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { CosService } from
|
|
7
|
-
import { CIPicService } from
|
|
8
|
-
import { CIMediaService } from
|
|
9
|
-
import { CIAIService } from
|
|
10
|
-
import { CIMateInsightService } from
|
|
11
|
-
import { CIDocService } from
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import COS from 'cos-nodejs-sdk-v5';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { CosService } from './services/cos/cos.service.js';
|
|
7
|
+
import { CIPicService } from './services/ci/pic.service.js';
|
|
8
|
+
import { CIMediaService } from './services/ci/media.service.js';
|
|
9
|
+
import { CIAIService } from './services/ci/ai.service.js';
|
|
10
|
+
import { CIMateInsightService } from './services/ci/mateInsight.service.js';
|
|
11
|
+
import { CIDocService } from './services/ci/doc.service.js';
|
|
12
12
|
export function maskSecret(secret) {
|
|
13
|
+
secret = String(secret);
|
|
13
14
|
if (secret.length <= 4)
|
|
14
|
-
return
|
|
15
|
+
return '****';
|
|
15
16
|
return `${secret.substring(0, 4)}****${secret.slice(-4)}`;
|
|
16
17
|
}
|
|
17
18
|
export const Logger = {
|
|
@@ -22,11 +23,11 @@ export const Logger = {
|
|
|
22
23
|
console.error(...args);
|
|
23
24
|
},
|
|
24
25
|
};
|
|
25
|
-
const USER_AGENT =
|
|
26
|
+
const USER_AGENT = 'modelcontextprotocol/servers/cos';
|
|
26
27
|
export function createCosMcpServer(config) {
|
|
27
28
|
const cos = new COS({
|
|
28
|
-
SecretId: config.cosConfig?.SecretId ||
|
|
29
|
-
SecretKey: config.cosConfig?.SecretKey ||
|
|
29
|
+
SecretId: config.cosConfig?.SecretId || '',
|
|
30
|
+
SecretKey: config.cosConfig?.SecretKey || '',
|
|
30
31
|
UserAgent: USER_AGENT,
|
|
31
32
|
});
|
|
32
33
|
const bucket = config.cosConfig.Bucket;
|
|
@@ -36,11 +37,11 @@ export function createCosMcpServer(config) {
|
|
|
36
37
|
const CIPicInstance = new CIPicService(bucket, region, cos);
|
|
37
38
|
const CIMediaInstance = new CIMediaService(bucket, region, cos);
|
|
38
39
|
const CIAIInstance = new CIAIService(bucket, region, cos);
|
|
39
|
-
const CIMateInsightInstance = new CIMateInsightService(bucket, region, datasetName ||
|
|
40
|
+
const CIMateInsightInstance = new CIMateInsightService(bucket, region, datasetName || '', cos);
|
|
40
41
|
const CIDocInstance = new CIDocService(bucket, region, cos);
|
|
41
42
|
const server = new McpServer({
|
|
42
|
-
name:
|
|
43
|
-
version:
|
|
43
|
+
name: 'COS MCP Server',
|
|
44
|
+
version: '1.0.0',
|
|
44
45
|
}, {
|
|
45
46
|
capabilities: {
|
|
46
47
|
tools: { listChanged: true },
|
|
@@ -49,7 +50,7 @@ export function createCosMcpServer(config) {
|
|
|
49
50
|
// logging: {},
|
|
50
51
|
},
|
|
51
52
|
});
|
|
52
|
-
server.tool(
|
|
53
|
+
server.tool('getCosConfig', '获取COS配置, 腾讯云配置', {}, async () => {
|
|
53
54
|
if (config.cosConfig) {
|
|
54
55
|
config.cosConfig.SecretId = maskSecret(config.cosConfig.SecretId);
|
|
55
56
|
config.cosConfig.SecretKey = maskSecret(config.cosConfig.SecretKey);
|
|
@@ -57,17 +58,20 @@ export function createCosMcpServer(config) {
|
|
|
57
58
|
return {
|
|
58
59
|
content: [
|
|
59
60
|
{
|
|
60
|
-
type:
|
|
61
|
+
type: 'text',
|
|
61
62
|
text: JSON.stringify(config, null, 2),
|
|
62
63
|
},
|
|
63
64
|
],
|
|
64
65
|
};
|
|
65
66
|
});
|
|
66
|
-
server.tool(
|
|
67
|
-
filePath: z.string().describe(
|
|
68
|
-
fileName: z.string().optional().describe(
|
|
69
|
-
targetDir: z
|
|
70
|
-
|
|
67
|
+
server.tool('putObject', '上传文件到存储桶', {
|
|
68
|
+
filePath: z.string().describe('文件路径 (包含文件名)'),
|
|
69
|
+
fileName: z.string().optional().describe('文件名 (存在存储桶里的名称)'),
|
|
70
|
+
targetDir: z
|
|
71
|
+
.string()
|
|
72
|
+
.optional()
|
|
73
|
+
.describe('目标目录 (存在存储桶的哪个目录)'),
|
|
74
|
+
}, async ({ fileName, filePath, targetDir }) => {
|
|
71
75
|
const res = await COSInstance.uploadFile({
|
|
72
76
|
fileName,
|
|
73
77
|
filePath,
|
|
@@ -76,35 +80,35 @@ export function createCosMcpServer(config) {
|
|
|
76
80
|
return {
|
|
77
81
|
content: [
|
|
78
82
|
{
|
|
79
|
-
type:
|
|
83
|
+
type: 'text',
|
|
80
84
|
text: JSON.stringify(res.data, null, 2),
|
|
81
85
|
isError: res.isSuccess ? false : true,
|
|
82
86
|
},
|
|
83
87
|
],
|
|
84
88
|
};
|
|
85
89
|
});
|
|
86
|
-
server.tool(
|
|
87
|
-
objectKey: z.string().describe(
|
|
88
|
-
}, async ({ objectKey =
|
|
90
|
+
server.tool('getObject', '下载存储桶内的文件', {
|
|
91
|
+
objectKey: z.string().describe('文件的路径'),
|
|
92
|
+
}, async ({ objectKey = '/' }) => {
|
|
89
93
|
const res = await COSInstance.getObject(objectKey);
|
|
90
94
|
return {
|
|
91
95
|
content: [
|
|
92
96
|
{
|
|
93
|
-
type:
|
|
97
|
+
type: 'text',
|
|
94
98
|
text: JSON.stringify(res.data, null, 2),
|
|
95
99
|
isError: res.isSuccess ? false : true,
|
|
96
100
|
},
|
|
97
101
|
],
|
|
98
102
|
};
|
|
99
103
|
});
|
|
100
|
-
server.tool(
|
|
101
|
-
Prefix: z.string().optional().describe(
|
|
102
|
-
}, async ({ Prefix =
|
|
104
|
+
server.tool('getBucket', '查询存储桶内的文件列表', {
|
|
105
|
+
Prefix: z.string().optional().describe('文件列表的路径前缀,默认根路径'),
|
|
106
|
+
}, async ({ Prefix = '' }) => {
|
|
103
107
|
const res = await COSInstance.getBucket(Prefix);
|
|
104
108
|
return {
|
|
105
109
|
content: [
|
|
106
110
|
{
|
|
107
|
-
type:
|
|
111
|
+
type: 'text',
|
|
108
112
|
text: JSON.stringify(res.data, null, 2),
|
|
109
113
|
isError: res.isSuccess ? false : true,
|
|
110
114
|
},
|
|
@@ -112,87 +116,91 @@ export function createCosMcpServer(config) {
|
|
|
112
116
|
};
|
|
113
117
|
});
|
|
114
118
|
// --CI--
|
|
115
|
-
server.tool(
|
|
116
|
-
objectKey: z.string().describe(
|
|
119
|
+
server.tool('imageInfo', '图片处理-获取图片信息', {
|
|
120
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
117
121
|
}, async ({ objectKey }) => {
|
|
118
122
|
const res = await CIPicInstance.imageInfo(objectKey);
|
|
119
123
|
return {
|
|
120
124
|
content: [
|
|
121
125
|
{
|
|
122
|
-
type:
|
|
126
|
+
type: 'text',
|
|
123
127
|
text: JSON.stringify(res.data, null, 2),
|
|
124
128
|
isError: res.isSuccess ? false : true,
|
|
125
129
|
},
|
|
126
130
|
],
|
|
127
131
|
};
|
|
128
132
|
});
|
|
129
|
-
server.tool(
|
|
130
|
-
objectKey: z.string().describe(
|
|
133
|
+
server.tool('assessQuality', '图片处理-图片质量评估', {
|
|
134
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
131
135
|
}, async ({ objectKey }) => {
|
|
132
136
|
const res = await CIAIInstance.assessQuality(objectKey);
|
|
133
137
|
return {
|
|
134
138
|
content: [
|
|
135
139
|
{
|
|
136
|
-
type:
|
|
140
|
+
type: 'text',
|
|
137
141
|
text: JSON.stringify(res.data, null, 2),
|
|
138
142
|
isError: res.isSuccess ? false : true,
|
|
139
143
|
},
|
|
140
144
|
],
|
|
141
145
|
};
|
|
142
146
|
});
|
|
143
|
-
server.tool(
|
|
144
|
-
objectKey: z.string().describe(
|
|
147
|
+
server.tool('aiSuperResolution', '图片处理-超分辨率', {
|
|
148
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
145
149
|
}, async ({ objectKey }) => {
|
|
146
150
|
const res = await CIAIInstance.aiSuperResolution(objectKey);
|
|
147
151
|
return {
|
|
148
152
|
content: [
|
|
149
153
|
{
|
|
150
|
-
type:
|
|
154
|
+
type: 'text',
|
|
151
155
|
text: JSON.stringify(res.data, null, 2),
|
|
152
156
|
isError: res.isSuccess ? false : true,
|
|
153
157
|
},
|
|
154
158
|
],
|
|
155
159
|
};
|
|
156
160
|
});
|
|
157
|
-
server.tool(
|
|
158
|
-
objectKey: z.string().describe(
|
|
159
|
-
width: z.string().optional().describe(
|
|
160
|
-
height: z.string().optional().describe(
|
|
161
|
-
}, async ({ objectKey, width =
|
|
161
|
+
server.tool('aiPicMatting', '图片处理-抠图', {
|
|
162
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
163
|
+
width: z.string().optional().describe('宽度'),
|
|
164
|
+
height: z.string().optional().describe('高度'),
|
|
165
|
+
}, async ({ objectKey, width = '5', height = '5' }) => {
|
|
162
166
|
const res = await CIAIInstance.aiPicMatting(objectKey, width, height);
|
|
163
167
|
return {
|
|
164
168
|
content: [
|
|
165
169
|
{
|
|
166
|
-
type:
|
|
170
|
+
type: 'text',
|
|
167
171
|
text: JSON.stringify(res.data, null, 2),
|
|
168
172
|
isError: res.isSuccess ? false : true,
|
|
169
173
|
},
|
|
170
174
|
],
|
|
171
175
|
};
|
|
172
176
|
});
|
|
173
|
-
server.tool(
|
|
174
|
-
objectKey: z
|
|
177
|
+
server.tool('aiQrcode', '图片处理-二维码识别-识别存储桶内二维码图片内容', {
|
|
178
|
+
objectKey: z
|
|
179
|
+
.string()
|
|
180
|
+
.describe('COS对象键(完整路径)示例: images/qrcode.jpg'),
|
|
175
181
|
}, async ({ objectKey }) => {
|
|
176
182
|
const res = await CIAIInstance.aiQrcode(objectKey);
|
|
177
183
|
return {
|
|
178
184
|
content: [
|
|
179
185
|
{
|
|
180
|
-
type:
|
|
186
|
+
type: 'text',
|
|
181
187
|
text: JSON.stringify(res.data, null, 2),
|
|
182
188
|
isError: res.isSuccess ? false : true,
|
|
183
189
|
},
|
|
184
190
|
],
|
|
185
191
|
};
|
|
186
192
|
});
|
|
187
|
-
server.tool(
|
|
188
|
-
objectKey: z
|
|
189
|
-
|
|
193
|
+
server.tool('waterMarkFont', '生成带文字水印的图片', {
|
|
194
|
+
objectKey: z
|
|
195
|
+
.string()
|
|
196
|
+
.describe('COS对象键(完整路径)示例: images/photo.jpg'),
|
|
197
|
+
text: z.string().describe('水印文字内容(支持中文)').default('test'),
|
|
190
198
|
}, async ({ objectKey, text }) => {
|
|
191
199
|
const res = await CIPicInstance.waterMarkFont({ objectKey, text });
|
|
192
200
|
return {
|
|
193
201
|
content: [
|
|
194
202
|
{
|
|
195
|
-
type:
|
|
203
|
+
type: 'text',
|
|
196
204
|
text: JSON.stringify(res.data, null, 2),
|
|
197
205
|
isError: res.isSuccess ? false : true,
|
|
198
206
|
},
|
|
@@ -200,28 +208,30 @@ export function createCosMcpServer(config) {
|
|
|
200
208
|
};
|
|
201
209
|
});
|
|
202
210
|
// --MEDIA--
|
|
203
|
-
server.tool(
|
|
204
|
-
objectKey: z.string().describe(
|
|
211
|
+
server.tool('createMediaSmartCoverJob', '创建媒体智能封面任务', {
|
|
212
|
+
objectKey: z.string().describe('对象在存储桶里的路径'),
|
|
205
213
|
}, async ({ objectKey }) => {
|
|
206
214
|
const res = await CIMediaInstance.createMediaSmartCoverJob(objectKey);
|
|
207
215
|
return {
|
|
208
216
|
content: [
|
|
209
217
|
{
|
|
210
|
-
type:
|
|
218
|
+
type: 'text',
|
|
211
219
|
text: JSON.stringify(res.data, null, 2),
|
|
212
220
|
isError: res.isSuccess ? false : true,
|
|
213
221
|
},
|
|
214
222
|
],
|
|
215
223
|
};
|
|
216
224
|
});
|
|
217
|
-
server.tool(
|
|
218
|
-
jobId: z
|
|
225
|
+
server.tool('describeMediaJob', '根据 jobid 查询指定的媒体智能封面任务结果', {
|
|
226
|
+
jobId: z
|
|
227
|
+
.string()
|
|
228
|
+
.describe('要查询的任务ID,可通过提交智能封面任务的响应中获取。'),
|
|
219
229
|
}, async ({ jobId }) => {
|
|
220
230
|
const res = await CIMediaInstance.describeMediaJob(jobId);
|
|
221
231
|
return {
|
|
222
232
|
content: [
|
|
223
233
|
{
|
|
224
|
-
type:
|
|
234
|
+
type: 'text',
|
|
225
235
|
text: JSON.stringify(res.data, null, 2),
|
|
226
236
|
isError: res.isSuccess ? false : true,
|
|
227
237
|
},
|
|
@@ -229,28 +239,28 @@ export function createCosMcpServer(config) {
|
|
|
229
239
|
};
|
|
230
240
|
});
|
|
231
241
|
// --METAINSIGHT--
|
|
232
|
-
server.tool(
|
|
233
|
-
uri: z.string().describe(
|
|
242
|
+
server.tool('imageSearchPic', '根据输入的图片,从数据集中检索出与输入的图片内容相似的图片', {
|
|
243
|
+
uri: z.string().describe('图片地址'),
|
|
234
244
|
}, async ({ uri }) => {
|
|
235
245
|
const res = await CIMateInsightInstance.imageSearchPic({ uri });
|
|
236
246
|
return {
|
|
237
247
|
content: [
|
|
238
248
|
{
|
|
239
|
-
type:
|
|
249
|
+
type: 'text',
|
|
240
250
|
text: JSON.stringify(res.data, null, 2),
|
|
241
251
|
isError: res.isSuccess ? false : true,
|
|
242
252
|
},
|
|
243
253
|
],
|
|
244
254
|
};
|
|
245
255
|
});
|
|
246
|
-
server.tool(
|
|
247
|
-
text: z.string().describe(
|
|
256
|
+
server.tool('imageSearchText', '根据输入的文本内容,从数据集中检索出与输入的文本内容相符的图片', {
|
|
257
|
+
text: z.string().describe('检索的文本'),
|
|
248
258
|
}, async ({ text }) => {
|
|
249
259
|
const res = await CIMateInsightInstance.imageSearchText({ text });
|
|
250
260
|
return {
|
|
251
261
|
content: [
|
|
252
262
|
{
|
|
253
|
-
type:
|
|
263
|
+
type: 'text',
|
|
254
264
|
text: JSON.stringify(res.data, null, 2),
|
|
255
265
|
isError: res.isSuccess ? false : true,
|
|
256
266
|
},
|
|
@@ -258,28 +268,30 @@ export function createCosMcpServer(config) {
|
|
|
258
268
|
};
|
|
259
269
|
});
|
|
260
270
|
// --DOCMENT--
|
|
261
|
-
server.tool(
|
|
262
|
-
objectKey: z.string().describe(
|
|
271
|
+
server.tool('createDocToPdfJob', '创建文档转 pdf 处理任务', {
|
|
272
|
+
objectKey: z.string().describe('对象在存储桶里的路径'),
|
|
263
273
|
}, async ({ objectKey }) => {
|
|
264
274
|
const res = await CIDocInstance.createDocToPdfJobs(objectKey);
|
|
265
275
|
return {
|
|
266
276
|
content: [
|
|
267
277
|
{
|
|
268
|
-
type:
|
|
278
|
+
type: 'text',
|
|
269
279
|
text: JSON.stringify(res.data, null, 2),
|
|
270
280
|
isError: res.isSuccess ? false : true,
|
|
271
281
|
},
|
|
272
282
|
],
|
|
273
283
|
};
|
|
274
284
|
});
|
|
275
|
-
server.tool(
|
|
276
|
-
jobId: z
|
|
285
|
+
server.tool('describeDocProcessJob', '根据 jobid 查询指定的文档转码任务结果', {
|
|
286
|
+
jobId: z
|
|
287
|
+
.string()
|
|
288
|
+
.describe('要查询的任务ID,可通过提交文档任务的响应中获取。'),
|
|
277
289
|
}, async ({ jobId }) => {
|
|
278
290
|
const res = await CIDocInstance.describeDocProcessJob(jobId);
|
|
279
291
|
return {
|
|
280
292
|
content: [
|
|
281
293
|
{
|
|
282
|
-
type:
|
|
294
|
+
type: 'text',
|
|
283
295
|
text: JSON.stringify(res.data, null, 2),
|
|
284
296
|
isError: res.isSuccess ? false : true,
|
|
285
297
|
},
|
|
@@ -293,22 +305,22 @@ export function startWithSSE(server, port = 3001) {
|
|
|
293
305
|
// to support multiple simultaneous connections we have a lookup object from
|
|
294
306
|
// sessionId to transport
|
|
295
307
|
const transports = {};
|
|
296
|
-
app.get(
|
|
297
|
-
const transport = new SSEServerTransport(
|
|
308
|
+
app.get('/sse', async (_, res) => {
|
|
309
|
+
const transport = new SSEServerTransport('/messages', res);
|
|
298
310
|
transports[transport.sessionId] = transport;
|
|
299
|
-
res.on(
|
|
311
|
+
res.on('close', () => {
|
|
300
312
|
delete transports[transport.sessionId];
|
|
301
313
|
});
|
|
302
314
|
await server.connect(transport);
|
|
303
315
|
});
|
|
304
|
-
app.post(
|
|
316
|
+
app.post('/messages', async (req, res) => {
|
|
305
317
|
const sessionId = req.query.sessionId;
|
|
306
318
|
const transport = transports[sessionId];
|
|
307
319
|
if (transport) {
|
|
308
320
|
await transport.handlePostMessage(req, res);
|
|
309
321
|
}
|
|
310
322
|
else {
|
|
311
|
-
res.status(400).send(
|
|
323
|
+
res.status(400).send('No transport found for sessionId');
|
|
312
324
|
}
|
|
313
325
|
});
|
|
314
326
|
app.listen(port, () => {
|