m365connector
v0.3.2
Published
MCP server for M365 Connector browser extension
Readme
m365connector
MCP server that lets AI agents search and read your Microsoft 365 data (emails, files, Teams chats, calendar events, and external connectors).
Works with any MCP-compatible client: Claude Code, Claude Desktop, etc.
How it works
MCP Client m365connector Browser Extension
(Claude Code) (this package) (Chrome/Edge MV3)
HTTP :52366 WebSocket :52365
───────────► ◄──────────────────►
Streamable HTTP IPC bridge Captures tokens,
transport (localhost) executes API callsThe MCP server runs as a long-lived process. A companion browser extension connects over WebSocket and handles all M365 API calls using tokens captured from the browser.
Prerequisites
- Node.js 18+
- The M365 Connector browser extension loaded in Chrome or Edge
- An M365 account (work or school)
Quick start
npx m365connectorYou should see:
[m365connector/ws] listening on ws://127.0.0.1:52365
[m365connector] MCP HTTP listening on http://127.0.0.1:52366/mcpThen add to your MCP client config (e.g. ~/.claude/mcp.json):
{
"mcpServers": {
"m365-connector": {
"type": "http",
"url": "http://127.0.0.1:52366/mcp"
}
}
}Global install
npm install -g m365connector
m365connectorEnvironment variables
| Variable | Default | Description |
|----------|---------|-------------|
| M365C_MCP_PORT | 52366 | HTTP port for MCP clients |
| M365C_WS_PORT | 52365 | WebSocket port for extension IPC |
Tools
search
Search across M365 data sources.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| query | string | yes | | Search query |
| conversation_id | string | yes | | Conversation identifier for grouping requests |
| source | string | no | "all" | all, email, files, chat, events, external |
| connector | string | no | | External connector name (when source=external) |
| size | integer | no | 10 | Results per page (1--25) |
| from | integer | no | 0 | Pagination offset |
open
Read the content of a search result.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| read_handle | string | yes | Opaque handle from a search result's _readHandle field |
| conversation_id | string | yes | Conversation identifier |
Returns content with a completeness field: full, partial, or snippet.
whoami
Get the current signed-in user's basic profile from Graph.
When directory scopes are available, response also includes best-effort manager, directReports, and directReportsCount info.
| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | conversation_id | string | yes | | Conversation identifier | | direct_reports_size | integer | no | 30 | Maximum number of direct reports to return (1--100) |
find_people
Find people via Graph directory query using free-text and structured filters.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| conversation_id | string | yes | | Conversation identifier |
| query | string | no | | Free-text query matched across person fields |
| alias | string | no | | Filter by alias (mailNickname) |
| principalName | string | no | | Filter by user principal name |
| displayName | string | no | | Filter by display name |
| department | string | no | | Filter by department (prefix match) |
| office | string | no | | Filter by office location (prefix match) |
| title | string | no | | Filter by job title (prefix match) |
| size | integer | no | 20 | Maximum people to return (1--50) |
| include_direct_reports | boolean | no | false | Include direct reports for each result |
| direct_reports_size | integer | no | 30 | Maximum direct reports per result (1--100) |
At least one of query, alias, principalName, displayName, department, office, or title is required.
count_people
Count people matching Graph directory filters without returning the full result list.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| conversation_id | string | yes | | Conversation identifier |
| query | string | no | | Free-text query matched across person fields |
| alias | string | no | | Filter by alias (mailNickname) |
| principalName | string | no | | Filter by user principal name |
| displayName | string | no | | Filter by display name |
| department | string | no | | Filter by department (prefix match) |
| office | string | no | | Filter by office location (prefix match) |
| title | string | no | | Filter by job title (prefix match) |
At least one of query, alias, principalName, displayName, department, office, or title is required.
Security
- Both servers bind to
127.0.0.1only (not accessible from the network) - WebSocket accepts connections only from
chrome-extension://origins - Read handles are server-issued opaque UUIDs with 30-minute TTL
License
MIT
