Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,54 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- **Update awareness (notify only).** The server now checks the public npm registry at
most once every 24 hours and, when a newer release of `@microsoft/spe-mcp` exists,
appends a single concise `Update available: …` notice to one tool result (plus an
optional `structuredContent.updateAvailable` payload). The check is fire-and-forget —
it never blocks a tool call, never writes to stdout, and **never downloads, installs, or
executes anything**; auto-update is explicitly out of scope. It is channel-aware (an
`alpha` install is compared against the `alpha` dist-tag, and a newer `latest` is
reported separately), adds **zero new runtime dependencies**, and is skipped
automatically in CI and when running from a source checkout. Disable it with
`SPE_MCP_UPDATE_CHECK=false` (preferred), `--no-update-check`, `SPE_NO_UPDATE_CHECK=1`
(legacy alias), `NO_UPDATE_NOTIFIER=1`, or `SPE_MCP_COLLECT_TELEMETRY=false` (the telemetry
opt-out suppresses the registry request entirely);
when disabled, **no network request, stderr notice, or cache write occurs**. Point it at a
mirror with `SPE_NPM_REGISTRY` (HTTPS-only).
- **Transparency for the update check.** Before the first registry request in a process, the
server prints a one-time **stderr** collection notice naming the endpoint, the boundary, and
the opt-out. `status_get` now reports the running server version, the update-check state,
the locally cached latest version, the time of the last check, the registry in use, the
cache-file path, and the opt-out controls — all read from disk, with **no network access**.
- **Update-check cache lifecycle.** The cached result at `<data dir>/update-check.json`
contains **no identifier** and is retained until deleted; `spe-mcp logout` and
`spe-mcp auth --reset` now remove it alongside the cached tokens. A version is recorded
as "already notified" only when the notice is actually delivered on a tool result, so a
process that exits before any tool call replays the notice on the next run instead of
losing it.
- **Boundary disclosure.** `NOTICE.md` (new **Third-party services contacted** section),
`README.md`, `PRIVACY.md`, `docs/DATA-FLOW.md`,
`docs/SECURITY-CONTROLS.md`, and `docs/TROUBLESHOOTING.md` document that
`registry.npmjs.org` (npm, Inc./GitHub) is **not a Microsoft 365 or Azure Online Service** and
is therefore the only endpoint **outside the Microsoft 365 / Azure compliance boundary** and
not covered by the Microsoft Product Terms, the DPA, or EU Data Boundary commitments; that the
connection discloses IP address, the static `User-Agent`, standard TLS/HTTP connection
metadata, and the request time; that no auto-update exists; and
that Node's built-in `fetch` cannot route through `HTTP(S)_PROXY` — an open, unresolved
tradeoff accepted to preserve the zero-runtime-dependency budget. `docs/DATA-FLOW.md`
states precisely that the registry lookup sends no customer content and no
application-level user, tenant, subscription, or install identifier, while the HTTPS
connection itself still exposes the source IP address and standard transport metadata —
it makes no absolute-anonymity claim.
- **Informational-only update guidance.** The update notice and `status_get` state that the
message is informational, that nothing is installed or changed automatically, and that
updating requires a person to change the MCP client configuration (or reinstall the copy the
client actually launches) — it is never phrased as a command to run. The guidance is
execution-mode neutral (`npx`, global install, or project-local install) and reports the
package spec to target rather than a single install command. The published package now also
ships `NOTICE.md`, `PRIVACY.md`, `CHANGELOG.md`, `SUPPORT.md`, `SECURITY.md`,
`CONTRIBUTING.md`, `docs/DATA-FLOW.md`, `docs/SECURITY-CONTROLS.md`, and
`docs/TROUBLESHOOTING.md`, so the disclosure links in the installed `README.md` resolve.
- **Per-instance data directory.** New `--data-dir <path>` flag and `SPE_DATA_DIR`
environment variable select where the provisioning `state.json` and MSAL token
cache are stored (precedence: flag > env > default `~/.spe-mcp`). Point each
Expand All @@ -18,6 +66,23 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Security

- **Update-check hardening (SEC-008).** The npm version check is HTTPS-only and requests
exactly one fixed package path with no query string; redirects and cross-host responses are
rejected. It is unauthenticated (no `Authorization`, cookies, `credentials: "omit"`, no
`.npmrc`, no `npm` subprocess), sends **no install GUID, machine, user, tenant, subscription,
correlation, or session identifier**, and discloses only what any HTTPS connection reveals
(IP address, the static product `User-Agent`, and standard TLS/HTTP connection metadata).
Setting `SPE_MCP_COLLECT_TELEMETRY=false` suppresses the registry request entirely.
It is bounded by a 2-second timeout and a 64 KB response
cap, parsed with strict SemVer and prototype-pollution-safe key filtering, and cached
owner-only (SEC-003) with a 24-hour TTL — a failed check backs off for the same 24 hours,
so at most one request per day is made either way — deleted on `logout` /
`auth --reset`. `SPE_NPM_REGISTRY` values carrying credentials, a query string, or a
fragment are rejected. Proxy routing follows the runtime configuration: releases that support
Node's environment-proxy mode (including current Node 24/26 releases) can use
`HTTP(S)_PROXY`/`NO_PROXY` when enabled with `NODE_USE_ENV_PROXY=1` or `--use-env-proxy`;
Node 22 may ignore those variables and attempt a direct connection.

