Skip to main content
Glama
README.md
# Teams MCP — with Meetings & Calendar

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A Model Context Protocol (MCP) server that provides seamless integration with Microsoft Graph APIs, enabling AI assistants to interact with Microsoft Teams, users, chats, files, organizational data — **and to create, update, list, and inspect Teams meetings and calendar events**.

> **About this project.** This project is a **fork of [`@floriscornel/teams-mcp`](https://github.com/floriscornel/teams-mcp)** (MIT). It starts from the upstream codebase — keeping all of its Teams messaging, chat, and search tooling — and is maintained here as an independent repository (it does not track the original upstream).
>
> **On top of that base, this fork adds a full meetings & calendar toolset:** `create_meeting`, `create_calendar_meeting`, `update_calendar_meeting`, `delete_meeting`, `delete_calendar_event`, `list_calendar_events`, `get_meeting`, `get_short_link`, and `get_attendance_report` — covering recurrence, Markdown agendas, auto-recording, attendance reports, and short-link reconstruction.
>
> It runs locally from a build — it is **not** published to npm, so install it from source as described below.

## 📦 Installation

```bash
# From the project directory
npm install        # install dependencies
npm run build      # compile TypeScript to dist/
node dist/index.js authenticate   # sign in (device code flow)
```

Then register the built server with your MCP client. For **Claude Code**:

```bash
# Global (available in every project)
claude mcp add teams --scope user -- node /absolute/path/to/teams-mcp/dist/index.js

# Or local to the current project (default scope)
claude mcp add teams -- node /absolute/path/to/teams-mcp/dist/index.js
```

For **Cursor / Claude Desktop / VS Code**, add to the MCP config:

```json
{
  "mcpServers": {
    "teams": {
      "command": "node",
      "args": ["/absolute/path/to/teams-mcp/dist/index.js"]
    }
  }
}
```

> **Tip:** the configured command points at `dist/index.js`. Don't move/delete the folder, and after changing the source run `npm run build` again (and reconnect the MCP server in your client) to pick up the new build.

## 🚀 Features

### 📅 Meetings & Calendar *(added in this fork)*
- **Create meetings**
  - Ad-hoc Teams meeting links (instant join URL, no calendar entry)
  - Scheduled calendar meetings (real Outlook event + Teams join link + invitees)
- **Recurrence** — daily / weekly / monthly series, bounded by a count or an end date
- **Markdown agendas** — meeting descriptions written in Markdown, converted to HTML
- **Auto-recording** — start recording automatically when the meeting begins (off by default)
- **Update & delete** — retitle/reschedule events, delete meetings or whole recurring series
- **List the calendar** — events in any date range (defaults to the current week), with organizer, location, join link, and event IDs
- **Short links** — reconstruct the human-readable `teams.microsoft.com/meet/<id>?p=<passcode>` link, which Graph does not expose directly
- **Attendance reports** — post-meeting participants, durations, and roles

> **Not possible via Graph:** real-time presence (who is *currently* in a call, or whether a meeting has started). Attendance data is historical only.

### 🔐 Authentication
- OAuth 2.0 device code authentication flow with Microsoft Graph
- Secure token management, cache persistence, and refresh token renewal
- Authentication status checking and logout support
- Read-only mode with reduced scopes
- Direct `AUTH_TOKEN` support for pre-issued Microsoft Graph access tokens

### 👥 User Management
- Get current user information
- Search users by name or email
- Retrieve detailed user profiles
- Access organizational directory data

### 🏢 Microsoft Teams Integration
- **Teams Management** — list joined teams, access team details and metadata
- **Channel Operations** — list channels, retrieve messages and replies, send/reply/edit/soft-delete, message reactions, importance levels, inline image attachments
- **Team Members** — list members and roles, search users for `@mentions`

### 💬 Chat & Messaging
- List, create, and read 1:1 and group chats (with pagination)
- Send, edit, and soft-delete chat messages
- Message reactions

### 📎 Media & Attachments
- Download hosted content (images, files) from chat and channel messages
- Upload and send any file type to channels (SharePoint) and chats (OneDrive), with large-file resumable sessions

### 🔍 Advanced Search & Discovery
- Search across Teams channels and chats via the Microsoft Search API (KQL)
- Filter by sender, mentions, attachments, read state, and date ranges
- Find messages mentioning the current user

## 📅 Meetings & Calendar — Tool Reference

### Read-only

| Tool | Parameters | Description |
| --- | --- | --- |
| `list_calendar_events` | `startDateTime?`, `endDateTime?`, `timeZone?`, `includeShortLinks?` | List events in a date range (defaults to the current week, Monday→next Monday). Expands recurring series into occurrences. With `includeShortLinks: true`, also resolves the short link for each meeting (one extra Graph call per event). |
| `get_meeting` | `meetingId` | Fetch an online meeting's subject, join link, and times by its **onlineMeeting** ID. |
| `get_short_link` | `joinWebUrl` | Resolve the short `teams.microsoft.com/meet/<id>?p=<passcode>` link from a long join URL. |
| `get_attendance_report` | `meetingId` | Post-meeting attendance: total participants, per-person duration and role. Requires `OnlineMeetingArtifact.Read.All` (admin consent). |

### Write

| Tool | Parameters | Description |
| --- | --- | --- |
| `create_meeting` | `subject`, `startDateTime?`, `endDateTime?`, `recordAutomatically?` | Create an **ad-hoc** Teams meeting link. Fast, but **does not** create a calendar entry or invite anyone. |
| `create_calendar_meeting` | `subject`, `startDateTime`, `endDateTime`, `timeZone?`, `attendees?`, `body?`, `recurrence?`, `recordAutomatically?` | Create a **scheduled** meeting as an Outlook calendar event with a Teams join link. Supports invitees, Markdown agenda, recurring series, and auto-recording. Also returns the reconstructed short link. |
| `update_calendar_meeting` | `eventId`, `subject?`, `startDateTime?`, `endDateTime?`, `timeZone?`, `location?`, `body?` | Edit an existing calendar event. Only the fields you pass are changed. |
| `delete_meeting` | `meetingId` | Delete an ad-hoc online meeting (invalidates its join link). |
| `delete_calendar_event` | `eventId` | Delete a calendar event. Deleting a recurring series' master event removes all occurrences. |

### Ad-hoc link vs. calendar meeting

| | `create_meeting` | `create_calendar_meeting` |
| --- | --- | --- |
| Appears in the calendar | ❌ No (ad-hoc link only) | ✅ Yes, on its date |
| Invitees / invitations | ❌ | ✅ |
| Recurrence | ❌ | ✅ |
| Markdown agenda | ❌ | ✅ |
| Auto-recording | ✅ | ✅ (resolved via the backing onlineMeeting) |

> `recordAutomatically` is a property of the `onlineMeeting` resource, not the calendar `event`. For calendar meetings, the server transparently looks up the backing onlineMeeting (by its join URL) and enables recording on it.

### Examples

**Recurring weekly meeting with a Markdown agenda:**

```json
{
  "subject": "Weekly sync",
  "startDateTime": "2026-06-04T16:00:00",
  "endDateTime": "2026-06-04T18:00:00",
  "timeZone": "Europe/Paris",
  "body": "## Agenda\n- Review last week\n- Blockers\n- Next steps",
  "recurrence": { "pattern": "weekly", "daysOfWeek": ["thursday"], "interval": 1 }
}
```

**Calendar meeting with invitees and auto-recording:**

```json
{
  "subject": "Quarterly review",
  "startDateTime": "2026-06-22T10:00:00",
  "endDateTime": "2026-06-22T11:00:00",
  "timeZone": "UTC",
  "attendees": [
    { "email": "alex@contoso.com", "name": "Alex", "type": "required" }
  ],
  "recordAutomatically": true
}
```

**Reschedule and rename an existing event:**

```json
{
  "eventId": "AAMk...",
  "subject": "Quarterly review (rescheduled)",
  "startDateTime": "2026-06-23T14:00:00",
  "endDateTime": "2026-06-23T15:00:00",
  "timeZone": "UTC"
}
```

## Rich Message Formatting Support

The following tools support rich message formatting in Teams channels and chats:
- `send_channel_message`
- `send_chat_message`
- `reply_to_channel_message`
- `update_channel_message`
- `update_chat_message`
- `send_file_to_channel`
- `send_file_to_chat`

### Format Options

You can specify the `format` parameter to control the message formatting:
- `text` (default): Plain text
- `markdown`: Markdown formatting (bold, italic, lists, links, code, etc.) converted to sanitized HTML

When `format` is set to `markdown`, the message content is converted to HTML using a secure markdown parser and sanitized to remove potentially dangerous content before being sent to Teams.

### Supported Markdown Features

- **Text formatting**: Bold (`**text**`), italic (`_text_`), strikethrough (`~~text~~`)
- **Links**: `[text](url)`
- **Lists**: Bulleted (`- item`) and numbered (`1. item`)
- **Code**: Inline `` `code` `` and fenced code blocks
- **Headings**: `# H1` through `###### H6`
- **Blockquotes**: `> quoted text`
- **Tables**: GitHub-flavored markdown tables

> The same Markdown→HTML conversion powers the `body` parameter of `create_calendar_meeting` and `update_calendar_meeting`.

## LLM-Friendly Content Format

Messages retrieved from the Microsoft Graph API are returned as raw HTML containing Teams-specific tags. To make this content more consumable by AI assistants, these tools support automatic HTML-to-Markdown conversion via the `contentFormat` parameter (`markdown` default, or `raw`):

- `get_chat_messages`
- `get_channel_messages`
- `get_channel_message_replies`
- `search_messages`
- `get_my_mentions`

## 🔧 Configuration

### Prerequisites
- Node.js 18+
- Microsoft 365 account (work/school tenant — personal accounts cannot create Teams meetings via Graph)
- Microsoft Graph delegated permissions for the scopes below

### Required Microsoft Graph Permissions

**Full mode (default):**
- `User.Read` — Read user profile
- `User.ReadBasic.All` — Read basic user info
- `Team.ReadBasic.All` — Read team information
- `Channel.ReadBasic.All` — Read channel information
- `ChannelMessage.Read.All` — Read channel messages
- `ChannelMessage.Send` — Send channel messages and replies
- `ChannelMessage.ReadWrite` — Edit and delete channel messages
- `Chat.Read` — Read chat messages (read-only scope)
- `Chat.ReadWrite` — Create/manage chats, send/edit/delete chat messages
- `TeamMember.Read.All` — Read team members
- `Files.ReadWrite.All` — File uploads to channels and chats
- `OnlineMeetings.ReadWrite` — Create/read/delete Teams meetings and enable auto-recording *(meetings)*
- `Calendars.ReadWrite` — Create/list/update/delete calendar events *(meetings)*
- `OnlineMeetingArtifact.Read.All` — Read attendance reports *(meetings; typically requires admin consent)*

**Read-only mode** (`TEAMS_MCP_READ_ONLY=true`) requests only the read scopes:
`User.Read`, `User.ReadBasic.All`, `Team.ReadBasic.All`, `Channel.ReadBasic.All`, `ChannelMessage.Read.All`, `TeamMember.Read.All`, `Chat.Read`.

> After adding a new scope (e.g. enabling attendance reports), re-authenticate so the cached token requests it: `node dist/index.js logout && node dist/index.js authenticate`.

### Token Storage

- Auth metadata: `~/.msgraph-mcp-auth.json`
- Token cache: `~/.teams-mcp-token-cache.json`

## 🛠️ Usage

### Starting the Server
```bash
# Development mode with hot reload
npm run dev

# Production mode
npm run build && node dist/index.js

# Read-only mode (disables all write tools)
TEAMS_MCP_READ_ONLY=true node dist/index.js
```

### CLI Commands

```bash
node dist/index.js authenticate              # Authenticate with full scopes
node dist/index.js authenticate --read-only  # Authenticate with read-only scopes
node dist/index.js check                     # Check authentication status
node dist/index.js logout                    # Clear authentication
node dist/index.js                           # Start MCP server (default)
```

### Environment Variables

- `TEAMS_MCP_READ_ONLY=true` — Start the MCP server in read-only mode
- `AUTH_TOKEN=<jwt>` — Use a pre-existing Microsoft Graph access token instead of MSAL login

## 🧰 Available MCP Tools

39 tools total — **20 read-only**, **19 write** (write tools are disabled when `TEAMS_MCP_READ_ONLY=true`).

#### Authentication
- `auth_status` — Check current authentication status

#### User Operations
- `get_current_user`, `search_users`, `get_user`

#### Teams Operations
- `list_teams`, `list_channels`, `get_channel_messages`, `get_channel_message_replies`, `list_team_members`, `search_users_for_mentions`
- `send_channel_message`, `reply_to_channel_message`, `update_channel_message`, `delete_channel_message`, `send_file_to_channel`
- `set_channel_message_reaction`, `unset_channel_message_reaction`

#### Chat Operations
- `list_chats`, `get_chat_messages`
- `send_chat_message`, `create_chat`, `update_chat_message`, `delete_chat_message`, `send_file_to_chat`
- `set_chat_message_reaction`, `unset_chat_message_reaction`

#### Meetings & Calendar
- `list_calendar_events`, `get_meeting`, `get_short_link`, `get_attendance_report` *(read-only)*
- `create_meeting`, `create_calendar_meeting`, `update_calendar_meeting`, `delete_meeting`, `delete_calendar_event` *(write)*

#### Media Operations
- `download_message_hosted_content`, `download_chat_hosted_content`

#### Search Operations
- `search_messages`, `get_my_mentions`

## 🔒 Security

- Authentication via Microsoft's OAuth 2.0 flow or a caller-provided Microsoft Graph token
- Access tokens are automatically renewed using cached refresh tokens
- Token cache and auth metadata are stored locally in your home directory
- Markdown content is sanitized before sending HTML to Teams (and into meeting agendas)
- `AUTH_TOKEN` is validated to ensure it targets `https://graph.microsoft.com`

## 📝 License

MIT License — see the `LICENSE` file. Original work © Floris Cornel; meeting/calendar additions in this fork are also MIT.

## 🙏 Credits

A fork of [`@floriscornel/teams-mcp`](https://github.com/floriscornel/teams-mcp) (MIT), extended with the meetings & calendar toolset.