@integraledger/lcp-mcp-server 0.9.0 → 0.10.1

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,65 @@
1
1
  # @integraledger/lcp-mcp-server
2
2
 
3
+ ## 0.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 5154cfb: Install one copy of the protocol packages, not two.
8
+
9
+ `lcp-mcp-server` pinned its `@integraledger/lcp-*` dependencies to an exact version while `agent-guard`
10
+ — which it depends on — declares the same packages as peers at a caret range. Those two declarations
11
+ cannot be satisfied by a single copy, so installing both packages resolved the protocol line **twice**:
12
+ once hoisted to satisfy the caret, and once nested under `lcp-mcp-server` to satisfy the exact pin. The
13
+ two halves of one install then read different protocol code, with `instanceof` failing across the seam
14
+ between them.
15
+
16
+ `lcp-mcp-server` now declares those dependencies as a caret at the minor line's zero patch, matching its
17
+ sibling. A tree holding both resolves a single copy, and `npx lcp-mcp` still installs standalone.
18
+
19
+ Nothing about either package's API, behaviour or guarantees changes. Both were correct in isolation; only
20
+ a tree holding both was affected.
21
+
22
+ - Updated dependencies [5154cfb]
23
+ - Updated dependencies [ccf4bb4]
24
+ - @integraledger/agent-guard@0.10.1
25
+
26
+ ## 0.10.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 06a25ac: Read the whole advertisement, and move to protocol 0.12.0.
31
+
32
+ The peer range was `^0.10.1`, which on a `0.x` version admits only patches — so this guard declared it did
33
+ not support the line every seller now writes, and a tree holding both resolved a second copy of the protocol
34
+ packages to satisfy it. The peers are `^0.12.0` and the build pins 0.12.0 exactly.
35
+
36
+ **The terms URL is no longer read by hand.** `PlacementManifest.termsUrlField` was singular and named one
37
+ path; it is now `termsUrlFields`, plural, and a slot that rides a container the placement owns is declared on
38
+ that container. Reading that by hand here would have been a second implementation of a manifest rule, so the
39
+ locator now comes from the placement's own `extract`, which reconciles every declared slot and refuses two
40
+ that disagree. The reference walk stays this package's own: "integrity carriers only" is a BUYER rule — a
41
+ discovery link locates a standing page and attests nothing — and the placement's reader does not apply it.
42
+
43
+ **`AdvertisedTermsUrl` loses a state, and could not keep it.** `undeclared-at-answering-carrier` existed
44
+ because the singular member could not reach the carrier a §C.4 challenge actually used: the hash answered
45
+ from `accepts[].extra` while the one declared path sat empty inside `extensions`, and reporting that as "no
46
+ terms advertised" would have asserted a silence this reader could not see. With every slot declared and
47
+ reconciled there is no such carrier, so the state is unreachable rather than merely unused, and the §C.4
48
+ challenge now simply reads its URL. `declared-field-empty` becomes `declared-fields-empty` and carries every
49
+ slot it looked at.
50
+
51
+ `lcp_place_reference` takes an optional `termsUrl` — required where the protocol declares a slot and the
52
+ reference is a digest, refused where it declares none — and `lcp_extract_reference` reports the locator
53
+ beside the reference, with its two absences distinguished: a protocol with no slot is not a seller who left
54
+ one empty.
55
+
56
+ Wire identities are unchanged apart from the protocol line itself.
57
+
58
+ ### Patch Changes
59
+
60
+ - Updated dependencies [06a25ac]
61
+ - @integraledger/agent-guard@0.10.0
62
+
3
63
  ## 0.9.0
4
64
 
