#
tokens: 14217/50000 10/10 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .github
│   └── workflows
│       └── npm-publish.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   ├── createEvent.vbs
│   ├── deleteEvent.vbs
│   ├── findFreeSlots.vbs
│   ├── getAttendeeStatus.vbs
│   ├── getCalendars.vbs
│   ├── listEvents.vbs
│   ├── updateEvent.vbs
│   └── utils.vbs
├── src
│   ├── index.js
│   ├── outlookTools.js
│   └── scriptRunner.js
└── test-outlook-connection.js
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | npm-debug.log
 4 | yarn-debug.log
 5 | yarn-error.log
 6 | 
 7 | # Environment variables
 8 | .env
 9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 | 
14 | # Build outputs
15 | dist/
16 | build/
17 | 
18 | # Logs
19 | logs
20 | *.log
21 | 
22 | # Runtime data
23 | pids
24 | *.pid
25 | *.seed
26 | *.pid.lock
27 | 
28 | # Directory for instrumented libs generated by jscoverage/JSCover
29 | lib-cov
30 | 
31 | # Coverage directory used by tools like istanbul
32 | coverage
33 | 
34 | # nyc test coverage
35 | .nyc_output
36 | 
37 | # IDEs and editors
38 | .idea/
39 | .vscode/
40 | *.swp
41 | *.swo
42 | .DS_Store
43 | .vs/
44 | *.sublime-workspace
45 | 
46 | # Optional npm cache directory
47 | .npm
48 | 
49 | # Optional eslint cache
50 | .eslintcache
51 | 
52 | # Optional REPL history
53 | .node_repl_history
54 | 
55 | # Output of 'npm pack'
56 | *.tgz
57 | 
58 | # Yarn Integrity file
59 | .yarn-integrity
60 | 
61 | #Cline
62 | .clinerules
63 | memory-bank/
64 | CLAUDE.md
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Outlook Calendar MCP Tool
  2 | 
  3 | A Model Context Protocol (MCP) server that allows Claude to access and manage your local Microsoft Outlook calendar (Windows only).
  4 | 
  5 | <a href="https://glama.ai/mcp/servers/08enllwrbp">
  6 |   <img width="380" height="200" src="https://glama.ai/mcp/servers/08enllwrbp/badge" alt="Outlook Calendar MCP server" />
  7 | </a>
  8 | 
  9 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
 10 | 
 11 | ## Features
 12 | 
 13 | - **View Calendar Events**: List events within a date range, view event details, check attendee status
 14 | - **Manage Calendar Events**: Create new events and meetings, update existing events
 15 | - **Calendar Intelligence**: Find free time slots for scheduling, identify optimal meeting times
 16 | - **Multiple Calendar Support**: Access different calendars in your Outlook profile
 17 | 
 18 | ## Prerequisites
 19 | 
 20 | - Windows operating system
 21 | - Microsoft Outlook desktop client installed
 22 | - **VBScript support** (see VBScript Installation below if you're on Windows 11 24H2+)
 23 | - Node.js (version 14.x or higher)
 24 | - npm (comes with Node.js)
 25 | 
 26 | ### VBScript Installation (Windows 11 24H2+ Users)
 27 | 
 28 | **Important**: Starting with Windows 11 24H2, VBScript is no longer installed by default and must be enabled as an optional feature.
 29 | 
 30 | If you're experiencing issues with the MCP server not working after a Windows update, you likely need to install VBScript:
 31 | 
 32 | 1. Open **Settings** (Windows + I)
 33 | 2. Go to **Apps** → **Optional features**
 34 | 3. Click **"View features"** next to **"Add an optional feature"**
 35 | 4. Search for **"VBScript"**
 36 | 5. Select **VBScript** and click **Install**
 37 | 6. Restart your computer after installation
 38 | 
 39 | **VBScript Deprecation Timeline:**
 40 | - **Phase 1** (Late 2024+): Available as optional feature in Windows 11 24H2
 41 | - **Phase 2** (~2027): Will no longer be enabled by default
 42 | - **Phase 3** (Future): Complete removal from Windows
 43 | 
 44 | *Note: Thanks to community feedback about VBScript deprecation, I'm considering architectural improvements to make the project more future-proof.*
 45 | 
 46 | ## Installation
 47 | 
 48 | ### Option 1: Install from npm
 49 | 
 50 | ```bash
 51 | npm install -g outlook-calendar-mcp
 52 | ```
 53 | 
 54 | You can also run it directly without installation using npx:
 55 | 
 56 | ```bash
 57 | npx outlook-calendar-mcp
 58 | ```
 59 | 
 60 | ### Option 2: Install from source
 61 | 
 62 | 1. Clone this repository or download the source code
 63 | 2. Install dependencies:
 64 | 
 65 | ```bash
 66 | npm install
 67 | ```
 68 | 
 69 | 3. Run the server:
 70 | 
 71 | ```bash
 72 | npm start
 73 | ```
 74 | 
 75 | ## MCP Server Configuration
 76 | 
 77 | To use this tool with Claude, you need to add it to your MCP settings configuration file.
 78 | 
 79 | ### For Claude Desktop App
 80 | 
 81 | Add the following to your Claude Desktop configuration file (located at `%APPDATA%\Claude\claude_desktop_config.json`):
 82 | 
 83 | #### If installed globally via npm:
 84 | 
 85 | ```json
 86 | {
 87 |   "mcpServers": {
 88 |     "outlook-calendar": {
 89 |       "command": "outlook-calendar-mcp",
 90 |       "args": [],
 91 |       "env": {}
 92 |     }
 93 |   }
 94 | }
 95 | ```
 96 | 
 97 | #### Using npx (without installation):
 98 | 
 99 | ```json
100 | {
101 |   "mcpServers": {
102 |     "outlook-calendar": {
103 |       "command": "npx",
104 |       "args": ["-y", "outlook-calendar-mcp"],
105 |       "env": {}
106 |     }
107 |   }
108 | }
109 | ```
110 | 
111 | #### If installed from source:
112 | 
113 | ```json
114 | {
115 |   "mcpServers": {
116 |     "outlook-calendar": {
117 |       "command": "node",
118 |       "args": ["path/to/outlook-calendar-mcp/src/index.js"],
119 |       "env": {}
120 |     }
121 |   }
122 | }
123 | ```
124 | 
125 | ### For Claude VSCode Extension
126 | 
127 | Add the following to your Claude VSCode extension MCP settings file (located at `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`):
128 | 
129 | #### If installed globally via npm:
130 | 
131 | ```json
132 | {
133 |   "mcpServers": {
134 |     "outlook-calendar": {
135 |       "command": "outlook-calendar-mcp",
136 |       "args": [],
137 |       "env": {}
138 |     }
139 |   }
140 | }
141 | ```
142 | 
143 | #### Using npx (without installation):
144 | 
145 | ```json
146 | {
147 |   "mcpServers": {
148 |     "outlook-calendar": {
149 |       "command": "npx",
150 |       "args": ["-y", "outlook-calendar-mcp"],
151 |       "env": {}
152 |     }
153 |   }
154 | }
155 | ```
156 | 
157 | #### If installed from source:
158 | 
159 | ```json
160 | {
161 |   "mcpServers": {
162 |     "outlook-calendar": {
163 |       "command": "node",
164 |       "args": ["path/to/outlook-calendar-mcp/src/index.js"],
165 |       "env": {}
166 |     }
167 |   }
168 | }
169 | ```
170 | 
171 | For source installation, replace `path/to/outlook-calendar-mcp` with the actual path to where you installed this tool.
172 | 
173 | ## Usage
174 | 
175 | Once configured, Claude will have access to the following tools:
176 | 
177 | ### List Calendar Events
178 | 
179 | ```
180 | list_events
181 | - startDate: Start date in MM/DD/YYYY format
182 | - endDate: End date in MM/DD/YYYY format (optional)
183 | - calendar: Calendar name (optional)
184 | ```
185 | 
186 | Example: "List my calendar events for next week"
187 | 
188 | ### Create Calendar Event
189 | 
190 | ```
191 | create_event
192 | - subject: Event subject/title
193 | - startDate: Start date in MM/DD/YYYY format
194 | - startTime: Start time in HH:MM AM/PM format
195 | - endDate: End date in MM/DD/YYYY format (optional)
196 | - endTime: End time in HH:MM AM/PM format (optional)
197 | - location: Event location (optional)
198 | - body: Event description (optional)
199 | - isMeeting: Whether this is a meeting with attendees (optional)
200 | - attendees: Semicolon-separated list of attendee email addresses (optional)
201 | - calendar: Calendar name (optional)
202 | ```
203 | 
204 | Example: "Add a meeting with John about the project proposal on Friday at 2 PM"
205 | 
206 | ### Find Free Time Slots
207 | 
208 | ```
209 | find_free_slots
210 | - startDate: Start date in MM/DD/YYYY format
211 | - endDate: End date in MM/DD/YYYY format (optional)
212 | - duration: Duration in minutes (optional)
213 | - workDayStart: Work day start hour (0-23) (optional)
214 | - workDayEnd: Work day end hour (0-23) (optional)
215 | - calendar: Calendar name (optional)
216 | ```
217 | 
218 | Example: "When am I free for a 1-hour meeting this week?"
219 | 
220 | ### Get Attendee Status
221 | 
222 | ```
223 | get_attendee_status
224 | - eventId: Event ID
225 | - calendar: Calendar name (optional)
226 | ```
227 | 
228 | Example: "Who hasn't responded to my team meeting invitation?"
229 | 
230 | > **Important Note**: When using operations that require an event ID (update_event, delete_event, get_attendee_status), you must use the `id` field from the list_events response. This is the unique EntryID that Outlook uses to identify events.
231 | 
232 | ### Update Calendar Event
233 | 
234 | ```
235 | update_event
236 | - eventId: Event ID to update
237 | - subject: New event subject/title (optional)
238 | - startDate: New start date in MM/DD/YYYY format (optional)
239 | - startTime: New start time in HH:MM AM/PM format (optional)
240 | - endDate: New end date in MM/DD/YYYY format (optional)
241 | - endTime: New end time in HH:MM AM/PM format (optional)
242 | - location: New event location (optional)
243 | - body: New event description (optional)
244 | - calendar: Calendar name (optional)
245 | ```
246 | 
247 | Example: "Update my team meeting tomorrow to start at 3 PM instead of 2 PM"
248 | 
249 | ### Get Calendars
250 | 
251 | ```
252 | get_calendars
253 | ```
254 | 
255 | Example: "Show me my available calendars"
256 | 
257 | ## Security Notes
258 | 
259 | - On first use, Outlook may display security prompts to allow script access
260 | - The tool only accesses your local Outlook client and does not send calendar data to external servers
261 | - All calendar operations are performed locally on your computer
262 | 
263 | ## Troubleshooting
264 | 
265 | - **VBScript Not Available (Windows 11 24H2+)**: If you get errors after a Windows update, VBScript may need to be installed. See [VBScript Installation](#vbscript-installation-windows-11-24h2-users) section above
266 | - **"Script execution failed" errors**: Usually indicates VBScript is not available or Outlook is not accessible
267 | - **Outlook Security Prompts**: If you see security prompts from Outlook, you need to allow the script to access your Outlook data
268 | - **Script Execution Policy**: If you encounter script execution errors, you may need to adjust your PowerShell execution policy
269 | - **Path Issues**: Ensure the path in your MCP configuration file points to the correct location of the tool
270 | 
271 | ## Contributing
272 | 
273 | We welcome contributions to the Outlook Calendar MCP Tool! Please see our [Contributing Guide](CONTRIBUTING.md) for details on how to get started.
274 | 
275 | By participating in this project, you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md).
276 | 
277 | ## License
278 | 
279 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Contributing to Outlook Calendar MCP Tool
 2 | 
 3 | Thank you for considering contributing to the Outlook Calendar MCP Tool! This document provides guidelines and instructions for contributing to this project.
 4 | 
 5 | ## Code of Conduct
 6 | 
 7 | By participating in this project, you agree to maintain a respectful and inclusive environment for everyone. Please be kind and courteous to others, and consider the impact of your words and actions.
 8 | 
 9 | ## How to Contribute
10 | 
11 | There are many ways to contribute to this project:
12 | 
13 | 1. **Reporting Bugs**: If you find a bug, please create an issue with a detailed description of the problem, steps to reproduce it, and your environment details.
14 | 
15 | 2. **Suggesting Enhancements**: Have an idea for a new feature or improvement? Create an issue with the tag "enhancement" and describe your suggestion in detail.
16 | 
17 | 3. **Code Contributions**: Want to fix a bug or implement a feature? Follow the steps below:
18 | 
19 | ### Pull Request Process
20 | 
21 | 1. **Fork the Repository**: Create your own fork of the project.
22 | 
23 | 2. **Create a Branch**: Create a branch for your changes with a descriptive name.
24 |    ```
25 |    git checkout -b feature/your-feature-name
26 |    ```
27 | 
28 | 3. **Make Your Changes**: Implement your changes, following the coding standards and practices used in the project.
29 | 
30 | 4. **Test Your Changes**: Ensure your changes work as expected and don't break existing functionality.
31 | 
32 | 5. **Update Documentation**: Update any relevant documentation, including README.md, if necessary.
33 | 
34 | 6. **Submit a Pull Request**: Push your changes to your fork and submit a pull request to the main repository.
35 | 
36 | 7. **Code Review**: Wait for a maintainer to review your pull request. You may need to make additional changes based on feedback.
37 | 
38 | ## Development Setup
39 | 
40 | To set up the project for development:
41 | 
42 | 1. Clone the repository:
43 |    ```
44 |    git clone https://github.com/yourusername/outlook-calendar-mcp.git
45 |    cd outlook-calendar-mcp
46 |    ```
47 | 
48 | 2. Install dependencies:
49 |    ```
50 |    npm install
51 |    ```
52 | 
53 | 3. Make your changes and test them locally.
54 | 
55 | ## Coding Standards
56 | 
57 | Please follow these coding standards when contributing:
58 | 
59 | 1. **JavaScript/Node.js**:
60 |    - Use ES6 syntax
61 |    - Follow the existing code style
62 |    - Use async/await for asynchronous operations
63 |    - Add JSDoc comments for functions and complex logic
64 | 
65 | 2. **VBScript**:
66 |    - Use Option Explicit for all scripts
67 |    - Follow the existing code style
68 |    - Use structured error handling with descriptive messages
69 |    - Add comments for functions and complex logic
70 | 
71 | ## Testing
72 | 
73 | Before submitting a pull request, please test your changes thoroughly:
74 | 
75 | 1. Test all affected functionality
76 | 2. Ensure error handling works correctly
77 | 3. Verify that your changes don't break existing features
78 | 
79 | ## License
80 | 
81 | By contributing to this project, you agree that your contributions will be licensed under the project's MIT License.
82 | 
83 | ## Questions?
84 | 
85 | If you have any questions about contributing, please create an issue with the tag "question".
86 | 
87 | Thank you for your contribution!
88 | 
```

--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Contributor Covenant Code of Conduct
  2 | 
  3 | ## Our Pledge
  4 | 
  5 | We as members, contributors, and leaders pledge to make participation in our
  6 | community a harassment-free experience for everyone, regardless of age, body
  7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
  8 | identity and expression, level of experience, education, socio-economic status,
  9 | nationality, personal appearance, race, religion, or sexual identity
 10 | and orientation.
 11 | 
 12 | We pledge to act and interact in ways that contribute to an open, welcoming,
 13 | diverse, inclusive, and healthy community.
 14 | 
 15 | ## Our Standards
 16 | 
 17 | Examples of behavior that contributes to a positive environment for our
 18 | community include:
 19 | 
 20 | * Demonstrating empathy and kindness toward other people
 21 | * Being respectful of differing opinions, viewpoints, and experiences
 22 | * Giving and gracefully accepting constructive feedback
 23 | * Accepting responsibility and apologizing to those affected by our mistakes,
 24 |   and learning from the experience
 25 | * Focusing on what is best not just for us as individuals, but for the
 26 |   overall community
 27 | 
 28 | Examples of unacceptable behavior include:
 29 | 
 30 | * The use of sexualized language or imagery, and sexual attention or
 31 |   advances of any kind
 32 | * Trolling, insulting or derogatory comments, and personal or political attacks
 33 | * Public or private harassment
 34 | * Publishing others' private information, such as a physical or email
 35 |   address, without their explicit permission
 36 | * Other conduct which could reasonably be considered inappropriate in a
 37 |   professional setting
 38 | 
 39 | ## Enforcement Responsibilities
 40 | 
 41 | Project maintainers are responsible for clarifying and enforcing our standards of
 42 | acceptable behavior and will take appropriate and fair corrective action in
 43 | response to any behavior that they deem inappropriate, threatening, offensive,
 44 | or harmful.
 45 | 
 46 | Project maintainers have the right and responsibility to remove, edit, or reject
 47 | comments, commits, code, wiki edits, issues, and other contributions that are
 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
 49 | decisions when appropriate.
 50 | 
 51 | ## Scope
 52 | 
 53 | This Code of Conduct applies within all community spaces, and also applies when
 54 | an individual is officially representing the community in public spaces.
 55 | Examples of representing our community include using an official e-mail address,
 56 | posting via an official social media account, or acting as an appointed
 57 | representative at an online or offline event.
 58 | 
 59 | ## Enforcement
 60 | 
 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
 62 | reported to the project maintainers responsible for enforcement.
 63 | All complaints will be reviewed and investigated promptly and fairly.
 64 | 
 65 | All project maintainers are obligated to respect the privacy and security of the
 66 | reporter of any incident.
 67 | 
 68 | ## Enforcement Guidelines
 69 | 
 70 | Project maintainers will follow these Community Impact Guidelines in determining
 71 | the consequences for any action they deem in violation of this Code of Conduct:
 72 | 
 73 | ### 1. Correction
 74 | 
 75 | **Community Impact**: Use of inappropriate language or other behavior deemed
 76 | unprofessional or unwelcome in the community.
 77 | 
 78 | **Consequence**: A private, written warning from project maintainers, providing
 79 | clarity around the nature of the violation and an explanation of why the
 80 | behavior was inappropriate. A public apology may be requested.
 81 | 
 82 | ### 2. Warning
 83 | 
 84 | **Community Impact**: A violation through a single incident or series
 85 | of actions.
 86 | 
 87 | **Consequence**: A warning with consequences for continued behavior. No
 88 | interaction with the people involved, including unsolicited interaction with
 89 | those enforcing the Code of Conduct, for a specified period of time. This
 90 | includes avoiding interactions in community spaces as well as external channels
 91 | like social media. Violating these terms may lead to a temporary or
 92 | permanent ban.
 93 | 
 94 | ### 3. Temporary Ban
 95 | 
 96 | **Community Impact**: A serious violation of community standards, including
 97 | sustained inappropriate behavior.
 98 | 
 99 | **Consequence**: A temporary ban from any sort of interaction or public
100 | communication with the community for a specified period of time. No public or
101 | private interaction with the people involved, including unsolicited interaction
102 | with those enforcing the Code of Conduct, is allowed during this period.
103 | Violating these terms may lead to a permanent ban.
104 | 
105 | ### 4. Permanent Ban
106 | 
107 | **Community Impact**: Demonstrating a pattern of violation of community
108 | standards, including sustained inappropriate behavior, harassment of an
109 | individual, or aggression toward or disparagement of classes of individuals.
110 | 
111 | **Consequence**: A permanent ban from any sort of public interaction within
112 | the community.
113 | 
114 | ## Attribution
115 | 
116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
117 | version 2.0, available at
118 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
119 | 
120 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
121 | enforcement ladder](https://github.com/mozilla/diversity).
122 | 
123 | [homepage]: https://www.contributor-covenant.org
124 | 
125 | For answers to common questions about this code of conduct, see the FAQ at
126 | https://www.contributor-covenant.org/faq. Translations are available at
127 | https://www.contributor-covenant.org/translations.
128 | 
```

--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # This workflow will publish a package to npm when a release is created
 2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
 3 | 
 4 | name: Node.js Package
 5 | 
 6 | on:
 7 |   release:
 8 |     types: [created]
 9 | 
10 | jobs:
11 |   publish-npm:
12 |     runs-on: ubuntu-latest
13 |     steps:
14 |       - uses: actions/checkout@v4
15 |       - uses: actions/setup-node@v4
16 |         with:
17 |           node-version: 16
18 |           registry-url: https://registry.npmjs.org/
19 |       - run: npm ci
20 |       - run: npm publish
21 |         env:
22 |           NODE_AUTH_TOKEN: ${{secrets.npm_token}}
23 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "outlook-calendar-mcp",
 3 |   "version": "1.0.5",
 4 |   "description": "MCP server for Outlook Calendar integration",
 5 |   "main": "src/index.js",
 6 |   "type": "module",
 7 |   "author": "Meraj Mehrabi",
 8 |   "bugs": "https://github.com/merajmehrabi/Outlook_Calendar_MCP/issues",
 9 |   "license": "MIT",
10 |   "bin": {
11 |     "outlook-calendar-mcp": "./src/index.js"
12 |   },
13 |   "scripts": {
14 |     "start": "chcp 65001 >nul 2>&1 && node src/index.js",
15 |     "start:utf8": "chcp 65001 >nul 2>&1 && node src/index.js",
16 |     "test": "chcp 65001 >nul 2>&1 && node test-outlook-connection.js",
17 |     "test:outlook": "chcp 65001 >nul 2>&1 && node test-outlook-connection.js"
18 |   },
19 |   "keywords": [
20 |     "outlook",
21 |     "calendar",
22 |     "mcp",
23 |     "claude",
24 |     "Model Context Protocol"
25 |   ],
26 |   "dependencies": {
27 |     "@modelcontextprotocol/sdk": "^1.0.3"
28 |   }
29 | }
30 | 
```

--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | /**
  3 |  * index.js - Entry point for the Outlook Calendar MCP server
  4 |  */
  5 | 
  6 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  7 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  8 | import {
  9 |   CallToolRequestSchema,
 10 |   ErrorCode,
 11 |   ListToolsRequestSchema,
 12 |   McpError
 13 | } from '@modelcontextprotocol/sdk/types.js';
 14 | import { defineOutlookTools } from './outlookTools.js';
 15 | 
 16 | /**
 17 |  * Main class for the Outlook Calendar MCP server
 18 |  */
 19 | class OutlookCalendarServer {
 20 |   constructor() {
 21 |     // Initialize the MCP server
 22 |     this.server = new Server(
 23 |       {
 24 |         name: 'outlook-calendar-server',
 25 |         version: '1.0.0',
 26 |       },
 27 |       {
 28 |         capabilities: {
 29 |           tools: {},
 30 |         },
 31 |       }
 32 |     );
 33 | 
 34 |     // Define the tools
 35 |     this.tools = defineOutlookTools();
 36 | 
 37 |     // Set up request handlers
 38 |     this.setupToolHandlers();
 39 |     
 40 |     // Error handling
 41 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
 42 |     process.on('SIGINT', async () => {
 43 |       await this.server.close();
 44 |       process.exit(0);
 45 |     });
 46 |   }
 47 | 
 48 |   /**
 49 |    * Sets up the tool request handlers
 50 |    */
 51 |   setupToolHandlers() {
 52 |     // List available tools
 53 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => {
 54 |       const toolsList = Object.values(this.tools).map(tool => ({
 55 |         name: tool.name,
 56 |         description: tool.description,
 57 |         inputSchema: tool.inputSchema,
 58 |       }));
 59 | 
 60 |       return {
 61 |         tools: toolsList,
 62 |       };
 63 |     });
 64 | 
 65 |     // Handle tool calls
 66 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
 67 |       const { name, arguments: args } = request.params;
 68 |       
 69 |       // Find the requested tool
 70 |       const tool = this.tools[name];
 71 |       
 72 |       if (!tool) {
 73 |         throw new McpError(
 74 |           ErrorCode.MethodNotFound,
 75 |           `Tool not found: ${name}`
 76 |         );
 77 |       }
 78 |       
 79 |       try {
 80 |         // Call the tool handler
 81 |         return await tool.handler(args);
 82 |       } catch (error) {
 83 |         console.error(`Error executing tool ${name}:`, error);
 84 |         
 85 |         return {
 86 |           content: [
 87 |             {
 88 |               type: 'text',
 89 |               text: `Error executing tool ${name}: ${error.message}`,
 90 |             },
 91 |           ],
 92 |           isError: true,
 93 |         };
 94 |       }
 95 |     });
 96 |   }
 97 | 
 98 |   /**
 99 |    * Starts the MCP server
100 |    */
101 |   async run() {
102 |     try {
103 |       const transport = new StdioServerTransport();
104 |       await this.server.connect(transport);
105 |       console.error('Outlook Calendar MCP server running on stdio');
106 |     } catch (error) {
107 |       console.error('Failed to start MCP server:', error);
108 |       process.exit(1);
109 |     }
110 |   }
111 | }
112 | 
113 | // Create and run the server
114 | const server = new OutlookCalendarServer();
115 | server.run().catch(console.error);
116 | 
```

