# Directory Structure
```
├── .env.example
├── package-lock.json
├── package.json
├── README.md
└── src
├── index.js
├── resources
│ └── api-docs.js
├── server.js
├── tools
│ ├── account.js
│ ├── chat.js
│ ├── contacts.js
│ ├── meetings.js
│ ├── phone.js
│ ├── recordings.js
│ ├── reports.js
│ ├── users.js
│ ├── webhooks.js
│ ├── webinars.js
│ └── zoom-rooms.js
└── utils
├── api.js
└── auth.js
```
# Files
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
```
1 | # Zoom API Credentials
2 | ZOOM_CLIENT_ID=your_client_id
3 | ZOOM_CLIENT_SECRET=your_client_secret
4 | ZOOM_ACCOUNT_ID=your_account_id
5 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Zoom API MCP Server
2 |
3 | A comprehensive Model Context Protocol (MCP) server for interacting with the Zoom API.
4 |
5 | ## Features
6 |
7 | - Complete coverage of Zoom API endpoints
8 | - OAuth 2.0 authentication
9 | - Structured tools with proper validation
10 | - API documentation resources
11 | - Error handling and response formatting
12 |
13 | ## Getting Started
14 |
15 | ### Prerequisites
16 |
17 | - Node.js 16+
18 | - Zoom API credentials (Client ID, Client Secret, Account ID)
19 |
20 | ### Installation
21 |
22 | 1. Clone the repository
23 | 2. Install dependencies:
24 | ```
25 | npm install
26 | ```
27 | 3. Create a `.env` file with your Zoom API credentials:
28 | ```
29 | ZOOM_CLIENT_ID=your_client_id
30 | ZOOM_CLIENT_SECRET=your_client_secret
31 | ZOOM_ACCOUNT_ID=your_account_id
32 | ```
33 |
34 | ### Running the Server
35 |
36 | ```
37 | npm run dev
38 | ```
39 |
40 | ### Testing with MCP Inspector
41 |
42 | ```
43 | npm run inspect
44 | ```
45 |
46 | ## API Categories
47 |
48 | - **Meetings**: Create, read, update, and delete meetings
49 | - **Users**: Manage users in your Zoom account
50 | - **Webinars**: Create and manage webinars
51 | - **Account**: Manage account settings and profile
52 | - **Chat**: Manage Zoom Chat channels and messages
53 | - **Phone**: Manage Zoom Phone users and numbers
54 | - **Contacts**: Manage contacts
55 | - **Recordings**: Access and manage cloud recordings
56 | - **Reports**: Generate various reports
57 | - **Webhooks**: Set up event notifications
58 | - **Zoom Rooms**: Manage Zoom Rooms
59 |
60 | ## Resources
61 |
62 | Access API documentation through resources:
63 |
64 | ```
65 | zoom-api://overview
66 | zoom-api://meetings
67 | zoom-api://users
68 | ```
69 |
70 | ## Authentication
71 |
72 | The server handles OAuth 2.0 authentication automatically using the Server-to-Server OAuth app credentials.
73 |
```
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
```javascript
1 | #!/usr/bin/env node
2 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3 | import { server } from './server.js';
4 | import dotenv from 'dotenv';
5 |
6 | // Load environment variables
7 | dotenv.config();
8 |
9 | console.log('Starting Zoom API MCP server...');
10 |
11 | // Start receiving messages on stdin and sending messages on stdout
12 | const transport = new StdioServerTransport();
13 | await server.connect(transport);
14 |
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "zoom-mcp-server",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "description": "MCP Server for Zoom API",
6 | "main": "src/index.js",
7 | "bin": {
8 | "zoom-mcp-server": "src/index.js"
9 | },
10 | "scripts": {
11 | "start": "node src/index.js",
12 | "dev": "node --watch src/index.js",
13 | "inspect": "npx -y @modelcontextprotocol/inspector node src/index.js"
14 | },
15 | "dependencies": {
16 | "@modelcontextprotocol/sdk": "^1.0.0",
17 | "axios": "^1.6.2",
18 | "dotenv": "^16.3.1",
19 | "zod": "^3.22.4"
20 | }
21 | }
22 |
```
--------------------------------------------------------------------------------
/src/utils/api.js:
--------------------------------------------------------------------------------
```javascript
1 | import axios from 'axios';
2 | import { getAccessToken } from './auth.js';
3 |
4 | const BASE_URL = 'https://api.zoom.us/v2';
5 |
6 | // Create an axios instance for Zoom API
7 | export const zoomApi = axios.create({
8 | baseURL: BASE_URL,
9 | headers: {
10 | 'Content-Type': 'application/json'
11 | }
12 | });
13 |
14 | // Request interceptor to add authorization header
15 | zoomApi.interceptors.request.use(async (config) => {
16 | const token = await getAccessToken();
17 | config.headers.Authorization = `Bearer ${token}`;
18 | return config;
19 | });
20 |
21 | // Response interceptor to handle errors
22 | zoomApi.interceptors.response.use(
23 | (response) => response,
24 | (error) => {
25 | console.error('API Error:', error.response?.data || error.message);
26 | return Promise.reject(error);
27 | }
28 | );
29 |
30 | // Helper function to handle API responses
31 | export const handleApiResponse = (response) => {
32 | return {
33 | content: [{
34 | type: "text",
35 | text: JSON.stringify(response.data, null, 2)
36 | }]
37 | };
38 | };
39 |
40 | // Helper function to handle API errors
41 | export const handleApiError = (error) => {
42 | const errorMessage = error.response?.data?.message || error.message;
43 | return {
44 | content: [{
45 | type: "text",
46 | text: `Error: ${errorMessage}`
47 | }],
48 | isError: true
49 | };
50 | };
51 |
```
--------------------------------------------------------------------------------
/src/utils/auth.js:
--------------------------------------------------------------------------------
```javascript
1 | import axios from 'axios';
2 |
3 | // Cache for the access token
4 | let accessToken = null;
5 | let tokenExpiry = 0;
6 |
7 | // Get access token using client credentials flow
8 | export const getAccessToken = async () => {
9 | // Check if we have a valid token
10 | if (accessToken && tokenExpiry > Date.now()) {
11 | return accessToken;
12 | }
13 |
14 | try {
15 | const clientId = process.env.ZOOM_CLIENT_ID;
16 | const clientSecret = process.env.ZOOM_CLIENT_SECRET;
17 | const accountId = process.env.ZOOM_ACCOUNT_ID;
18 |
19 | if (!clientId || !clientSecret || !accountId) {
20 | throw new Error('Missing Zoom API credentials. Please set ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET, and ZOOM_ACCOUNT_ID in .env file.');
21 | }
22 |
23 | // Get new token
24 | const response = await axios.post(
25 | 'https://zoom.us/oauth/token',
26 | null,
27 | {
28 | params: {
29 | grant_type: 'account_credentials',
30 | account_id: accountId
31 | },
32 | headers: {
33 | 'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`
34 | }
35 | }
36 | );
37 |
38 | accessToken = response.data.access_token;
39 | // Set expiry time with a small buffer
40 | tokenExpiry = Date.now() + (response.data.expires_in * 1000) - 60000;
41 |
42 | return accessToken;
43 | } catch (error) {
44 | console.error('Error getting access token:', error.response?.data || error.message);
45 | throw error;
46 | }
47 | };
48 |
```
--------------------------------------------------------------------------------
/src/server.js:
--------------------------------------------------------------------------------
```javascript
1 | import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2 | import { meetingsTools } from './tools/meetings.js';
3 | import { usersTools } from './tools/users.js';
4 | import { webinarsTools } from './tools/webinars.js';
5 | import { accountTools } from './tools/account.js';
6 | import { chatTools } from './tools/chat.js';
7 | import { phoneTools } from './tools/phone.js';
8 | import { contactsTools } from './tools/contacts.js';
9 | import { recordingsTools } from './tools/recordings.js';
10 | import { reportsTools } from './tools/reports.js';
11 | import { webhooksTools } from './tools/webhooks.js';
12 | import { zoomRoomsTools } from './tools/zoom-rooms.js';
13 | import { apiDocs } from './resources/api-docs.js';
14 |
15 | // Create an MCP server for Zoom API
16 | const server = new McpServer({
17 | name: "Zoom API",
18 | version: "1.0.0",
19 | description: "MCP Server for interacting with the Zoom API"
20 | });
21 |
22 | // Register all tools
23 | const registerTools = (toolsArray) => {
24 | toolsArray.forEach(tool => {
25 | server.tool(
26 | tool.name,
27 | tool.schema,
28 | tool.handler,
29 | { description: tool.description }
30 | );
31 | });
32 | };
33 |
34 | // Register all resources
35 | const registerResources = (resourcesArray) => {
36 | resourcesArray.forEach(resource => {
37 | server.resource(
38 | resource.name,
39 | resource.template,
40 | resource.handler
41 | );
42 | });
43 | };
44 |
45 | // Register all tools
46 | registerTools(meetingsTools);
47 | registerTools(usersTools);
48 | registerTools(webinarsTools);
49 | registerTools(accountTools);
50 | registerTools(chatTools);
51 | registerTools(phoneTools);
52 | registerTools(contactsTools);
53 | registerTools(recordingsTools);
54 | registerTools(reportsTools);
55 | registerTools(webhooksTools);
56 | registerTools(zoomRoomsTools);
57 |
58 | // Register all resources
59 | registerResources(apiDocs);
60 |
61 | export { server };
62 |
```
--------------------------------------------------------------------------------
/src/tools/contacts.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const contactsTools = [
5 | {
6 | name: "list_contacts",
7 | description: "List contacts",
8 | schema: {
9 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
10 | next_page_token: z.string().optional().describe("Next page token"),
11 | status: z.enum(["active", "inactive", "pending"]).optional().describe("Contact status")
12 | },
13 | handler: async ({ page_size, next_page_token, status }) => {
14 | try {
15 | const params = {};
16 | if (page_size) params.page_size = page_size;
17 | if (next_page_token) params.next_page_token = next_page_token;
18 | if (status) params.status = status;
19 |
20 | const response = await zoomApi.get('/contacts', { params });
21 | return handleApiResponse(response);
22 | } catch (error) {
23 | return handleApiError(error);
24 | }
25 | }
26 | },
27 | {
28 | name: "get_contact",
29 | description: "Get a contact's information",
30 | schema: {
31 | contact_id: z.string().describe("The contact ID")
32 | },
33 | handler: async ({ contact_id }) => {
34 | try {
35 | const response = await zoomApi.get(`/contacts/${contact_id}`);
36 | return handleApiResponse(response);
37 | } catch (error) {
38 | return handleApiError(error);
39 | }
40 | }
41 | },
42 | {
43 | name: "search_company_contacts",
44 | description: "Search company contacts",
45 | schema: {
46 | query_string: z.string().describe("Search query string"),
47 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
48 | next_page_token: z.string().optional().describe("Next page token")
49 | },
50 | handler: async ({ query_string, page_size, next_page_token }) => {
51 | try {
52 | const params = { query_string };
53 | if (page_size) params.page_size = page_size;
54 | if (next_page_token) params.next_page_token = next_page_token;
55 |
56 | const response = await zoomApi.get('/contacts/search', { params });
57 | return handleApiResponse(response);
58 | } catch (error) {
59 | return handleApiError(error);
60 | }
61 | }
62 | }
63 | ];
64 |
```
--------------------------------------------------------------------------------
/src/tools/phone.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const phoneTools = [
5 | {
6 | name: "list_phone_users",
7 | description: "List phone users",
8 | schema: {
9 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
10 | next_page_token: z.string().optional().describe("Next page token"),
11 | site_id: z.string().optional().describe("Site ID")
12 | },
13 | handler: async ({ page_size, next_page_token, site_id }) => {
14 | try {
15 | const params = {};
16 | if (page_size) params.page_size = page_size;
17 | if (next_page_token) params.next_page_token = next_page_token;
18 | if (site_id) params.site_id = site_id;
19 |
20 | const response = await zoomApi.get('/phone/users', { params });
21 | return handleApiResponse(response);
22 | } catch (error) {
23 | return handleApiError(error);
24 | }
25 | }
26 | },
27 | {
28 | name: "get_phone_user",
29 | description: "Get a phone user's information",
30 | schema: {
31 | user_id: z.string().describe("The user ID or email address")
32 | },
33 | handler: async ({ user_id }) => {
34 | try {
35 | const response = await zoomApi.get(`/phone/users/${user_id}`);
36 | return handleApiResponse(response);
37 | } catch (error) {
38 | return handleApiError(error);
39 | }
40 | }
41 | },
42 | {
43 | name: "update_phone_user",
44 | description: "Update a phone user's information",
45 | schema: {
46 | user_id: z.string().describe("The user ID or email address"),
47 | extension_number: z.string().optional().describe("Extension number"),
48 | site_id: z.string().optional().describe("Site ID"),
49 | policy_id: z.string().optional().describe("Policy ID")
50 | },
51 | handler: async ({ user_id, ...userData }) => {
52 | try {
53 | const response = await zoomApi.patch(`/phone/users/${user_id}`, userData);
54 | return handleApiResponse(response);
55 | } catch (error) {
56 | return handleApiError(error);
57 | }
58 | }
59 | },
60 | {
61 | name: "list_phone_numbers",
62 | description: "List phone numbers",
63 | schema: {
64 | type: z.enum(["assigned", "unassigned", "all"]).optional().describe("Phone number type"),
65 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
66 | next_page_token: z.string().optional().describe("Next page token")
67 | },
68 | handler: async ({ type, page_size, next_page_token }) => {
69 | try {
70 | const params = {};
71 | if (type) params.type = type;
72 | if (page_size) params.page_size = page_size;
73 | if (next_page_token) params.next_page_token = next_page_token;
74 |
75 | const response = await zoomApi.get('/phone/numbers', { params });
76 | return handleApiResponse(response);
77 | } catch (error) {
78 | return handleApiError(error);
79 | }
80 | }
81 | }
82 | ];
83 |
```
--------------------------------------------------------------------------------
/src/tools/webhooks.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const webhooksTools = [
5 | {
6 | name: "list_webhooks",
7 | description: "List webhooks",
8 | schema: {},
9 | handler: async () => {
10 | try {
11 | const response = await zoomApi.get('/webhooks');
12 | return handleApiResponse(response);
13 | } catch (error) {
14 | return handleApiError(error);
15 | }
16 | }
17 | },
18 | {
19 | name: "create_webhook",
20 | description: "Create a webhook",
21 | schema: {
22 | url: z.string().url().describe("Webhook URL"),
23 | event_types: z.array(z.string()).describe("Event types to subscribe to"),
24 | authorization_header: z.string().optional().describe("Authorization header"),
25 | description: z.string().optional().describe("Webhook description")
26 | },
27 | handler: async (webhookData) => {
28 | try {
29 | const response = await zoomApi.post('/webhooks', webhookData);
30 | return handleApiResponse(response);
31 | } catch (error) {
32 | return handleApiError(error);
33 | }
34 | }
35 | },
36 | {
37 | name: "get_webhook",
38 | description: "Get a webhook's information",
39 | schema: {
40 | webhook_id: z.string().describe("The webhook ID")
41 | },
42 | handler: async ({ webhook_id }) => {
43 | try {
44 | const response = await zoomApi.get(`/webhooks/${webhook_id}`);
45 | return handleApiResponse(response);
46 | } catch (error) {
47 | return handleApiError(error);
48 | }
49 | }
50 | },
51 | {
52 | name: "update_webhook",
53 | description: "Update a webhook's information",
54 | schema: {
55 | webhook_id: z.string().describe("The webhook ID"),
56 | url: z.string().url().optional().describe("Webhook URL"),
57 | event_types: z.array(z.string()).optional().describe("Event types to subscribe to"),
58 | authorization_header: z.string().optional().describe("Authorization header"),
59 | description: z.string().optional().describe("Webhook description"),
60 | status: z.enum(["active", "inactive"]).optional().describe("Webhook status")
61 | },
62 | handler: async ({ webhook_id, ...webhookData }) => {
63 | try {
64 | const response = await zoomApi.patch(`/webhooks/${webhook_id}`, webhookData);
65 | return handleApiResponse(response);
66 | } catch (error) {
67 | return handleApiError(error);
68 | }
69 | }
70 | },
71 | {
72 | name: "delete_webhook",
73 | description: "Delete a webhook",
74 | schema: {
75 | webhook_id: z.string().describe("The webhook ID")
76 | },
77 | handler: async ({ webhook_id }) => {
78 | try {
79 | const response = await zoomApi.delete(`/webhooks/${webhook_id}`);
80 | return {
81 | content: [{
82 | type: "text",
83 | text: "Webhook deleted successfully"
84 | }]
85 | };
86 | } catch (error) {
87 | return handleApiError(error);
88 | }
89 | }
90 | }
91 | ];
92 |
```
--------------------------------------------------------------------------------
/src/tools/reports.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const reportsTools = [
5 | {
6 | name: "get_daily_report",
7 | description: "Get daily usage report",
8 | schema: {
9 | year: z.number().describe("Year"),
10 | month: z.number().min(1).max(12).describe("Month")
11 | },
12 | handler: async ({ year, month }) => {
13 | try {
14 | const response = await zoomApi.get(`/report/daily`, {
15 | params: { year, month }
16 | });
17 | return handleApiResponse(response);
18 | } catch (error) {
19 | return handleApiError(error);
20 | }
21 | }
22 | },
23 | {
24 | name: "get_meeting_participants_report",
25 | description: "Get meeting participants report",
26 | schema: {
27 | meeting_id: z.string().describe("The meeting ID"),
28 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
29 | next_page_token: z.string().optional().describe("Next page token")
30 | },
31 | handler: async ({ meeting_id, page_size, next_page_token }) => {
32 | try {
33 | const params = {};
34 | if (page_size) params.page_size = page_size;
35 | if (next_page_token) params.next_page_token = next_page_token;
36 |
37 | const response = await zoomApi.get(`/report/meetings/${meeting_id}/participants`, { params });
38 | return handleApiResponse(response);
39 | } catch (error) {
40 | return handleApiError(error);
41 | }
42 | }
43 | },
44 | {
45 | name: "get_meeting_details_report",
46 | description: "Get meeting details report",
47 | schema: {
48 | meeting_id: z.string().describe("The meeting ID")
49 | },
50 | handler: async ({ meeting_id }) => {
51 | try {
52 | const response = await zoomApi.get(`/report/meetings/${meeting_id}`);
53 | return handleApiResponse(response);
54 | } catch (error) {
55 | return handleApiError(error);
56 | }
57 | }
58 | },
59 | {
60 | name: "get_webinar_participants_report",
61 | description: "Get webinar participants report",
62 | schema: {
63 | webinar_id: z.string().describe("The webinar ID"),
64 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
65 | next_page_token: z.string().optional().describe("Next page token")
66 | },
67 | handler: async ({ webinar_id, page_size, next_page_token }) => {
68 | try {
69 | const params = {};
70 | if (page_size) params.page_size = page_size;
71 | if (next_page_token) params.next_page_token = next_page_token;
72 |
73 | const response = await zoomApi.get(`/report/webinars/${webinar_id}/participants`, { params });
74 | return handleApiResponse(response);
75 | } catch (error) {
76 | return handleApiError(error);
77 | }
78 | }
79 | },
80 | {
81 | name: "get_webinar_details_report",
82 | description: "Get webinar details report",
83 | schema: {
84 | webinar_id: z.string().describe("The webinar ID")
85 | },
86 | handler: async ({ webinar_id }) => {
87 | try {
88 | const response = await zoomApi.get(`/report/webinars/${webinar_id}`);
89 | return handleApiResponse(response);
90 | } catch (error) {
91 | return handleApiError(error);
92 | }
93 | }
94 | }
95 | ];
96 |
```
--------------------------------------------------------------------------------
/src/tools/recordings.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const recordingsTools = [
5 | {
6 | name: "list_recordings",
7 | description: "List all recordings for a user",
8 | schema: {
9 | user_id: z.string().describe("The user ID or email address"),
10 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
11 | next_page_token: z.string().optional().describe("Next page token"),
12 | from: z.string().optional().describe("Start date in 'yyyy-MM-dd' format"),
13 | to: z.string().optional().describe("End date in 'yyyy-MM-dd' format")
14 | },
15 | handler: async ({ user_id, page_size, next_page_token, from, to }) => {
16 | try {
17 | const params = {};
18 | if (page_size) params.page_size = page_size;
19 | if (next_page_token) params.next_page_token = next_page_token;
20 | if (from) params.from = from;
21 | if (to) params.to = to;
22 |
23 | const response = await zoomApi.get(`/users/${user_id}/recordings`, { params });
24 | return handleApiResponse(response);
25 | } catch (error) {
26 | return handleApiError(error);
27 | }
28 | }
29 | },
30 | {
31 | name: "get_meeting_recordings",
32 | description: "Get recordings for a specific meeting",
33 | schema: {
34 | meeting_id: z.string().describe("The meeting ID")
35 | },
36 | handler: async ({ meeting_id }) => {
37 | try {
38 | const response = await zoomApi.get(`/meetings/${meeting_id}/recordings`);
39 | return handleApiResponse(response);
40 | } catch (error) {
41 | return handleApiError(error);
42 | }
43 | }
44 | },
45 | {
46 | name: "delete_meeting_recordings",
47 | description: "Delete recordings for a specific meeting",
48 | schema: {
49 | meeting_id: z.string().describe("The meeting ID"),
50 | action: z.enum(["trash", "delete"]).optional().describe("Delete action (trash: move to trash, delete: delete permanently)")
51 | },
52 | handler: async ({ meeting_id, action }) => {
53 | try {
54 | const params = {};
55 | if (action) params.action = action;
56 |
57 | const response = await zoomApi.delete(`/meetings/${meeting_id}/recordings`, { params });
58 | return {
59 | content: [{
60 | type: "text",
61 | text: "Meeting recordings deleted successfully"
62 | }]
63 | };
64 | } catch (error) {
65 | return handleApiError(error);
66 | }
67 | }
68 | },
69 | {
70 | name: "delete_recording_file",
71 | description: "Delete a specific recording file",
72 | schema: {
73 | meeting_id: z.string().describe("The meeting ID"),
74 | recording_id: z.string().describe("The recording ID"),
75 | action: z.enum(["trash", "delete"]).optional().describe("Delete action (trash: move to trash, delete: delete permanently)")
76 | },
77 | handler: async ({ meeting_id, recording_id, action }) => {
78 | try {
79 | const params = {};
80 | if (action) params.action = action;
81 |
82 | const response = await zoomApi.delete(`/meetings/${meeting_id}/recordings/${recording_id}`, { params });
83 | return {
84 | content: [{
85 | type: "text",
86 | text: "Recording file deleted successfully"
87 | }]
88 | };
89 | } catch (error) {
90 | return handleApiError(error);
91 | }
92 | }
93 | }
94 | ];
95 |
```
--------------------------------------------------------------------------------
/src/tools/account.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const accountTools = [
5 | {
6 | name: "get_account_settings",
7 | description: "Get account settings",
8 | schema: {
9 | option: z.enum(["meeting_authentication", "recording_authentication", "security"]).optional().describe("Setting option to query")
10 | },
11 | handler: async ({ option }) => {
12 | try {
13 | const params = {};
14 | if (option) params.option = option;
15 |
16 | const response = await zoomApi.get('/accounts/me/settings', { params });
17 | return handleApiResponse(response);
18 | } catch (error) {
19 | return handleApiError(error);
20 | }
21 | }
22 | },
23 | {
24 | name: "update_account_settings",
25 | description: "Update account settings",
26 | schema: {
27 | settings: z.object({}).passthrough().describe("Account settings to update")
28 | },
29 | handler: async ({ settings }) => {
30 | try {
31 | const response = await zoomApi.patch('/accounts/me/settings', settings);
32 | return handleApiResponse(response);
33 | } catch (error) {
34 | return handleApiError(error);
35 | }
36 | }
37 | },
38 | {
39 | name: "get_account_profile",
40 | description: "Get account profile information",
41 | schema: {},
42 | handler: async () => {
43 | try {
44 | const response = await zoomApi.get('/accounts/me');
45 | return handleApiResponse(response);
46 | } catch (error) {
47 | return handleApiError(error);
48 | }
49 | }
50 | },
51 | {
52 | name: "list_sub_accounts",
53 | description: "List sub accounts",
54 | schema: {
55 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
56 | page_number: z.number().min(1).optional().describe("Page number")
57 | },
58 | handler: async ({ page_size, page_number }) => {
59 | try {
60 | const params = {};
61 | if (page_size) params.page_size = page_size;
62 | if (page_number) params.page_number = page_number;
63 |
64 | const response = await zoomApi.get('/accounts', { params });
65 | return handleApiResponse(response);
66 | } catch (error) {
67 | return handleApiError(error);
68 | }
69 | }
70 | },
71 | {
72 | name: "create_sub_account",
73 | description: "Create a sub account",
74 | schema: {
75 | first_name: z.string().describe("First name of the account owner"),
76 | last_name: z.string().describe("Last name of the account owner"),
77 | email: z.string().email().describe("Email address of the account owner"),
78 | password: z.string().describe("Password"),
79 | phone_country: z.string().optional().describe("Country for phone"),
80 | phone_number: z.string().optional().describe("Phone number"),
81 | company_name: z.string().describe("Company name"),
82 | address: z.string().optional().describe("Address"),
83 | city: z.string().optional().describe("City"),
84 | state: z.string().optional().describe("State/Province"),
85 | zip: z.string().optional().describe("ZIP/Postal Code"),
86 | country: z.string().describe("Country")
87 | },
88 | handler: async (accountData) => {
89 | try {
90 | const response = await zoomApi.post('/accounts', accountData);
91 | return handleApiResponse(response);
92 | } catch (error) {
93 | return handleApiError(error);
94 | }
95 | }
96 | }
97 | ];
98 |
```
--------------------------------------------------------------------------------
/src/tools/chat.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const chatTools = [
5 | {
6 | name: "list_channels",
7 | description: "List channels",
8 | schema: {
9 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
10 | next_page_token: z.string().optional().describe("Next page token")
11 | },
12 | handler: async ({ page_size, next_page_token }) => {
13 | try {
14 | const params = {};
15 | if (page_size) params.page_size = page_size;
16 | if (next_page_token) params.next_page_token = next_page_token;
17 |
18 | const response = await zoomApi.get('/chat/users/me/channels', { params });
19 | return handleApiResponse(response);
20 | } catch (error) {
21 | return handleApiError(error);
22 | }
23 | }
24 | },
25 | {
26 | name: "create_channel",
27 | description: "Create a channel",
28 | schema: {
29 | name: z.string().describe("Channel name"),
30 | type: z.number().min(1).max(2).describe("Channel type (1: Private, 2: Public)"),
31 | members: z.array(z.object({
32 | email: z.string().email().describe("Member email address")
33 | })).optional().describe("Channel members")
34 | },
35 | handler: async (channelData) => {
36 | try {
37 | const response = await zoomApi.post('/chat/users/me/channels', channelData);
38 | return handleApiResponse(response);
39 | } catch (error) {
40 | return handleApiError(error);
41 | }
42 | }
43 | },
44 | {
45 | name: "get_channel",
46 | description: "Get a channel's information",
47 | schema: {
48 | channel_id: z.string().describe("The channel ID")
49 | },
50 | handler: async ({ channel_id }) => {
51 | try {
52 | const response = await zoomApi.get(`/chat/channels/${channel_id}`);
53 | return handleApiResponse(response);
54 | } catch (error) {
55 | return handleApiError(error);
56 | }
57 | }
58 | },
59 | {
60 | name: "update_channel",
61 | description: "Update a channel's information",
62 | schema: {
63 | channel_id: z.string().describe("The channel ID"),
64 | name: z.string().optional().describe("Channel name")
65 | },
66 | handler: async ({ channel_id, ...channelData }) => {
67 | try {
68 | const response = await zoomApi.patch(`/chat/channels/${channel_id}`, channelData);
69 | return handleApiResponse(response);
70 | } catch (error) {
71 | return handleApiError(error);
72 | }
73 | }
74 | },
75 | {
76 | name: "delete_channel",
77 | description: "Delete a channel",
78 | schema: {
79 | channel_id: z.string().describe("The channel ID")
80 | },
81 | handler: async ({ channel_id }) => {
82 | try {
83 | const response = await zoomApi.delete(`/chat/channels/${channel_id}`);
84 | return {
85 | content: [{
86 | type: "text",
87 | text: "Channel deleted successfully"
88 | }]
89 | };
90 | } catch (error) {
91 | return handleApiError(error);
92 | }
93 | }
94 | },
95 | {
96 | name: "send_channel_message",
97 | description: "Send a message to a channel",
98 | schema: {
99 | channel_id: z.string().describe("The channel ID"),
100 | message: z.string().describe("Message content")
101 | },
102 | handler: async ({ channel_id, message }) => {
103 | try {
104 | const response = await zoomApi.post(`/chat/users/me/channels/${channel_id}/messages`, {
105 | message
106 | });
107 | return handleApiResponse(response);
108 | } catch (error) {
109 | return handleApiError(error);
110 | }
111 | }
112 | }
113 | ];
114 |
```
--------------------------------------------------------------------------------
/src/tools/zoom-rooms.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const zoomRoomsTools = [
5 | {
6 | name: "list_zoom_rooms",
7 | description: "List Zoom Rooms",
8 | schema: {
9 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
10 | page_number: z.number().min(1).optional().describe("Page number"),
11 | location_id: z.string().optional().describe("Location ID")
12 | },
13 | handler: async ({ page_size, page_number, location_id }) => {
14 | try {
15 | const params = {};
16 | if (page_size) params.page_size = page_size;
17 | if (page_number) params.page_number = page_number;
18 | if (location_id) params.location_id = location_id;
19 |
20 | const response = await zoomApi.get('/rooms', { params });
21 | return handleApiResponse(response);
22 | } catch (error) {
23 | return handleApiError(error);
24 | }
25 | }
26 | },
27 | {
28 | name: "get_zoom_room",
29 | description: "Get a Zoom Room's information",
30 | schema: {
31 | room_id: z.string().describe("The Zoom Room ID")
32 | },
33 | handler: async ({ room_id }) => {
34 | try {
35 | const response = await zoomApi.get(`/rooms/${room_id}`);
36 | return handleApiResponse(response);
37 | } catch (error) {
38 | return handleApiError(error);
39 | }
40 | }
41 | },
42 | {
43 | name: "update_zoom_room",
44 | description: "Update a Zoom Room's information",
45 | schema: {
46 | room_id: z.string().describe("The Zoom Room ID"),
47 | name: z.string().optional().describe("Room name"),
48 | location_id: z.string().optional().describe("Location ID"),
49 | calendar_resource_id: z.string().optional().describe("Calendar resource ID"),
50 | room_passcode: z.string().optional().describe("Room passcode")
51 | },
52 | handler: async ({ room_id, ...roomData }) => {
53 | try {
54 | const response = await zoomApi.patch(`/rooms/${room_id}`, roomData);
55 | return handleApiResponse(response);
56 | } catch (error) {
57 | return handleApiError(error);
58 | }
59 | }
60 | },
61 | {
62 | name: "list_zoom_room_locations",
63 | description: "List Zoom Room locations",
64 | schema: {
65 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
66 | page_number: z.number().min(1).optional().describe("Page number"),
67 | parent_location_id: z.string().optional().describe("Parent location ID")
68 | },
69 | handler: async ({ page_size, page_number, parent_location_id }) => {
70 | try {
71 | const params = {};
72 | if (page_size) params.page_size = page_size;
73 | if (page_number) params.page_number = page_number;
74 | if (parent_location_id) params.parent_location_id = parent_location_id;
75 |
76 | const response = await zoomApi.get('/rooms/locations', { params });
77 | return handleApiResponse(response);
78 | } catch (error) {
79 | return handleApiError(error);
80 | }
81 | }
82 | },
83 | {
84 | name: "create_zoom_room_location",
85 | description: "Create a Zoom Room location",
86 | schema: {
87 | name: z.string().describe("Location name"),
88 | parent_location_id: z.string().optional().describe("Parent location ID"),
89 | type: z.enum(["country", "state", "city", "campus", "building", "floor"]).describe("Location type")
90 | },
91 | handler: async (locationData) => {
92 | try {
93 | const response = await zoomApi.post('/rooms/locations', locationData);
94 | return handleApiResponse(response);
95 | } catch (error) {
96 | return handleApiError(error);
97 | }
98 | }
99 | }
100 | ];
101 |
```
--------------------------------------------------------------------------------
/src/tools/users.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const usersTools = [
5 | {
6 | name: "list_users",
7 | description: "List users on the account",
8 | schema: {
9 | status: z.enum(["active", "inactive", "pending"]).optional().describe("User status"),
10 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
11 | page_number: z.number().min(1).optional().describe("Page number"),
12 | role_id: z.string().optional().describe("Role ID")
13 | },
14 | handler: async ({ status, page_size, page_number, role_id }) => {
15 | try {
16 | const params = {};
17 | if (status) params.status = status;
18 | if (page_size) params.page_size = page_size;
19 | if (page_number) params.page_number = page_number;
20 | if (role_id) params.role_id = role_id;
21 |
22 | const response = await zoomApi.get('/users', { params });
23 | return handleApiResponse(response);
24 | } catch (error) {
25 | return handleApiError(error);
26 | }
27 | }
28 | },
29 | {
30 | name: "create_user",
31 | description: "Create a new user on the account",
32 | schema: {
33 | action: z.enum(["create", "autoCreate", "custCreate", "ssoCreate"]).describe("Action to create user"),
34 | user_info: z.object({
35 | email: z.string().email().describe("User email address"),
36 | type: z.number().min(1).max(99).describe("User type (1: Basic, 2: Licensed, 3: On-prem)"),
37 | first_name: z.string().optional().describe("User's first name"),
38 | last_name: z.string().optional().describe("User's last name"),
39 | password: z.string().optional().describe("User password")
40 | }).describe("User information")
41 | },
42 | handler: async ({ action, user_info }) => {
43 | try {
44 | const response = await zoomApi.post('/users', { action, user_info });
45 | return handleApiResponse(response);
46 | } catch (error) {
47 | return handleApiError(error);
48 | }
49 | }
50 | },
51 | {
52 | name: "get_user",
53 | description: "Get a user's information",
54 | schema: {
55 | user_id: z.string().describe("The user ID or email address")
56 | },
57 | handler: async ({ user_id }) => {
58 | try {
59 | const response = await zoomApi.get(`/users/${user_id}`);
60 | return handleApiResponse(response);
61 | } catch (error) {
62 | return handleApiError(error);
63 | }
64 | }
65 | },
66 | {
67 | name: "update_user",
68 | description: "Update a user's information",
69 | schema: {
70 | user_id: z.string().describe("The user ID or email address"),
71 | first_name: z.string().optional().describe("User's first name"),
72 | last_name: z.string().optional().describe("User's last name"),
73 | type: z.number().min(1).max(99).optional().describe("User type"),
74 | pmi: z.string().optional().describe("Personal Meeting ID"),
75 | use_pmi: z.boolean().optional().describe("Use Personal Meeting ID for instant meetings"),
76 | timezone: z.string().optional().describe("User timezone"),
77 | dept: z.string().optional().describe("Department")
78 | },
79 | handler: async ({ user_id, ...userData }) => {
80 | try {
81 | const response = await zoomApi.patch(`/users/${user_id}`, userData);
82 | return handleApiResponse(response);
83 | } catch (error) {
84 | return handleApiError(error);
85 | }
86 | }
87 | },
88 | {
89 | name: "delete_user",
90 | description: "Delete a user",
91 | schema: {
92 | user_id: z.string().describe("The user ID or email address"),
93 | action: z.enum(["delete", "disassociate"]).describe("Delete action (delete: permanently delete, disassociate: disassociate from account)")
94 | },
95 | handler: async ({ user_id, action }) => {
96 | try {
97 | const response = await zoomApi.delete(`/users/${user_id}`, {
98 | params: { action }
99 | });
100 | return {
101 | content: [{
102 | type: "text",
103 | text: "User deleted successfully"
104 | }]
105 | };
106 | } catch (error) {
107 | return handleApiError(error);
108 | }
109 | }
110 | }
111 | ];
112 |
```
--------------------------------------------------------------------------------
/src/resources/api-docs.js:
--------------------------------------------------------------------------------
```javascript
1 | import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
2 |
3 | // API documentation resources
4 | export const apiDocs = [
5 | {
6 | name: "api_docs",
7 | template: new ResourceTemplate("zoom-api://{category}", { list: undefined }),
8 | handler: async (uri, { category }) => {
9 | const docs = getApiDocs(category);
10 |
11 | return {
12 | contents: [{
13 | uri: uri.href,
14 | text: docs
15 | }]
16 | };
17 | }
18 | }
19 | ];
20 |
21 | // Helper function to get API documentation
22 | function getApiDocs(category) {
23 | const categories = {
24 | "overview": `# Zoom API Overview
25 |
26 | The Zoom API is a REST API that allows developers to access information from Zoom and to update information in Zoom. The API is available to all Zoom accounts.
27 |
28 | ## Authentication
29 |
30 | Zoom API uses OAuth 2.0 for authentication. You need to create a Server-to-Server OAuth app in the Zoom App Marketplace to get your credentials.
31 |
32 | ## Rate Limits
33 |
34 | Zoom implements rate limits to protect against overuse and abuse of the API. The rate limits are based on the number of requests per second.
35 |
36 | ## Base URL
37 |
38 | All API requests should be made to: \`https://api.zoom.us/v2/\``,
39 |
40 | "meetings": `# Zoom Meetings API
41 |
42 | The Meetings API allows you to create, read, update, and delete Zoom meetings.
43 |
44 | ## Endpoints
45 |
46 | - GET /users/{userId}/meetings - List a user's meetings
47 | - POST /users/{userId}/meetings - Create a meeting for a user
48 | - GET /meetings/{meetingId} - Get a meeting
49 | - PATCH /meetings/{meetingId} - Update a meeting
50 | - DELETE /meetings/{meetingId} - Delete a meeting
51 | - GET /report/meetings/{meetingId}/participants - Get meeting participants report`,
52 |
53 | "users": `# Zoom Users API
54 |
55 | The Users API allows you to manage users in your Zoom account.
56 |
57 | ## Endpoints
58 |
59 | - GET /users - List users
60 | - POST /users - Create a user
61 | - GET /users/{userId} - Get a user
62 | - PATCH /users/{userId} - Update a user
63 | - DELETE /users/{userId} - Delete a user`,
64 |
65 | "webinars": `# Zoom Webinars API
66 |
67 | The Webinars API allows you to create, read, update, and delete Zoom webinars.
68 |
69 | ## Endpoints
70 |
71 | - GET /users/{userId}/webinars - List a user's webinars
72 | - POST /users/{userId}/webinars - Create a webinar for a user
73 | - GET /webinars/{webinarId} - Get a webinar
74 | - PATCH /webinars/{webinarId} - Update a webinar
75 | - DELETE /webinars/{webinarId} - Delete a webinar
76 | - GET /report/webinars/{webinarId}/participants - Get webinar participants report`,
77 |
78 | "account": `# Zoom Account API
79 |
80 | The Account API allows you to manage your Zoom account settings and profile.
81 |
82 | ## Endpoints
83 |
84 | - GET /accounts/me/settings - Get account settings
85 | - PATCH /accounts/me/settings - Update account settings
86 | - GET /accounts/me - Get account profile
87 | - GET /accounts - List sub accounts
88 | - POST /accounts - Create a sub account`,
89 |
90 | "chat": `# Zoom Chat API
91 |
92 | The Chat API allows you to manage Zoom Chat channels and messages.
93 |
94 | ## Endpoints
95 |
96 | - GET /chat/users/me/channels - List channels
97 | - POST /chat/users/me/channels - Create a channel
98 | - GET /chat/channels/{channelId} - Get a channel
99 | - PATCH /chat/channels/{channelId} - Update a channel
100 | - DELETE /chat/channels/{channelId} - Delete a channel
101 | - POST /chat/users/me/channels/{channelId}/messages - Send a message to a channel`,
102 |
103 | "phone": `# Zoom Phone API
104 |
105 | The Phone API allows you to manage Zoom Phone users and numbers.
106 |
107 | ## Endpoints
108 |
109 | - GET /phone/users - List phone users
110 | - GET /phone/users/{userId} - Get a phone user
111 | - PATCH /phone/users/{userId} - Update a phone user
112 | - GET /phone/numbers - List phone numbers`,
113 |
114 | "recordings": `# Zoom Recordings API
115 |
116 | The Recordings API allows you to manage cloud recordings.
117 |
118 | ## Endpoints
119 |
120 | - GET /users/{userId}/recordings - List all recordings for a user
121 | - GET /meetings/{meetingId}/recordings - Get recordings for a specific meeting
122 | - DELETE /meetings/{meetingId}/recordings - Delete recordings for a specific meeting
123 | - DELETE /meetings/{meetingId}/recordings/{recordingId} - Delete a specific recording file`,
124 |
125 | "webhooks": `# Zoom Webhooks API
126 |
127 | The Webhooks API allows you to manage webhooks for event notifications.
128 |
129 | ## Endpoints
130 |
131 | - GET /webhooks - List webhooks
132 | - POST /webhooks - Create a webhook
133 | - GET /webhooks/{webhookId} - Get a webhook
134 | - PATCH /webhooks/{webhookId} - Update a webhook
135 | - DELETE /webhooks/{webhookId} - Delete a webhook`
136 | };
137 |
138 | return categories[category.toLowerCase()] ||
139 | `# Zoom API Documentation
140 |
141 | Available categories:
142 | - overview
143 | - meetings
144 | - users
145 | - webinars
146 | - account
147 | - chat
148 | - phone
149 | - recordings
150 | - webhooks
151 |
152 | Access documentation by using: zoom-api://{category}`;
153 | }
154 |
```
--------------------------------------------------------------------------------
/src/tools/webinars.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const webinarsTools = [
5 | {
6 | name: "list_webinars",
7 | description: "List all webinars for a user",
8 | schema: {
9 | user_id: z.string().describe("The user ID or email address"),
10 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
11 | page_number: z.number().min(1).optional().describe("Page number")
12 | },
13 | handler: async ({ user_id, page_size, page_number }) => {
14 | try {
15 | const params = {};
16 | if (page_size) params.page_size = page_size;
17 | if (page_number) params.page_number = page_number;
18 |
19 | const response = await zoomApi.get(`/users/${user_id}/webinars`, { params });
20 | return handleApiResponse(response);
21 | } catch (error) {
22 | return handleApiError(error);
23 | }
24 | }
25 | },
26 | {
27 | name: "create_webinar",
28 | description: "Create a webinar for a user",
29 | schema: {
30 | user_id: z.string().describe("The user ID or email address"),
31 | topic: z.string().describe("Webinar topic"),
32 | type: z.number().min(5).max(9).describe("Webinar type (5: Webinar, 6: Recurring webinar with no fixed time, 9: Recurring webinar with fixed time)"),
33 | start_time: z.string().optional().describe("Webinar start time"),
34 | duration: z.number().optional().describe("Webinar duration in minutes"),
35 | timezone: z.string().optional().describe("Time zone"),
36 | password: z.string().optional().describe("Webinar password"),
37 | agenda: z.string().optional().describe("Webinar description"),
38 | settings: z.object({}).passthrough().optional().describe("Webinar settings")
39 | },
40 | handler: async ({ user_id, ...webinarData }) => {
41 | try {
42 | const response = await zoomApi.post(`/users/${user_id}/webinars`, webinarData);
43 | return handleApiResponse(response);
44 | } catch (error) {
45 | return handleApiError(error);
46 | }
47 | }
48 | },
49 | {
50 | name: "get_webinar",
51 | description: "Retrieve a webinar's details",
52 | schema: {
53 | webinar_id: z.string().describe("The webinar ID")
54 | },
55 | handler: async ({ webinar_id }) => {
56 | try {
57 | const response = await zoomApi.get(`/webinars/${webinar_id}`);
58 | return handleApiResponse(response);
59 | } catch (error) {
60 | return handleApiError(error);
61 | }
62 | }
63 | },
64 | {
65 | name: "update_webinar",
66 | description: "Update a webinar's details",
67 | schema: {
68 | webinar_id: z.string().describe("The webinar ID"),
69 | topic: z.string().optional().describe("Webinar topic"),
70 | type: z.number().min(5).max(9).optional().describe("Webinar type"),
71 | start_time: z.string().optional().describe("Webinar start time"),
72 | duration: z.number().optional().describe("Webinar duration in minutes"),
73 | timezone: z.string().optional().describe("Time zone"),
74 | password: z.string().optional().describe("Password"),
75 | agenda: z.string().optional().describe("Webinar description"),
76 | settings: z.object({}).passthrough().optional().describe("Webinar settings")
77 | },
78 | handler: async ({ webinar_id, ...webinarData }) => {
79 | try {
80 | const response = await zoomApi.patch(`/webinars/${webinar_id}`, webinarData);
81 | return handleApiResponse(response);
82 | } catch (error) {
83 | return handleApiError(error);
84 | }
85 | }
86 | },
87 | {
88 | name: "delete_webinar",
89 | description: "Delete a webinar",
90 | schema: {
91 | webinar_id: z.string().describe("The webinar ID"),
92 | occurrence_id: z.string().optional().describe("The occurrence ID for a recurring webinar"),
93 | cancel_webinar_reminder: z.boolean().optional().describe("Send cancellation email to registrants")
94 | },
95 | handler: async ({ webinar_id, occurrence_id, cancel_webinar_reminder }) => {
96 | try {
97 | const params = {};
98 | if (occurrence_id) params.occurrence_id = occurrence_id;
99 | if (cancel_webinar_reminder !== undefined) params.cancel_webinar_reminder = cancel_webinar_reminder;
100 |
101 | const response = await zoomApi.delete(`/webinars/${webinar_id}`, { params });
102 | return {
103 | content: [{
104 | type: "text",
105 | text: "Webinar deleted successfully"
106 | }]
107 | };
108 | } catch (error) {
109 | return handleApiError(error);
110 | }
111 | }
112 | },
113 | {
114 | name: "list_webinar_participants",
115 | description: "List participants from a webinar",
116 | schema: {
117 | webinar_id: z.string().describe("The webinar ID"),
118 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
119 | next_page_token: z.string().optional().describe("Next page token")
120 | },
121 | handler: async ({ webinar_id, page_size, next_page_token }) => {
122 | try {
123 | const params = {};
124 | if (page_size) params.page_size = page_size;
125 | if (next_page_token) params.next_page_token = next_page_token;
126 |
127 | const response = await zoomApi.get(`/report/webinars/${webinar_id}/participants`, { params });
128 | return handleApiResponse(response);
129 | } catch (error) {
130 | return handleApiError(error);
131 | }
132 | }
133 | }
134 | ];
135 |
```
--------------------------------------------------------------------------------
/src/tools/meetings.js:
--------------------------------------------------------------------------------
```javascript
1 | import { z } from 'zod';
2 | import { zoomApi, handleApiResponse, handleApiError } from '../utils/api.js';
3 |
4 | export const meetingsTools = [
5 | {
6 | name: "list_meetings",
7 | description: "List all meetings for a user",
8 | schema: {
9 | user_id: z.string().describe("The user ID or email address"),
10 | type: z.enum(["scheduled", "live", "upcoming", "pending"]).optional().describe("Meeting type"),
11 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned per page"),
12 | page_number: z.number().min(1).optional().describe("Page number")
13 | },
14 | handler: async ({ user_id, type, page_size, page_number }) => {
15 | try {
16 | const params = {};
17 | if (type) params.type = type;
18 | if (page_size) params.page_size = page_size;
19 | if (page_number) params.page_number = page_number;
20 |
21 | const response = await zoomApi.get(`/users/${user_id}/meetings`, { params });
22 | return handleApiResponse(response);
23 | } catch (error) {
24 | return handleApiError(error);
25 | }
26 | }
27 | },
28 | {
29 | name: "create_meeting",
30 | description: "Create a new meeting for a user",
31 | schema: {
32 | user_id: z.string().describe("The user ID or email address"),
33 | topic: z.string().describe("Meeting topic"),
34 | type: z.number().min(1).max(8).describe("Meeting type (1: instant, 2: scheduled, 3: recurring with no fixed time, 8: recurring with fixed time)"),
35 | start_time: z.string().optional().describe("Meeting start time in format YYYY-MM-DDThh:mm:ss"),
36 | duration: z.number().optional().describe("Meeting duration in minutes"),
37 | timezone: z.string().optional().describe("Time zone for start_time"),
38 | password: z.string().optional().describe("Password for the meeting"),
39 | agenda: z.string().optional().describe("Meeting description"),
40 | settings: z.object({}).passthrough().optional().describe("Meeting settings")
41 | },
42 | handler: async ({ user_id, ...meetingData }) => {
43 | try {
44 | const response = await zoomApi.post(`/users/${user_id}/meetings`, meetingData);
45 | return handleApiResponse(response);
46 | } catch (error) {
47 | return handleApiError(error);
48 | }
49 | }
50 | },
51 | {
52 | name: "get_meeting",
53 | description: "Retrieve a meeting's details",
54 | schema: {
55 | meeting_id: z.string().describe("The meeting ID")
56 | },
57 | handler: async ({ meeting_id }) => {
58 | try {
59 | const response = await zoomApi.get(`/meetings/${meeting_id}`);
60 | return handleApiResponse(response);
61 | } catch (error) {
62 | return handleApiError(error);
63 | }
64 | }
65 | },
66 | {
67 | name: "update_meeting",
68 | description: "Update a meeting's details",
69 | schema: {
70 | meeting_id: z.string().describe("The meeting ID"),
71 | topic: z.string().optional().describe("Meeting topic"),
72 | type: z.number().min(1).max(8).optional().describe("Meeting type"),
73 | start_time: z.string().optional().describe("Meeting start time"),
74 | duration: z.number().optional().describe("Meeting duration in minutes"),
75 | timezone: z.string().optional().describe("Time zone"),
76 | password: z.string().optional().describe("Password"),
77 | agenda: z.string().optional().describe("Meeting description"),
78 | settings: z.object({}).passthrough().optional().describe("Meeting settings")
79 | },
80 | handler: async ({ meeting_id, ...meetingData }) => {
81 | try {
82 | const response = await zoomApi.patch(`/meetings/${meeting_id}`, meetingData);
83 | return handleApiResponse(response);
84 | } catch (error) {
85 | return handleApiError(error);
86 | }
87 | }
88 | },
89 | {
90 | name: "delete_meeting",
91 | description: "Delete a meeting",
92 | schema: {
93 | meeting_id: z.string().describe("The meeting ID"),
94 | occurrence_id: z.string().optional().describe("The occurrence ID for a recurring meeting"),
95 | schedule_for_reminder: z.boolean().optional().describe("Send cancellation email to registrants")
96 | },
97 | handler: async ({ meeting_id, occurrence_id, schedule_for_reminder }) => {
98 | try {
99 | const params = {};
100 | if (occurrence_id) params.occurrence_id = occurrence_id;
101 | if (schedule_for_reminder !== undefined) params.schedule_for_reminder = schedule_for_reminder;
102 |
103 | const response = await zoomApi.delete(`/meetings/${meeting_id}`, { params });
104 | return {
105 | content: [{
106 | type: "text",
107 | text: "Meeting deleted successfully"
108 | }]
109 | };
110 | } catch (error) {
111 | return handleApiError(error);
112 | }
113 | }
114 | },
115 | {
116 | name: "list_meeting_participants",
117 | description: "List participants from a meeting",
118 | schema: {
119 | meeting_id: z.string().describe("The meeting ID"),
120 | page_size: z.number().min(1).max(300).optional().describe("Number of records returned"),
121 | next_page_token: z.string().optional().describe("Next page token")
122 | },
123 | handler: async ({ meeting_id, page_size, next_page_token }) => {
124 | try {
125 | const params = {};
126 | if (page_size) params.page_size = page_size;
127 | if (next_page_token) params.next_page_token = next_page_token;
128 |
129 | const response = await zoomApi.get(`/report/meetings/${meeting_id}/participants`, { params });
130 | return handleApiResponse(response);
131 | } catch (error) {
132 | return handleApiError(error);
133 | }
134 | }
135 | }
136 | ];
137 |
```