Skip to content

Security & stability hardening, MCP annotations, label/DLP completeness, Azure Functions host#7

Open
Sealjay wants to merge 2 commits into
mainfrom
fix/ultra-review-hardening
Open

Security & stability hardening, MCP annotations, label/DLP completeness, Azure Functions host#7
Sealjay wants to merge 2 commits into
mainfrom
fix/ultra-review-hardening

Conversation

@Sealjay

@Sealjay Sealjay commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Multi-model review (opus/sonnet/haiku research + review agents, adversarially verified, synthesised by fable) of the ground-up rebuild, followed by the fixes. Priority order: security & stability first, then feature completeness. 180 tests passing (was 158). The user-visible stdio behaviour is unchanged; the repo now also deploys to Azure Functions.

Security & stability

  • PowerShell bridge — stale-frame race fixed. Frame markers are now unique per request (@@PVW_<uuid>_START/END@@). Before: a timed-out cmdlet's late output was consumed as the next request's response — wrong data returned to the wrong tool call; tenant data containing the literal marker string could also corrupt or spoof a frame. Neither is possible now.
  • Timeout resets the session. A timed-out command previously left the serialised pwsh pipe wedged for every later call; the child is now killed and the next call reconnects cleanly (clear error message says so).
  • No crash on pwsh death. stdin now has an error handler and writes are guarded (an EPIPE previously killed the whole MCP server); in-flight requests reject promptly on process exit instead of hanging until timeout.
  • Single-flight connect. Concurrent first calls used to queue two Connect-IPPSSession sign-ins; now deduplicated behind one promise.
  • Windows-only gate for the IPPS plane, called out clearly. Microsoft doesn't support Security & Compliance PowerShell in PS7 on macOS/Linux — on those platforms DLP/label-write tools now fail fast with an explanatory error instead of a baffling sign-in failure (README has a matching Platform support section; PURVIEW_ALLOW_UNSUPPORTED_OS=1 skips the gate). Graph label reads still work everywhere. This, plus the WAM window-handle failure the existing -DisableWAM default already handles, accounts for the DLP auth grief.
  • Graph pagination. list_sensitivity_labels follows @odata.nextLink — large tenants were silently truncated to the first page.
  • Certificate app-only auth on both planes (Graph ClientCertificateCredential + tenant-wide path; Connect-IPPSSession -AppId/-Certificate*/-Organization) — Microsoft's recommended fix for unattended use, and required for remote hosting. Documented in the README, including required app permissions (InformationProtectionPolicy.Read.All, Exchange.ManageAsApp) and role assignment.

MCP tool quality (glama tool-definition-quality-score rubric)

  • All 26 tools now declare full annotationstitle, readOnlyHint, destructiveHint, idempotentHint, openWorldHint — consistently by verb class (list/get, create, set, remove), so hosts can gate destructive calls. Enforced by a test.
  • Unknown prompt/resource names now return JSON-RPC InvalidParams rather than InternalError.
  • advanced_settings schemas document the common keys (Mandatory, DefaultLabelId, …) and the string-typed values quirk.

