ms365-mcp

ms365-mcp

Provides a minimal Microsoft 365 MCP server with fourteen hand-written tools for email, people, and drafts, designed to fit small local models.

Category
访问服务器

README

ms365-mcp

A Microsoft 365 MCP server sized for small local models.

Most MCP servers are built for frontier models with large context windows, so they expose everything the vendor API offers and let the model sort it out. The reference Microsoft 365 server exposes 326 tools generated from Microsoft's Graph OpenAPI spec.

That does not work for an 8B model at 8k context, where the entire tool list sits in the system prompt and the model starts choosing at random somewhere past twenty-five tools. This server takes the opposite approach:

  • Fourteen hand-written tools, with a hard ceiling of twenty. The tool list is a budget, not a feature list.
  • Descriptions written for a small model, not salvaged from API metadata.
  • Draft-first. Exactly one tool can transmit to another person, it takes a draft id rather than a recipient, and it is annotated destructive.
  • Every tool declares its own effect through MCP readOnlyHint and destructiveHint annotations, so a host can classify it without guessing from the tool's name.

Built for the Edge Harness, and useful to any MCP client.

Status

Feature complete, not yet run against a real account. All fourteen tools are implemented and 171 tests pass, none of which touch the network. What has not happened is the part only a real tenant can prove: a live sign-in and a Graph call that gets answered. See docs/PLAN.md for the ten commits and the reasoning behind each decision.

Scaffold, licence, CI done
MCP protocol over stdio done
The fourteen-tool surface done, all fourteen implemented
Sign-in done, untested against a live tenant
Microsoft Graph done, tested against recorded shapes only
Retries and circuit breaker done

Seeing the tool surface

--list-tools starts nothing and needs no account, so it answers "what would a host be offered?" before any of it is wired up:

.venv/bin/python -m ms365_mcp --list-tools

Add --json for a machine-readable version.

   read  whoami          Return the display name, email address and timezone…
   read  resolve_person  Look up a person by name or partial name and return…
   read  list_messages   List messages in a mail folder, newest first, as se…
  write  create_draft    Create a draft message. This does NOT send anything…
! write  send_draft      Send a draft that already exists, by its id. This r…
   ...
14 tools, 6 that change something, 4 marked destructive (!)

Handlers are stubs today: a call returns a sentence saying the tool is declared but not implemented. The surface is deliberately fixed before any of it is built, because the tool names, descriptions and effect classes are what a host classifies and a model is prompted against, and those are expensive to change later.

Signing in

Sign-in is the Microsoft device code flow, so there is no redirect URL to host and no secret to store. You need one thing first: the application id of an Azure app registration that has the delegated Graph permissions this server's tools declare.

export MS365_MCP_CLIENT_ID=<your app registration's application id>
export MS365_MCP_TENANT_ID=organizations   # 'consumers' for outlook.com
.venv/bin/python -m ms365_mcp --login

Then check it, before wiring anything into a host:

.venv/bin/python -m ms365_mcp --verify-login

--verify-login prints the client id, tenant, authority, scopes and cache location, and if an account is cached it calls Graph once. That last part is the point. A cached token can look completely healthy and still be refused, because a work or school tenant can withhold consent for a scope the surface needs, and that only ever shows up as a 403 on a real request. --logout forgets the account and removes the cache.

The token cache lives in the operating system's config directory, never in this repository. It is created with mode 0600 rather than written and then made private, since the gap between those two is a window where a refresh token is readable by every account on the machine. It is replaced by an atomic rename, so an interrupted write costs nothing.

Using it from the Edge Harness

The harness launches this server as a subprocess over stdio, so it runs under its own interpreter and shares no dependencies with the host. That is not incidental: the harness has a local package called mcp/ and the official SDK on PyPI is also called mcp, so installing this server into the harness's virtualenv shadows the harness's own package.

Its registry entry there is ms365-own, and pressing Check in the Agent Lab run options lists every tool with its effect class. All fourteen classify as declared, meaning the harness took them from this server's annotations rather than guessing from tool names, and the entry needs no overrides.

In the harness's default draft mode, send_draft is withheld and the other thirteen are available, so a run cannot reach a person.

Errors are raised as the SDK's ToolError rather than allowed to propagate. That is worth knowing if you are writing a handler here: the SDK treats any other exception as a crash and replaces its message with a generic one, so a sentence like "No signed-in account, run --login" is discarded before it ever reaches the model. ToolError is the deliberate-failure channel and its text survives, while the result is still flagged as an error.

Security

This repository is public and holds no credential of any kind.

Authentication uses the Microsoft device-code flow. The resulting token cache is written to the operating system's config directory with owner-only permissions, never into this repository or its working tree. .gitignore covers token and cache filenames anyway, and a pre-commit hook scans staged changes for credential-shaped strings, so committing one takes deliberate effort rather than a slip.

A line ending in # pragma: allowlist secret is skipped by the hook. That exists so this repository's own tests can contain fake credentials, and it leaves a marker a reviewer can see in the diff, which --no-verify does not. Use it only for data that is provably fake.

Development

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -q

Enable the secret-scan hook once per clone:

git config core.hooksPath .githooks

Licence

MIT. See LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选