#
tokens: 16212/50000 19/19 files
lines: on (toggle) GitHub
raw markdown copy reset
# 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 | 
```