# M365-Copilot2API: a self-hosted gateway that turns M365 Copilot into an OpenAI-compatible endpoint

> M365-Copilot2API is a Go gateway that translates the private M365 Copilot ChatHub WebSocket protocol into OpenAI and Anthropic compatible HTTP APIs. It is a personal, self-hosted bridge, and the README's own disclaimer is the first thing to read.

**HEXUXIU/M365-Copilot2API** — Microsoft 365 Copilot → OpenAI / Anthropic 兼容 API 网关。

- Repository: https://github.com/HEXUXIU/M365-Copilot2API
- Stars: 527 · Forks: 185
- Language: Go
- License: NOASSERTION
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/hexuxiu-m365-copilot2api

## The protocol gap M365-Copilot2API tries to close

Microsoft 365 Copilot does not ship a public chat completion endpoint that mirrors OpenAI's. The README describes what the gateway talks to as the ChatHub private protocol over WebSocket, and says the project exists to translate that into standard OpenAI and Anthropic compatible APIs. That framing is the whole pitch: your client keeps speaking the format it already speaks, and the gateway absorbs the difference.

The audience is narrow and the README says so. It lists Claude Code, OpenCode, Cursor and any OpenAI client as the consumers, and describes the deployment target as personal self-hosting. The disclaimer is blunt: the project is not a Microsoft product, has no affiliation with Microsoft, OpenAI or Anthropic, and is intended for personal learning and research only, with commercial resale and large-scale operation explicitly prohibited. If you are looking for a supported integration path for a company, this is not it, and the repository does not pretend otherwise.

## How the ChatHub translation layer is structured

The repository layout puts the protocol work in internal/chathub and the HTTP surface in internal/web. The README states that connection handshake, heartbeat keepalive, event stream parsing (streaming tokens, tool calls, multimodal input) are all wrapped in the chathub layer, which exposes a single event interface upward. Everything above that layer only sees standard endpoints such as /v1/chat/completions and /v1/messages.

Session resolution lives in internal/web/session_resolver.go. In a multi-account setup it pins each client request to a fixed account and cloud conversation. The interesting mechanism is content-key session reuse: the gateway keys a cloud conversation by dialogue context, and on a hit it sends only the incremental message. The README compares this to DeepSeek's context caching, and there is a separate cache hit rate dashboard in the console. A request header, X-M365-Session-Id, lets a client name the conversation it wants to continue instead of relying on the key.

Accounts are rotated round-robin, and the README says authentication failures or dropped connections trigger automatic failover to the next available account. Tool calling is converted in both directions, with two planning modes named router and native. That choice matters more than it looks: the mode determines how the model's intent is mapped onto the M365 tool protocol, and the README does not explain when to pick which.

## Installing M365-Copilot2API from a release binary

The README's quick start downloads a prebuilt binary from GitHub Releases for the target platform and runs it. On Linux x86_64 the command is a single curl piped through chmod and execution. The default listener is 127.0.0.1:4141 and the default administrator password is admin123, which the README says must be changed on first login.

```bash
curl -fL -o m365-copilot2api https://github.com/HEXUXIU/M365-Copilot2API/releases/latest/download/m365-copilot2api-linux-amd64 && chmod +x m365-copilot2api && ./m365-copilot2api
```

After that the process starts and the web console becomes reachable on the loopback address. The README notes that macOS may refuse to launch the binary with an unidentified developer warning, and gives the workaround: either allow it under Privacy and Security in System Settings, or clear the quarantine attribute.

```bash
xattr -d com.apple.quarantine m365-copilot2api
```

For a container deployment the repository ships a docker-compose.yml that builds the image, maps 127.0.0.1:4141 on the host to 4141 in the container, and mounts ./data at /data. The environment block sets M365_LISTEN, M365_DATA_DIR, M365_CONFIG, M365_TOKEN_CACHE, M365_SESSION_CACHE, M365_API_KEYS, M365_ADMIN_PASSWORD_FILE and M365_ADMIN_PASSWORD_BOOTSTRAP_FILE, plus M365_CHAT_TIMEOUT_SECONDS at 120 and M365_IMAGE_TIMEOUT_SECONDS at 150.

```yaml
services:
  m365-copilot2api:
    build: .
    image: m365-copilot2api:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:4141:4141"
    environment:
      M365_LISTEN: 0.0.0.0:4141
      M365_DATA_DIR: /data
      M365_CHAT_TIMEOUT_SECONDS: "120"
```

The .env.example file documents the same variables for a non-container run and adds M365_ACCOUNT_DEFAULT_CONCURRENCY, defaulting to 8, described as the maximum number of simultaneous upstream calls per account. It also shows optional separate app registrations for browser PKCE and device code OAuth, with the legacy M365_CLIENT_ID, M365_AUTHORITY and M365_SCOPE kept as fallbacks. The first real use after boot is account authorisation in the console, then creating an API key, then pointing a client at the local endpoint.

## Where the gateway breaks or becomes the wrong tool

