dingtalk-mcp-calendar
Version:
DingTalk Calendar MCP Server - TypeScript implementation for AI assistants
849 lines (764 loc) • 27.1 kB
YAML
server:
name: dingtalk-calendar
securitySchemes:
- id: DingTalkAuth
type: apiKey
in: header
name: x-acs-dingtalk-access-token
tools:
- name: addAttendee
description: "向指定日程添加参与者,支持批量添加多人,可设置参与者类型和通知方式"
args:
- name: attendeesToAdd
description: "需要添加的参与者列表,包含unionId和参与类型"
type: array
required: true
items:
type: object
position: body
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: chatNotification
description: "是否发送单聊通知"
type: boolean
position: body
- name: eventId
description: "日程ID"
type: string
required: true
position: path
- name: id
description: "参与者的unionId"
type: string
position: body
- name: isOptional
description: "是否为可选参与者(true=可选,false=必须)"
type: boolean
position: body
- name: pushNotification
description: "是否发送弹窗提醒"
type: boolean
position: body
- name: userId
description: "日程创建者的userId"
type: string
required: true
position: path
- name: x-client-token
description: "幂等性校验令牌,避免重复请求"
type: string
position: header
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}/attendees
method: POST
headers:
- key: Content-Type
value: application/json
security:
id: DingTalkAuth
responseTemplate:
body: |
# 日程参与者添加结果
{{if .success}}
✅ **操作成功** - 已成功向日程添加参与者
**日程信息**:
- 日程ID: {{.eventId}}
- 操作时间: {{.timestamp}}
**添加的参与者**:
{{range $i, $attendee := .attendees}}
{{add $i 1}}. {{$attendee.displayName}}
- unionId: {{$attendee.id}}
- 参与类型: {{if $attendee.isOptional}}可选参与{{else}}必须参与{{end}}
- 通知状态: {{if $attendee.notified}}已通知{{else}}未通知{{end}}
{{end}}
{{if .notifications}}
**通知发送状态**:
- 单聊通知: {{if .notifications.chatSent}}已发送{{else}}未发送{{end}}
- 弹窗提醒: {{if .notifications.pushSent}}已发送{{else}}未发送{{end}}
{{end}}
{{else}}
❌ **操作失败** - {{.error}}
**错误详情**: {{.errorMessage}}
{{end}}
- name: createEvent
description: "创建新的日程,支持设置时间、参与者、提醒等完整功能"
args:
- name: userId
description: "日程创建者的userId"
type: string
required: true
position: path
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: summary
description: "日程标题"
type: string
required: true
position: body
- name: start
description: "日程开始时间"
type: object
required: true
position: body
- name: end
description: "日程结束时间"
type: object
required: true
position: body
- name: description
description: "日程描述内容"
type: string
position: body
- name: isAllDay
description: "是否为全天日程"
type: boolean
position: body
- name: attendees
description: "参与者列表"
type: array
items:
type: object
position: body
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events
method: POST
security:
id: DingTalkAuth
responseTemplate:
body: |
# 日程创建结果
{{if .success}}
✅ **日程创建成功**
**日程信息**:
- 📅 标题: {{.summary}}
- 🆔 日程ID: {{.id}}
- ⏰ 开始时间: {{.start.dateTime | formatTime}}
- ⏰ 结束时间: {{.end.dateTime | formatTime}}
- 📍 类型: {{if .isAllDay}}全天日程{{else}}定时日程{{end}}
{{if .description}}
- 📝 描述: {{.description}}
{{end}}
{{if .location}}
- 📍 地点: {{.location.displayName}}
{{end}}
{{if .attendees}}
**参与者** ({{len .attendees}}人):
{{range $i, $attendee := .attendees}}
{{add $i 1}}. {{$attendee.displayName}}{{if $attendee.isOptional}} (可选){{end}}
{{end}}
{{end}}
**访问方式**:
- 日程链接: {{.webLink}}
{{if .onlineMeeting}}
- 会议链接: {{.onlineMeeting.joinUrl}}
{{end}}
{{else}}
❌ **日程创建失败** - {{.error}}
**错误详情**: {{.errorMessage}}
{{end}}
- name: deleteEvent
description: "删除指定日程,组织者删除将通知所有参与者,参与者删除仅从自己日历移除"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: eventId
description: "要删除的日程ID"
type: string
required: true
position: path
- name: pushNotification
description: "是否发送弹窗通知"
type: boolean
position: query
- name: userId
description: "执行删除操作的userId"
type: string
required: true
position: path
- name: x-client-token
description: "幂等性校验令牌"
type: string
position: header
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}?pushNotification=Boolean
method: DELETE
security:
id: DingTalkAuth
responseTemplate:
body: |
# 日程删除结果
{{if .success}}
✅ **日程删除成功**
**删除信息**:
- 日程ID: {{.eventId}}
- 删除者: {{.deletedBy}}
- 删除时间: {{.deletedAt | formatTime}}
- 影响范围: {{if .isOrganizer}}所有参与者(组织者删除){{else}}仅自己(参与者退出){{end}}
{{if .notifications}}
**通知状态**:
{{if .isOrganizer}}
- 取消通知已发送给 {{.notifications.notifiedCount}} 位参与者
{{end}}
- 弹窗提醒: {{if .notifications.pushSent}}已发送{{else}}未发送{{end}}
{{end}}
{{else}}
❌ **日程删除失败** - {{.error}}
**错误详情**: {{.errorMessage}}
{{end}}
- name: getEventsView
description: "查询指定时间范围内的日程视图,支持循环日程展开显示"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: maxAttendees
description: "每个日程返回的参与者数量上限(默认100,最大100)"
type: integer
position: query
- name: maxResults
description: "返回的日程数量上限(默认100,最大100)"
type: integer
position: query
- name: nextToken
description: "分页标记,用于获取下一页数据"
type: string
position: query
- name: timeMax
description: "查询结束时间(ISO-8601格式)"
type: string
position: query
- name: timeMin
description: "查询开始时间(ISO-8601格式)"
type: string
position: query
- name: userId
description: "要查询的userId"
type: string
required: true
position: path
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/eventsview?timeMin=String&timeMax=String&maxResults=Long&nextToken=String
method: GET
security:
id: DingTalkAuth
responseTemplate:
body: |
# 📅 日程视图查询结果
{{if .events}}
**查询范围**: {{.timeMin | formatTime}} 至 {{.timeMax | formatTime}}
**找到日程**: {{len .events}} 个{{if .hasMore}}(显示部分,还有更多){{end}}
{{range $i, $event := .events}}
## {{add $i 1}}. {{$event.summary}}
**⏰ 时间**: {{$event.start.dateTime | formatTime}} - {{$event.end.dateTime | formatTime}}
{{if $event.isAllDay}}**📅 类型**: 全天日程{{end}}
{{if $event.location}}**📍 地点**: {{$event.location.displayName}}{{end}}
{{if $event.description}}**📝 描述**: {{$event.description | truncate 100}}{{end}}
{{if $event.attendees}}**👥 参与者**: {{len $event.attendees}}人{{end}}
{{if $event.seriesMasterId}}**🔄 循环**: 这是循环日程的一个实例{{end}}
{{end}}
{{if .nextToken}}
---
**📄 分页信息**: 使用 nextToken "{{.nextToken}}" 获取更多结果
{{end}}
{{else}}
📭 **暂无日程**
指定时间范围内没有找到任何日程。
{{end}}
- name: getEventDetails
description: "获取指定日程的详细信息,包含完整的参与者、位置、描述等信息"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: eventId
description: "日程ID"
type: string
required: true
position: path
- name: userId
description: "查询者的userId"
type: string
required: true
position: path
- name: maxAttendees
description: "返回的参与者数量上限(默认100,最大100)"
type: integer
position: query
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}?maxAttendees=Long
method: GET
security:
id: DingTalkAuth
responseTemplate:
body: |
# 📅 日程详情
## {{.summary}}
**基本信息**:
- 🆔 日程ID: {{.id}}
- ⏰ 开始时间: {{.start.dateTime | formatTime}}
- ⏰ 结束时间: {{.end.dateTime | formatTime}}
- 📅 类型: {{if .isAllDay}}全天日程{{else}}定时日程{{end}}
- 👤 创建者: {{.organizer.displayName}}
- 📊 状态: {{.status}}
{{if .description}}
**📝 详细描述**:
{{.description}}
{{end}}
{{if .location}}
**📍 会议地点**:
{{.location.displayName}}
{{end}}
{{if .onlineMeeting}}
**💻 在线会议**:
- 会议链接: {{.onlineMeeting.joinUrl}}
- 会议ID: {{.onlineMeeting.conferenceId}}
{{end}}
{{if .attendees}}
**👥 参与者** ({{len .attendees}}人):
{{range $i, $attendee := .attendees}}
{{add $i 1}}. {{$attendee.displayName}}
- 状态: {{$attendee.responseStatus}}{{if $attendee.isOptional}} (可选参与){{end}}
{{if $attendee.comment}}- 备注: {{$attendee.comment}}{{end}}
{{end}}
{{end}}
{{if .recurrence}}
**🔄 重复设置**:
{{.recurrence | formatRecurrence}}
{{end}}
{{if .reminders}}
**⏰ 提醒设置**:
{{range $reminder := .reminders}}
- {{$reminder.method}}: 提前{{$reminder.minutes}}分钟
{{end}}
{{end}}
- name: listAttendees
description: "获取指定日程的所有参与者列表及其状态信息"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: eventId
description: "日程ID"
type: string
required: true
position: path
- name: maxResults
description: "返回的参与者数量上限(默认100,最大500)"
type: integer
position: query
- name: nextToken
description: "分页标记,用于获取下一页数据"
type: string
position: query
- name: userId
description: "查询者的userId"
type: string
required: true
position: path
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}/attendees?maxResults=Long&nextToken=String
method: GET
security:
id: DingTalkAuth
responseTemplate:
body: |
# 👥 日程参与者列表
**日程**: {{.eventSummary}}
**参与者总数**: {{.totalCount}}人{{if .hasMore}}(显示部分){{end}}
{{range $i, $attendee := .attendees}}
## {{add $i 1}}. {{$attendee.displayName}}
- 🆔 unionId: {{$attendee.id}}
- 📧 邮箱: {{$attendee.email}}
- 📱 状态: {{if eq $attendee.responseStatus "accepted"}}✅ 已接受{{else if eq $attendee.responseStatus "declined"}}❌ 已拒绝{{else if eq $attendee.responseStatus "tentative"}}❓ 待定{{else}}⏳ 未回复{{end}}
- 👤 类型: {{if $attendee.isOptional}}可选参与者{{else}}必须参与者{{end}}
{{if $attendee.comment}}- 💬 备注: {{$attendee.comment}}{{end}}
{{if $attendee.isOrganizer}}- 🎯 **组织者**{{end}}
{{end}}
{{if .nextToken}}
---
**📄 分页信息**: 使用 nextToken "{{.nextToken}}" 获取更多参与者
{{end}}
- name: listEvents
description: "查询指定时间范围内的日程列表,支持分页和增量同步"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: maxAttendees
description: "每个日程返回的参与者数量上限(默认100)"
type: integer
position: query
- name: maxResults
description: "返回的日程数量上限(默认100,最大100)"
type: integer
position: query
- name: nextToken
description: "分页标记,用于获取下一页数据"
type: string
position: query
- name: seriesMasterId
description: "重复日程的主日程ID,用于查询特定循环日程"
type: string
position: query
- name: showDeleted
description: "是否包含已删除的日程"
type: boolean
position: query
- name: syncToken
description: "同步标记,用于增量数据同步"
type: string
position: query
- name: timeMax
description: "查询结束时间(ISO-8601格式)"
type: string
position: query
- name: timeMin
description: "查询开始时间(ISO-8601格式)"
type: string
position: query
- name: userId
description: "要查询的userId"
type: string
required: true
position: path
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events?timeMin=String&timeMax=String&showDeleted=Boolean&maxResults=Integer&maxAttendees=Integer&nextToken=String&syncToken=String
method: GET
security:
id: DingTalkAuth
responseTemplate:
body: |
# 📋 日程列表
{{if .events}}
**查询时间**: {{if .timeMin}}{{.timeMin | formatTime}}{{else}}不限{{end}} 至 {{if .timeMax}}{{.timeMax | formatTime}}{{else}}不限{{end}}
**日程数量**: {{len .events}}个{{if .hasMore}}(显示部分){{end}}
{{range $i, $event := .events}}
## {{add $i 1}}. {{$event.summary}}
- 🆔 ID: {{$event.id}}
- ⏰ 时间: {{$event.start.dateTime | formatTime}} - {{$event.end.dateTime | formatTime}}
{{if $event.isAllDay}}- 📅 全天日程{{end}}
{{if $event.location}}- 📍 地点: {{$event.location.displayName}}{{end}}
{{if $event.attendees}}- 👥 参与者: {{len $event.attendees}}人{{end}}
{{if $event.recurrenceId}}- 🔄 这是循环日程的实例{{end}}
{{if $event.status}}- 📊 状态: {{$event.status}}{{end}}
{{end}}
{{if .nextToken}}
**📄 分页**: 使用 nextToken "{{.nextToken}}" 获取更多
{{end}}
{{if .syncToken}}
**🔄 同步**: 使用 syncToken "{{.syncToken}}" 进行增量同步
{{end}}
{{else}}
📭 **暂无日程**
指定时间范围内没有找到任何日程。
{{end}}
- name: updateEvent
description: "修改现有日程的信息,支持更新标题、时间、参与者、地点等任意字段,仅需要组织者权限"
args:
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: eventId
description: "要修改的日程ID"
type: string
required: true
position: path
- name: userId
description: "日程组织者的userId"
type: string
required: true
position: path
- name: summary
description: "日程标题"
type: string
position: body
- name: description
description: "日程描述"
type: string
position: body
- name: start
description: "日程开始时间"
type: object
position: body
- name: end
description: "日程结束时间"
type: object
position: body
- name: location
description: "日程地点"
type: object
position: body
- name: attendees
description: "参与者列表"
type: array
items:
type: object
position: body
- name: isAllDay
description: "是否为全天日程"
type: boolean
position: body
- name: reminders
description: "提醒设置"
type: array
items:
type: object
position: body
- name: recurrence
description: "重复设置"
type: object
position: body
- name: onlineMeetingInfo
description: "在线会议设置"
type: object
position: body
- name: x-client-token
description: "幂等性校验令牌"
type: string
position: header
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}
method: PUT
headers:
- key: Content-Type
value: application/json
security:
id: DingTalkAuth
responseTemplate:
body: |
# ✏️ 日程修改结果
{{if .success}}
✅ **日程修改成功**
**更新后的日程信息**:
- 📅 标题: {{.summary}}
- 🆔 日程ID: {{.id}}
- ⏰ 开始时间: {{.start.dateTime | formatTime}}
- ⏰ 结束时间: {{.end.dateTime | formatTime}}
- 📍 类型: {{if .isAllDay}}全天日程{{else}}定时日程{{end}}
{{if .description}}
- 📝 描述: {{.description}}
{{end}}
{{if .location}}
- 📍 地点: {{.location.displayName}}
{{end}}
**修改的内容**:
{{range $change := .changes}}
- {{$change.field}}: {{$change.oldValue}} → {{$change.newValue}}
{{end}}
{{if .attendees}}
**参与者** ({{len .attendees}}人):
{{range $i, $attendee := .attendees}}
{{add $i 1}}. {{$attendee.displayName}}{{if $attendee.isOptional}} (可选){{end}}
{{end}}
{{end}}
{{if .onlineMeeting}}
**在线会议**:
- 会议链接: {{.onlineMeeting.joinUrl}}
{{end}}
{{else}}
❌ **日程修改失败** - {{.error}}
**错误详情**: {{.errorMessage}}
{{end}}
- name: removeAttendee
description: "从指定日程中移除参与者,支持批量移除多人"
args:
- name: attendeesToRemove
description: "需要移除的参与者列表"
type: array
items:
type: object
position: body
- name: calendarId
description: "日历ID,使用'primary'表示主日历"
type: string
required: true
position: path
- name: eventId
description: "日程ID"
type: string
required: true
position: path
- name: id
description: "要移除的unionId"
type: string
position: body
- name: userId
description: "日程创建者的userId"
type: string
required: true
position: path
- name: x-client-token
description: "幂等性校验令牌"
type: string
position: header
requestTemplate:
url: https://api.dingtalk.com/v1.0/calendar/users/{userId}/calendars/{calendarId}/events/{eventId}/attendees/remove
method: POST
headers:
- key: Content-Type
value: application/json
security:
id: DingTalkAuth
responseTemplate:
body: |
# 👥➖ 日程参与者移除结果
{{if .success}}
✅ **操作成功** - 已从日程中移除参与者
**日程信息**:
- 日程ID: {{.eventId}}
- 操作时间: {{.timestamp}}
**移除的参与者**:
{{range $i, $attendee := .removedAttendees}}
{{add $i 1}}. {{$attendee.displayName}}
- unionId: {{$attendee.id}}
- 移除原因: {{$attendee.reason}}
{{end}}
**剩余参与者数量**: {{.remainingCount}}人
{{if .notifications}}
**通知状态**:
{{if .notifications.attendeesNotified}}
- 已向移除的参与者发送通知
{{end}}
{{end}}
{{else}}
❌ **操作失败** - {{.error}}
**错误详情**: {{.errorMessage}}
{{end}}
- name: searchUser
description: "在企业组织中搜索用户,支持按姓名、邮箱、手机号等关键词查找"
args:
- name: query_word
description: "搜索关键词(姓名、邮箱、手机号等)"
type: string
required: true
position: body
- name: dept_id
description: "限定搜索的部门ID,不填则搜索整个企业"
type: number
position: body
- name: offset
description: "分页偏移量(从0开始)"
type: number
position: body
- name: size
description: "返回结果数量(最大50)"
type: number
position: body
- name: only_active
description: "是否只搜索激活状态的用户"
type: boolean
position: body
requestTemplate:
url: https://api.dingtalk.com/v1.0/contact/users/search
method: POST
headers:
- key: Content-Type
value: application/json
security:
id: DingTalkAuth
responseTemplate:
body: |
# 🔍 用户搜索结果
{{if .users}}
**搜索关键词**: "{{.query}}"
{{if .deptName}}**搜索范围**: {{.deptName}}{{else}}**搜索范围**: 全企业{{end}}
**找到用户**: {{len .users}}个{{if .hasMore}}(显示部分){{end}}
{{range $i, $user := .users}}
## {{add $i 1}}. {{$user.name}}
- 🆔 unionId: {{$user.unionid}}
- 📧 邮箱: {{$user.email}}
- 📱 手机: {{$user.mobile}}
- 🏢 部门: {{$user.deptName}}
- 💼 职位: {{$user.title}}
- 📊 状态: {{if $user.active}}✅ 激活{{else}}❌ 未激活{{end}}
{{if $user.avatar}}- 📷 头像: {{$user.avatar}}{{end}}
{{end}}
{{if .hasMore}}
---
**📄 分页信息**: 还有更多结果,使用 offset={{.nextOffset}} 获取更多
{{end}}
{{else}}
🔍 **未找到用户**
关键词"{{.query}}"没有匹配到任何用户,请尝试:
- 检查关键词拼写
- 使用更准确的姓名或邮箱
- 扩大搜索范围(不限制部门)
{{end}}
- name: getUserDetails
description: "获取指定用户的详细信息,包含完整的个人资料和组织架构信息"
args:
- name: userid
description: "用户的userId"
type: string
required: true
position: body
- name: language
description: "返回信息的语言(zh_CN=中文,en_US=英文)"
type: string
position: body
requestTemplate:
url: https://oapi.dingtalk.com/topapi/v2/user/get
method: POST
headers:
- key: Content-Type
value: application/json
security:
id: DingTalkAuth
responseTemplate:
body: |
# 👤 用户详细信息
{{if .user}}
## {{.user.name}}
**基本信息**:
- 🆔 unionId: {{.user.unionid}}
- 📧 邮箱: {{.user.email}}
- 📱 手机: {{.user.mobile}}
- 🏢 工号: {{.user.jobNumber}}
- 💼 职位: {{.user.title}}
- 📊 状态: {{if .user.active}}✅ 激活{{else}}❌ 未激活{{end}}
{{if .user.avatar}}
**头像**: {{.user.avatar}}
{{end}}
**组织架构**:
{{range $i, $dept := .user.departments}}
{{add $i 1}}. {{$dept.name}}
- 部门ID: {{$dept.id}}
{{if $dept.isLeader}}- 🎯 **部门负责人**{{end}}
{{if $dept.isMainDept}}- 🏠 **主部门**{{end}}
{{end}}
{{if .user.extension}}
**扩展信息**:
{{range $key, $value := .user.extension}}
- {{$key}}: {{$value}}
{{end}}
{{end}}
**账号信息**:
- 创建时间: {{.user.hiredDate | formatTime}}
{{if .user.workPlace}}- 工作地点: {{.user.workPlace}}{{end}}
{{if .user.remark}}- 备注: {{.user.remark}}{{end}}
{{else}}
❌ **用户不存在**
用户ID "{{.userid}}" 未找到,请检查:
- 用户ID是否正确
- 用户是否已被删除
- 是否有权限访问该用户信息
{{end}}