5
65
  **First public release** — Apache-2.0, free forever, no account and no token to install.
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":"extract-reference.d.ts","sourceRoot":"","sources":["../../src/tools/extract-reference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAS9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsB/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CAkCN"}
1
+ {"version":3,"file":"extract-reference.d.ts","sourceRoot":"","sources":["../../src/tools/extract-reference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAS9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkC/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CAuCN"}
@@ -17,6 +17,16 @@ const outputSchema = z.object({
17
17
  .describe("The LCP §8.1 carrier string recovered from the document."),
18
18
  type: z.string().describe("The §8.2 carrier type, e.g. `sha256`."),
19
19
  value: z.string().describe("The carrier value, e.g. the 0x ATR hash."),
20
+ termsUrl: z
21
+ .discriminatedUnion("kind", [
22
+ z.object({ kind: z.literal("read"), url: z.string() }),
23
+ z.object({ kind: z.literal("no-field-declared") }),
24
+ z.object({
25
+ kind: z.literal("declared-fields-empty"),
26
+ fields: z.array(z.string()),
27
+ }),
28
+ ])
29
+ .describe("Where the document says its terms live. The absences are DISTINCT and both are answers: `no-field-declared` is a fact about the PROTOCOL — it has no slot for a locator — while `declared-fields-empty` is a fact about this DOCUMENT, whose seller left every declared slot empty. Collapsing them would report a seller's silence as a protocol's."),
20
30
  placement: PLACEMENT_SUMMARY_SCHEMA,
21
31
  });
22
32
  /**
@@ -48,10 +58,15 @@ export function registerExtractReference(server, ports) {
48
58
  const outcome = adapter.extract(args.document);
49
59
  if (!("ok" in outcome))
50
60
  return refusalResult(outcome);
61
+ // `extract` answers with the whole advertisement — the reference, and what the document says about
62
+ // where its terms live. The locator's ABSENCE is typed, so the reader is told whether the protocol
63
+ // has no slot at all or the seller left a declared one empty.
64
+ const { ref, termsUrl } = outcome.value;
51
65
  const out = {
52
- reference: encodeLegalContextString(outcome.value),
53
- type: outcome.value.type,
54
- value: outcome.value.value,
66
+ reference: encodeLegalContextString(ref),
67
+ type: ref.type,
68
+ value: ref.value,
69
+ termsUrl,
55
70
  placement: manifestSummary(adapter.manifest),
56
71
  };
57
72
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"extract-reference.js","sourceRoot":"","sources":["../../src/tools/extract-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,CACP,mGAAmG,CACpG;IACH,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;SAC/B,QAAQ,CAAC,4CAA4C,CAAC;CAC1D,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,CAAC,0DAA0D,CAAC;IACvE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAClE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;IACtE,SAAS,EAAE,wBAAwB;CACpC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,KAAkB;IAElB,MAAM,CAAC,YAAY,CACjB,uBAAuB,EACvB;QACE,WAAW,EACT,+FAA+F;YAC/F,wFAAwF;YACxF,GAAG,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,gEAAgE;YAClG,8FAA8F;QAChG,WAAW;QACX,YAAY;QACZ,WAAW,EAAE,uBAAuB,CAClC,0BAA0B,EAC1B,QAAQ,CACT;KACF,EACD,CAAC,IAAI,EAAE,EAAE;QACP,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC;YAAE,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG;YACV,SAAS,EAAE,wBAAwB,CAAC,OAAO,CAAC,KAAK,CAAC;YAClD,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;YAC1B,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;SAC7C,CAAC;QACF,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aAC9D;YACD,iBAAiB,EAAE,GAAG;SACvB,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"extract-reference.js","sourceRoot":"","sources":["../../src/tools/extract-reference.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"place-reference.d.ts","sourceRoot":"","sources":["../../src/tools/place-reference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAS9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4B/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CAsCN"}
1
+ {"version":3,"file":"place-reference.d.ts","sourceRoot":"","sources":["../../src/tools/place-reference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAS9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkC/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CA8CN"}
@@ -12,6 +12,10 @@ const inputSchema = z.object({
12
12
  reference: z
13
13
  .string()
14
14
  .describe("The LCP §8.1 carrier string, `lcp:{type}:{value}` — exactly what `lcp_compute_atrhash` returns as `reference`."),
15
+ termsUrl: z
16
+ .string()
17
+ .optional()
18
+ .describe("Where the terms document the reference identifies can be fetched — `https://` only. REQUIRED where the protocol declares a slot for it and the reference is a digest: a hash no counterparty can resolve is unverifiable to anyone who does not already hold the terms, so the placement refuses one. Where the protocol declares no slot, supplying it is refused rather than silently dropped."),
15
19
  document: documentShape.describe("The host protocol's own document, as JSON. Returned unchanged with the reference added; the input is never mutated."),
16
20
  });
17
21
  const outputSchema = z.object({
@@ -48,7 +52,12 @@ export function registerPlaceReference(server, ports) {
48
52
  const ref = decodeLegalContextString(args.reference);
49
53
  if (ref === undefined)
50
54
  throw new Error(`"${args.reference}" is not a recognized LCP §8.1 carrier string — expected lcp:{type}:{value} with a registered type`);
51
- const outcome = adapter.place(ref, args.document);
55
+ // An ADVERTISEMENT: the reference, and — where the protocol has room for one — the locator. Passed
56
+ // through by omission rather than as an explicit `undefined`, because the manifest decides which of
57
+ // the two refusals an incomplete one earns.
58
+ const outcome = adapter.place(args.termsUrl === undefined
59
+ ? { ref }
60
+ : { ref, termsUrl: args.termsUrl }, args.document);
52
61
  if (!("ok" in outcome))
53
62
  return refusalResult(outcome);
54
63
  // `place` is typed `Outcome<unknown>` because a host document is whatever the host protocol says it
@@ -1 +1 @@
1
- {"version":3,"file":"place-reference.js","sourceRoot":"","sources":["../../src/tools/place-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,8FAA8F;AAC9F,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAExD,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,CACP,8HAA8H,CAC/H;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,CACP,gHAAgH,CACjH;IACH,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAC9B,qHAAqH,CACtH;CACF,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAC9B,8CAA8C,CAC/C;IACD,SAAS,EAAE,wBAAwB;CACpC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,KAAkB;IAElB,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EACT,kGAAkG;YAClG,6EAA6E;YAC7E,GAAG,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,+DAA+D;YACjG,mGAAmG;YACnG,kFAAkF;QACpF,WAAW;QACX,YAAY;QACZ,WAAW,EAAE,uBAAuB,CAAC,wBAAwB,EAAE,QAAQ,CAAC;KACzE,EACD,CAAC,IAAI,EAAE,EAAE;QACP,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,wBAAwB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,GAAG,KAAK,SAAS;YACnB,MAAM,IAAI,KAAK,CACb,IAAI,IAAI,CAAC,SAAS,oGAAoG,CACvH,CAAC;QACJ,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC;YAAE,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;QACtD,oGAAoG;QACpG,gGAAgG;QAChG,kGAAkG;QAClG,MAAM,GAAG,GAAG;YACV,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC5C,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;SAC7C,CAAC;QACF,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aAC9D;YACD,iBAAiB,EAAE,GAAG;SACvB,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"place-reference.js","sourceRoot":"","sources":["../../src/tools/place-reference.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integraledger/lcp-mcp-server",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
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.10.1",
32
- "@integraledger/lcp-binding-core": "0.10.1",
33
- "@integraledger/lcp-discovery": "0.10.1",
34
- "@integraledger/lcp-evidence": "0.10.1",
35
- "@integraledger/lcp-kernel": "0.10.1",
36
- "@integraledger/lcp-placement-ack": "0.10.1",
37
- "@integraledger/lcp-placement-ap2": "0.10.1",
38
- "@integraledger/lcp-placements": "0.10.1",
39
- "@integraledger/lcp-verify": "0.10.1",
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",
40
40
  "@modelcontextprotocol/server": "2.0.0",
41
41
  "zod": "4.4.3",
42
- "@integraledger/agent-guard": "0.9.0"
42
+ "@integraledger/agent-guard": "0.10.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@modelcontextprotocol/client": "2.0.0",
@@ -28,6 +28,18 @@ const outputSchema = z.object({
28
28
  .describe("The LCP §8.1 carrier string recovered from the document."),
29
29
  type: z.string().describe("The §8.2 carrier type, e.g. `sha256`."),
30
30
  value: z.string().describe("The carrier value, e.g. the 0x ATR hash."),
31
+ termsUrl: z
32
+ .discriminatedUnion("kind", [
33
+ z.object({ kind: z.literal("read"), url: z.string() }),
34
+ z.object({ kind: z.literal("no-field-declared") }),
35
+ z.object({
36
+ kind: z.literal("declared-fields-empty"),
37
+ fields: z.array(z.string()),
38
+ }),
39
+ ])
40
+ .describe(
41
+ "Where the document says its terms live. The absences are DISTINCT and both are answers: `no-field-declared` is a fact about the PROTOCOL — it has no slot for a locator — while `declared-fields-empty` is a fact about this DOCUMENT, whose seller left every declared slot empty. Collapsing them would report a seller's silence as a protocol's.",
42
+ ),
31
43
  placement: PLACEMENT_SUMMARY_SCHEMA,
32
44
  });
33
45
 
@@ -69,10 +81,15 @@ export function registerExtractReference(
69
81
  const adapter = resolveAdapter(args.protocol, ports);
70
82
  const outcome = adapter.extract(args.document);
71
83
  if (!("ok" in outcome)) return refusalResult(outcome);
84
+ // `extract` answers with the whole advertisement — the reference, and what the document says about
85
+ // where its terms live. The locator's ABSENCE is typed, so the reader is told whether the protocol
86
+ // has no slot at all or the seller left a declared one empty.
87
+ const { ref, termsUrl } = outcome.value;
72
88
  const out = {
73
- reference: encodeLegalContextString(outcome.value),
74
- type: outcome.value.type,
75
- value: outcome.value.value,
89
+ reference: encodeLegalContextString(ref),
90
+ type: ref.type,
91
+ value: ref.value,
92
+ termsUrl,
76
93
  placement: manifestSummary(adapter.manifest),
77
94
  };
78
95
  return {
@@ -25,6 +25,12 @@ const inputSchema = z.object({
25
25
  .describe(
26
26
  "The LCP §8.1 carrier string, `lcp:{type}:{value}` — exactly what `lcp_compute_atrhash` returns as `reference`.",
27
27
  ),
28
+ termsUrl: z
29
+ .string()
30
+ .optional()
31
+ .describe(
32
+ "Where the terms document the reference identifies can be fetched — `https://` only. REQUIRED where the protocol declares a slot for it and the reference is a digest: a hash no counterparty can resolve is unverifiable to anyone who does not already hold the terms, so the placement refuses one. Where the protocol declares no slot, supplying it is refused rather than silently dropped.",
33
+ ),
28
34
  document: documentShape.describe(
29
35
  "The host protocol's own document, as JSON. Returned unchanged with the reference added; the input is never mutated.",
30
36
  ),
@@ -76,7 +82,15 @@ export function registerPlaceReference(
76
82
  throw new Error(
77
83
  `"${args.reference}" is not a recognized LCP §8.1 carrier string — expected lcp:{type}:{value} with a registered type`,
78
84
  );
79
- const outcome = adapter.place(ref, args.document);
85
+ // An ADVERTISEMENT: the reference, and — where the protocol has room for one — the locator. Passed
86
+ // through by omission rather than as an explicit `undefined`, because the manifest decides which of
87
+ // the two refusals an incomplete one earns.
88
+ const outcome = adapter.place(
89
+ args.termsUrl === undefined
90
+ ? { ref }
91
+ : { ref, termsUrl: args.termsUrl },
92
+ args.document,
93
+ );
80
94
  if (!("ok" in outcome)) return refusalResult(outcome);
81
95
  // `place` is typed `Outcome<unknown>` because a host document is whatever the host protocol says it
82
96
  // is. Parsing rather than casting keeps the widening honest: an adapter that somehow returned a