--------------------------------------------------------------------------------
/src/scriptRunner.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * scriptRunner.js - Handles execution of VBScript files and processes their output
  3 |  */
  4 | 
  5 | import { exec } from 'child_process';
  6 | import path from 'path';
  7 | import { fileURLToPath } from 'url';
  8 | 
  9 | // Get the directory name of the current module
 10 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
 11 | 
 12 | // Constants
 13 | const SCRIPTS_DIR = path.resolve(__dirname, '../scripts');
 14 | const SUCCESS_PREFIX = 'SUCCESS:';
 15 | const ERROR_PREFIX = 'ERROR:';
 16 | 
 17 | /**
 18 |  * Executes a VBScript file with the given parameters
 19 |  * @param {string} scriptName - Name of the script file (without .vbs extension)
 20 |  * @param {Object} params - Parameters to pass to the script
 21 |  * @returns {Promise<Object>} - Promise that resolves with the script output
 22 |  */
 23 | export async function executeScript(scriptName, params = {}) {
 24 |   return new Promise((resolve, reject) => {
 25 |     // Build the command with UTF-8 support
 26 |     const scriptPath = path.join(SCRIPTS_DIR, `${scriptName}.vbs`);
 27 |     let command = `chcp 65001 >nul 2>&1 && cscript //NoLogo "${scriptPath}"`;
 28 |     
 29 |     // Add parameters
 30 |     for (const [key, value] of Object.entries(params)) {
 31 |       if (value !== undefined && value !== null && value !== '') {
 32 |         // Handle special characters in values
 33 |         const escapedValue = value.toString().replace(/"/g, '\\"');
 34 |         command += ` /${key}:"${escapedValue}"`;
 35 |       }
 36 |     }
 37 |     
 38 |     // Execute the command with UTF-8 encoding
 39 |     exec(command, { encoding: 'utf8' }, (error, stdout, stderr) => {
 40 |       // Check for execution errors
 41 |       if (error && !stdout.includes(SUCCESS_PREFIX)) {
 42 |         return reject(new Error(`Script execution failed: ${error.message}`));
 43 |       }
 44 |       
 45 |       // Check for script errors
 46 |       if (stdout.includes(ERROR_PREFIX)) {
 47 |         const errorMessage = stdout.substring(stdout.indexOf(ERROR_PREFIX) + ERROR_PREFIX.length).trim();
 48 |         return reject(new Error(`Script error: ${errorMessage}`));
 49 |       }
 50 |       
 51 |       // Process successful output
 52 |       if (stdout.includes(SUCCESS_PREFIX)) {
 53 |         try {
 54 |           const jsonStr = stdout.substring(stdout.indexOf(SUCCESS_PREFIX) + SUCCESS_PREFIX.length).trim();
 55 |           const result = JSON.parse(jsonStr);
 56 |           return resolve(result);
 57 |         } catch (parseError) {
 58 |           return reject(new Error(`Failed to parse script output: ${parseError.message}`));
 59 |         }
 60 |       }
 61 |       
 62 |       // If we get here, something unexpected happened
 63 |       reject(new Error(`Unexpected script output: ${stdout}`));
 64 |     });
 65 |   });
 66 | }
 67 | 
 68 | /**
 69 |  * Lists calendar events within a specified date range
 70 |  * @param {string} startDate - Start date in MM/DD/YYYY format
 71 |  * @param {string} endDate - End date in MM/DD/YYYY format (optional)
 72 |  * @param {string} calendar - Calendar name (optional)
 73 |  * @returns {Promise<Array>} - Promise that resolves with an array of events
 74 |  */
 75 | export async function listEvents(startDate, endDate, calendar) {
 76 |   return executeScript('listEvents', { startDate, endDate, calendar });
 77 | }
 78 | 
 79 | /**
 80 |  * Creates a new calendar event
 81 |  * @param {Object} eventDetails - Event details
 82 |  * @returns {Promise<Object>} - Promise that resolves with the created event ID
 83 |  */
 84 | export async function createEvent(eventDetails) {
 85 |   return executeScript('createEvent', eventDetails);
 86 | }
 87 | 
 88 | /**
 89 |  * Finds free time slots in the calendar
 90 |  * @param {string} startDate - Start date in MM/DD/YYYY format
 91 |  * @param {string} endDate - End date in MM/DD/YYYY format (optional)
 92 |  * @param {number} duration - Duration in minutes (optional)
 93 |  * @param {number} workDayStart - Work day start hour (0-23) (optional)
 94 |  * @param {number} workDayEnd - Work day end hour (0-23) (optional)
 95 |  * @param {string} calendar - Calendar name (optional)
 96 |  * @returns {Promise<Array>} - Promise that resolves with an array of free time slots
 97 |  */
 98 | export async function findFreeSlots(startDate, endDate, duration, workDayStart, workDayEnd, calendar) {
 99 |   return executeScript('findFreeSlots', {
100 |     startDate,
101 |     endDate,
102 |     duration,
103 |     workDayStart,
104 |     workDayEnd,
105 |     calendar
106 |   });
107 | }
108 | 
109 | /**
110 |  * Gets the response status of meeting attendees
111 |  * @param {string} eventId - Event ID
112 |  * @param {string} calendar - Calendar name (optional)
113 |  * @returns {Promise<Object>} - Promise that resolves with meeting details and attendee status
114 |  */
115 | export async function getAttendeeStatus(eventId, calendar) {
116 |   return executeScript('getAttendeeStatus', { eventId, calendar });
117 | }
118 | 
119 | /**
120 |  * Deletes a calendar event by its ID
121 |  * @param {string} eventId - Event ID
122 |  * @param {string} calendar - Calendar name (optional)
123 |  * @returns {Promise<Object>} - Promise that resolves with the deletion result
124 |  */
125 | export async function deleteEvent(eventId, calendar) {
126 |   return executeScript('deleteEvent', { eventId, calendar });
127 | }
128 | 
129 | /**
130 |  * Updates an existing calendar event
131 |  * @param {string} eventId - Event ID to update
132 |  * @param {string} subject - New subject (optional)
133 |  * @param {string} startDate - New start date in MM/DD/YYYY format (optional)
134 |  * @param {string} startTime - New start time in HH:MM AM/PM format (optional)
135 |  * @param {string} endDate - New end date in MM/DD/YYYY format (optional)
136 |  * @param {string} endTime - New end time in HH:MM AM/PM format (optional)
137 |  * @param {string} location - New location (optional)
138 |  * @param {string} body - New body/description (optional)
139 |  * @param {string} calendar - Calendar name (optional)
140 |  * @returns {Promise<Object>} - Promise that resolves with the update result
141 |  */
142 | export async function updateEvent(eventId, subject, startDate, startTime, endDate, endTime, location, body, calendar) {
143 |   return executeScript('updateEvent', {
144 |     eventId,
145 |     subject,
146 |     startDate,
147 |     startTime,
148 |     endDate,
149 |     endTime,
150 |     location,
151 |     body,
152 |     calendar
153 |   });
154 | }
155 | 
156 | /**
157 |  * Lists available calendars
158 |  * @returns {Promise<Array>} - Promise that resolves with an array of calendars
159 |  */
160 | export async function getCalendars() {
161 |   return executeScript('getCalendars');
162 | }
163 | 
```

--------------------------------------------------------------------------------
/test-outlook-connection.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * test-outlook-connection.js - Comprehensive test script for Outlook calendar operations
  3 |  * 
  4 |  * This script tests if the MCP tool can access and manipulate your Outlook calendar by:
  5 |  * 1. Testing connection by listing available calendars
  6 |  * 2. Testing READ operation by listing events
  7 |  * 3. Testing WRITE operation by creating a test event
  8 |  * 4. Testing DELETE operation by removing the test event
  9 |  */
 10 | 
 11 | import { exec } from 'child_process';
 12 | import path from 'path';
 13 | import { fileURLToPath } from 'url';
 14 | import { promisify } from 'util';
 15 | 
 16 | // Convert exec to promise-based
 17 | const execPromise = promisify(exec);
 18 | 
 19 | // Get the directory name of the current module
 20 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
 21 | 
 22 | // Script paths
 23 | const scriptsDir = path.join(__dirname, 'scripts');
 24 | const getCalendarsScript = path.join(scriptsDir, 'getCalendars.vbs');
 25 | const listEventsScript = path.join(scriptsDir, 'listEvents.vbs');
 26 | const createEventScript = path.join(scriptsDir, 'createEvent.vbs');
 27 | const updateEventScript = path.join(scriptsDir, 'updateEvent.vbs');
 28 | const deleteEventScript = path.join(scriptsDir, 'deleteEvent.vbs');
 29 | 
 30 | // Test event details
 31 | const testEventSubject = `Test Event ${new Date().toISOString()}`;
 32 | const today = new Date();
 33 | const formattedDate = `${today.getMonth() + 1}/${today.getDate()}/${today.getFullYear()}`;
 34 | let testEventId = null;
 35 | 
 36 | // Helper function to parse script output
 37 | function parseScriptOutput(stdout) {
 38 |   if (stdout.includes('SUCCESS:')) {
 39 |     const jsonStr = stdout.substring(stdout.indexOf('SUCCESS:') + 'SUCCESS:'.length).trim();
 40 |     try {
 41 |       return { success: true, data: JSON.parse(jsonStr) };
 42 |     } catch (parseError) {
 43 |       return { success: false, error: `Error parsing JSON: ${parseError.message}`, raw: jsonStr };
 44 |     }
 45 |   } else if (stdout.includes('ERROR:')) {
 46 |     const errorMessage = stdout.substring(stdout.indexOf('ERROR:') + 'ERROR:'.length).trim();
 47 |     return { success: false, error: errorMessage };
 48 |   } else {
 49 |     return { success: false, error: 'Unexpected script output', raw: stdout };
 50 |   }
 51 | }
 52 | 
 53 | // Execute a VBScript with parameters
 54 | async function executeScript(scriptPath, params = []) {
 55 |   const paramString = params.map(p => `/${p.name}:"${p.value}"`).join(' ');
 56 |   const command = `cscript //NoLogo "${scriptPath}" ${paramString}`;
 57 |   
 58 |   try {
 59 |     const { stdout, stderr } = await execPromise(command);
 60 |     
 61 |     if (stderr) {
 62 |       return { success: false, error: stderr };
 63 |     }
 64 |     
 65 |     return parseScriptOutput(stdout);
 66 |   } catch (error) {
 67 |     return { success: false, error: error.message };
 68 |   }
 69 | }
 70 | 
 71 | // Main test function
 72 | async function runTests() {
 73 |   console.log('🔍 TESTING OUTLOOK CALENDAR MCP TOOL');
 74 |   console.log('====================================');
 75 |   
 76 |   // Test 1: Connection Test
 77 |   console.log('\n📋 TEST 1: Connection Test (getCalendars.vbs)');
 78 |   console.log('-------------------------------------------');
 79 |   
 80 |   const connectionResult = await executeScript(getCalendarsScript);
 81 |   
 82 |   if (connectionResult.success) {
 83 |     console.log('✅ Connection test passed!');
 84 |     console.log('Available calendars:');
 85 |     console.log(JSON.stringify(connectionResult.data, null, 2));
 86 |   } else {
 87 |     console.error('❌ Connection test failed:', connectionResult.error);
 88 |     console.error('Cannot proceed with further tests without Outlook connection.');
 89 |     process.exit(1);
 90 |   }
 91 |   
 92 |   // Test 2: Read Test
 93 |   console.log('\n📋 TEST 2: Read Test (listEvents.vbs)');
 94 |   console.log('-------------------------------------------');
 95 |   
 96 |   const readResult = await executeScript(listEventsScript, [
 97 |     { name: 'startDate', value: formattedDate },
 98 |     { name: 'endDate', value: formattedDate }
 99 |   ]);
100 |   
101 |   if (readResult.success) {
102 |     console.log('✅ Read test passed!');
103 |     console.log(`Found ${readResult.data.length} events for today (${formattedDate}).`);
104 |   } else {
105 |     console.error('❌ Read test failed:', readResult.error);
106 |     console.error('Cannot proceed with further tests.');
107 |     process.exit(1);
108 |   }
109 |   
110 |   // Test 3: Write Test
111 |   console.log('\n📋 TEST 3: Write Test (createEvent.vbs)');
112 |   console.log('-------------------------------------------');
113 |   
114 |   const writeResult = await executeScript(createEventScript, [
115 |     { name: 'subject', value: testEventSubject },
116 |     { name: 'startDate', value: formattedDate },
117 |     { name: 'startTime', value: '2:00 PM' },
118 |     { name: 'endDate', value: formattedDate },
119 |     { name: 'endTime', value: '2:30 PM' },
120 |     { name: 'location', value: 'Test Location' },
121 |     { name: 'body', value: 'This is a test event created by the Outlook Calendar MCP Tool test script.' }
122 |   ]);
123 |   
124 |   if (writeResult.success) {
125 |     testEventId = writeResult.data.eventId;
126 |     console.log('✅ Write test passed!');
127 |     console.log(`Created test event with ID: ${testEventId}`);
128 |   } else {
129 |     console.error('❌ Write test failed:', writeResult.error);
130 |     console.error('Cannot proceed with delete test.');
131 |     process.exit(1);
132 |   }
133 |   
134 |   // Test 4: Update Test
135 |   console.log('\n📋 TEST 4: Update Test (updateEvent.vbs)');
136 |   console.log('-------------------------------------------');
137 |   
138 |   if (!testEventId) {
139 |     console.error('❌ Update test skipped: No event ID from write test.');
140 |     process.exit(1);
141 |   }
142 |   
143 |   const updateResult = await executeScript(updateEventScript, [
144 |     { name: 'eventId', value: testEventId },
145 |     { name: 'subject', value: `${testEventSubject} - UPDATED` },
146 |     { name: 'location', value: 'Updated Test Location' }
147 |   ]);
148 |   
149 |   if (updateResult.success && updateResult.data.success) {
150 |     console.log('✅ Update test passed!');
151 |     console.log(`Successfully updated test event with ID: ${testEventId}`);
152 |   } else {
153 |     console.error('❌ Update test failed:', updateResult.error || 'Unknown error');
154 |     process.exit(1);
155 |   }
156 |   
157 |   // Test 5: Delete Test
158 |   console.log('\n📋 TEST 5: Delete Test (deleteEvent.vbs)');
159 |   console.log('-------------------------------------------');
160 |   
161 |   if (!testEventId) {
162 |     console.error('❌ Delete test skipped: No event ID from write test.');
163 |     process.exit(1);
164 |   }
165 |   
166 |   const deleteResult = await executeScript(deleteEventScript, [
167 |     { name: 'eventId', value: testEventId }
168 |   ]);
169 |   
170 |   if (deleteResult.success && deleteResult.data.success) {
171 |     console.log('✅ Delete test passed!');
172 |     console.log(`Successfully deleted test event with ID: ${testEventId}`);
173 |   } else {
174 |     console.error('❌ Delete test failed:', deleteResult.error || 'Unknown error');
175 |     process.exit(1);
176 |   }
177 |   
178 |   // Summary
179 |   console.log('\n📋 TEST SUMMARY');
180 |   console.log('-------------------------------------------');
181 |   console.log('✅ Connection Test: PASSED');
182 |   console.log('✅ Read Test: PASSED');
183 |   console.log('✅ Write Test: PASSED');
184 |   console.log('✅ Update Test: PASSED');
185 |   console.log('✅ Delete Test: PASSED');
186 |   console.log('\n🎉 All tests passed! The Outlook Calendar MCP Tool is working correctly.');
187 | }
188 | 
189 | // Run the tests
190 | runTests().catch(error => {
191 |   console.error('Error running tests:', error);
192 |   process.exit(1);
193 | });
194 | 
```

--------------------------------------------------------------------------------
/src/outlookTools.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * outlookTools.js - Defines MCP tools for Outlook calendar operations
  3 |  */
  4 | 
  5 | import {
  6 |   listEvents,
  7 |   createEvent,
  8 |   findFreeSlots,
  9 |   getAttendeeStatus,
 10 |   getCalendars,
 11 |   deleteEvent,
 12 |   updateEvent
 13 | } from './scriptRunner.js';
 14 | 
 15 | /**
 16 |  * Defines the MCP tools for Outlook calendar operations
 17 |  * @returns {Object} - Object containing tool definitions
 18 |  */
 19 | export function defineOutlookTools() {
 20 |   return {
 21 |     // List calendar events
 22 |     list_events: {
 23 |       name: 'list_events',
 24 |       description: 'List calendar events within a specified date range',
 25 |       inputSchema: {
 26 |         type: 'object',
 27 |         properties: {
 28 |           startDate: {
 29 |             type: 'string',
 30 |             description: 'Start date in MM/DD/YYYY format'
 31 |           },
 32 |           endDate: {
 33 |             type: 'string',
 34 |             description: 'End date in MM/DD/YYYY format'
 35 |           },
 36 |           calendar: {
 37 |             type: 'string',
 38 |             description: 'Calendar name (optional)'
 39 |           }
 40 |         },
 41 |         required: ['startDate', 'endDate']
 42 |       },
 43 |       handler: async ({ startDate, endDate, calendar }) => {
 44 |         try {
 45 |           const events = await listEvents(startDate, endDate, calendar);
 46 |           return {
 47 |             content: [
 48 |               {
 49 |                 type: 'text',
 50 |                 text: JSON.stringify(events, null, 2)
 51 |               }
 52 |             ]
 53 |           };
 54 |         } catch (error) {
 55 |           return {
 56 |             content: [
 57 |               {
 58 |                 type: 'text',
 59 |                 text: `Error listing events: ${error.message}`
 60 |               }
 61 |             ],
 62 |             isError: true
 63 |           };
 64 |         }
 65 |       }
 66 |     },
 67 | 
 68 |     // Create calendar event
 69 |     create_event: {
 70 |       name: 'create_event',
 71 |       description: 'Create a new calendar event or meeting',
 72 |       inputSchema: {
 73 |         type: 'object',
 74 |         properties: {
 75 |           subject: {
 76 |             type: 'string',
 77 |             description: 'Event subject/title'
 78 |           },
 79 |           startDate: {
 80 |             type: 'string',
 81 |             description: 'Start date in MM/DD/YYYY format'
 82 |           },
 83 |           startTime: {
 84 |             type: 'string',
 85 |             description: 'Start time in HH:MM AM/PM format'
 86 |           },
 87 |           endDate: {
 88 |             type: 'string',
 89 |             description: 'End date in MM/DD/YYYY format (optional, defaults to start date)'
 90 |           },
 91 |           endTime: {
 92 |             type: 'string',
 93 |             description: 'End time in HH:MM AM/PM format (optional, defaults to 30 minutes after start time)'
 94 |           },
 95 |           location: {
 96 |             type: 'string',
 97 |             description: 'Event location (optional)'
 98 |           },
 99 |           body: {
100 |             type: 'string',
101 |             description: 'Event description/body (optional)'
102 |           },
103 |           isMeeting: {
104 |             type: 'boolean',
105 |             description: 'Whether this is a meeting with attendees (optional, defaults to false)'
106 |           },
107 |           attendees: {
108 |             type: 'string',
109 |             description: 'Semicolon-separated list of attendee email addresses (optional)'
110 |           },
111 |           calendar: {
112 |             type: 'string',
113 |             description: 'Calendar name (optional)'
114 |           }
115 |         },
116 |         required: ['subject', 'startDate', 'startTime']
117 |       },
118 |       handler: async (eventDetails) => {
119 |         try {
120 |           const result = await createEvent(eventDetails);
121 |           return {
122 |             content: [
123 |               {
124 |                 type: 'text',
125 |                 text: `Event created successfully with ID: ${result.eventId}`
126 |               }
127 |             ]
128 |           };
129 |         } catch (error) {
130 |           return {
131 |             content: [
132 |               {
133 |                 type: 'text',
134 |                 text: `Error creating event: ${error.message}`
135 |               }
136 |             ],
137 |             isError: true
138 |           };
139 |         }
140 |       }
141 |     },
142 | 
143 |     // Find free time slots
144 |     find_free_slots: {
145 |       name: 'find_free_slots',
146 |       description: 'Find available time slots in the calendar',
147 |       inputSchema: {
148 |         type: 'object',
149 |         properties: {
150 |           startDate: {
151 |             type: 'string',
152 |             description: 'Start date in MM/DD/YYYY format'
153 |           },
154 |           endDate: {
155 |             type: 'string',
156 |             description: 'End date in MM/DD/YYYY format (optional, defaults to 7 days from start date)'
157 |           },
158 |           duration: {
159 |             type: 'number',
160 |             description: 'Duration in minutes (optional, defaults to 30)'
161 |           },
162 |           workDayStart: {
163 |             type: 'number',
164 |             description: 'Work day start hour (0-23) (optional, defaults to 9)'
165 |           },
166 |           workDayEnd: {
167 |             type: 'number',
168 |             description: 'Work day end hour (0-23) (optional, defaults to 17)'
169 |           },
170 |           calendar: {
171 |             type: 'string',
172 |             description: 'Calendar name (optional)'
173 |           }
174 |         },
175 |         required: ['startDate']
176 |       },
177 |       handler: async ({ startDate, endDate, duration, workDayStart, workDayEnd, calendar }) => {
178 |         try {
179 |           const freeSlots = await findFreeSlots(startDate, endDate, duration, workDayStart, workDayEnd, calendar);
180 |           return {
181 |             content: [
182 |               {
183 |                 type: 'text',
184 |                 text: JSON.stringify(freeSlots, null, 2)
185 |               }
186 |             ]
187 |           };
188 |         } catch (error) {
189 |           return {
190 |             content: [
191 |               {
192 |                 type: 'text',
193 |                 text: `Error finding free slots: ${error.message}`
194 |               }
195 |             ],
196 |             isError: true
197 |           };
198 |         }
199 |       }
200 |     },
201 | 
202 |     // Get attendee status
203 |     get_attendee_status: {
204 |       name: 'get_attendee_status',
205 |       description: 'Check the response status of meeting attendees',
206 |       inputSchema: {
207 |         type: 'object',
208 |         properties: {
209 |           eventId: {
210 |             type: 'string',
211 |             description: 'Event ID'
212 |           },
213 |           calendar: {
214 |             type: 'string',
215 |             description: 'Calendar name (optional)'
216 |           }
217 |         },
218 |         required: ['eventId']
219 |       },
220 |       handler: async ({ eventId, calendar }) => {
221 |         try {
222 |           const attendeeStatus = await getAttendeeStatus(eventId, calendar);
223 |           return {
224 |             content: [
225 |               {
226 |                 type: 'text',
227 |                 text: JSON.stringify(attendeeStatus, null, 2)
228 |               }
229 |             ]
230 |           };
231 |         } catch (error) {
232 |           return {
233 |             content: [
234 |               {
235 |                 type: 'text',
236 |                 text: `Error getting attendee status: ${error.message}`
237 |               }
238 |             ],
239 |             isError: true
240 |           };
241 |         }
242 |       }
243 |     },
244 | 
245 |     // Delete calendar event
246 |     delete_event: {
247 |       name: 'delete_event',
248 |       description: 'Delete a calendar event by its ID',
249 |       inputSchema: {
250 |         type: 'object',
251 |         properties: {
252 |           eventId: {
253 |             type: 'string',
254 |             description: 'Event ID to delete'
255 |           },
256 |           calendar: {
257 |             type: 'string',
258 |             description: 'Calendar name (optional)'
259 |           }
260 |         },
261 |         required: ['eventId']
262 |       },
263 |       handler: async ({ eventId, calendar }) => {
264 |         try {
265 |           const result = await deleteEvent(eventId, calendar);
266 |           return {
267 |             content: [
268 |               {
269 |                 type: 'text',
270 |                 text: result.success 
271 |                   ? `Event deleted successfully` 
272 |                   : `Failed to delete event`
273 |               }
274 |             ]
275 |           };
276 |         } catch (error) {
277 |           return {
278 |             content: [
279 |               {
280 |                 type: 'text',
281 |                 text: `Error deleting event: ${error.message}`
282 |               }
283 |             ],
284 |             isError: true
285 |           };
286 |         }
287 |       }
288 |     },
289 | 
290 |     // Update calendar event
291 |     update_event: {
292 |       name: 'update_event',
293 |       description: 'Update an existing calendar event',
294 |       inputSchema: {
295 |         type: 'object',
296 |         properties: {
297 |           eventId: {
298 |             type: 'string',
299 |             description: 'Event ID to update'
300 |           },
301 |           subject: {
302 |             type: 'string',
303 |             description: 'New event subject/title (optional)'
304 |           },
305 |           startDate: {
306 |             type: 'string',
307 |             description: 'New start date in MM/DD/YYYY format (optional)'
308 |           },
309 |           startTime: {
310 |             type: 'string',
311 |             description: 'New start time in HH:MM AM/PM format (optional)'
312 |           },
313 |           endDate: {
314 |             type: 'string',
315 |             description: 'New end date in MM/DD/YYYY format (optional)'
316 |           },
317 |           endTime: {
318 |             type: 'string',
319 |             description: 'New end time in HH:MM AM/PM format (optional)'
320 |           },
321 |           location: {
322 |             type: 'string',
323 |             description: 'New event location (optional)'
324 |           },
325 |           body: {
326 |             type: 'string',
327 |             description: 'New event description/body (optional)'
328 |           },
329 |           calendar: {
330 |             type: 'string',
331 |             description: 'Calendar name (optional)'
332 |           }
333 |         },
334 |         required: ['eventId']
335 |       },
336 |       handler: async ({ eventId, subject, startDate, startTime, endDate, endTime, location, body, calendar }) => {
337 |         try {
338 |           const result = await updateEvent(eventId, subject, startDate, startTime, endDate, endTime, location, body, calendar);
339 |           return {
340 |             content: [
341 |               {
342 |                 type: 'text',
343 |                 text: result.success 
344 |                   ? `Event updated successfully` 
345 |                   : `Failed to update event`
346 |               }
347 |             ]
348 |           };
349 |         } catch (error) {
350 |           return {
351 |             content: [
352 |               {
353 |                 type: 'text',
354 |                 text: `Error updating event: ${error.message}`
355 |               }
356 |             ],
357 |             isError: true
358 |           };
359 |         }
360 |       }
361 |     },
362 | 
363 |     // Get calendars
364 |     get_calendars: {
365 |       name: 'get_calendars',
366 |       description: 'List available calendars',
367 |       inputSchema: {
368 |         type: 'object',
369 |         properties: {}
370 |       },
371 |       handler: async () => {
372 |         try {
373 |           const calendars = await getCalendars();
374 |           return {
375 |             content: [
376 |               {
377 |                 type: 'text',
378 |                 text: JSON.stringify(calendars, null, 2)
379 |               }
380 |             ]
381 |           };
382 |         } catch (error) {
383 |           return {
384 |             content: [
385 |               {
386 |                 type: 'text',
387 |                 text: `Error getting calendars: ${error.message}`
388 |               }
389 |             ],
390 |             isError: true
391 |           };
392 |         }
393 |       }
394 |     }
395 |   };
396 | }
397 | 
```