Metadata-Version: 2.5
Name: keos-microsoft365-mcp
Version: 0.1.0
Summary: Stateless Microsoft 365 (Graph) MCP server: SharePoint, OneDrive, Mail, Calendar, Users, Groups, plus Office/PDF text extraction.
Project-URL: Homepage, https://github.com/KaarProducts/keos-mcp
Project-URL: Repository, https://github.com/KaarProducts/keos-mcp
Author-email: Vijayaraghavan C P <cpvijayaraghavan@kaartech.com>
License: MIT
Keywords: mcp,microsoft-graph,microsoft365,onedrive,outlook,sharepoint
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp<2,>=1.2.0
Requires-Dist: pypdf>=4.0.0
Description-Content-Type: text/markdown

# Microsoft 365 MCP Server

An [MCP](https://modelcontextprotocol.io) server that exposes Microsoft 365
operations as tools, backed by Microsoft Graph — SharePoint, OneDrive, Mail,
Calendar, Users & Directory, and Groups — plus text extraction from Office/PDF
documents and mail attachments.

It is **stateless** and **does not do any OAuth**: your application already holds
a valid Microsoft Graph access token, and it supplies that token with each
request. No re-authentication, no token exchange, no gateway.

## Why this exists

If you already obtained a Microsoft Graph delegated access token
(`aud = https://graph.microsoft.com`) via a 3LO flow in your app, you cannot feed
that token into an On-Behalf-Of (OBO) exchange — Entra requires the OBO assertion
to target a middle-tier app, not Graph itself. This server avoids the problem
entirely by calling Graph directly with the token you already have.

## Install & run with uvx

The server ships as a `uvx`-runnable package. [`uv`](https://docs.astral.sh/uv/)
builds and runs it in an isolated environment on demand — no manual `pip install`.

Once published to an index you can run it by name:

```bash
uvx microsoft365-mcp
```


## Providing the access token

The token is resolved per request in this order:

1. **Explicit argument** — pass `access_token` in the tool call arguments.
2. **Bearer header** — when running over HTTP, send `Authorization: Bearer <token>`.
3. **Environment** — `GRAPH_ACCESS_TOKEN` (or the legacy `SHAREPOINT_ACCESS_TOKEN`).

The token must be a Microsoft Graph delegated access token
(`aud = https://graph.microsoft.com`). Grant the scopes for the tools you use:

| Area | Delegated scopes |
|------|------------------|
| SharePoint / OneDrive / Groups files | `Sites.Read.All` / `Sites.ReadWrite.All`, `Files.Read.All` / `Files.ReadWrite.All`, `Group.Read.All` |
| Mail | `Mail.Read`, `Mail.ReadWrite`, `Mail.Send` |
| Calendar | `Calendars.ReadWrite` |
| Users & Directory | `User.Read.All`, `Directory.Read.All` |

> Tokens are short-lived (~1 hour). This server never refreshes them — supplying
> a fresh token is the caller's responsibility.

## Tools

### Identity
| Tool | Description |
|------|-------------|
| `test_token` | Verify the token by fetching the signed-in user's profile |
| `get_me` | Get the signed-in user's full profile |

### SharePoint
| Tool | Description |
|------|-------------|
| `list_sites` | List or search SharePoint sites |
| `get_site` | Get a site by Graph site ID |
| `get_site_by_path` | Resolve a site by hostname + server-relative path |
| `list_drives` | List document libraries (drives) in a site |
| `list_items` | List folders/files in a drive or folder |
| `get_item` | Get file/folder metadata by path or item ID |
| `read_file` | Download a file's content (text when decodable) |
| `extract_file` | Download and extract text from docx/xlsx/pptx/pdf/text |
| `list_sharepoint_lists` | Get SharePoint lists in a site |
| `get_list_items` | Get items (with fields) from a list |
| `search_files` | Search files within a drive |
| `search_query` | Cross-service keyword/KQL search (Microsoft Search API) |

### OneDrive
| Tool | Description |
|------|-------------|
| `get_my_drive` | Get the signed-in user's OneDrive metadata |
| `get_user_drive` | Get another user's OneDrive by id/UPN |
| `list_my_drive_items` | List files/folders in the user's OneDrive |

> The drive tools (`read_file`, `extract_file`, `get_item`, `list_items`) work
> against OneDrive and Group/Teams drives too — pass the relevant `drive_id`.

### Mail
| Tool | Description |
|------|-------------|
| `list_messages` | List or search messages (by folder or across mailbox) |
| `get_message` | Get a single message with body |
| `list_attachments` | List a message's attachments (metadata) |
| `extract_mail_attachment` | Download an attachment and extract its text |
| `send_mail` | Send an email |
| `reply_to_message` | Reply / reply-all to a message |
| `create_draft` | Create a draft message |
| `move_message` | Move a message to another folder |
| `list_mail_folders` | List mail folders |

### Calendar
| Tool | Description |
|------|-------------|
| `list_events` | List events (or a calendarView window) |
| `create_event` | Create an event |
| `update_event` | Patch an event |
| `delete_event` | Delete an event |
| `get_schedule` | Free/busy availability for one or more mailboxes |

### Users & Directory
| Tool | Description |
|------|-------------|
| `get_user` | Get a user by id/UPN |
| `list_users` | List or search directory users |
| `get_manager` | Get a user's manager |
| `get_direct_reports` | Get a user's direct reports |

### Groups
| Tool | Description |
|------|-------------|
| `list_groups` | List or search Microsoft 365 groups |
| `list_group_members` | List a group's members |
| `get_group_drive` | Get a group's document library (the Teams "Files" store) |

## Document extraction

`extract_file` and `extract_mail_attachment` return readable text from binary
formats that `read_file` cannot decode:

- **Word** `.docx`, **Excel** `.xlsx`, **PowerPoint** `.pptx` — parsed with the
  Python standard library (no third-party dependency).
- **PDF** `.pdf` — via `pypdf` (a declared dependency, installed automatically).
- **Text family** `.txt .csv .tsv .json .md .xml .html .yaml`, etc.

Legacy binary formats (`.doc`, `.xls`, `.ppt`) are not supported — convert to the
OpenXML equivalent or PDF first.


## Response shape

Every tool returns a normalized object:

```jsonc
// success
{ "ok": true, "data": { /* Graph response, or extracted text */ } }

// failure
{ "ok": false, "error": "graph_error", "status_code": 403, "message": "...", "body": { } }
```

Extraction failures use `"error": "extraction_error"`; a missing token uses
`"error": "missing_token"`.

## Notes

- The server never stores or logs tokens.
- Token expiry/refresh is the caller's responsibility — this server only forwards
  what it is given.
- Write and send operations (`send_mail`, `create_event`, `move_message`, ...)
  act as the signed-in user. Guard them with `autoApprove` care in your client.

