@integraledger/lcp-mcp-server 0.10.0 → 0.11.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,74 @@
1
1
  # @integraledger/lcp-mcp-server
2
2
 
3
+ ## 0.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5159d60: The server declares the LCP capability, and the protocol line moves to 0.13.
8
+
9
+ `lcp-mcp-server` now advertises `com.integraledger/legal-context` in
10
+ `capabilities.extensions`, so an MCP host can discover that this server verifies the legal context bound
11
+ to a payment **without calling a tool**. The identifier and its settings value are both imported —
12
+ `LCP_MCP_EXTENSION_ID` from `lcp-discovery`, `LCP_SPEC_VERSION` from `lcp-kernel` — because a wire
13
+ identity spelled locally is a second home the wire seal cannot see, and a hardcoded spec version drifts
14
+ the first time the specification moves.
15
+
16
+ ⭐ **This is the one capability that must be asserted in the constructor, and it does not contradict the
17
+ rule beside it.** `tools` is left to the registrations because the SDK DERIVES it, so restating it would
18
+ duplicate a fact something else owns. Nothing derives an extension: no registration implies this server
19
+ speaks LCP, so the constructor is the only place the declaration can come from. Measured — deleting it
20
+ makes the extension vanish from what a client sees.
21
+
22
+ **Graceful degradation is total, which is what makes this safe to ship.** A client that ignores the
23
+ identifier gets a byte-identical server; there is no branch in which the extension refuses a request, and
24
+ a test asserts the tool list is unchanged. A client must not read the declaration as a claim that any
25
+ seller's terms are bound — it describes the server's capability, not a transaction.
26
+
27
+ Three assertions, each driven red against a planted defect: the declaration removed (the "consistency
28
+ fix" the docblock warns against), UCP's `com.integraledger.legal_context` substituted for MCP's
29
+ slash-form identifier, and the spec version hardcoded rather than derived.
30
+
31
+ ⛔ **Protocol repin: `0.13.0`.** Exact in `devDependencies`, `^0.13.0` in shipped `dependencies` and
32
+ `peerDependencies` — the three shapes `check:wire` enforces. The line moves for a reason rather than a
33
+ bump: `LCP_MCP_EXTENSION_ID` is new API, and it first shipped as `0.12.3`, a **patch**. That broke the
34
+ invariant `check:wire` is built on — every patch inside a line is API-equivalent — while the gate
35
+ requires the caret at the minor's zero patch and refuses a raised floor. With `0.12.2` resolved, squarely
36
+ inside `^0.12.0`, the export is `undefined` and the capability key serialises as
37
+ `{"extensions":{"undefined":{}}}`. The declaration was deliberately not shipped against that floor.
38
+ Verified afterwards that the invariant had otherwise held: of the nine runtime protocol dependencies,
39
+ eight added no exports anywhere across `0.12.x`.
40
+
41
+ ⚠️ The spec is `docs/2026-08-25-lcp-mcp-extension-specification.md`. `@modelcontextprotocol/server@2.0.0`
42
+ negotiates wire era `2025-11-25` and has no `server/discover`, so the declaration rides the `initialize`
43
+ handshake today and carries forward unchanged when the SDK ships the modern era.
44
+
45
+ ### Patch Changes
46
+
47
+ - @integraledger/agent-guard@0.11.0
48
+
49
+ ## 0.10.1
50
+
51
+ ### Patch Changes
52
+
53
+ - 5154cfb: Install one copy of the protocol packages, not two.
54
+
55
+ `lcp-mcp-server` pinned its `@integraledger/lcp-*` dependencies to an exact version while `agent-guard`
56
+ — which it depends on — declares the same packages as peers at a caret range. Those two declarations
57
+ cannot be satisfied by a single copy, so installing both packages resolved the protocol line **twice**:
58
+ once hoisted to satisfy the caret, and once nested under `lcp-mcp-server` to satisfy the exact pin. The
59
+ two halves of one install then read different protocol code, with `instanceof` failing across the seam
60
+ between them.
61
+
62
+ `lcp-mcp-server` now declares those dependencies as a caret at the minor line's zero patch, matching its
63
+ sibling. A tree holding both resolves a single copy, and `npx lcp-mcp` still installs standalone.
64
+
65
+ Nothing about either package's API, behaviour or guarantees changes. Both were correct in isolation; only
66
+ a tree holding both was affected.
67
+
68
+ - Updated dependencies [5154cfb]
69
+ - Updated dependencies [ccf4bb4]
70
+ - @integraledger/agent-guard@0.10.1
71
+
3
72
  ## 0.10.0
4
73
 
5
74
  ### Minor Changes
package/README.md CHANGED
@@ -80,15 +80,17 @@ document for your agent to send with its own keys.
80
80
 
81
81
  ## One protocol line in the tree
82
82
 
83
- Every `@integraledger/*` package pins its own dependencies **exactly**, so a published version states the
84
- protocol line it was cut against and cannot be argued out of it. This server and `agent-guard` release
85
- against the same `@integraledger/lcp-*` line, so installing this puts **one** line of the protocol packages
86
- in `node_modules`. If a mixed install ever puts two lines in one tree exact pinning makes that expected
87
- rather than pathological the seam stays safe: what this package takes from `agent-guard` is the fetcher
88
- and nothing else — `makeCachingFetcher`, `nodeDnsLookup`, and the `TermsFetcher` type — whose entire
89
- vocabulary is `fetch(url: string)` in, `{ bytes, format, fetchedAt }` out, plus a `{ address, family }` DNS
90
- answer. Not one of those names an `lcp-kernel`, `lcp-binding-core` or `lcp-discovery` type in either
91
- direction, so two lines never exchange a value.
83
+ This server declares the protocol line as a **caret at the minor's zero patch**, and `agent-guard` peers it
84
+ the same way. That is what puts **one** line of the protocol packages in `node_modules` when you install
85
+ both: the two ranges overlap, so a package manager resolves a single copy that satisfies each. An exact
86
+ runtime pin would do the opposite it cannot be satisfied by the sibling's range, so the resolver nests a
87
+ second copy underneath this package, and the two halves of one install then read different protocol code.
88
+
89
+ If a mixed install ever does put two lines in one tree, the seam stays safe: what this package takes from
90
+ `agent-guard` is the fetcher and nothing else `makeCachingFetcher`, `nodeDnsLookup`, and the
91
+ `TermsFetcher` type whose entire vocabulary is `fetch(url: string)` in, `{ bytes, format, fetchedAt }`
92
+ out, plus a `{ address, family }` DNS answer. Not one of those names an `lcp-kernel`, `lcp-binding-core` or
93
+ `lcp-discovery` type in either direction, so two lines never exchange a value.
92
94
 
93
95
  ## Checked against the live MCP specification — 2026-07-30
94
96
 
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,YACzB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,CACf,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CAShE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,YACzB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,CACf,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CA+BhE"}
package/dist/server.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { LCP_MCP_EXTENSION_ID } from "@integraledger/lcp-discovery";
2
+ import { LCP_SPEC_VERSION } from "@integraledger/lcp-kernel";
1
3
  import { McpServer } from "@modelcontextprotocol/server";
2
4
  import { registerComputeAtrHash } from "./tools/compute-atrhash.js";
3
5
  import { registerExtractReference } from "./tools/extract-reference.js";
@@ -55,7 +57,26 @@ export const LCP_TOOL_NAMES = [
55
57
  * the boundary above. When there is a resource to serve that is not one of those, it is declared then.
56
58
  */
57
59
  export function createLcpMcpServer(ports) {
58
- const server = new McpServer({ name: SERVER_NAME, version: serverVersion() });
60
+ const server = new McpServer({ name: SERVER_NAME, version: serverVersion() }, {
61
+ // THE ONE CAPABILITY THAT MUST BE ASSERTED, AND IT DOES NOT CONTRADICT THE PARAGRAPH ABOVE.
62
+ //
63
+ // `tools` is left to the registrations because the SDK DERIVES it — restating it in the constructor
64
+ // is a second statement of a fact something else already owns. An extension has no such deriver:
65
+ // nothing about registering a tool implies this server speaks LCP, so the constructor is the only
66
+ // place the declaration can come from, and asserting it here states a fact rather than duplicating
67
+ // one. Do not "consistency-fix" this by deleting it; measured, removing it makes the extension
68
+ // vanish from what a client sees, which is precisely what the sibling test asserts.
69
+ //
70
+ // BOTH VALUES ARE IMPORTED, NEITHER IS SPELLED HERE. The identifier is a wire identity a
71
+ // counterparty must recognise, and `check:wire` seals it by importing `lcp-discovery`; a local copy
72
+ // would be a second home the gate cannot see. `LCP_SPEC_VERSION` is the kernel's own answer to which
73
+ // revision this stack implements, so a literal here would drift the first time the spec moved.
74
+ capabilities: {
75
+ extensions: {
76
+ [LCP_MCP_EXTENSION_ID]: { specVersion: LCP_SPEC_VERSION },
77
+ },
78
+ },
79
+ });
59
80
  registerComputeAtrHash(server, ports);
60
81
  registerGenerateLegalContext(server, ports);
61
82
  registerVerifyBeforePay(server, ports);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AAErC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,qBAAqB;IACrB,4BAA4B;IAC5B,uBAAuB;IACvB,0BAA0B;IAC1B,qBAAqB;IACrB,uBAAuB;CACf,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB;IACnD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9E,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,4BAA4B,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5C,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,wBAAwB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AAErC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,qBAAqB;IACrB,4BAA4B;IAC5B,uBAAuB;IACvB,0BAA0B;IAC1B,qBAAqB;IACrB,uBAAuB;CACf,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB;IACnD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAC/C;QACE,4FAA4F;QAC5F,EAAE;QACF,oGAAoG;QACpG,iGAAiG;QACjG,kGAAkG;QAClG,mGAAmG;QACnG,+FAA+F;QAC/F,oFAAoF;QACpF,EAAE;QACF,yFAAyF;QACzF,oGAAoG;QACpG,qGAAqG;QACrG,+FAA+F;QAC/F,YAAY,EAAE;YACZ,UAAU,EAAE;gBACV,CAAC,oBAAoB,CAAC,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE;aAC1D;SACF;KACF,CACF,CAAC;IACF,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,4BAA4B,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5C,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,wBAAwB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integraledger/lcp-mcp-server",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -28,18 +28,18 @@
28
28
  "directory": "packages/lcp-mcp-server"
29
29
  },
30
30
  "dependencies": {
31
- "@integraledger/lcp-authority": "0.12.0",
32
- "@integraledger/lcp-binding-core": "0.12.0",
33
- "@integraledger/lcp-discovery": "0.12.0",
34
- "@integraledger/lcp-evidence": "0.12.0",
35
- "@integraledger/lcp-kernel": "0.12.0",
36
- "@integraledger/lcp-placement-ack": "0.12.0",
37
- "@integraledger/lcp-placement-ap2": "0.12.0",
38
- "@integraledger/lcp-placements": "0.12.0",
39
- "@integraledger/lcp-verify": "0.12.0",
31
+ "@integraledger/lcp-authority": "^0.13.0",
32
+ "@integraledger/lcp-binding-core": "^0.13.0",
33
+ "@integraledger/lcp-discovery": "^0.13.0",
34
+ "@integraledger/lcp-evidence": "^0.13.0",
35
+ "@integraledger/lcp-kernel": "^0.13.0",
36
+ "@integraledger/lcp-placement-ack": "^0.13.0",
37
+ "@integraledger/lcp-placement-ap2": "^0.13.0",
38
+ "@integraledger/lcp-placements": "^0.13.0",
39
+ "@integraledger/lcp-verify": "^0.13.0",
40
40
  "@modelcontextprotocol/server": "2.0.0",
41
41
  "zod": "4.4.3",
42
- "@integraledger/agent-guard": "0.10.0"
42
+ "@integraledger/agent-guard": "0.11.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@modelcontextprotocol/client": "2.0.0",
package/src/server.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { LCP_MCP_EXTENSION_ID } from "@integraledger/lcp-discovery";
2
+ import { LCP_SPEC_VERSION } from "@integraledger/lcp-kernel";
1
3
  import { McpServer } from "@modelcontextprotocol/server";
2
4
  import type { LcpMcpPorts } from "./ports.js";
3
5
  import { registerComputeAtrHash } from "./tools/compute-atrhash.js";
@@ -59,7 +61,29 @@ export const LCP_TOOL_NAMES = [
59
61
  * the boundary above. When there is a resource to serve that is not one of those, it is declared then.
60
62
  */
61
63
  export function createLcpMcpServer(ports: LcpMcpPorts): McpServer {
62
- const server = new McpServer({ name: SERVER_NAME, version: serverVersion() });
64
+ const server = new McpServer(
65
+ { name: SERVER_NAME, version: serverVersion() },
66
+ {
67
+ // THE ONE CAPABILITY THAT MUST BE ASSERTED, AND IT DOES NOT CONTRADICT THE PARAGRAPH ABOVE.
68
+ //
69
+ // `tools` is left to the registrations because the SDK DERIVES it — restating it in the constructor
70
+ // is a second statement of a fact something else already owns. An extension has no such deriver:
71
+ // nothing about registering a tool implies this server speaks LCP, so the constructor is the only
72
+ // place the declaration can come from, and asserting it here states a fact rather than duplicating
73
+ // one. Do not "consistency-fix" this by deleting it; measured, removing it makes the extension
74
+ // vanish from what a client sees, which is precisely what the sibling test asserts.
75
+ //
76
+ // BOTH VALUES ARE IMPORTED, NEITHER IS SPELLED HERE. The identifier is a wire identity a
77
+ // counterparty must recognise, and `check:wire` seals it by importing `lcp-discovery`; a local copy
78
+ // would be a second home the gate cannot see. `LCP_SPEC_VERSION` is the kernel's own answer to which
79
+ // revision this stack implements, so a literal here would drift the first time the spec moved.
80
+ capabilities: {
81
+ extensions: {
82
+ [LCP_MCP_EXTENSION_ID]: { specVersion: LCP_SPEC_VERSION },
83
+ },
84
+ },
85
+ },
86
+ );
63
87
  registerComputeAtrHash(server, ports);
64
88
  registerGenerateLegalContext(server, ports);
65
89
  registerVerifyBeforePay(server, ports);