@unbrained/pm-cli 2026.8.25 → 2026.8.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +33 -0
  3. package/dist/cli-bundle/bundle-manifest.json +133 -133
  4. package/dist/cli-bundle/chunks/chunk-E2GCFJSU.js +35 -0
  5. package/dist/cli-bundle/chunks/{chunk-QKGMHGEI.js → chunk-ES25LX3D.js} +51 -51
  6. package/dist/cli-bundle/chunks/{chunk-TPQIBSL2.js → chunk-FRDWWB6R.js} +2 -2
  7. package/dist/cli-bundle/chunks/{chunk-65MHLHAA.js → chunk-ICQ3RVIY.js} +2 -2
  8. package/dist/cli-bundle/chunks/chunk-IV64RJVE.js +13 -0
  9. package/dist/cli-bundle/chunks/{chunk-QLUORNIB.js → chunk-KBFP3E4E.js} +2 -2
  10. package/dist/cli-bundle/chunks/{chunk-T2ENPRXF.js → chunk-MVYLQ67M.js} +2 -2
  11. package/dist/cli-bundle/chunks/{chunk-5I5RWIJC.js → chunk-S4U76VZF.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-OWHNAR2B.js → chunk-UKBCRPA2.js} +2 -2
  13. package/dist/cli-bundle/chunks/chunk-WRHJ3MB6.js +8 -0
  14. package/dist/cli-bundle/chunks/{chunk-244MI4GS.js → chunk-ZNRLJ54C.js} +60 -60
  15. package/dist/cli-bundle/chunks/{register-list-query-XVN2ZLI7.js → register-list-query-EMCPMICY.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-mutation-QCKAEGIJ.js → register-mutation-OJ67ABCB.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-operations-SDEAXE7E.js → register-operations-H2GLP7LT.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-setup-LXVBRCJ3.js → register-setup-GLZAHLVI.js} +2 -2
  19. package/dist/cli-bundle/focused-chunks/{chunk-NOOZGIXP.js → chunk-4K2II4TV.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/{chunk-IBZZZGK3.js → chunk-4XNH2HM7.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/{chunk-VXWATRFL.js → chunk-57XY346D.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/{chunk-GQR3WH3F.js → chunk-66VGB23P.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/{chunk-42S3GGZ7.js → chunk-72T6JGAE.js} +45 -45
  24. package/dist/cli-bundle/focused-chunks/{chunk-RAFKLNZX.js → chunk-FXDLT6FL.js} +2 -2
  25. package/dist/cli-bundle/focused-chunks/{chunk-H5JZEIQV.js → chunk-IBHXMFE7.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/{chunk-N7W67YIG.js → chunk-LV5N3LK5.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/{chunk-2UIWOP3O.js → chunk-MMXUPDDJ.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/{chunk-ONYQCALA.js → chunk-P2E6LDAE.js} +6 -6
  29. package/dist/cli-bundle/focused-chunks/{chunk-XUQPEKRN.js → chunk-TMJDFHVD.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-OVJL6NZE.js → chunk-UYBA57GY.js} +4 -4
  31. package/dist/cli-bundle/main.js +2 -2
  32. package/dist/cli-bundle/sdk-authoring.js +1 -1
  33. package/dist/cli-bundle/sdk-contracts.js +1 -1
  34. package/dist/cli-bundle/sdk-core.js +31 -31
  35. package/dist/cli-bundle/sdk-governance.js +1 -1
  36. package/dist/cli-bundle/sdk-graph.js +1 -1
  37. package/dist/cli-bundle/sdk-merge.js +18 -18
  38. package/dist/cli-bundle/sdk-query.js +1 -1
  39. package/dist/cli-bundle/sdk-runtime.js +1 -1
  40. package/dist/cli-bundle/sdk-testing.js +1 -1
  41. package/dist/cli-bundle/sdk.js +7 -6
  42. package/dist/core/extensions/manifest-schema.d.ts +20 -0
  43. package/dist/core/extensions/manifest-schema.js +28 -10
  44. package/dist/mcp/http-server.d.ts +60 -0
  45. package/dist/mcp/http-server.js +451 -0
  46. package/dist/mcp/legacy-adapter.d.ts +50 -0
  47. package/dist/mcp/legacy-adapter.js +64 -0
  48. package/dist/mcp/server.d.ts +42 -9
  49. package/dist/mcp/server.js +457 -58
  50. package/dist/sdk/agent/refusal-closure-census.d.ts +6 -2
  51. package/dist/sdk/agent/refusal-closure-census.js +16 -8
  52. package/dist/sdk/compose.d.ts +4 -1
  53. package/dist/sdk/compose.js +23 -36
  54. package/dist/sdk/extension/author-manifest.d.ts +22 -0
  55. package/dist/sdk/extension/author-manifest.js +93 -0
  56. package/dist/sdk/extension.js +6 -3
  57. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +20 -5
  58. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +6 -3
  59. package/dist/sdk/governance/health.js +7 -2
  60. package/dist/sdk/index.d.ts +6 -0
  61. package/dist/sdk/index.js +8 -2
  62. package/dist/sdk/mcp/authorization.d.ts +134 -0
  63. package/dist/sdk/mcp/authorization.js +405 -0
  64. package/dist/sdk/mcp/interactions.d.ts +118 -0
  65. package/dist/sdk/mcp/interactions.js +337 -0
  66. package/dist/sdk/mcp/protocol.d.ts +142 -0
  67. package/dist/sdk/mcp/protocol.js +174 -0
  68. package/dist/sdk/mcp/subscriptions.d.ts +65 -0
  69. package/dist/sdk/mcp/subscriptions.js +212 -0
  70. package/dist/sdk/mcp/tasks.d.ts +107 -0
  71. package/dist/sdk/mcp/tasks.js +431 -0
  72. package/dist/sdk/mcp/transport.d.ts +30 -0
  73. package/dist/sdk/mcp/transport.js +261 -0
  74. package/dist/sdk/merge/receipts.d.ts +16 -0
  75. package/dist/sdk/merge/receipts.js +9 -8
  76. package/dist/sdk/runtime-primitives.d.ts +1 -1
  77. package/dist/sdk/runtime-primitives.js +3 -3
  78. package/dist/sdk/test/execution.d.ts +6 -0
  79. package/dist/sdk/test/execution.js +32 -3
  80. package/docs/AGENT_PROVENANCE_ADR.md +6 -4
  81. package/docs/AGENT_RUNTIME_PRIMITIVES.md +6 -5
  82. package/docs/CLAUDE_CODE_PLUGIN.md +12 -5
  83. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +8 -0
  84. package/docs/EXTENSIONS.md +3 -4
  85. package/docs/MCP_2026_07_28.md +138 -0
  86. package/docs/MCP_2026_07_28_CONFORMANCE.md +30 -0
  87. package/docs/MCP_REMOTE_TRANSPORT_SECURITY.md +180 -0
  88. package/docs/README.md +4 -0
  89. package/docs/RELEASING.md +3 -2
  90. package/docs/SDK.md +22 -1
  91. package/docs/SDK_AGENT_SESSION_CONTEXT.md +18 -13
  92. package/docs/SDK_MCP_INTERACTIONS.md +227 -0
  93. package/docs/TESTING.md +4 -0
  94. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +9 -8
  95. package/marketplace.json +2 -2
  96. package/package.json +7 -5
  97. package/packages/pm-beads/package.json +1 -1
  98. package/packages/pm-calendar/package.json +1 -1
  99. package/packages/pm-command-kit/package.json +1 -1
  100. package/packages/pm-digital-twin/package.json +1 -1
  101. package/packages/pm-governance-audit/package.json +1 -1
  102. package/packages/pm-guide-shell/package.json +1 -1
  103. package/packages/pm-kanban/package.json +1 -1
  104. package/packages/pm-lifecycle-hooks/package.json +1 -1
  105. package/packages/pm-linked-test-adapters/package.json +1 -1
  106. package/packages/pm-search-advanced/package.json +1 -1
  107. package/packages/pm-templates/package.json +1 -1
  108. package/packages/pm-todos/package.json +1 -1
  109. package/packages/pm-vcs/package.json +1 -1
  110. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  111. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  112. package/scripts/finalize-build.mjs +1 -0
  113. package/sdk/public-surface.json +628 -2
  114. package/dist/cli-bundle/chunks/chunk-2F3LUFMW.js +0 -8
  115. package/dist/cli-bundle/chunks/chunk-6C7GIMIL.js +0 -13
  116. package/dist/cli-bundle/chunks/chunk-YQMYF3YD.js +0 -35
@@ -0,0 +1,138 @@
1
+ # MCP 2026-07-28 Protocol and Compatibility Decision
2
+
3
+ Tracker references: [pm-sqvshj](../.agents/pm/decisions/pm-sqvshj.toon),
4
+ [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon), and
5
+ [pm-55yf1t](../.agents/pm/tasks/pm-55yf1t.toon). MRTR, durable tasks,
6
+ and the cache/schema surface are tracked by
7
+ [pm-rz9gep](../.agents/pm/features/pm-rz9gep.toon),
8
+ [pm-rzs24j](../.agents/pm/features/pm-rzs24j.toon), and
9
+ [pm-hv1x1x](../.agents/pm/features/pm-hv1x1x.toon). Subscriptions,
10
+ Streamable HTTP, remote authorization, and the deprecation ratchet are tracked
11
+ by [pm-v7e337](../.agents/pm/features/pm-v7e337.toon),
12
+ [pm-3zh9s4](../.agents/pm/features/pm-3zh9s4.toon), and
13
+ [pm-vzcisw](../.agents/pm/chores/pm-vzcisw.toon).
14
+
15
+ Status: accepted. MCP `2026-07-28` is pm's canonical protocol revision.
16
+
17
+ ## Decision
18
+
19
+ The public pm SDK owns protocol versions, request metadata validation,
20
+ capability checks, discovery, result envelopes, error codes, HTTP header
21
+ parity, subscriptions, authorization boundaries, trace isolation, and legacy
22
+ result interpretation. `pm-mcp` is a JSON-RPC/stdio adapter over those
23
+ contracts; `pm-mcp-http` binds the same dispatcher to sessionless Streamable
24
+ HTTP POST.
25
+
26
+ Modern requests are stateless. Every request carries:
27
+
28
+ - `io.modelcontextprotocol/protocolVersion` = `2026-07-28`;
29
+ - `io.modelcontextprotocol/clientCapabilities` as an object, including `{}`;
30
+ - optional `io.modelcontextprotocol/clientInfo` with `name` and `version`.
31
+
32
+ Every modern result carries an explicit `resultType` (`complete`,
33
+ `input_required`, or `task`) and `io.modelcontextprotocol/serverInfo` in
34
+ result `_meta`. The mandatory
35
+ `server/discover` method returns the supported modern revisions, deterministic
36
+ capabilities, public cache policy, server identity, and bounded instructions.
37
+ No modern request reads identity, capabilities, or version from a previous
38
+ request.
39
+
40
+ ## Legacy boundary
41
+
42
+ The sole supported legacy revision is `2025-06-18`, accepted through the
43
+ existing stdio adapter. Unversioned requests stay on this legacy path because
44
+ they cannot claim the current revision; `initialize` enriches their client
45
+ identity but is not required for compatibility with older pm hosts. The
46
+ adapter has no session id, does not affect modern requests, and is excluded
47
+ from `server/discover`'s `supportedVersions` because it cannot be selected
48
+ through modern per-request metadata.
49
+
50
+ The adapter is scheduled for removal only after published-client telemetry and
51
+ release probes show no required legacy consumers for two consecutive release
52
+ windows. Removal is a reviewed compatibility change, never a history rewrite.
53
+
54
+ ## Transport behavior
55
+
56
+ - Stdio modern clients call `server/discover` with current request metadata,
57
+ then send the same version and capability keys on every request.
58
+ - Stdio legacy clients retain their existing response shapes and may use
59
+ `initialize` with `2025-06-18` to supply client identity.
60
+ - Streamable HTTP requires `MCP-Protocol-Version` and `Mcp-Method` on every
61
+ request. `Mcp-Name` is required only for `prompts/get`, `resources/read`, and
62
+ `tools/call`; other methods omit it. Schema-declared `x-mcp-header` values are
63
+ encoded, decoded, and compared with tool arguments before dispatch.
64
+ Header/version mismatch uses code `-32020` and HTTP 400.
65
+ - `subscriptions/listen` is a request-scoped stdio or SSE stream. The first
66
+ message acknowledges the supported filter; later messages carry its request
67
+ id as `io.modelcontextprotocol/subscriptionId`. Disconnect deletes the
68
+ subscription and a caller retries lost work with a new request id.
69
+ - The remote adapter defaults to loopback, enforces exact browser origins,
70
+ bounds bodies, maps parse/invalid requests to HTTP 400, and can require an
71
+ issuer-, audience-, and scope-bound bearer token.
72
+ - Unsupported modern versions return `-32022` plus the exact supported modern
73
+ list. Missing required capabilities return `-32021` with a structured
74
+ capability map. Malformed metadata uses JSON-RPC Invalid Params `-32602`.
75
+
76
+ ## Removed, migrated, and deprecated behavior
77
+
78
+ | Prior behavior | Disposition |
79
+ | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
80
+ | `initialize` and `notifications/initialized` | Legacy stdio adapter only; absent from modern behavior. |
81
+ | `Mcp-Session-Id` and protocol sessions | Removed; explicit application handles are ordinary arguments. |
82
+ | `ping` | Legacy adapter only; modern calls return Method Not Found. |
83
+ | `resources/subscribe` and `resources/unsubscribe` | Replaced by the implemented `subscriptions/listen` filter. |
84
+ | SSE event ids and `Last-Event-ID` replay | Removed; callers retry with a new request id. |
85
+ | Reverse `roots/list`, sampling, and elicitation requests | Migrate to MRTR `input_required` under `pm-rz9gep`. |
86
+ | Core tasks | Migrate to `io.modelcontextprotocol/tasks` under `pm-rzs24j`. |
87
+ | `logging/setLevel` | Removed; optional request-local log metadata is never shared, and remote operations use host OpenTelemetry. |
88
+ | Roots, Sampling, Logging, HTTP+SSE, and non-none `includeContext` | Retain only in bounded legacy compatibility while `pm-vzcisw` drives deprecation removal. |
89
+ | Dynamic Client Registration | Legacy authorization fallback; Client ID Metadata Documents are canonical under `pm-3zh9s4`. |
90
+
91
+ ## Rollout, rollback, and proof
92
+
93
+ Local and hosted gates must prove SDK primitives, direct server calls, real
94
+ stdio, packed artifacts, npx, bunx, and published artifacts agree on discovery
95
+ and the canonical revision. Negative controls cover unsupported versions,
96
+ missing/malformed metadata, missing capabilities, header mismatch, removed
97
+ methods, and omitted modern `resultType`.
98
+
99
+ Rollback preserves the SDK contract and re-enables only the reviewed legacy
100
+ adapter. It must never reintroduce session ids or make modern behavior depend
101
+ on initialization. Release evidence records exact source, package, tag, and
102
+ consumer revisions separately.
103
+
104
+ ## MRTR, tasks, and cache behavior
105
+
106
+ An SDK handler that cannot finish without host input throws
107
+ `PmMcpInputRequiredError`. The modern adapter validates the requested
108
+ `elicitation/create`, `roots/list`, or `sampling/createMessage` capability and
109
+ returns `resultType: "input_required"`. Continuation state can be bounded,
110
+ HMAC-sealed, expiry-bound, method-bound, parameter-bound, principal-bound, and
111
+ protected from in-process replay with the public interaction helpers. Retry
112
+ payloads arrive as request-local `inputResponses`; they never depend on a
113
+ protocol session.
114
+
115
+ Clients negotiate `io.modelcontextprotocol/tasks` in request capabilities.
116
+ Eligible long-running `tools/call` operations can then return a durable task
117
+ handle. `tasks/get`, `tasks/update`, and `tasks/cancel` are principal-scoped,
118
+ persist records atomically under the ignored tracker runtime area, enforce
119
+ immutable terminal states, expire abandoned work deterministically, and turn
120
+ a disappeared worker into an actionable terminal failure. Task state remains
121
+ retrieved through the task methods. Change subscriptions do not become
122
+ task-progress channels, and pm's current handlers do not emit request progress
123
+ or deprecated log-message notifications.
124
+
125
+ Modern tool, resource, resource-template, and prompt list/read results carry
126
+ explicit `ttlMs` and `cacheScope`. Tool schemas are validated as bounded JSON
127
+ Schema 2020-12 documents before advertisement. Tool and resource data stay
128
+ private; public metadata lists may be cached for their advertised lifetime.
129
+
130
+ ## Public SDK
131
+
132
+ Use `PM_MCP_PROTOCOL_VERSION`, `resolveMcpRequestContext()`,
133
+ `buildMcpDiscoverResult()`, `buildMcpCompleteResult()`,
134
+ `PmMcpSubscriptionRegistry`, `buildMcpHttpRequestHeaders()`,
135
+ `validateMcpHttpRequestHeaders()`, `buildMcpProtectedResourceMetadata()`, and
136
+ the issuer/trace authorization helpers from `@unbrained/pm-cli/sdk`. See
137
+ [MCP interaction and task SDK](SDK_MCP_INTERACTIONS.md) and
138
+ [remote transport, authorization, and migration](MCP_REMOTE_TRANSPORT_SECURITY.md).
@@ -0,0 +1,30 @@
1
+ # MCP 2026-07-28 Conformance Matrix
2
+
3
+ Tracker: [pm-55yf1t](../.agents/pm/tasks/pm-55yf1t.toon). The official
4
+ 2026-07-28 schema and key-changes document are normative; this matrix assigns
5
+ every revision-level change to one canonical pm owner and records executable
6
+ evidence or an explicit open obligation.
7
+
8
+ | Requirement family | Canonical owner | Current disposition | Executable evidence |
9
+ | -------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
10
+ | Stateless per-request version, client capabilities, and identity | [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon) | Implemented | `tests/unit/sdk/mcp/protocol.spec.ts`, `tests/integration/mcp-stateless-protocol.spec.ts` |
11
+ | Mandatory `server/discover`, deterministic capabilities and identity | [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon) | Implemented | direct SDK/server tests plus plugin and release real-process probes |
12
+ | Unsupported version `-32022` | [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon) | Implemented | SDK and server negative controls |
13
+ | Header mismatch `-32020` and missing capability `-32021` | [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon) | Implemented in SDK, stdio, and Streamable HTTP | SDK negative controls and `tests/integration/mcp-streamable-http.spec.ts` |
14
+ | Required result `resultType`; legacy omission means complete only at compatibility boundary | [pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon) | Implemented for modern pm results | SDK unit and modern direct-server tests |
15
+ | No modern initialize, initialized notification, ping, or protocol session | [pm-sqvshj](../.agents/pm/decisions/pm-sqvshj.toon) | Implemented with bounded legacy stdio adapter | modern removed-method and legacy handshake tests |
16
+ | MRTR `input_required`, retry state, and reverse-request removal | [pm-rz9gep](../.agents/pm/features/pm-rz9gep.toon) | Implemented for SDK and stateless stdio adapter | `tests/unit/sdk/mcp/interactions.spec.ts`; direct server negative controls |
17
+ | `subscriptions/listen`, request-scoped streams, no SSE resumability | [pm-v7e337](../.agents/pm/features/pm-v7e337.toon) | Implemented locally; packed and published proof follows merge | subscription SDK, stdio, HTTP, backpressure, disconnect, and retry tests |
18
+ | Official `io.modelcontextprotocol/tasks` extension | [pm-rzs24j](../.agents/pm/features/pm-rzs24j.toon) | Implemented for eligible tool calls, durable lifecycle, and stdio methods; notifications remain with subscriptions owner | `tests/unit/sdk/mcp/tasks.spec.ts`, `tests/integration/mcp-stateless-protocol.spec.ts` |
19
+ | Cacheable list/read results, deterministic tools, JSON Schema 2020-12, any JSON structured content | [pm-hv1x1x](../.agents/pm/features/pm-hv1x1x.toon) | Implemented for current pm tool/resource/prompt surfaces | SDK schema/cache tests and direct modern server surface suite |
20
+ | Issuer-bound authorization, client metadata documents, consent, headers, OpenTelemetry | [pm-3zh9s4](../.agents/pm/features/pm-3zh9s4.toon) | Implemented locally; deployment verifier integration remains host-owned | authorization SDK adversarial tests, real HTTP bearer suite, and threat model |
21
+ | Core extension negotiation and official extension fallback | [pm-pznhee](../.agents/pm/features/pm-pznhee.toon) | Open | owner acceptance criteria and release matrix |
22
+ | Skills over MCP | [pm-8nzivt](../.agents/pm/features/pm-8nzivt.toon) | Open | owner acceptance criteria define capability and token-budget proof |
23
+ | Deprecated Roots, Sampling, Logging, HTTP+SSE, `includeContext`, dynamic registration | [pm-vzcisw](../.agents/pm/chores/pm-vzcisw.toon) | Canonical source ratcheted; bounded stdio adapter and dated migration policy remain | generated inventory, negative controls, adapter tests, and migration guide |
24
+ | Official schema, real stdio/HTTP, packed/published, npx/bunx, negative controls | [pm-55yf1t](../.agents/pm/tasks/pm-55yf1t.toon) | Foundation implemented; remains open until every owner above closes | SDK/server suites, plugin smokes, published-release verifier |
25
+
26
+ The programme gate remains intentionally incomplete while any row says `Open`
27
+ or while local-only rows lack their packed and published evidence. Provider
28
+ silence, a successful legacy initialize, or source-only unit coverage cannot
29
+ promote such a row. Completion requires the owner's positive and negative
30
+ tests plus exact packed and published consumer proof.
@@ -0,0 +1,180 @@
1
+ # MCP Remote Transport, Authorization, and Migration
2
+
3
+ Tracker references: [pm-v7e337](../.agents/pm/features/pm-v7e337.toon),
4
+ [pm-3zh9s4](../.agents/pm/features/pm-3zh9s4.toon), and
5
+ [pm-vzcisw](../.agents/pm/chores/pm-vzcisw.toon).
6
+
7
+ pm exposes the same MCP 2026-07-28 dispatcher through two adapters:
8
+
9
+ - `pm-mcp` is the local JSON-RPC/stdio process. It retains a bounded
10
+ `2025-06-18` compatibility adapter for existing local consumers.
11
+ - `pm-mcp-http` is the canonical sessionless Streamable HTTP POST process. It
12
+ accepts only modern request-local protocol metadata and never creates an
13
+ MCP session.
14
+
15
+ The public `@unbrained/pm-cli/sdk` entrypoint owns subscription filtering,
16
+ HTTP header projection, authorization discovery and validation, issuer-keyed
17
+ credentials, bearer enforcement, and trace-context isolation. Adapters remain
18
+ thin bindings over those contracts.
19
+
20
+ ## Run the HTTP adapter
21
+
22
+ The safe default binds only `127.0.0.1:3000`:
23
+
24
+ ```bash
25
+ pm-mcp-http
26
+ ```
27
+
28
+ Configuration is explicit and environment-only:
29
+
30
+ | Variable | Meaning | Default |
31
+ | ----------------------------- | --------------------------------------------------- | ------------------ |
32
+ | `PM_MCP_HTTP_HOST` | Bind host | `127.0.0.1` |
33
+ | `PM_MCP_HTTP_PORT` | Bind port, including `0` for an ephemeral test port | `3000` |
34
+ | `PM_MCP_HTTP_ALLOWED_ORIGINS` | Comma-separated exact browser origins | none |
35
+ | `PM_MCP_HTTP_BEARER_TOKEN` | Opaque deployment token for the bundled verifier | none |
36
+ | `PM_MCP_HTTP_AUTH_ISSUER` | Exact HTTPS authorization-server issuer | none |
37
+ | `PM_MCP_HTTP_RESOURCE` | Canonical MCP resource/audience URI | none |
38
+ | `PM_MCP_HTTP_SCOPES` | Space-separated consent scopes | `pm:read pm:write` |
39
+
40
+ A non-loopback bind fails closed unless token, issuer, and resource are all
41
+ present. Production deployments should normally call
42
+ `createPmMcpHttpServer()` with an OAuth access-token verifier backed by their
43
+ authorization server instead of using the executable's single opaque-token
44
+ bootstrap verifier.
45
+
46
+ For example, this starts a deliberately local protected endpoint without
47
+ placing a real credential in documentation:
48
+
49
+ ```bash
50
+ PM_MCP_HTTP_BEARER_TOKEN='<deployment-secret>' \
51
+ PM_MCP_HTTP_AUTH_ISSUER='https://auth.example.test' \
52
+ PM_MCP_HTTP_RESOURCE='http://127.0.0.1:3000/mcp' \
53
+ pm-mcp-http
54
+ ```
55
+
56
+ The adapter serves RFC 9728 protected-resource metadata at both
57
+ `/.well-known/oauth-protected-resource` and the path-qualified
58
+ `/.well-known/oauth-protected-resource/mcp` location.
59
+
60
+ ## Stream and header contract
61
+
62
+ Every HTTP request is a POST to `/mcp` and negotiates both
63
+ `application/json` and `text/event-stream`. Normal finite requests return
64
+ JSON. `subscriptions/listen` returns an SSE response whose first message is
65
+ `notifications/subscriptions/acknowledged`; every later subscription
66
+ notification carries the listen request's JSON-RPC id in
67
+ `io.modelcontextprotocol/subscriptionId`.
68
+
69
+ The supported opt-ins are tool-list, prompt-list, resource-list, and exact
70
+ resource-update notifications. Each stream serializes writes and drops a sink
71
+ that fails or remains backpressured beyond the bounded write deadline; tool
72
+ calls do not await subscriber delivery. Disconnecting deletes the
73
+ request-scoped subscription. A broken stream has no replay cursor: there are no
74
+ SSE event ids and `Last-Event-ID` is rejected. The caller retries the lost
75
+ operation with a new JSON-RPC request id.
76
+
77
+ `MCP-Protocol-Version` and `Mcp-Method` are built and validated against every
78
+ JSON-RPC request body. `Mcp-Name` is required only for `prompts/get`,
79
+ `resources/read`, and `tools/call`; methods such as `tools/list` omit it. Tool
80
+ properties may declare `x-mcp-header` in their JSON Schema; the SDK validates
81
+ the header name, rejects reserved or duplicate mappings, encodes non-ASCII and
82
+ ambiguous values with the MCP Base64 sentinel, and compares the decoded header
83
+ with the argument value before dispatch. CR/LF and control-character values
84
+ are always rejected.
85
+
86
+ Current pm handlers do not emit request progress or deprecated MCP log-message
87
+ notifications. A `progressToken` or request-local
88
+ `io.modelcontextprotocol/logLevel` is therefore never promoted to a shared
89
+ subscription. Work that returns a durable task remains observable through the
90
+ task lifecycle; remote operational logging belongs in the deployment's
91
+ OpenTelemetry pipeline.
92
+
93
+ ## Authorization lifecycle
94
+
95
+ Remote hosts can compose the public SDK primitives into a complete OAuth
96
+ client/resource lifecycle:
97
+
98
+ 1. Build or read protected-resource metadata and choose an advertised
99
+ authorization-server issuer.
100
+ 2. Probe OAuth and OpenID discovery URLs in the specified order. Require the
101
+ metadata `issuer` to match exactly and require S256 PKCE.
102
+ 3. Prefer a pre-registered client, then a validated Client ID Metadata
103
+ Document, then bounded Dynamic Client Registration, and finally explicit
104
+ user-supplied registration.
105
+ 4. Validate a returned `iss` when present or advertised, bind stored
106
+ credentials to the exact issuer, and never reuse them across issuers.
107
+ 5. Request only the scopes needed for the operation. The resource verifies
108
+ bearer location, issuer, audience, and every required consent scope before
109
+ MCP dispatch.
110
+ 6. Replace an issuer's stored credential after refresh. Delete only that
111
+ issuer's entry on revocation, invalid grant, or re-registration; discovery
112
+ and consent then run again without affecting other issuers.
113
+
114
+ `PmMcpIssuerCredentialStore` deliberately provides cloned `set`, `get`, and
115
+ `delete` operations rather than owning token refresh network traffic. This
116
+ keeps refresh, revocation, persistence encryption, and user interaction in the
117
+ host that owns the authorization relationship.
118
+
119
+ ## Trace and privacy boundary
120
+
121
+ Modern request `_meta` may carry W3C `traceparent`, `tracestate`, and baggage.
122
+ The SDK validates syntax and byte bounds, drops every baggage member that is
123
+ not on the host-provided allowlist, and stores the resulting context in an
124
+ `AsyncLocalStorage` scope for only that request. Concurrent requests cannot
125
+ inherit one another's trace context. Raw bearer tokens are hashed for
126
+ constant-time comparison by the bundled verifier and are never included in
127
+ claims, errors, traces, or JSON-RPC result data.
128
+
129
+ | Threat | Enforced boundary |
130
+ | ------------------------------ | ------------------------------------------------------------------------------- |
131
+ | DNS rebinding/browser drive-by | Loopback default plus exact `Origin` allowlist |
132
+ | Token passthrough | Bearer is verified at pm and never forwarded to another service |
133
+ | Issuer mix-up | Exact discovery/response issuer checks and issuer-keyed credentials |
134
+ | Confused audience | Exact protected-resource audience check |
135
+ | Excess authority | Required-scope intersection before dispatch |
136
+ | Query/log credential leak | Query tokens rejected; challenges and errors omit token material |
137
+ | Header injection | Schema-derived allowlist, reserved-name checks, control-byte rejection |
138
+ | Trace privacy leak | Syntax/size validation, baggage-key allowlist, request-local storage |
139
+ | Proxy cache disclosure | MCP and metadata errors use explicit content types; MCP results use `no-store` |
140
+ | Replay after disconnect | No session, event id, resume cursor, or redelivery; retry uses a new request id |
141
+
142
+ ## Deprecated-feature inventory and sunset
143
+
144
+ Run the generated ratchet locally or in CI:
145
+
146
+ ```bash
147
+ pnpm quality:mcp-deprecations
148
+ ```
149
+
150
+ The inventory classifies every match as canonical source, the isolated legacy
151
+ adapter, migration documentation, a negative control, or
152
+ `bounded_source_control`. The last disposition applies only to exact,
153
+ single-use source lines in the reviewed fixed allowlist; an adjacent marker or
154
+ an unlisted source path cannot create that exemption. Any canonical match for a
155
+ removed method, session header, SSE resume mechanism, legacy
156
+ resource-subscription method, or deprecated server policy fails the gate.
157
+
158
+ The compatibility adapter supports only protocol `2025-06-18` on local stdio.
159
+ It may be removed after telemetry and installed-consumer probes show no
160
+ required legacy clients for two consecutive release windows. Deprecated
161
+ 2026-07-28 fields remain available only where the normative registry requires
162
+ its minimum compatibility period; no pm sunset occurs earlier than
163
+ 2027-07-28. A removal is always a reviewed release change with packed and
164
+ published consumer proof.
165
+
166
+ ## Verification
167
+
168
+ Focused release evidence is reproducible with:
169
+
170
+ ```bash
171
+ node scripts/run-tests.mjs test -- tests/unit/sdk/mcp/subscriptions.spec.ts
172
+ node scripts/run-tests.mjs test -- tests/unit/sdk/mcp/transport.spec.ts
173
+ node scripts/run-tests.mjs test -- tests/unit/sdk/mcp/authorization.spec.ts
174
+ node scripts/run-tests.mjs test -- tests/integration/mcp-streamable-http.spec.ts
175
+ node scripts/run-tests.mjs test -- tests/unit/scripts/release/mcp-deprecation-gate.spec.ts
176
+ pnpm quality:mcp-deprecations
177
+ ```
178
+
179
+ The full release gates, packed artifact probes, installed `npx`/`bunx`
180
+ consumers, and published artifact checks remain distinct closeout evidence.
package/docs/README.md CHANGED
@@ -44,6 +44,10 @@ pm guide release --json
44
44
  - [SDK Primitive Inventory](SDK_PRIMITIVE_INVENTORY.md) - SDK-first migration map and private-import ratchet for CLI/MCP layering.
45
45
  - [Package SDK Contract Conformance](PACKAGE_SDK_CONTRACT_CONFORMANCE.md) - authoritative public types, `typeof` module derivation, and the first-party parity gate.
46
46
  - [SDK Action and Boundary Conformance](SDK_ACTION_CONFORMANCE.md) - derived CLI/SDK/MCP action vocabulary, public-import ratchets, intent budget diagnostics, and package-runner proof.
47
+ - [MCP 2026-07-28 Protocol Decision](MCP_2026_07_28.md) - stateless request metadata, discovery, result envelopes, explicit legacy boundary, and migration policy.
48
+ - [MCP 2026-07-28 Conformance Matrix](MCP_2026_07_28_CONFORMANCE.md) - official revision changes mapped to canonical owners and executable evidence.
49
+ - [MCP Interaction and Task SDK](SDK_MCP_INTERACTIONS.md) - public MRTR continuation, cache/schema validation, and durable task-store contracts.
50
+ - [MCP Remote Transport, Authorization, and Migration](MCP_REMOTE_TRANSPORT_SECURITY.md) - Streamable HTTP operation, subscriptions, OAuth and trace boundaries, threat model, and deprecated-feature ratchet.
47
51
  - [SDK Artifact Output Contracts](SDK_ARTIFACT_OUTPUT.md) - clean stdout/file exporter channels, bounded receipts, binary-safe delivery, and shared NDJSON terminal framing.
48
52
  - [Context Relevance and Packing](CONTEXT_RELEVANCE.md) - shared CLI/SDK signals, derived-store provenance, ranking explanations, and token budgets.
49
53
  - [Output Projection and Omission Contracts](OUTPUT_PROJECTION_CONTRACTS.md) - explicit withheld-field receipts, mode-paired row keys, and completion resolver outcomes.
package/docs/RELEASING.md CHANGED
@@ -386,8 +386,9 @@ git push origin v<version>
386
386
  Bun caches plus an empty npm user config so maintainer credentials and cached
387
387
  metadata cannot mask a public-registry outage. The verifier dispatches a real
388
388
  `pm contracts` command through both explicit-bin and package-default
389
- invocations, performs a JSON-RPC initialize handshake against the
390
- symlink-resolved `pm-mcp` bin under both npx and bunx, derives bin coverage
389
+ invocations, performs stateless JSON-RPC `server/discover` against the
390
+ symlink-resolved `pm-mcp` bin under both npx and bunx, requires canonical
391
+ `2026-07-28` metadata/result envelopes, derives bin coverage
391
392
  from `package.json`, and proves missing-bin and missing-command controls fail.
392
393
  - exact-package installed acceptance through
393
394
  `scripts/release/verify-installed-agent-session.mjs`. Separate npm and Bun
package/docs/SDK.md CHANGED
@@ -62,6 +62,13 @@ Terminal recurrence and executable recovery are tracked by
62
62
 
63
63
  Use it for extension authoring, package authoring, command/action contract discovery, and deterministic app or CI automation. Do not import private `src/core/...` modules from external integrations or packages.
64
64
 
65
+ MCP hosts can build on the public stateless protocol, MRTR, cache/schema, and
66
+ durable task primitives described in
67
+ [MCP Interaction and Task SDK](SDK_MCP_INTERACTIONS.md). Those contracts are
68
+ owned by [pm-rz9gep](../.agents/pm/features/pm-rz9gep.toon),
69
+ [pm-rzs24j](../.agents/pm/features/pm-rzs24j.toon), and
70
+ [pm-hv1x1x](../.agents/pm/features/pm-hv1x1x.toon).
71
+
65
72
  ## Install
66
73
 
67
74
  ```bash
@@ -244,6 +251,7 @@ Common authoring exports:
244
251
  the same remediation used by runtime activation.
245
252
  - `renderExtensionSurfaceMarkdown` (render a describe summary to a drift-free Markdown reference doc for a package README)
246
253
  - `checkExtensionManifestCompatibility` (author-time `pm_min_version`/`pm_max_version` check against a target pm version)
254
+ - `inspectExtensionManifestSchema` / `lintExtensionManifestSchema` (pure raw-manifest schema inspection and actionable finding boundary)
247
255
  - `preflightExtension` (one-call capstone: lint + manifest synthesis + version-compat in a single consolidated report)
248
256
  - `RESERVED_ITEM_FIELD_NAMES` (the shared runtime/authoring denylist); `lintExtensionBlueprint`, preflight, and the test harness reject blueprint item fields that shadow these metadata keys before publication
249
257
  - `EXTENSION_CAPABILITIES`
@@ -2783,8 +2791,18 @@ bound, a `pm_min_version` the target is below, or a `block`-mode `pm_max_version
2783
2791
  the target exceeds) and stays quiet on advisory `*_unchecked` / `*_exceeded_warn`
2784
2792
  warnings, which still load:
2785
2793
 
2794
+ Use `lintExtensionManifestSchema(manifest)` when only the manifest vocabulary is
2795
+ in scope. It returns stable `manifest_unknown_key` and
2796
+ `no_version_bounds_declared` findings without requiring a target pm version.
2797
+ Compatibility results retain the existing combined `findings` array, while the
2798
+ dedicated lint result gives SDK, CLI, and MCP adapters a stable schema-only
2799
+ boundary.
2800
+
2786
2801
  ```ts
2787
- import { checkExtensionManifestCompatibility } from "@unbrained/pm-cli/sdk";
2802
+ import {
2803
+ checkExtensionManifestCompatibility,
2804
+ lintExtensionManifestSchema,
2805
+ } from "@unbrained/pm-cli/sdk";
2788
2806
  import { assertExtensionManifestCompatible } from "@unbrained/pm-cli/sdk/testing";
2789
2807
 
2790
2808
  // Inspect every bound outcome against a target version…
@@ -2793,6 +2811,9 @@ const report = checkExtensionManifestCompatibility(manifest, {
2793
2811
  });
2794
2812
  // report.compatible === false, report.findings[0].code === "pm_min_version_unmet", …
2795
2813
 
2814
+ const schema = lintExtensionManifestSchema(manifest);
2815
+ // schema.ok === false, schema.findings[0].path === "compatibility", …
2816
+
2796
2817
  // …or fail the package's own suite when a bound would block the load.
2797
2818
  assertExtensionManifestCompatible(manifest, { pmVersion: "2026.6.23" });
2798
2819
  ```
@@ -152,22 +152,27 @@ invalid values.
152
152
 
153
153
  ## Cross an MCP boundary
154
154
 
155
- An embedding MCP client can add bounded `provenance` and `episode` fields to
156
- its initialize `clientInfo`. The server retains only those fields and applies
157
- them to later tool calls from that initialized client.
155
+ An embedding MCP 2026-07-28 client can add bounded `provenance` and `episode`
156
+ fields to request-local `io.modelcontextprotocol/clientInfo`. The server
157
+ retains only those fields while processing that request; no later request
158
+ inherits them.
158
159
 
159
160
  ```json
160
161
  {
161
- "clientInfo": {
162
- "name": "agent-host",
163
- "version": "1.0.0",
164
- "provenance": {
165
- "role": "implementer",
166
- "topic": "release readiness"
167
- },
168
- "episode": {
169
- "id": "release-2026-08-01",
170
- "label": "Release readiness"
162
+ "_meta": {
163
+ "io.modelcontextprotocol/protocolVersion": "2026-07-28",
164
+ "io.modelcontextprotocol/clientCapabilities": {},
165
+ "io.modelcontextprotocol/clientInfo": {
166
+ "name": "agent-host",
167
+ "version": "1.0.0",
168
+ "provenance": {
169
+ "role": "implementer",
170
+ "topic": "release readiness"
171
+ },
172
+ "episode": {
173
+ "id": "release-2026-08-01",
174
+ "label": "Release readiness"
175
+ }
171
176
  }
172
177
  }
173
178
  }