- **Fail-closed credential/state file handling.** The data directory and token
cache files are now validated fail-closed: a symlinked, foreign-owned, or
group/other-accessible directory is refused (POSIX `0o700`); an off-`%USERPROFILE%`
Expand Down
43 changes: 42 additions & 1 deletion NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ consent to these practices.
> (`spe-mcp-server/<version>`) attached to the Microsoft Graph and Azure Resource Manager
> requests you already make on your own behalf; it carries no personal, tenant, or usage
> data and is used only for aggregate traffic attribution. It is **on by default** and can be
> suppressed with `SPE_MCP_COLLECT_TELEMETRY=false` (see below). See [PRIVACY.md](PRIVACY.md) and
> suppressed with `SPE_MCP_COLLECT_TELEMETRY=false` (see below). Separately from anything sent
> to Microsoft, a default-on update check contacts the public npm registry — see
> [Third-party services contacted](#third-party-services-contacted) below. See
> [PRIVACY.md](PRIVACY.md) and
> [docs/DATA-FLOW.md](docs/DATA-FLOW.md) for the full data-flow description.

## Telemetry configuration
Expand All @@ -35,6 +38,44 @@ attribution — there is no usage-analytics channel and no personal, tenant, or
opt out, set `SPE_MCP_COLLECT_TELEMETRY=false` in your environment; the product token is then
omitted from all outbound requests.

## Third-party services contacted

Beyond the Microsoft services you explicitly configure (Microsoft Graph, Azure Resource Manager,
and Microsoft Entra ID), this build contacts **one non-Microsoft service by default**.

**Public npm registry — `https://registry.npmjs.org` (npm, Inc., a GitHub company).**

- **Purpose.** After the server connects, it makes a single fire-and-forget request to read the
published version list (`dist-tags`) for `@microsoft/spe-mcp`, so it can tell you in a tool
result when a newer release exists.
- **What is sent.** The request is **unauthenticated and carries no user identifier**. No
credentials, tokens, cookies, account, tenant, machine, session, install, or customer data are
sent. The only application-supplied values are the package name in the request path and a
static product `User-Agent` (`spe-mcp-server/<version>`), which is omitted entirely when
telemetry is disabled — and in that case no request is made at all.
- **What the endpoint can observe.** As with any HTTPS request, the operator can see your
**source IP address**, the requested **package path**, the static **`User-Agent`**, and
standard **TLS/HTTP connection metadata** (TLS handshake details, timestamps, request size).
- **Compliance boundary.** npm and GitHub are **not Microsoft 365 or Azure Online Services**.
This endpoint sits **outside the Microsoft 365 / Azure compliance boundary** and is **not**
covered by the Microsoft Product Terms, the Microsoft Products and Services Data Protection
Addendum (DPA), or the EU Data Boundary. Data handling is governed by the applicable
**GitHub/npm privacy statements**, not by your Microsoft agreements.
- **Configured registry.** If you set `SPE_NPM_REGISTRY`, the update check contacts that endpoint
instead of the public npm registry. Its operator, terms, data handling, and compliance boundary
depend on your configuration; the server's notice identifies it neutrally rather than
attributing it to npm/GitHub or assigning it to a boundary.
- **Nothing is downloaded or installed.** The check reads version metadata only. This build
never downloads, installs, executes, or self-updates anything. Acting on a notice is a human
decision.
- **Local retention.** The result is cached in a local file under the server data directory
until you delete it (`spe-mcp logout` and `spe-mcp auth --reset` remove it).
- **How to turn it off (no request is made).** `--no-update-check`,
`SPE_MCP_UPDATE_CHECK=false` (preferred), `SPE_NO_UPDATE_CHECK` (legacy alias),
`NO_UPDATE_NOTIFIER`, `SPE_MCP_COLLECT_TELEMETRY=false`, or any recognized CI environment.

See [PRIVACY.md](PRIVACY.md) and [docs/DATA-FLOW.md](docs/DATA-FLOW.md) for the full disclosure.

## Compliance responsibility

This MCP server may interact with clients and services outside Microsoft compliance
Expand Down
Loading
Loading