The dependency on a private WebSocket protocol is the structural weakness. Anything Microsoft changes in ChatHub handshake, heartbeat or event framing lands directly on internal/chathub, and the README offers no compatibility statement, no version pinning against a specific M365 build, and no rollback procedure. That is not a criticism of the implementation, it is the nature of translating an undocumented protocol.

The README is also silent on several things a self-hoster would want. There is no documented rate limit behaviour, no statement about what happens to in-flight streams during account failover, and no description of how the content-key session reuse handles two clients that produce colliding context keys. The auto-cleanup defaults are given (idle time of 2h, or a retention count), but the README does not say how to tune either from the console or from environment variables.

The licence field reports NOASSERTION, so the repository metadata does not declare a recognised licence even though a LICENSE file exists at the top level. Until you read that file yourself, treat redistribution as unresolved. And the disclaimer's restriction to personal use is not a soft preference; it is stated in the README as a prohibition on commercial resale and scale operation. Running this as a shared internal service for a team sits uncomfortably close to that line.

## How it differs from a plain OpenAI-compatible proxy

The obvious alternative category is a generic OpenAI-compatible proxy such as LiteLLM, which routes between provider APIs that already speak HTTP. The difference is not features, it is where the translation happens. LiteLLM maps one public API shape onto another public API shape and never has to maintain a WebSocket client against an undocumented server. M365-Copilot2API has to do exactly that, which is why internal/chathub exists as its own layer and why the project carries protocol-drift risk that a routing proxy does not.

The second alternative is simply using the M365 Copilot client Microsoft provides, or an OpenAI account directly. That avoids the entire class of ToS and account-ban risk the README warns about, at the cost of not having your existing Claude Code or Cursor configuration point at your M365 subscription. The trade is straightforward: this project buys client compatibility with a subscription you already pay for, and pays for it with an unsupported protocol bridge and a disclaimer you have to take seriously.

## Maintenance, upgrade path and licence questions

The last push to the default branch was on 2026-09-15, and the most recent release listed is v0.7.0 on 2026-09-04, preceded by v0.6.5 and v0.6.1 in late August. That is a tight release cadence over a few weeks, and the repository is not archived. It does not tell you how the project behaves over a year, and the README does not describe an upgrade procedure: no migration notes for the accounts.json, token-cache.json, sessions.json or api-keys.json files that the Dockerfile and compose file place under /data.

Upgrade cost therefore has to be inferred from the layout. The container image bundles the web console assets from /app/web, so a binary swap and a console asset swap move together. The state files are JSON under a mounted volume, which suggests in-place upgrades are the intended path, but the README does not confirm that a newer binary reads an older accounts.json without intervention. Back up /data before pulling a new release.

On licence: the repository metadata reports NOASSERTION, so no SPDX identifier is declared. The README's own terms are separate from the licence file and are stricter in practice, restricting use to personal learning and research and prohibiting commercial resale. Check LICENSE directly before you depend on any redistribution right. This is a description of what the repository states, not legal advice.

## Conclusion

Adopt M365-Copilot2API only if you already hold a legitimate M365 Copilot subscription, you want your existing OpenAI or Anthropic client to point at it, and you accept the README's own terms: personal study and research, no commercial resale, no scale operation. Skip it if you need a vendor-supported integration, an SLA, or a multi-tenant service. Verify first that the release binary for your platform runs, that the web console forces an admin password change on first login, and that your account authorisation completes through PKCE before you wire any client to it.

## FAQ

### How much does it cost to use the Copilot API?

The project itself is a self-hosted gateway you run on your own machine, and the README does not list any price or paid tier for it. What it consumes is a Microsoft 365 Copilot commercial subscription, since the gateway translates that subscription's ChatHub protocol. The README does not state subscription pricing.

### What is Microsoft 365 Copilot?

The README does not define Microsoft 365 Copilot itself; it treats it as the upstream service the gateway connects to over the private ChatHub WebSocket protocol. All the project claims is that it translates that upstream into OpenAI and Anthropic compatible endpoints for clients such as Claude Code and Cursor.

### Is Copilot just chatgpt?

The README does not compare the two models or describe what runs behind M365 Copilot. It only states that the gateway exposes M365 Copilot through OpenAI and Anthropic compatible API shapes, which is a protocol compatibility claim, not a statement about the underlying model.

### What is the price of Microsoft 365 Copilot?

The README does not list any Microsoft 365 Copilot pricing. It only notes that the gateway targets the commercial subscription and that the project is not affiliated with Microsoft, OpenAI or Anthropic.

## Sources

- [HEXUXIU/M365-Copilot2API on GitHub](https://github.com/HEXUXIU/M365-Copilot2API)
- [Issues](https://github.com/HEXUXIU/M365-Copilot2API/issues)
- [README](https://github.com/HEXUXIU/M365-Copilot2API/blob/main/README.md)
- [Releases](https://github.com/HEXUXIU/M365-Copilot2API/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hexuxiu-m365-copilot2api