Labels + DLP completeness (v1 scope only)

  • Label publishing policies are now readable: new list_label_policies / get_label_policy (Get-LabelPolicy) — previously create/set/remove had no read-back at all.
  • Label protection settings are now readable: get_sensitivity_label gained include_protection_settings, reading back the encryption/marking/container/Teams settings the write tools set (Graph doesn't carry them). Degrades gracefully off-Windows.
  • set_dlp_policy can edit locations (add_locations/remove_locations for Exchange/SharePoint/OneDrive/Teams/Endpoint) and create_dlp_policy gained teams_location.
  • set_dlp_rule covers endpoint & Copilot rules: endpoint_restrictions replacement (audit→block tuning) and SIT condition changes.
  • Endpoint restrictions corrected to the documented surface. CopyToClipboardCopyPaste; undocumented PasteToBrowser/Bluetooth/RemoteDesktopServices and BlockWithOverride removed (they aren't valid EndpointDlpRestrictions settings/values — rules using them would fail or silently do nothing). Browser/AI-site paste control is portal-side sensitive-service-domain config; README now says so honestly. Block/Warn actions require notify_user per the cmdlet docs — enforced client-side with a clear error.
  • Copilot label rules are now visible: label-based conditions surface in list_dlp_rules/get_dlp_rule output (previously showed as empty conditions). Copilot location GUID 470f2276-e011-4e9d-a6ec-20768be3a4b0 and ExcludeContentProcessing confirmed against the New-DlpCompliancePolicy/-Rule references — "verify on live tenant" hedges removed.

Hosting: stdio + Azure Functions

  • stdio entry point unchanged (index.js, still the bin); the tool surface moved to src/server.js behind a createServer() factory.
  • New Azure Functions host (host.json + functions/server.js) using Microsoft's self-hosted MCP servers pattern: stateless streamable HTTP at POST /mcp, fresh server+transport per request, node:http (no new dependencies), function-key auth by default. Smoke-tested end-to-end in CI (test/functions.test.js drives real HTTP: initialize, tools/list = 26 annotated tools).
  • Containerfile (podman-friendly) for full-surface hosting on Premium/Dedicated/ACA — pwsh + ExchangeOnlineManagement + app-only cert auth. Code-only Flex Consumption deploys serve the Graph-read tools. Container not built in CI; the Linux IPPS caveat is documented inline.
  • CI workflow: npm test on ubuntu/windows × node 20/22.

Deferred (documented in ROADMAP)

  • Migration of label reads from /beta informationProtection to the GA v1.0 dataSecurityAndGovernance surface — needs new scopes + live-tenant shape validation; labelPolicySettings has no GA equivalent so that read stays beta regardless.
  • UnallowedApps endpoint setting (different value shape), on-prem scanner/Power BI locations, auto-labeling.

Verification

  • 180/180 tests (node --test), including new coverage for stale frames, timeout reset, process death, connect dedup, the platform gate, pagination, annotations, label-policy read-back, and the HTTP host.
  • End-to-end: real stdio round trip via the MCP SDK client (spawned child process) and real HTTP against the Functions entry point.
  • Not verified here: live-tenant behaviour of the new cmdlet parameters (no tenant/pwsh on this machine) — worth one pass on the demo tenant, especially set_dlp_policy location edits and get_label_policy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H9bG3RxF9V4ooiVvSCbT4D

Sealjay and others added 2 commits July 12, 2026 19:05
Ran on every push/PR but never found a TODO/FIXME marker or opened an issue in this repo's history — dead weight.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Bw6YFkqeMH2cYtukzSQDu
…host

Security & stability (review-driven):
- PowerShell bridge: request-scoped frame markers (stale/timed-out output
  can never be mis-attributed to a later call; marker-lookalike tenant data
  cannot spoof a frame), child killed on timeout so the session never wedges,
  stdin error handling (no crash on pwsh death), single-flight connect (no
  double interactive sign-in on concurrent first use).
- Windows-only platform gate with a clear error for the IPPS plane (Microsoft
  does not support Security & Compliance PowerShell on macOS/Linux);
  PURVIEW_ALLOW_UNSUPPORTED_OS=1 escape hatch. Graph label reads unaffected.
- Graph: @odata.nextLink pagination (no silent truncation on large tenants).
- Certificate app-only auth on both planes (Graph ClientCertificateCredential
  + tenant-wide path; Connect-IPPSSession -AppId/-Certificate*/-Organization)
  for headless/unattended hosts.

MCP quality:
- All 26 tools now declare annotations (title, readOnlyHint, destructiveHint,
  idempotentHint, openWorldHint) per the tool-definition-quality rubric.
- Unknown prompt/resource names return InvalidParams instead of InternalError.
- advanced_settings schemas document common keys and string-typed values.

Completeness (labels + DLP):
- New list_label_policies / get_label_policy read-back (Get-LabelPolicy).
- get_sensitivity_label include_protection_settings reads back the
  encryption/marking/container/Teams settings the write tools set.
- set_dlp_policy add_locations/remove_locations (Exchange, SharePoint,
  OneDrive, Teams, Endpoint); create_dlp_policy teams_location.
- set_dlp_rule handles endpoint_restrictions and SIT condition changes.
- Endpoint restrictions aligned to the documented EndpointDlpRestrictions
  settings (CopyPaste et al; undocumented PasteToBrowser/Bluetooth/RDS
  removed — browser/AI-site control is portal-side sensitive service
  domains); Block/Warn now require notify_user, enforced client-side.
- Copilot location GUID + ExcludeContentProcessing confirmed against the
  New-DlpCompliancePolicy/-Rule references; label conditions now surface in
  rule list/detail output.

Hosting:
- Azure Functions custom-handler host (stateless streamable HTTP, per-request
  server instances) alongside the unchanged stdio entry point; Containerfile
  for full-surface container plans; smoke-tested end-to-end in CI.
- CI workflow: npm test on ubuntu/windows x node 20/22.

Tests: 180 passing (was 158), including stale-frame, timeout-reset,
process-death, connect-dedup, platform-gate, pagination, annotation, and
HTTP-host coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9bG3RxF9V4ooiVvSCbT4D
@Sealjay
Sealjay requested a review from KnowledgeRatio July 13, 2026 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant