feat: added m365 mcp server#44
Conversation
| test("odataString doubles single quotes and percent-encodes", () => { | ||
| assert.equal(odataString("inbox"), "inbox"); | ||
| assert.equal(odataString("a'b"), "a''b"); | ||
| assert.equal(odataString("a b"), "a%20b"); |
There was a problem hiding this comment.
odataString test mismatch
Low Severity
The unit test expects odataString("a'b") to be a''b, but the helper also runs encodeURIComponent, producing a%27%27b. npm test fails on this assertion.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 962efac. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
There are 5 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit eea1ff1. Configure here.
|
|
||
| const body = { chatType: type, members: allMembers.map(memberBind) }; | ||
| if (topic && type === "group") body.topic = topic; | ||
| return graphPost(token, "/chats", body); |
There was a problem hiding this comment.
create_chat oneOnOne member count
Medium Severity
The create_chat tool can build a oneOnOne request with only one member (e.g. empty members, or only the caller’s UPN) or with three or more after auto-adding the signed-in user when chat_type is oneOnOne and multiple addresses are supplied. Microsoft Graph requires exactly two members for oneOnOne chats, so these calls fail or behave incorrectly.
Reviewed by Cursor Bugbot for commit eea1ff1. Configure here.
| (m) => m.toLowerCase() === upn.toLowerCase(), | ||
| ) | ||
| ? members | ||
| : [...members, me.id]; |
There was a problem hiding this comment.
create_chat duplicate caller member
Medium Severity
When deciding whether to add the signed-in user to members, create_chat only checks for a matching userPrincipalName, not the user’s Graph id. If the client already passes the caller’s object id, the handler still appends me.id, producing a duplicate member entry and a failed Graph request.
Reviewed by Cursor Bugbot for commit eea1ff1. Configure here.
| /** Per-attempt request timeout (ms). */ | ||
| const REQUEST_TIMEOUT_MS = Number(process.env.GRAPH_TIMEOUT_MS) || 30_000; | ||
| /** Extra attempts after the first for transient failures. */ | ||
| const MAX_RETRIES = Number(process.env.GRAPH_MAX_RETRIES) || 3; |
There was a problem hiding this comment.
GRAPH_MAX_RETRIES zero ignored
Low Severity
GRAPH_MAX_RETRIES and GRAPH_TIMEOUT_MS are parsed with Number(...) || default, so an explicit 0 is treated as missing and replaced by 3 retries and 30000 ms. Operators cannot disable retries or set a zero timeout via environment variables as the README implies.
Reviewed by Cursor Bugbot for commit eea1ff1. Configure here.
|
|
||
| if (isRetryable(res.status) && attempt < MAX_RETRIES) { | ||
| await sleep(retryDelayMs(res, attempt)); | ||
| continue; |
There was a problem hiding this comment.
Retry leaves response unread
Medium Severity
On retryable HTTP statuses (429, 503, 504), sendWithRetry loops without reading or canceling the response body. Under Graph throttling, unconsumed bodies can hold connections open and reduce throughput or exhaust sockets in the pod.
Reviewed by Cursor Bugbot for commit eea1ff1. Configure here.


Note
High Risk
New externally reachable service that proxies bearer tokens to Microsoft Graph and exposes write-capable tools (mail send, file upload, Teams messages, SharePoint changes); misconfiguration or overly broad token scopes could cause real tenant impact.
Overview
Introduces a new
m365-mcppackage: a stateless Node.js MCP server that exposes Microsoft 365 (Mail, Calendar, Teams, OneDrive, SharePoint) as Graph-backed tools on Streamable HTTP atPOST /mcp, withAuthorization: Bearerrequired and the token forwarded to Graph without storage or exchange.The runtime builds a fresh
McpServerand transport per request, servesGET /health, enforces 401 on missing bearer tokens, and includes graceful shutdown for container rollouts. A sharedgraph.jsclient adds timeouts, retry/backoff on throttling and transient errors, and caps in-memory file transfer size; tool modules use Zod schemas and map Graph failures to MCP tool errors.Deployment and packaging: multi-stage Dockerfile (
npm ci, non-rootnodeuser,/healthHEALTHCHECK),.dockerignore/.tfyignore,deploy.pyfor TrueFoundry remote build, plusnpm test(util unit tests and a server smoke test).Reviewed by Cursor Bugbot for commit eea1ff1. Bugbot is set up for automated code reviews on this repo. Configure here.