cos-mcp 1.0.6 → 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 +92 -97
- package/dist/server.js.map +1 -1
- package/dist/services/ci/ai.service.js +32 -34
- 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 +14 -17
- 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 +13 -10
- 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,10 +23,12 @@ export const Logger = {
|
|
|
22
23
|
console.error(...args);
|
|
23
24
|
},
|
|
24
25
|
};
|
|
26
|
+
const USER_AGENT = 'modelcontextprotocol/servers/cos';
|
|
25
27
|
export function createCosMcpServer(config) {
|
|
26
28
|
const cos = new COS({
|
|
27
|
-
SecretId: config.cosConfig?.SecretId ||
|
|
28
|
-
SecretKey: config.cosConfig?.SecretKey ||
|
|
29
|
+
SecretId: config.cosConfig?.SecretId || '',
|
|
30
|
+
SecretKey: config.cosConfig?.SecretKey || '',
|
|
31
|
+
UserAgent: USER_AGENT,
|
|
29
32
|
});
|
|
30
33
|
const bucket = config.cosConfig.Bucket;
|
|
31
34
|
const region = config.cosConfig.Region;
|
|
@@ -34,11 +37,11 @@ export function createCosMcpServer(config) {
|
|
|
34
37
|
const CIPicInstance = new CIPicService(bucket, region, cos);
|
|
35
38
|
const CIMediaInstance = new CIMediaService(bucket, region, cos);
|
|
36
39
|
const CIAIInstance = new CIAIService(bucket, region, cos);
|
|
37
|
-
const CIMateInsightInstance = new CIMateInsightService(bucket, region, datasetName ||
|
|
40
|
+
const CIMateInsightInstance = new CIMateInsightService(bucket, region, datasetName || '', cos);
|
|
38
41
|
const CIDocInstance = new CIDocService(bucket, region, cos);
|
|
39
42
|
const server = new McpServer({
|
|
40
|
-
name:
|
|
41
|
-
version:
|
|
43
|
+
name: 'COS MCP Server',
|
|
44
|
+
version: '1.0.0',
|
|
42
45
|
}, {
|
|
43
46
|
capabilities: {
|
|
44
47
|
tools: { listChanged: true },
|
|
@@ -47,7 +50,7 @@ export function createCosMcpServer(config) {
|
|
|
47
50
|
// logging: {},
|
|
48
51
|
},
|
|
49
52
|
});
|
|
50
|
-
server.tool(
|
|
53
|
+
server.tool('getCosConfig', '获取COS配置, 腾讯云配置', {}, async () => {
|
|
51
54
|
if (config.cosConfig) {
|
|
52
55
|
config.cosConfig.SecretId = maskSecret(config.cosConfig.SecretId);
|
|
53
56
|
config.cosConfig.SecretKey = maskSecret(config.cosConfig.SecretKey);
|
|
@@ -55,17 +58,20 @@ export function createCosMcpServer(config) {
|
|
|
55
58
|
return {
|
|
56
59
|
content: [
|
|
57
60
|
{
|
|
58
|
-
type:
|
|
61
|
+
type: 'text',
|
|
59
62
|
text: JSON.stringify(config, null, 2),
|
|
60
63
|
},
|
|
61
64
|
],
|
|
62
65
|
};
|
|
63
66
|
});
|
|
64
|
-
server.tool(
|
|
65
|
-
filePath: z.string().describe(
|
|
66
|
-
fileName: z.string().optional().describe(
|
|
67
|
-
targetDir: z
|
|
68
|
-
|
|
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 }) => {
|
|
69
75
|
const res = await COSInstance.uploadFile({
|
|
70
76
|
fileName,
|
|
71
77
|
filePath,
|
|
@@ -74,142 +80,127 @@ export function createCosMcpServer(config) {
|
|
|
74
80
|
return {
|
|
75
81
|
content: [
|
|
76
82
|
{
|
|
77
|
-
type:
|
|
83
|
+
type: 'text',
|
|
78
84
|
text: JSON.stringify(res.data, null, 2),
|
|
79
85
|
isError: res.isSuccess ? false : true,
|
|
80
86
|
},
|
|
81
87
|
],
|
|
82
88
|
};
|
|
83
89
|
});
|
|
84
|
-
server.tool(
|
|
85
|
-
objectKey: z.string().describe(
|
|
86
|
-
}, async ({ objectKey =
|
|
90
|
+
server.tool('getObject', '下载存储桶内的文件', {
|
|
91
|
+
objectKey: z.string().describe('文件的路径'),
|
|
92
|
+
}, async ({ objectKey = '/' }) => {
|
|
87
93
|
const res = await COSInstance.getObject(objectKey);
|
|
88
94
|
return {
|
|
89
95
|
content: [
|
|
90
96
|
{
|
|
91
|
-
type:
|
|
97
|
+
type: 'text',
|
|
92
98
|
text: JSON.stringify(res.data, null, 2),
|
|
93
99
|
isError: res.isSuccess ? false : true,
|
|
94
100
|
},
|
|
95
101
|
],
|
|
96
102
|
};
|
|
97
103
|
});
|
|
98
|
-
server.tool(
|
|
99
|
-
Prefix: z.string().optional().describe(
|
|
100
|
-
}, async ({ Prefix =
|
|
104
|
+
server.tool('getBucket', '查询存储桶内的文件列表', {
|
|
105
|
+
Prefix: z.string().optional().describe('文件列表的路径前缀,默认根路径'),
|
|
106
|
+
}, async ({ Prefix = '' }) => {
|
|
101
107
|
const res = await COSInstance.getBucket(Prefix);
|
|
102
108
|
return {
|
|
103
109
|
content: [
|
|
104
110
|
{
|
|
105
|
-
type:
|
|
111
|
+
type: 'text',
|
|
106
112
|
text: JSON.stringify(res.data, null, 2),
|
|
107
113
|
isError: res.isSuccess ? false : true,
|
|
108
114
|
},
|
|
109
115
|
],
|
|
110
116
|
};
|
|
111
117
|
});
|
|
112
|
-
// server.tool(
|
|
113
|
-
// "getObjectUrl",
|
|
114
|
-
// "私有读, 获取带签名的 url",
|
|
115
|
-
// {
|
|
116
|
-
// ObjectKey: z.string().optional().describe("文件在存储桶里的路径"),
|
|
117
|
-
// },
|
|
118
|
-
// async ({ ObjectKey = "" }) => {
|
|
119
|
-
// const res = await COSInstance.getObjectUrl(ObjectKey);
|
|
120
|
-
// return {
|
|
121
|
-
// content: [
|
|
122
|
-
// {
|
|
123
|
-
// type: "text",
|
|
124
|
-
// text: JSON.stringify(res.data, null, 2),
|
|
125
|
-
// isError: res.isSuccess ? false : true,
|
|
126
|
-
// },
|
|
127
|
-
// ],
|
|
128
|
-
// };
|
|
129
|
-
// }
|
|
130
|
-
// );
|
|
131
118
|
// --CI--
|
|
132
|
-
server.tool(
|
|
133
|
-
objectKey: z.string().describe(
|
|
119
|
+
server.tool('imageInfo', '图片处理-获取图片信息', {
|
|
120
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
134
121
|
}, async ({ objectKey }) => {
|
|
135
122
|
const res = await CIPicInstance.imageInfo(objectKey);
|
|
136
123
|
return {
|
|
137
124
|
content: [
|
|
138
125
|
{
|
|
139
|
-
type:
|
|
126
|
+
type: 'text',
|
|
140
127
|
text: JSON.stringify(res.data, null, 2),
|
|
141
128
|
isError: res.isSuccess ? false : true,
|
|
142
129
|
},
|
|
143
130
|
],
|
|
144
131
|
};
|
|
145
132
|
});
|
|
146
|
-
server.tool(
|
|
147
|
-
objectKey: z.string().describe(
|
|
133
|
+
server.tool('assessQuality', '图片处理-图片质量评估', {
|
|
134
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
148
135
|
}, async ({ objectKey }) => {
|
|
149
136
|
const res = await CIAIInstance.assessQuality(objectKey);
|
|
150
137
|
return {
|
|
151
138
|
content: [
|
|
152
139
|
{
|
|
153
|
-
type:
|
|
140
|
+
type: 'text',
|
|
154
141
|
text: JSON.stringify(res.data, null, 2),
|
|
155
142
|
isError: res.isSuccess ? false : true,
|
|
156
143
|
},
|
|
157
144
|
],
|
|
158
145
|
};
|
|
159
146
|
});
|
|
160
|
-
server.tool(
|
|
161
|
-
objectKey: z.string().describe(
|
|
147
|
+
server.tool('aiSuperResolution', '图片处理-超分辨率', {
|
|
148
|
+
objectKey: z.string().describe('图片在存储桶里的路径'),
|
|
162
149
|
}, async ({ objectKey }) => {
|
|
163
150
|
const res = await CIAIInstance.aiSuperResolution(objectKey);
|
|
164
151
|
return {
|
|
165
152
|
content: [
|
|
166
153
|
{
|
|
167
|
-
type:
|
|
154
|
+
type: 'text',
|
|
168
155
|
text: JSON.stringify(res.data, null, 2),
|
|
169
156
|
isError: res.isSuccess ? false : true,
|
|
170
157
|
},
|
|
171
158
|
],
|
|
172
159
|
};
|
|
173
160
|
});
|
|
174
|
-
server.tool(
|
|
175
|
-
objectKey: z.string().describe(
|
|
176
|
-
width: z.string().optional().describe(
|
|
177
|
-
height: z.string().optional().describe(
|
|
178
|
-
}, 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' }) => {
|
|
179
166
|
const res = await CIAIInstance.aiPicMatting(objectKey, width, height);
|
|
180
167
|
return {
|
|
181
168
|
content: [
|
|
182
169
|
{
|
|
183
|
-
type:
|
|
170
|
+
type: 'text',
|
|
184
171
|
text: JSON.stringify(res.data, null, 2),
|
|
185
172
|
isError: res.isSuccess ? false : true,
|
|
186
173
|
},
|
|
187
174
|
],
|
|
188
175
|
};
|
|
189
176
|
});
|
|
190
|
-
server.tool(
|
|
191
|
-
objectKey: z
|
|
177
|
+
server.tool('aiQrcode', '图片处理-二维码识别-识别存储桶内二维码图片内容', {
|
|
178
|
+
objectKey: z
|
|
179
|
+
.string()
|
|
180
|
+
.describe('COS对象键(完整路径)示例: images/qrcode.jpg'),
|
|
192
181
|
}, async ({ objectKey }) => {
|
|
193
182
|
const res = await CIAIInstance.aiQrcode(objectKey);
|
|
194
183
|
return {
|
|
195
184
|
content: [
|
|
196
185
|
{
|
|
197
|
-
type:
|
|
186
|
+
type: 'text',
|
|
198
187
|
text: JSON.stringify(res.data, null, 2),
|
|
199
188
|
isError: res.isSuccess ? false : true,
|
|
200
189
|
},
|
|
201
190
|
],
|
|
202
191
|
};
|
|
203
192
|
});
|
|
204
|
-
server.tool(
|
|
205
|
-
objectKey: z
|
|
206
|
-
|
|
193
|
+
server.tool('waterMarkFont', '生成带文字水印的图片', {
|
|
194
|
+
objectKey: z
|
|
195
|
+
.string()
|
|
196
|
+
.describe('COS对象键(完整路径)示例: images/photo.jpg'),
|
|
197
|
+
text: z.string().describe('水印文字内容(支持中文)').default('test'),
|
|
207
198
|
}, async ({ objectKey, text }) => {
|
|
208
199
|
const res = await CIPicInstance.waterMarkFont({ objectKey, text });
|
|
209
200
|
return {
|
|
210
201
|
content: [
|
|
211
202
|
{
|
|
212
|
-
type:
|
|
203
|
+
type: 'text',
|
|
213
204
|
text: JSON.stringify(res.data, null, 2),
|
|
214
205
|
isError: res.isSuccess ? false : true,
|
|
215
206
|
},
|
|
@@ -217,28 +208,30 @@ export function createCosMcpServer(config) {
|
|
|
217
208
|
};
|
|
218
209
|
});
|
|
219
210
|
// --MEDIA--
|
|
220
|
-
server.tool(
|
|
221
|
-
objectKey: z.string().describe(
|
|
211
|
+
server.tool('createMediaSmartCoverJob', '创建媒体智能封面任务', {
|
|
212
|
+
objectKey: z.string().describe('对象在存储桶里的路径'),
|
|
222
213
|
}, async ({ objectKey }) => {
|
|
223
214
|
const res = await CIMediaInstance.createMediaSmartCoverJob(objectKey);
|
|
224
215
|
return {
|
|
225
216
|
content: [
|
|
226
217
|
{
|
|
227
|
-
type:
|
|
218
|
+
type: 'text',
|
|
228
219
|
text: JSON.stringify(res.data, null, 2),
|
|
229
220
|
isError: res.isSuccess ? false : true,
|
|
230
221
|
},
|
|
231
222
|
],
|
|
232
223
|
};
|
|
233
224
|
});
|
|
234
|
-
server.tool(
|
|
235
|
-
jobId: z
|
|
225
|
+
server.tool('describeMediaJob', '根据 jobid 查询指定的媒体智能封面任务结果', {
|
|
226
|
+
jobId: z
|
|
227
|
+
.string()
|
|
228
|
+
.describe('要查询的任务ID,可通过提交智能封面任务的响应中获取。'),
|
|
236
229
|
}, async ({ jobId }) => {
|
|
237
230
|
const res = await CIMediaInstance.describeMediaJob(jobId);
|
|
238
231
|
return {
|
|
239
232
|
content: [
|
|
240
233
|
{
|
|
241
|
-
type:
|
|
234
|
+
type: 'text',
|
|
242
235
|
text: JSON.stringify(res.data, null, 2),
|
|
243
236
|
isError: res.isSuccess ? false : true,
|
|
244
237
|
},
|
|
@@ -246,28 +239,28 @@ export function createCosMcpServer(config) {
|
|
|
246
239
|
};
|
|
247
240
|
});
|
|
248
241
|
// --METAINSIGHT--
|
|
249
|
-
server.tool(
|
|
250
|
-
uri: z.string().describe(
|
|
242
|
+
server.tool('imageSearchPic', '根据输入的图片,从数据集中检索出与输入的图片内容相似的图片', {
|
|
243
|
+
uri: z.string().describe('图片地址'),
|
|
251
244
|
}, async ({ uri }) => {
|
|
252
245
|
const res = await CIMateInsightInstance.imageSearchPic({ uri });
|
|
253
246
|
return {
|
|
254
247
|
content: [
|
|
255
248
|
{
|
|
256
|
-
type:
|
|
249
|
+
type: 'text',
|
|
257
250
|
text: JSON.stringify(res.data, null, 2),
|
|
258
251
|
isError: res.isSuccess ? false : true,
|
|
259
252
|
},
|
|
260
253
|
],
|
|
261
254
|
};
|
|
262
255
|
});
|
|
263
|
-
server.tool(
|
|
264
|
-
text: z.string().describe(
|
|
256
|
+
server.tool('imageSearchText', '根据输入的文本内容,从数据集中检索出与输入的文本内容相符的图片', {
|
|
257
|
+
text: z.string().describe('检索的文本'),
|
|
265
258
|
}, async ({ text }) => {
|
|
266
259
|
const res = await CIMateInsightInstance.imageSearchText({ text });
|
|
267
260
|
return {
|
|
268
261
|
content: [
|
|
269
262
|
{
|
|
270
|
-
type:
|
|
263
|
+
type: 'text',
|
|
271
264
|
text: JSON.stringify(res.data, null, 2),
|
|
272
265
|
isError: res.isSuccess ? false : true,
|
|
273
266
|
},
|
|
@@ -275,28 +268,30 @@ export function createCosMcpServer(config) {
|
|
|
275
268
|
};
|
|
276
269
|
});
|
|
277
270
|
// --DOCMENT--
|
|
278
|
-
server.tool(
|
|
279
|
-
objectKey: z.string().describe(
|
|
271
|
+
server.tool('createDocToPdfJob', '创建文档转 pdf 处理任务', {
|
|
272
|
+
objectKey: z.string().describe('对象在存储桶里的路径'),
|
|
280
273
|
}, async ({ objectKey }) => {
|
|
281
274
|
const res = await CIDocInstance.createDocToPdfJobs(objectKey);
|
|
282
275
|
return {
|
|
283
276
|
content: [
|
|
284
277
|
{
|
|
285
|
-
type:
|
|
278
|
+
type: 'text',
|
|
286
279
|
text: JSON.stringify(res.data, null, 2),
|
|
287
280
|
isError: res.isSuccess ? false : true,
|
|
288
281
|
},
|
|
289
282
|
],
|
|
290
283
|
};
|
|
291
284
|
});
|
|
292
|
-
server.tool(
|
|
293
|
-
jobId: z
|
|
285
|
+
server.tool('describeDocProcessJob', '根据 jobid 查询指定的文档转码任务结果', {
|
|
286
|
+
jobId: z
|
|
287
|
+
.string()
|
|
288
|
+
.describe('要查询的任务ID,可通过提交文档任务的响应中获取。'),
|
|
294
289
|
}, async ({ jobId }) => {
|
|
295
290
|
const res = await CIDocInstance.describeDocProcessJob(jobId);
|
|
296
291
|
return {
|
|
297
292
|
content: [
|
|
298
293
|
{
|
|
299
|
-
type:
|
|
294
|
+
type: 'text',
|
|
300
295
|
text: JSON.stringify(res.data, null, 2),
|
|
301
296
|
isError: res.isSuccess ? false : true,
|
|
302
297
|
},
|
|
@@ -310,22 +305,22 @@ export function startWithSSE(server, port = 3001) {
|
|
|
310
305
|
// to support multiple simultaneous connections we have a lookup object from
|
|
311
306
|
// sessionId to transport
|
|
312
307
|
const transports = {};
|
|
313
|
-
app.get(
|
|
314
|
-
const transport = new SSEServerTransport(
|
|
308
|
+
app.get('/sse', async (_, res) => {
|
|
309
|
+
const transport = new SSEServerTransport('/messages', res);
|
|
315
310
|
transports[transport.sessionId] = transport;
|
|
316
|
-
res.on(
|
|
311
|
+
res.on('close', () => {
|
|
317
312
|
delete transports[transport.sessionId];
|
|
318
313
|
});
|
|
319
314
|
await server.connect(transport);
|
|
320
315
|
});
|
|
321
|
-
app.post(
|
|
316
|
+
app.post('/messages', async (req, res) => {
|
|
322
317
|
const sessionId = req.query.sessionId;
|
|
323
318
|
const transport = transports[sessionId];
|
|
324
319
|
if (transport) {
|
|
325
320
|
await transport.handlePostMessage(req, res);
|
|
326
321
|
}
|
|
327
322
|
else {
|
|
328
|
-
res.status(400).send(
|
|
323
|
+
res.status(400).send('No transport found for sessionId');
|
|
329
324
|
}
|
|
330
325
|
});
|
|
331
326
|
app.listen(port, () => {
|