dingtalk-mcp 1.0.15 → 1.1.1
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 +18 -16
- package/dingtalk_calendar_mcp_server.yaml +1 -0
- package/dingtalk_notice_mcp_server.yaml +41 -17
- package/dingtalk_robot_im_mcp_server.yaml +3 -7
- package/dingtalk_servicewindow_mcp_server.yaml +97 -60
- package/dist/DingTalkMCPServer.d.ts +1 -0
- package/dist/DingTalkMCPServer.js +65 -41
- package/dist/cli.js +4 -1
- package/dist/index.js +2 -2
- package/dist/types.js +1 -1
- package/dist/utils/messageBuilder.js +37 -183
- package/package.json +4 -2
- package/dist/DingTalkMCPServer.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils/apiClient.d.ts +0 -49
- package/dist/utils/apiClient.d.ts.map +0 -1
- package/dist/utils/apiClient.js +0 -85
- package/dist/utils/apiClient.js.map +0 -1
- package/dist/utils/errorFormatter.d.ts +0 -44
- package/dist/utils/errorFormatter.d.ts.map +0 -1
- package/dist/utils/errorFormatter.js +0 -164
- package/dist/utils/errorFormatter.js.map +0 -1
- package/dist/utils/messageBuilder.d.ts +0 -57
- package/dist/utils/messageBuilder.d.ts.map +0 -1
- package/dist/utils/messageBuilder.js.map +0 -1
- package/dist/utils/messageProcessor.d.ts +0 -36
- package/dist/utils/messageProcessor.d.ts.map +0 -1
- package/dist/utils/messageProcessor.js +0 -145
- package/dist/utils/messageProcessor.js.map +0 -1
- package/dist/utils/validator.d.ts +0 -64
- package/dist/utils/validator.d.ts.map +0 -1
- package/dist/utils/validator.js +0 -181
- package/dist/utils/validator.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
- 钉钉待办
|
|
10
10
|
- 钉钉日程
|
|
11
11
|
- 钉钉签到
|
|
12
|
-
- 钉钉服务窗
|
|
13
12
|
- 钉钉工作通知
|
|
14
13
|
- 钉钉应用管理
|
|
14
|
+
- 钉钉服务窗
|
|
15
15
|
|
|
16
16
|
## 如何使用
|
|
17
17
|
```json
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
],
|
|
26
26
|
"env": {
|
|
27
27
|
"DINGTALK_Client_ID": "your dingtalk client id",
|
|
28
|
-
"DINGTALK_Client_Secret": "your dingtalk client secret"
|
|
28
|
+
"DINGTALK_Client_Secret": "your dingtalk client secret",
|
|
29
|
+
"ACTIVE_PROFILES": "dingtalk-contacts,dingtalk-calendar"
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -36,21 +37,22 @@
|
|
|
36
37
|
2. DINGTALK_Client_Secret
|
|
37
38
|
3. ACTIVE_PROFILES,激活哪些钉钉MCP服务,逗号风格,如果是ALL则激活全部。可选集合
|
|
38
39
|
|
|
39
|
-
| ProfileId
|
|
40
|
-
|
|
41
|
-
| dingtalk-contacts
|
|
42
|
-
| dingtalk-department
|
|
43
|
-
| dingtalk-robot-send-message | 钉钉机器人发消息/DING |
|
|
44
|
-
| dingtalk-honor
|
|
45
|
-
| dingtalk-tasks
|
|
46
|
-
| dingtalk-calendar
|
|
47
|
-
| dingtalk-checkin
|
|
48
|
-
| dingtalk-
|
|
49
|
-
| dingtalk-
|
|
50
|
-
| dingtalk-
|
|
51
|
-
4. ROBOT_CODE,用于发消息/DING的机器人Code
|
|
52
|
-
5. ROBOT_ACCESS_TOKEN,群自定义机器人ACCESS_TOEKN,用于自定义机器人发消息
|
|
40
|
+
| ProfileId | Description | Permission |
|
|
41
|
+
|--------------------------|--------------------|-------------------------------------------------|
|
|
42
|
+
| dingtalk-contacts | 钉钉通讯录,默认激活 |
|
|
43
|
+
| dingtalk-department | 钉钉部门管理 |
|
|
44
|
+
| dingtalk-robot-send-message | 钉钉机器人发消息/DING,默认激活 | 需要企业内机器人发送消息权限 |
|
|
45
|
+
| dingtalk-honor | 钉钉企业文化荣誉 |
|
|
46
|
+
| dingtalk-tasks | 钉钉待办 | Todo.Todo.Write<br>Todo.Todo.Read |
|
|
47
|
+
| dingtalk-calendar | 钉钉日程 |
|
|
48
|
+
| dingtalk-checkin | 钉钉签到 |
|
|
49
|
+
| dingtalk-notice | 钉钉工作通知 |
|
|
50
|
+
| dingtalk-app-manage | 钉钉应用管理 | qyapi_microapp_manage<br>qyapi_get_microapp_list |
|
|
51
|
+
| dingtalk-service-window | 钉钉服务窗 | |
|
|
53
52
|
|
|
53
|
+
4. ROBOT_CODE,用于发消息/DING的机器人Code
|
|
54
|
+
5. ROBOT_ACCESS_TOKEN,群自定义机器人ACCESS_TOKEN,用于自定义机器人发消息
|
|
55
|
+
6. DINGTALK_AGENT_ID 用于发送工作通知
|
|
54
56
|
### 如何获取钉钉Client ID和Client Secret
|
|
55
57
|
1. [成为钉钉开发者](https://open.dingtalk.com/document/orgapp/obtain-developer-permissions)
|
|
56
58
|
2. [创建应用](https://open.dingtalk.com/document/orgapp/create-an-application)
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
server:
|
|
2
2
|
name: dingtalk-notice
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description: DingTalk Work Notice MCP Server - 钉钉工作通知
|
|
4
|
+
description: DingTalk Work Notice MCP Server - 钉钉工作通知MCP服务器
|
|
5
5
|
|
|
6
6
|
tools:
|
|
7
7
|
# 发送工作通知消息
|
|
8
8
|
- name: sendNotice
|
|
9
|
-
description: 发送工作通知消息,支持
|
|
9
|
+
description: 发送工作通知消息,支持 markdown 消息类型
|
|
10
10
|
requestTemplate:
|
|
11
11
|
method: POST
|
|
12
12
|
url: https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2
|
|
13
13
|
args:
|
|
14
|
+
- name: agent_id
|
|
15
|
+
type: number
|
|
16
|
+
required: true
|
|
17
|
+
position: body
|
|
18
|
+
description: 发送消息时使用的微应用的AgentID
|
|
19
|
+
system: DINGTALK_AGENT_ID
|
|
14
20
|
- name: userid_list
|
|
15
21
|
type: string
|
|
16
22
|
required: false
|
|
@@ -26,11 +32,23 @@ tools:
|
|
|
26
32
|
required: false
|
|
27
33
|
position: body
|
|
28
34
|
description: 是否发送给全员(可选,默认false)
|
|
29
|
-
- name: msg
|
|
30
|
-
|
|
35
|
+
- name: msg.msgtype
|
|
36
|
+
not_need_model_transform: true
|
|
37
|
+
type: string
|
|
38
|
+
required: true
|
|
39
|
+
position: body
|
|
40
|
+
description: markdown消息格式
|
|
41
|
+
default: markdown
|
|
42
|
+
- name: msg.markdown.title
|
|
43
|
+
type: string
|
|
44
|
+
required: true
|
|
45
|
+
position: body
|
|
46
|
+
description: markdown消息标题
|
|
47
|
+
- name: msg.markdown.text
|
|
48
|
+
type: string
|
|
31
49
|
required: true
|
|
32
50
|
position: body
|
|
33
|
-
description:
|
|
51
|
+
description: markdown消息内容
|
|
34
52
|
|
|
35
53
|
# 获取工作通知消息的发送结果
|
|
36
54
|
- name: getSendResult
|
|
@@ -39,6 +57,12 @@ tools:
|
|
|
39
57
|
method: POST
|
|
40
58
|
url: https://oapi.dingtalk.com/topapi/message/corpconversation/getsendresult
|
|
41
59
|
args:
|
|
60
|
+
- name: agent_id
|
|
61
|
+
type: number
|
|
62
|
+
required: true
|
|
63
|
+
position: body
|
|
64
|
+
description: 发送消息时使用的微应用的AgentID
|
|
65
|
+
system: DINGTALK_AGENT_ID
|
|
42
66
|
- name: task_id
|
|
43
67
|
type: number
|
|
44
68
|
required: true
|
|
@@ -52,6 +76,12 @@ tools:
|
|
|
52
76
|
method: POST
|
|
53
77
|
url: https://oapi.dingtalk.com/topapi/message/corpconversation/getsendprogress
|
|
54
78
|
args:
|
|
79
|
+
- name: agent_id
|
|
80
|
+
type: number
|
|
81
|
+
required: true
|
|
82
|
+
position: body
|
|
83
|
+
description: 发送消息时使用的微应用的AgentID
|
|
84
|
+
system: DINGTALK_AGENT_ID
|
|
55
85
|
- name: task_id
|
|
56
86
|
type: number
|
|
57
87
|
required: true
|
|
@@ -65,21 +95,15 @@ tools:
|
|
|
65
95
|
method: POST
|
|
66
96
|
url: https://oapi.dingtalk.com/topapi/message/corpconversation/recall
|
|
67
97
|
args:
|
|
98
|
+
- name: agent_id
|
|
99
|
+
type: number
|
|
100
|
+
required: true
|
|
101
|
+
position: body
|
|
102
|
+
description: 发送消息时使用的微应用的AgentID
|
|
103
|
+
system: DINGTALK_AGENT_ID
|
|
68
104
|
- name: msg_task_id
|
|
69
105
|
type: number
|
|
70
106
|
required: true
|
|
71
107
|
position: body
|
|
72
108
|
description: 要撤回的消息任务ID
|
|
73
109
|
|
|
74
|
-
# 获取消息模板(内置功能)
|
|
75
|
-
- name: getMessageTemplates
|
|
76
|
-
description: 获取所有支持的消息类型模板和示例,帮助用户快速了解消息格式
|
|
77
|
-
requestTemplate:
|
|
78
|
-
method: LOCAL
|
|
79
|
-
url: local://templates
|
|
80
|
-
args:
|
|
81
|
-
- name: msgtype
|
|
82
|
-
type: string
|
|
83
|
-
required: false
|
|
84
|
-
position: query
|
|
85
|
-
description: 指定消息类型(text、link、markdown),不指定则返回所有类型
|
|
@@ -79,11 +79,6 @@ tools:
|
|
|
79
79
|
description: 会话ID。
|
|
80
80
|
position: body
|
|
81
81
|
required: true
|
|
82
|
-
- name: coolAppCode
|
|
83
|
-
type: string
|
|
84
|
-
description: 群聊酷应用编码。
|
|
85
|
-
system: COOL_APP_CODE
|
|
86
|
-
position: body
|
|
87
82
|
- name: msgKey
|
|
88
83
|
type: string
|
|
89
84
|
description: 消息模板key,默认为"sampleMarkdown"。
|
|
@@ -93,10 +88,11 @@ tools:
|
|
|
93
88
|
not_need_model_transform: true
|
|
94
89
|
- name: msgParam
|
|
95
90
|
type: string
|
|
96
|
-
description:
|
|
91
|
+
description: 消息内容,格式为JSON字符串,必须遵循此格式 {"title":"title", "text":"markdown内容"}
|
|
97
92
|
position: body
|
|
98
93
|
required: true
|
|
99
94
|
|
|
95
|
+
|
|
100
96
|
requestTemplate:
|
|
101
97
|
url: https://api.dingtalk.com/v1.0/robot/groupMessages/send
|
|
102
98
|
method: POST
|
|
@@ -162,7 +158,7 @@ tools:
|
|
|
162
158
|
not_need_model_transform: true
|
|
163
159
|
- name: msgParam
|
|
164
160
|
type: string
|
|
165
|
-
description:
|
|
161
|
+
description: 消息内容,格式为JSON字符串,必须遵循此格式 {"title":"title", "text":"markdown内容"}
|
|
166
162
|
position: body
|
|
167
163
|
required: true
|
|
168
164
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
server:
|
|
2
|
-
name: dingtalk-
|
|
2
|
+
name: dingtalk-service-window
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description:
|
|
4
|
+
description: DingTalk ServiceWindow MCP Server with Message Builder
|
|
5
5
|
securitySchemes:
|
|
6
6
|
- id: DingTalkAuth
|
|
7
7
|
type: apiKey
|
|
@@ -10,11 +10,6 @@ server:
|
|
|
10
10
|
|
|
11
11
|
# 注意:当前版本的工具定义在代码中,此配置文件为预留扩展
|
|
12
12
|
tools:
|
|
13
|
-
- name: buildServiceWindowMessage
|
|
14
|
-
description: "构建服务窗消息体,支持文本、链接、markdown、卡片等多种类型"
|
|
15
|
-
requestTemplate:
|
|
16
|
-
method: POST
|
|
17
|
-
url: "internal://message-builder"
|
|
18
13
|
|
|
19
14
|
- name: sendServiceWindowMessage
|
|
20
15
|
description: "发送服务窗单人消息"
|
|
@@ -23,7 +18,30 @@ tools:
|
|
|
23
18
|
url: "https://api.dingtalk.com/v1.0/crm/officialAccounts/oToMessages/send"
|
|
24
19
|
security:
|
|
25
20
|
id: DingTalkAuth
|
|
26
|
-
|
|
21
|
+
args:
|
|
22
|
+
- name: userId
|
|
23
|
+
description: 用户userId
|
|
24
|
+
type: string
|
|
25
|
+
required: true
|
|
26
|
+
position: body
|
|
27
|
+
- name: accountId
|
|
28
|
+
description: 服务窗帐号ID
|
|
29
|
+
type: string
|
|
30
|
+
required: true
|
|
31
|
+
position: body
|
|
32
|
+
- name: messageTitle
|
|
33
|
+
description: 消息标题
|
|
34
|
+
type: string
|
|
35
|
+
required: true
|
|
36
|
+
position: body
|
|
37
|
+
- name: messageContent
|
|
38
|
+
description: markdown格式的消息内容
|
|
39
|
+
type: string
|
|
40
|
+
required: true
|
|
41
|
+
position: body
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
27
45
|
- name: batchSendServiceWindowMessage
|
|
28
46
|
description: "批量发送服务窗消息"
|
|
29
47
|
requestTemplate:
|
|
@@ -31,79 +49,98 @@ tools:
|
|
|
31
49
|
url: "https://api.dingtalk.com/v1.0/crm/officialAccounts/oToMessages/batchSend"
|
|
32
50
|
security:
|
|
33
51
|
id: DingTalkAuth
|
|
52
|
+
args:
|
|
53
|
+
- name: userIdList
|
|
54
|
+
description: 用户userId
|
|
55
|
+
type: array
|
|
56
|
+
required: false
|
|
57
|
+
position: body
|
|
58
|
+
items:
|
|
59
|
+
type: string
|
|
60
|
+
- name: accountId
|
|
61
|
+
description: 服务窗帐号ID
|
|
62
|
+
type: string
|
|
63
|
+
required: true
|
|
64
|
+
position: body
|
|
65
|
+
- name: messageTitle
|
|
66
|
+
description: 消息标题
|
|
67
|
+
type: string
|
|
68
|
+
required: true
|
|
69
|
+
position: body
|
|
70
|
+
- name: messageContent
|
|
71
|
+
description: markdown格式的消息内容
|
|
72
|
+
type: string
|
|
73
|
+
required: true
|
|
74
|
+
position: body
|
|
34
75
|
|
|
35
|
-
- name:
|
|
76
|
+
- name: getServiceWindowFollowerInfo
|
|
36
77
|
description: "获取关注服务窗的单个用户信息"
|
|
37
78
|
requestTemplate:
|
|
38
79
|
method: GET
|
|
39
|
-
url: "https://api.dingtalk.com/v1.0/link/followers/infos"
|
|
80
|
+
url: "https://api.dingtalk.com/v1.0/link/followers/infos?userId={String}&accountId={String}"
|
|
40
81
|
security:
|
|
41
82
|
id: DingTalkAuth
|
|
83
|
+
args:
|
|
84
|
+
- name: accountId
|
|
85
|
+
description: 服务窗帐号ID
|
|
86
|
+
type: string
|
|
87
|
+
required: true
|
|
88
|
+
position: query
|
|
89
|
+
- name: userId
|
|
90
|
+
description: 关注服务窗用户的userId
|
|
91
|
+
type: string
|
|
92
|
+
required: true
|
|
93
|
+
position: query
|
|
42
94
|
|
|
43
|
-
- name:
|
|
44
|
-
description: "
|
|
95
|
+
- name: listServiceWindowFollowersInfo
|
|
96
|
+
description: "批量获取关注服务窗用户信息"
|
|
45
97
|
requestTemplate:
|
|
46
98
|
method: GET
|
|
47
|
-
url: "https://api.dingtalk.com/v1.0/link/followers"
|
|
99
|
+
url: "https://api.dingtalk.com/v1.0/link/followers?accountId={String}&nextToken={String}&maxResults={String}"
|
|
48
100
|
security:
|
|
49
101
|
id: DingTalkAuth
|
|
102
|
+
args:
|
|
103
|
+
- name: accountId
|
|
104
|
+
description: 服务窗帐号ID
|
|
105
|
+
type: string
|
|
106
|
+
required: true
|
|
107
|
+
position: query
|
|
108
|
+
- name: nextToken
|
|
109
|
+
description: 分页游标
|
|
110
|
+
type: string
|
|
111
|
+
required: false
|
|
112
|
+
position: query
|
|
113
|
+
- name: maxResults
|
|
114
|
+
description: 每页最大条目数,最大值100
|
|
115
|
+
type: string
|
|
116
|
+
required: false
|
|
117
|
+
position: query
|
|
118
|
+
|
|
50
119
|
|
|
51
120
|
- name: getUserFollowStatus
|
|
52
121
|
description: "获取用户的服务窗关注状态"
|
|
53
122
|
requestTemplate:
|
|
54
123
|
method: GET
|
|
55
|
-
url: "https://api.dingtalk.com/v1.0/link/followers/
|
|
124
|
+
url: "https://api.dingtalk.com/v1.0/link/followers/statuses?accountId={String}&userId={String}"
|
|
56
125
|
security:
|
|
57
126
|
id: DingTalkAuth
|
|
127
|
+
args:
|
|
128
|
+
- name: accountId
|
|
129
|
+
description: 服务窗帐号ID
|
|
130
|
+
type: string
|
|
131
|
+
required: true
|
|
132
|
+
position: query
|
|
133
|
+
- name: userId
|
|
134
|
+
description: 关注服务窗用户的userId
|
|
135
|
+
type: string
|
|
136
|
+
required: true
|
|
137
|
+
position: query
|
|
138
|
+
|
|
58
139
|
|
|
59
140
|
- name: listServiceWindows
|
|
60
|
-
description: "
|
|
141
|
+
description: "获取企业下的服务窗列表,以获取服务窗accountId"
|
|
61
142
|
requestTemplate:
|
|
62
143
|
method: GET
|
|
63
144
|
url: "https://api.dingtalk.com/v1.0/link/accounts"
|
|
64
145
|
security:
|
|
65
|
-
id: DingTalkAuth
|
|
66
|
-
|
|
67
|
-
# 消息类型定义
|
|
68
|
-
messageTypes:
|
|
69
|
-
text:
|
|
70
|
-
description: "纯文本消息"
|
|
71
|
-
maxLength: 500
|
|
72
|
-
|
|
73
|
-
link:
|
|
74
|
-
description: "链接消息"
|
|
75
|
-
fields:
|
|
76
|
-
title:
|
|
77
|
-
maxLength: 128
|
|
78
|
-
required: true
|
|
79
|
-
text:
|
|
80
|
-
maxLength: 500
|
|
81
|
-
required: true
|
|
82
|
-
messageUrl:
|
|
83
|
-
pattern: "^https?://.+"
|
|
84
|
-
required: true
|
|
85
|
-
picUrl:
|
|
86
|
-
required: true
|
|
87
|
-
|
|
88
|
-
markdown:
|
|
89
|
-
description: "Markdown格式消息"
|
|
90
|
-
fields:
|
|
91
|
-
title:
|
|
92
|
-
maxLength: 30
|
|
93
|
-
required: true
|
|
94
|
-
text:
|
|
95
|
-
maxLength: 500
|
|
96
|
-
required: true
|
|
97
|
-
|
|
98
|
-
actionCard:
|
|
99
|
-
description: "卡片消息"
|
|
100
|
-
fields:
|
|
101
|
-
title:
|
|
102
|
-
maxLength: 30
|
|
103
|
-
required: true
|
|
104
|
-
markdown:
|
|
105
|
-
maxLength: 1000
|
|
106
|
-
required: true
|
|
107
|
-
cardType:
|
|
108
|
-
enum: ["single", "independent"]
|
|
109
|
-
required: true
|
|
146
|
+
id: DingTalkAuth
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { ServiceWindowMessageBuilder } from './utils/messageBuilder.js'
|
|
4
5
|
import axios from 'axios';
|
|
5
6
|
import * as yaml from 'js-yaml';
|
|
6
7
|
import fs from 'fs';
|
|
7
8
|
import path from 'path';
|
|
8
9
|
import { fileURLToPath } from 'url';
|
|
10
|
+
import {ifError} from "node:assert";
|
|
11
|
+
import {resolveObjectURL} from "node:buffer";
|
|
9
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
13
|
const __dirname = path.dirname(__filename);
|
|
11
14
|
export class DingTalkMCPServer {
|
|
@@ -319,6 +322,9 @@ export class DingTalkMCPServer {
|
|
|
319
322
|
};
|
|
320
323
|
}
|
|
321
324
|
catch (error) {
|
|
325
|
+
if (this.debug){
|
|
326
|
+
console.log(error)
|
|
327
|
+
}
|
|
322
328
|
let errorMessage = error.message;
|
|
323
329
|
if (axios.isAxiosError(error) && error.response) {
|
|
324
330
|
// 如果是token相关错误,清除缓存
|
|
@@ -375,7 +381,7 @@ export class DingTalkMCPServer {
|
|
|
375
381
|
return finalQuery ? `${baseUrl}?${finalQuery}` : baseUrl;
|
|
376
382
|
}
|
|
377
383
|
// 特殊处理oapi.dingtalk.com接口且配置了security(自定义机器人发消息不使用这个),将access_token作为URL参数传递
|
|
378
|
-
if (url.includes('oapi.dingtalk.com') &&
|
|
384
|
+
if (url.includes('oapi.dingtalk.com') && this.accessToken) {
|
|
379
385
|
const separator = url.includes('?') ? '&' : '?';
|
|
380
386
|
return `${url}${separator}access_token=${encodeURIComponent(this.accessToken)}`;
|
|
381
387
|
}
|
|
@@ -396,10 +402,44 @@ export class DingTalkMCPServer {
|
|
|
396
402
|
}
|
|
397
403
|
return headers;
|
|
398
404
|
}
|
|
405
|
+
|
|
406
|
+
processMultiParam(body, name, value){
|
|
407
|
+
let objParmas = name.split('.');
|
|
408
|
+
if (objParmas && objParmas.length > 1) {
|
|
409
|
+
if (objParmas.length == 2){
|
|
410
|
+
if (!body[objParmas[0]]){
|
|
411
|
+
body[objParmas[0]] = {};
|
|
412
|
+
}
|
|
413
|
+
body[objParmas[0]][objParmas[1]] = value;
|
|
414
|
+
}
|
|
415
|
+
if (objParmas.length == 3){
|
|
416
|
+
if (!body[objParmas[0]]){
|
|
417
|
+
body[objParmas[0]] = {};
|
|
418
|
+
}
|
|
419
|
+
if (!body[objParmas[0]][objParmas[1]]){
|
|
420
|
+
body[objParmas[0]][objParmas[1]] = {};
|
|
421
|
+
}
|
|
422
|
+
body[objParmas[0]][objParmas[1]][objParmas[2]] = value;
|
|
423
|
+
}
|
|
424
|
+
return true;
|
|
425
|
+
} else {
|
|
426
|
+
body[name] = value;
|
|
427
|
+
}
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
|
|
399
431
|
buildBody(tool, args) {
|
|
400
432
|
if (tool.requestTemplate.method === 'GET' || tool.requestTemplate.method === 'DELETE') {
|
|
401
433
|
return undefined;
|
|
402
434
|
}
|
|
435
|
+
|
|
436
|
+
if (tool.name === 'sendServiceWindowMessage'){
|
|
437
|
+
return ServiceWindowMessageBuilder.buildSendServiceWindowMarkdownBody(args);
|
|
438
|
+
}else if (tool.name === 'batchSendServiceWindowMessage'){
|
|
439
|
+
return ServiceWindowMessageBuilder.buildBatchSendServiceWindowMarkdownBody(args);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
|
|
403
443
|
const body = {};
|
|
404
444
|
(tool.args || []).forEach(arg => {
|
|
405
445
|
if (arg.position === 'body') {
|
|
@@ -413,7 +453,7 @@ export class DingTalkMCPServer {
|
|
|
413
453
|
}
|
|
414
454
|
// 不需要模型处理,直接取默认值赋值
|
|
415
455
|
if (arg.not_need_model_transform){
|
|
416
|
-
body
|
|
456
|
+
this.processMultiParam(body, arg.name, arg.default);
|
|
417
457
|
return;
|
|
418
458
|
}
|
|
419
459
|
|
|
@@ -422,56 +462,40 @@ export class DingTalkMCPServer {
|
|
|
422
462
|
return;
|
|
423
463
|
}
|
|
424
464
|
//打平Object类型参数,递归处理
|
|
425
|
-
|
|
426
|
-
if (objParmas && objParmas.length > 1) {
|
|
427
|
-
if (objParmas.length == 2){
|
|
428
|
-
if (!body[objParmas[0]]){
|
|
429
|
-
body[objParmas[0]] = {};
|
|
430
|
-
}
|
|
431
|
-
body[objParmas[0]][objParmas[1]] = args[arg.name];
|
|
432
|
-
}
|
|
433
|
-
if (objParmas.length == 3){
|
|
434
|
-
if (!body[objParmas[0]]){
|
|
435
|
-
body[objParmas[0]] = {};
|
|
436
|
-
}
|
|
437
|
-
if (!body[objParmas[1]]){
|
|
438
|
-
body[objParmas[1]] = {};
|
|
439
|
-
}
|
|
440
|
-
body[objParmas[0]][objParmas[1]][objParmas[2]] = args[arg.name];
|
|
441
|
-
}
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
465
|
+
this.processMultiParam(body, arg.name, args[arg.name]);
|
|
444
466
|
|
|
445
|
-
|
|
446
|
-
// userIds
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
//
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
467
|
+
// // userIds参数直接传递为数组类型,保证请求体为正确的JSON对象
|
|
468
|
+
// if (arg.name === 'userIds' && Array.isArray(args[arg.name])) {
|
|
469
|
+
// body[arg.name] = args[arg.name];
|
|
470
|
+
// }
|
|
471
|
+
// // 搜索用户API参数名称转换,从snake_case转为camelCase
|
|
472
|
+
// else if (tool.name === 'searchUser') {
|
|
473
|
+
// // Convert snake_case to camelCase for the search user API
|
|
474
|
+
// const camelCaseName = arg.name.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
|
|
475
|
+
// body[camelCaseName] = args[arg.name];
|
|
476
|
+
// }
|
|
477
|
+
// else {
|
|
478
|
+
// body[arg.name] = args[arg.name];
|
|
479
|
+
// }
|
|
459
480
|
}
|
|
460
481
|
});
|
|
461
482
|
// 为searchUser/searchDepartment添加默认的分页参数
|
|
462
483
|
|
|
463
484
|
// 设置默认的offset为0
|
|
464
|
-
if (
|
|
465
|
-
body.offset
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
body.size
|
|
485
|
+
if (tool.name === 'searchDepartment' || tool.name === 'searchUser'){
|
|
486
|
+
if (body.offset === undefined) {
|
|
487
|
+
body.offset = 0;
|
|
488
|
+
}
|
|
489
|
+
// 设置默认的size为20
|
|
490
|
+
if (body.size === undefined) {
|
|
491
|
+
body.size = 20;
|
|
492
|
+
}
|
|
470
493
|
}
|
|
471
494
|
console.error(`SearchUser API with params: offset=${body.offset}, size=${body.size}`);
|
|
472
495
|
|
|
473
496
|
return Object.keys(body).length > 0 ? body : undefined;
|
|
474
497
|
}
|
|
498
|
+
|
|
475
499
|
async run() {
|
|
476
500
|
const transport = new StdioServerTransport();
|
|
477
501
|
await this.server.connect(transport);
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { DingTalkMCPServer } from './DingTalkMCPServer.js';
|
|
3
|
+
import {json} from "node:stream/consumers";
|
|
3
4
|
async function main() {
|
|
4
5
|
// 检查环境变量
|
|
5
6
|
const appId = process.env.DINGTALK_Client_ID;
|
|
6
7
|
const appSecret = process.env.DINGTALK_Client_Secret;
|
|
7
8
|
const accessToken = process.env.DINGTALK_ACCESS_TOKEN;
|
|
8
|
-
|
|
9
|
+
|
|
9
10
|
// 如果既没有AppKey/Secret也没有AccessToken,显示帮助信息
|
|
10
11
|
if (!accessToken && (!appId || !appSecret)) {
|
|
11
12
|
console.error('🔧 DingTalk MCP Server 配置指南');
|
|
@@ -50,6 +51,8 @@ async function main() {
|
|
|
50
51
|
console.error('');
|
|
51
52
|
process.exit(1);
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
|
|
53
56
|
}
|
|
54
57
|
// 处理未捕获的异常
|
|
55
58
|
process.on('uncaughtException', (error) => {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DingTalk Calendar MCP Server
|
|
3
|
-
|
|
4
|
-
* A TypeScript-based MCP server for DingTalk
|
|
3
|
+
|
|
4
|
+
* A TypeScript-based MCP server for DingTalk integration
|
|
5
5
|
*/
|
|
6
6
|
export { DingTalkMCPServer } from './DingTalkMCPServer.js';
|
|
7
7
|
export * from './types.js';
|
package/dist/types.js
CHANGED