@try-works/dsh-model-as-tool 0.1.0 → 0.1.2

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 (79) hide show
  1. package/README.md +51 -0
  2. package/bin/dsh-tool-mode-mcp-stdio.mjs +80 -0
  3. package/catalog/desert-ant-models.json +77 -13
  4. package/lib/adapters/index.d.ts +19 -6
  5. package/lib/adapters/index.d.ts.map +1 -1
  6. package/lib/adapters/index.js +28 -13
  7. package/lib/adapters/tongue.d.ts +11 -3
  8. package/lib/adapters/tongue.d.ts.map +1 -1
  9. package/lib/adapters/tongue.js +12 -4
  10. package/lib/adapters/types.d.ts +11 -0
  11. package/lib/adapters/types.d.ts.map +1 -1
  12. package/lib/adapters/voz.d.ts +7 -1
  13. package/lib/adapters/voz.d.ts.map +1 -1
  14. package/lib/adapters/voz.js +16 -4
  15. package/lib/asset-acquisition.d.ts +137 -0
  16. package/lib/asset-acquisition.d.ts.map +1 -0
  17. package/lib/asset-acquisition.js +161 -0
  18. package/lib/authority.d.ts +153 -0
  19. package/lib/authority.d.ts.map +1 -0
  20. package/lib/authority.js +194 -0
  21. package/lib/bindings.d.ts +115 -0
  22. package/lib/bindings.d.ts.map +1 -0
  23. package/lib/bindings.js +239 -0
  24. package/lib/catalog.d.ts.map +1 -1
  25. package/lib/catalog.js +57 -0
  26. package/lib/contract-payload.d.ts +47 -0
  27. package/lib/contract-payload.d.ts.map +1 -0
  28. package/lib/contract-payload.js +137 -0
  29. package/lib/deployment-coordinator.d.ts +213 -0
  30. package/lib/deployment-coordinator.d.ts.map +1 -0
  31. package/lib/deployment-coordinator.js +274 -0
  32. package/lib/harness-budgets.d.ts +158 -0
  33. package/lib/harness-budgets.d.ts.map +1 -0
  34. package/lib/harness-budgets.js +152 -0
  35. package/lib/index.d.ts +41 -0
  36. package/lib/index.d.ts.map +1 -1
  37. package/lib/index.js +424 -16
  38. package/lib/licensing.d.ts +221 -0
  39. package/lib/licensing.d.ts.map +1 -0
  40. package/lib/licensing.js +188 -0
  41. package/lib/mcp/host-binding.d.ts +91 -0
  42. package/lib/mcp/host-binding.d.ts.map +1 -0
  43. package/lib/mcp/host-binding.js +133 -0
  44. package/lib/mcp/http.d.ts +130 -0
  45. package/lib/mcp/http.d.ts.map +1 -0
  46. package/lib/mcp/http.js +274 -0
  47. package/lib/mcp/protocol.d.ts +261 -0
  48. package/lib/mcp/protocol.d.ts.map +1 -0
  49. package/lib/mcp/protocol.js +387 -0
  50. package/lib/mcp/server.d.ts +115 -0
  51. package/lib/mcp/server.d.ts.map +1 -0
  52. package/lib/mcp/server.js +200 -0
  53. package/lib/mcp/stdio.d.ts +80 -0
  54. package/lib/mcp/stdio.d.ts.map +1 -0
  55. package/lib/mcp/stdio.js +176 -0
  56. package/lib/mcp/subscriptions.d.ts +135 -0
  57. package/lib/mcp/subscriptions.d.ts.map +1 -0
  58. package/lib/mcp/subscriptions.js +207 -0
  59. package/lib/provider-bridge.d.ts +69 -0
  60. package/lib/provider-bridge.d.ts.map +1 -0
  61. package/lib/provider-bridge.js +218 -0
  62. package/lib/publication.d.ts +160 -0
  63. package/lib/publication.d.ts.map +1 -0
  64. package/lib/publication.js +173 -0
  65. package/lib/receipt.d.ts +208 -0
  66. package/lib/receipt.d.ts.map +1 -0
  67. package/lib/receipt.js +150 -0
  68. package/lib/registrar.d.ts +13 -0
  69. package/lib/registrar.d.ts.map +1 -1
  70. package/lib/registrar.js +20 -3
  71. package/lib/resource-governance.d.ts +204 -0
  72. package/lib/resource-governance.d.ts.map +1 -0
  73. package/lib/resource-governance.js +213 -0
  74. package/lib/server-lifecycle.d.ts +175 -0
  75. package/lib/server-lifecycle.d.ts.map +1 -0
  76. package/lib/server-lifecycle.js +269 -0
  77. package/lib/types.d.ts +21 -0
  78. package/lib/types.d.ts.map +1 -1
  79. package/package.json +9 -2
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Licensing, attribution and permission records (LIC-01..LIC-04).
3
+ *
4
+ * Two rules here exist to stop a technical decision standing in for a legal one.
5
+ *
6
+ * - **A config boolean is not a licence grant** (LIC-03). A person records the
7
+ * permission basis, the scope it covers, and their name. Turning on a setting
8
+ * cannot produce that record, so the type has no way to express "someone ticked a
9
+ * box".
10
+ * - **Do not describe telemetry-bearing software as network-free** (LIC-04). An
11
+ * implementation that must report usage telemetry is INELIGIBLE for a strict
12
+ * no-network deployment, and the ineligibility is reported rather than resolved by
13
+ * quietly suppressing the telemetry — which would breach the licence and misdescribe
14
+ * the product at the same time.
15
+ *
16
+ * LIC-01's other half is that the layers are tracked INDEPENDENTLY: an adapter's MIT
17
+ * licence says nothing about the weights it loads, and a missing layer is a gap rather
18
+ * than a default.
19
+ *
20
+ * @module @try-works/dsh-model-as-tool/licensing
21
+ */
22
+ /** The layers whose licences are tracked separately (LIC-01). */
23
+ export type LicenseLayer =
24
+ /** The extension's own source. */
25
+ 'code'
26
+ /** The inference engine or runtime. */
27
+ | 'engine'
28
+ /** The model weights. */
29
+ | 'weights'
30
+ /** Scripts or tools that converted the weights. */
31
+ | 'conversion-artifacts'
32
+ /** A vendor SDK the extension depends on. */
33
+ | 'sdk';
34
+ /** Every layer, so a missing one is detectable rather than absent. */
35
+ export declare const LICENSE_LAYERS: readonly LicenseLayer[];
36
+ /**
37
+ * Whether redistribution of a layer is permitted.
38
+ *
39
+ * `unclear` is a first-class value, because treating an unexamined licence as
40
+ * permitted is how a package ships bytes it had no right to.
41
+ */
42
+ export type Redistribution = 'permitted' | 'not-permitted' | 'unclear';
43
+ /** One layer's licence. */
44
+ export interface LayerLicense {
45
+ readonly layer: LicenseLayer;
46
+ /** The licence name, e.g. `MIT` or `LicenseRef-DAL-Source-Available-1.0`. */
47
+ readonly name: string;
48
+ /** Where the terms live, so a reviewer can read them rather than trust a label. */
49
+ readonly url: string;
50
+ /** Whether the licence requires attribution in the product or its notices. */
51
+ readonly attributionRequired: boolean;
52
+ /** The exact notice text, when attribution is required. */
53
+ readonly attributionText?: string;
54
+ /**
55
+ * Whether the licence is OSI-approved open source.
56
+ *
57
+ * LIC-02 is explicit that Desert Ant's licence is source-available and NOT open
58
+ * source, so this is recorded per layer rather than inferred from the presence of a
59
+ * licence file.
60
+ */
61
+ readonly openSource: boolean;
62
+ /** Whether these bytes may be redistributed inside a package. */
63
+ readonly redistribution: Redistribution;
64
+ /** Obligations a deployer must meet, stated rather than implied. */
65
+ readonly obligations: readonly string[];
66
+ }
67
+ /**
68
+ * The Desert Ant Labs licence, as recorded from the vendor's own terms (LIC-02).
69
+ *
70
+ * Named as a constant because getting it wrong in one place is how a wrong belief
71
+ * spreads: this is source-available, NOT open source, and it forbids redistributing
72
+ * the models or SDKs as a standalone product.
73
+ */
74
+ export declare function desertAntLabsLicense(layer: LicenseLayer): LayerLicense;
75
+ /** A resolved licence record for one extension (LIC-01). */
76
+ export interface ResolvedLicenseRecord {
77
+ readonly extensionId: string;
78
+ /** One entry per layer. A missing layer is a GAP, not a default. */
79
+ readonly layers: readonly LayerLicense[];
80
+ /** Where the notices must appear, kept with the record rather than looked up. */
81
+ readonly notices: readonly string[];
82
+ }
83
+ /**
84
+ * Build a licence record, reporting missing layers (LIC-01).
85
+ *
86
+ * @param extensionId - the extension.
87
+ * @param layers - the declared licences.
88
+ * @returns the record and the layers that were not declared.
89
+ */
90
+ export declare function resolveLicenses(extensionId: string, layers: readonly LayerLicense[]): {
91
+ readonly record: ResolvedLicenseRecord;
92
+ readonly gaps: readonly LicenseLayer[];
93
+ };
94
+ /** The uses a permission basis can cover (LIC-03). */
95
+ export type PermissionScope = 'native' | 'external-export' | 'distribution' | 'telemetry';
96
+ /**
97
+ * How a permission was established (LIC-03).
98
+ *
99
+ * There is deliberately no `config-boolean` member: the requirement says a config
100
+ * boolean is not a licence grant, and a type that cannot express one is a stronger
101
+ * guarantee than a comment saying not to use one.
102
+ */
103
+ export type PermissionBasis =
104
+ /** The vendor answered the question in writing. */
105
+ {
106
+ readonly kind: 'vendor-clarification';
107
+ readonly reference: string;
108
+ }
109
+ /** Qualified review, e.g. counsel, decided the boundary. */
110
+ | {
111
+ readonly kind: 'qualified-review';
112
+ readonly reference: string;
113
+ }
114
+ /** The vendor's own published terms address it directly. */
115
+ | {
116
+ readonly kind: 'published-terms';
117
+ readonly url: string;
118
+ }
119
+ /** A commercial agreement covers it. */
120
+ | {
121
+ readonly kind: 'commercial-agreement';
122
+ readonly reference: string;
123
+ };
124
+ /** A human's record of one permission (LIC-03). */
125
+ export interface PermissionRecord {
126
+ readonly extensionId: string;
127
+ readonly scope: PermissionScope;
128
+ readonly basis: PermissionBasis;
129
+ /**
130
+ * The responsible human.
131
+ *
132
+ * Required: an unattributed permission record cannot be reviewed or revisited, and
133
+ * the requirement says a RESPONSIBLE HUMAN must record it.
134
+ */
135
+ readonly recordedBy: string;
136
+ readonly recordedAt: string;
137
+ /** What the permission does NOT cover, so its limits travel with it. */
138
+ readonly excludes?: readonly string[];
139
+ }
140
+ /**
141
+ * Reject a permission claim that is not a human record (LIC-03).
142
+ *
143
+ * A boolean, a string or an empty object would all be "someone said yes" without a
144
+ * person or a reference, which is what the requirement forbids.
145
+ * @param value - the purported record.
146
+ * @returns whether it is a usable record.
147
+ */
148
+ export declare function isUsablePermissionRecord(value: unknown): value is PermissionRecord;
149
+ /**
150
+ * Whether a provider may be exposed over MCP (LIC-03).
151
+ *
152
+ * An unresolved EXTERNAL-EXPORT permission blocks THAT PROVIDER's export and nothing
153
+ * else. Blocking the whole plugin would punish every other provider for one
154
+ * unresolved question, which the requirement explicitly rules out.
155
+ * @param extensionId - the provider.
156
+ * @param permissions - every recorded permission.
157
+ * @returns the decision.
158
+ */
159
+ export declare function exportDecision(extensionId: string, permissions: readonly PermissionRecord[]): {
160
+ readonly exportable: boolean;
161
+ readonly reason?: string;
162
+ };
163
+ /** An implementation's network behaviour, as DECLARED rather than assumed (LIC-04). */
164
+ export interface NetworkBehaviour {
165
+ readonly extensionId: string;
166
+ /**
167
+ * Whether the software reports usage telemetry the licence REQUIRES.
168
+ *
169
+ * When true, suppressing it to appear network-free would breach the licence, so the
170
+ * implementation is ineligible for a no-network deployment instead.
171
+ */
172
+ readonly requiredTelemetry: boolean;
173
+ /** Whether it makes any other network call. */
174
+ readonly otherNetworkUse: boolean;
175
+ /** What the telemetry carries, so a description can be accurate. */
176
+ readonly telemetryContent?: readonly string[];
177
+ }
178
+ /** The verdict for a strict no-network deployment (LIC-04). */
179
+ export interface NoNetworkVerdict {
180
+ readonly eligible: boolean;
181
+ /** Why not, when it is not. */
182
+ readonly reason?: string;
183
+ /** What a deployer should choose instead, rather than a bare refusal. */
184
+ readonly alternative?: string;
185
+ }
186
+ /**
187
+ * Decide whether an implementation is eligible for a strict no-network deployment
188
+ * (LIC-04).
189
+ *
190
+ * @param behaviour - the implementation's declared network behaviour.
191
+ * @returns the verdict, with an alternative when it is ineligible.
192
+ */
193
+ export declare function noNetworkEligibility(behaviour: NetworkBehaviour): NoNetworkVerdict;
194
+ /**
195
+ * How a deployment may DESCRIBE itself (LIC-04).
196
+ *
197
+ * The requirement forbids describing telemetry-bearing software as entirely
198
+ * network-free, so a description is derived from the declared behaviour rather than
199
+ * chosen by the deployer.
200
+ * @param behaviour - the implementation's network behaviour.
201
+ * @returns a description that is true of the implementation.
202
+ */
203
+ export declare function describeNetwork(behaviour: NetworkBehaviour): string;
204
+ /**
205
+ * Whether packaging a model grants the right to redistribute its weights (LIC-01).
206
+ *
207
+ * It does not. Packaging means an adapter plus licensed assets or ACQUISITION
208
+ * INSTRUCTIONS; technical availability does not imply export or redistribution
209
+ * permission.
210
+ * @param record - the licence record.
211
+ * @returns whether the weights may be shipped inside the package.
212
+ */
213
+ export declare function mayPackageWeights(record: ResolvedLicenseRecord): boolean;
214
+ /**
215
+ * Whether the notices required by a record are present in a shipped notice file.
216
+ * @param record - the licence record.
217
+ * @param noticeText - the notice file's contents.
218
+ * @returns the notices that are missing.
219
+ */
220
+ export declare function missingNotices(record: ResolvedLicenseRecord, noticeText: string): readonly string[];
221
+ //# sourceMappingURL=licensing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licensing.d.ts","sourceRoot":"","sources":["../src/licensing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Licensing, attribution and permission records (LIC-01..LIC-04).
3
+ *
4
+ * Two rules here exist to stop a technical decision standing in for a legal one.
5
+ *
6
+ * - **A config boolean is not a licence grant** (LIC-03). A person records the
7
+ * permission basis, the scope it covers, and their name. Turning on a setting
8
+ * cannot produce that record, so the type has no way to express "someone ticked a
9
+ * box".
10
+ * - **Do not describe telemetry-bearing software as network-free** (LIC-04). An
11
+ * implementation that must report usage telemetry is INELIGIBLE for a strict
12
+ * no-network deployment, and the ineligibility is reported rather than resolved by
13
+ * quietly suppressing the telemetry — which would breach the licence and misdescribe
14
+ * the product at the same time.
15
+ *
16
+ * LIC-01's other half is that the layers are tracked INDEPENDENTLY: an adapter's MIT
17
+ * licence says nothing about the weights it loads, and a missing layer is a gap rather
18
+ * than a default.
19
+ *
20
+ * @module @try-works/dsh-model-as-tool/licensing
21
+ */
22
+ /** Every layer, so a missing one is detectable rather than absent. */
23
+ export const LICENSE_LAYERS = [
24
+ 'code', 'engine', 'weights', 'conversion-artifacts', 'sdk',
25
+ ];
26
+ /**
27
+ * The Desert Ant Labs licence, as recorded from the vendor's own terms (LIC-02).
28
+ *
29
+ * Named as a constant because getting it wrong in one place is how a wrong belief
30
+ * spreads: this is source-available, NOT open source, and it forbids redistributing
31
+ * the models or SDKs as a standalone product.
32
+ */
33
+ export function desertAntLabsLicense(layer) {
34
+ return {
35
+ layer,
36
+ name: 'Desert Ant Labs Source-Available License 1.0',
37
+ url: 'https://license.desertant.com/1.0',
38
+ attributionRequired: true,
39
+ attributionText: 'Powered by Desert Ant Labs',
40
+ // LIC-02 says this in as many words.
41
+ openSource: false,
42
+ // No redistribution or re-hosting of the models, SDKs or a hosted service.
43
+ redistribution: 'not-permitted',
44
+ obligations: [
45
+ 'display the attribution notice with a link to Desert Ant Labs',
46
+ 'a commercial licence is required above the per-platform, per-model active-device threshold',
47
+ 'do not redistribute the model, SDK or a hosted service as a standalone product',
48
+ 'do not use outputs or logs to train a competing on-device model',
49
+ 'do not extract weights or tamper with the usage telemetry',
50
+ ],
51
+ };
52
+ }
53
+ /**
54
+ * Build a licence record, reporting missing layers (LIC-01).
55
+ *
56
+ * @param extensionId - the extension.
57
+ * @param layers - the declared licences.
58
+ * @returns the record and the layers that were not declared.
59
+ */
60
+ export function resolveLicenses(extensionId, layers) {
61
+ const declared = new Set(layers.map(layer => layer.layer));
62
+ // An undeclared layer is reported rather than assumed permissive: an adapter's MIT
63
+ // licence says nothing about the weights it loads.
64
+ const gaps = LICENSE_LAYERS.filter(layer => !declared.has(layer));
65
+ return {
66
+ record: {
67
+ extensionId,
68
+ layers,
69
+ // Collected from every layer that requires one, so a notice is never dropped by
70
+ // being attached to a layer nobody reads.
71
+ notices: layers
72
+ .filter(layer => layer.attributionRequired && layer.attributionText !== undefined)
73
+ .map(layer => layer.attributionText),
74
+ },
75
+ gaps,
76
+ };
77
+ }
78
+ /**
79
+ * Reject a permission claim that is not a human record (LIC-03).
80
+ *
81
+ * A boolean, a string or an empty object would all be "someone said yes" without a
82
+ * person or a reference, which is what the requirement forbids.
83
+ * @param value - the purported record.
84
+ * @returns whether it is a usable record.
85
+ */
86
+ export function isUsablePermissionRecord(value) {
87
+ if (typeof value !== 'object' || value === null)
88
+ return false;
89
+ const candidate = value;
90
+ return typeof candidate.extensionId === 'string'
91
+ && typeof candidate.scope === 'string'
92
+ && typeof candidate.recordedBy === 'string' && candidate.recordedBy.length > 0
93
+ && typeof candidate.recordedAt === 'string'
94
+ && typeof candidate.basis === 'object' && candidate.basis !== null;
95
+ }
96
+ /**
97
+ * Whether a provider may be exposed over MCP (LIC-03).
98
+ *
99
+ * An unresolved EXTERNAL-EXPORT permission blocks THAT PROVIDER's export and nothing
100
+ * else. Blocking the whole plugin would punish every other provider for one
101
+ * unresolved question, which the requirement explicitly rules out.
102
+ * @param extensionId - the provider.
103
+ * @param permissions - every recorded permission.
104
+ * @returns the decision.
105
+ */
106
+ export function exportDecision(extensionId, permissions) {
107
+ const relevant = permissions.find(record => record.extensionId === extensionId && record.scope === 'external-export');
108
+ if (relevant === undefined) {
109
+ return {
110
+ exportable: false,
111
+ reason: `no external-export permission is recorded for ${extensionId}; `
112
+ + 'this blocks that provider only, not the other providers',
113
+ };
114
+ }
115
+ if (!isUsablePermissionRecord(relevant)) {
116
+ return { exportable: false, reason: `the external-export record for ${extensionId} is not a usable record` };
117
+ }
118
+ return { exportable: true };
119
+ }
120
+ /**
121
+ * Decide whether an implementation is eligible for a strict no-network deployment
122
+ * (LIC-04).
123
+ *
124
+ * @param behaviour - the implementation's declared network behaviour.
125
+ * @returns the verdict, with an alternative when it is ineligible.
126
+ */
127
+ export function noNetworkEligibility(behaviour) {
128
+ if (behaviour.requiredTelemetry) {
129
+ // The honest outcome. Suppressing the telemetry would breach the licence AND
130
+ // misdescribe the software, so neither is offered.
131
+ return {
132
+ eligible: false,
133
+ reason: 'this implementation must report usage telemetry, so it cannot be described or deployed as network-free',
134
+ alternative: 'choose an implementation whose licence requires no telemetry, or run a profile that permits its telemetry',
135
+ };
136
+ }
137
+ if (behaviour.otherNetworkUse) {
138
+ return {
139
+ eligible: false,
140
+ reason: 'this implementation makes network calls unrelated to telemetry',
141
+ alternative: 'choose a local-only implementation, or run a profile that permits those destinations',
142
+ };
143
+ }
144
+ return { eligible: true };
145
+ }
146
+ /**
147
+ * How a deployment may DESCRIBE itself (LIC-04).
148
+ *
149
+ * The requirement forbids describing telemetry-bearing software as entirely
150
+ * network-free, so a description is derived from the declared behaviour rather than
151
+ * chosen by the deployer.
152
+ * @param behaviour - the implementation's network behaviour.
153
+ * @returns a description that is true of the implementation.
154
+ */
155
+ export function describeNetwork(behaviour) {
156
+ if (behaviour.requiredTelemetry) {
157
+ const content = behaviour.telemetryContent ?? [];
158
+ return 'reports usage telemetry'
159
+ + (content.length > 0 ? ` (${content.join(', ')})` : '')
160
+ + '; it is not network-free';
161
+ }
162
+ return behaviour.otherNetworkUse ? 'makes network calls' : 'runs without network access';
163
+ }
164
+ /**
165
+ * Whether packaging a model grants the right to redistribute its weights (LIC-01).
166
+ *
167
+ * It does not. Packaging means an adapter plus licensed assets or ACQUISITION
168
+ * INSTRUCTIONS; technical availability does not imply export or redistribution
169
+ * permission.
170
+ * @param record - the licence record.
171
+ * @returns whether the weights may be shipped inside the package.
172
+ */
173
+ export function mayPackageWeights(record) {
174
+ const weights = record.layers.find(layer => layer.layer === 'weights');
175
+ // `unclear` is not permission: treating an unexamined licence as permitted is how a
176
+ // package ships bytes it had no right to.
177
+ return weights?.redistribution === 'permitted';
178
+ }
179
+ /**
180
+ * Whether the notices required by a record are present in a shipped notice file.
181
+ * @param record - the licence record.
182
+ * @param noticeText - the notice file's contents.
183
+ * @returns the notices that are missing.
184
+ */
185
+ export function missingNotices(record, noticeText) {
186
+ return record.notices.filter(notice => !noticeText.includes(notice));
187
+ }
188
+ //# sourceMappingURL=licensing.js.map
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Binding the MCP surface to the real DSH tool registry (MCP-08, MCP-09, MCP-12).
3
+ *
4
+ * Two requirements shape this module, and both are about where data comes from
5
+ * rather than what it looks like:
6
+ *
7
+ * - **MCP-09**: DSH's model-facing `schemas()` projection INTENTIONALLY omits the
8
+ * output schema, so an export built from it would publish a tool with no declared
9
+ * result shape. The canonical schemas therefore come from the CONTRACTS, which is
10
+ * the only place that has them; `schemas()` is never consulted for a schema.
11
+ * - **MCP-08**: invocation goes through the host's `execute` path with a
12
+ * server-issued call identity and the caller's abort signal. Resolving a tool and
13
+ * calling it directly would bypass the grant, the receipt and the result policy —
14
+ * the three things the host path exists to apply — so this module is given an
15
+ * executor rather than a registry to reach into.
16
+ *
17
+ * §16.4 defines the payload derivation precisely: an implementation returns the
18
+ * domain payload with the reserved root `meta` OMITTED, and the payload schema is
19
+ * the final tool schema with only that property and its required entry removed.
20
+ * Everything else is preserved, because a schema that quietly dropped more would
21
+ * under-declare the result.
22
+ *
23
+ * @module @try-works/dsh-model-as-tool/mcp/host-binding
24
+ */
25
+ import type { ToolContract } from '@try-works/tool-mode-contracts';
26
+ import type { McpHost } from './server.ts';
27
+ /**
28
+ * Derive the payload schema from a contract's final output schema (§16.4).
29
+ *
30
+ * Only the reserved `meta` property and its `required` entry are removed. The rest
31
+ * of the schema — including constraints on the remaining properties — is preserved
32
+ * verbatim, because removing anything else would advertise a looser result than the
33
+ * contract actually enforces.
34
+ * @param outputSchema - the contract's output schema, including `meta`.
35
+ * @returns the payload schema.
36
+ */
37
+ export declare function derivePayloadSchema(outputSchema: Readonly<Record<string, unknown>>): Record<string, unknown>;
38
+ /** One published tool as the host knows it. */
39
+ export interface PublishedTool {
40
+ /** The tool name a caller uses. */
41
+ readonly toolName: string;
42
+ /** The contract it implements, which carries the canonical schemas. */
43
+ readonly contract: ToolContract;
44
+ /**
45
+ * Why this tool is not exportable, when it is not (MCP-12).
46
+ *
47
+ * A host tool using a non-JSON callback, a UI-only API, an unsupported attachment
48
+ * or a non-exportable policy must be REJECTED WITH A REASON rather than partly
49
+ * serialized, so the reason travels with the tool instead of being discovered by a
50
+ * caller whose call fails in a way nobody can explain.
51
+ */
52
+ readonly notExportableReason?: string;
53
+ }
54
+ /** What the binding needs from the host. */
55
+ export interface HostSurface {
56
+ /** The tools the host currently publishes. */
57
+ readonly published: readonly PublishedTool[];
58
+ /**
59
+ * Execute one tool through the host path (MCP-08).
60
+ *
61
+ * Takes a server-issued call identity and the caller's signal; the implementation
62
+ * MUST route this through the same execution path a native call uses.
63
+ */
64
+ execute(request: {
65
+ readonly name: string;
66
+ readonly arguments: Readonly<Record<string, unknown>>;
67
+ readonly signal: AbortSignal;
68
+ /** Server-issued. A caller-supplied id would let a caller forge a receipt. */
69
+ readonly callId: string;
70
+ }): Promise<{
71
+ readonly isError: boolean;
72
+ readonly value?: unknown;
73
+ readonly message?: string;
74
+ }>;
75
+ }
76
+ /**
77
+ * Build the MCP host surface over a DSH tool surface.
78
+ *
79
+ * @param options - the host surface and this server's identity.
80
+ * @returns the MCP host the dispatch layer consumes.
81
+ */
82
+ export declare function createMcpHost(options: {
83
+ readonly surface: HostSurface;
84
+ readonly serverInfo: {
85
+ readonly name: string;
86
+ readonly version: string;
87
+ };
88
+ /** Called for each tool withheld, so a reason is recorded rather than lost. */
89
+ readonly onWithheld?: (tool: PublishedTool) => void;
90
+ }): McpHost;
91
+ //# sourceMappingURL=host-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-binding.d.ts","sourceRoot":"","sources":["../../src/mcp/host-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,KAAK,EAAE,OAAO,EAA4C,MAAM,aAAa,CAAA;AAKpF;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B;;;;;;;OAOG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CACtC;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAA;IAC5C;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE;QACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACrD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;QAC5B,8EAA8E;QAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KACxB,GAAG,OAAO,CAAC;QACV,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAC,CAAA;CACH;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACxE,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAA;CACpD,GAAG,OAAO,CAqEV"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Binding the MCP surface to the real DSH tool registry (MCP-08, MCP-09, MCP-12).
3
+ *
4
+ * Two requirements shape this module, and both are about where data comes from
5
+ * rather than what it looks like:
6
+ *
7
+ * - **MCP-09**: DSH's model-facing `schemas()` projection INTENTIONALLY omits the
8
+ * output schema, so an export built from it would publish a tool with no declared
9
+ * result shape. The canonical schemas therefore come from the CONTRACTS, which is
10
+ * the only place that has them; `schemas()` is never consulted for a schema.
11
+ * - **MCP-08**: invocation goes through the host's `execute` path with a
12
+ * server-issued call identity and the caller's abort signal. Resolving a tool and
13
+ * calling it directly would bypass the grant, the receipt and the result policy —
14
+ * the three things the host path exists to apply — so this module is given an
15
+ * executor rather than a registry to reach into.
16
+ *
17
+ * §16.4 defines the payload derivation precisely: an implementation returns the
18
+ * domain payload with the reserved root `meta` OMITTED, and the payload schema is
19
+ * the final tool schema with only that property and its required entry removed.
20
+ * Everything else is preserved, because a schema that quietly dropped more would
21
+ * under-declare the result.
22
+ *
23
+ * @module @try-works/dsh-model-as-tool/mcp/host-binding
24
+ */
25
+ /** The reserved root field the host authors, never the implementation. */
26
+ const RESERVED_META = 'meta';
27
+ /**
28
+ * Derive the payload schema from a contract's final output schema (§16.4).
29
+ *
30
+ * Only the reserved `meta` property and its `required` entry are removed. The rest
31
+ * of the schema — including constraints on the remaining properties — is preserved
32
+ * verbatim, because removing anything else would advertise a looser result than the
33
+ * contract actually enforces.
34
+ * @param outputSchema - the contract's output schema, including `meta`.
35
+ * @returns the payload schema.
36
+ */
37
+ export function derivePayloadSchema(outputSchema) {
38
+ const clone = structuredClone(outputSchema);
39
+ if (typeof clone.properties === 'object' && clone.properties !== null) {
40
+ delete clone.properties[RESERVED_META];
41
+ }
42
+ if (Array.isArray(clone.required)) {
43
+ clone.required = clone.required.filter(entry => entry !== RESERVED_META);
44
+ }
45
+ return clone;
46
+ }
47
+ /**
48
+ * Build the MCP host surface over a DSH tool surface.
49
+ *
50
+ * @param options - the host surface and this server's identity.
51
+ * @returns the MCP host the dispatch layer consumes.
52
+ */
53
+ export function createMcpHost(options) {
54
+ let counter = 0;
55
+ return {
56
+ serverInfo: options.serverInfo,
57
+ listTools() {
58
+ const out = [];
59
+ for (const published of options.surface.published) {
60
+ // MCP-12: a tool that cannot be exported faithfully is withheld entirely,
61
+ // with its reason recorded. Exporting a partial tool would tell a client the
62
+ // tool exists and then fail in a way the client cannot interpret.
63
+ if (published.notExportableReason !== undefined) {
64
+ options.onWithheld?.(published);
65
+ continue;
66
+ }
67
+ out.push({
68
+ name: published.toolName,
69
+ description: published.contract.description,
70
+ // Both schemas come from the CONTRACT. `schemas()` omits output, so using
71
+ // it here would publish a tool with no declared result shape (MCP-09).
72
+ inputSchema: published.contract.inputSchema,
73
+ outputSchema: derivePayloadSchema(published.contract.outputSchema),
74
+ // Nothing in this binding imports from another MCP server, so no tool is
75
+ // a re-export (MCP-13).
76
+ importedFromMcp: false,
77
+ });
78
+ }
79
+ return out;
80
+ },
81
+ async callTool(name, args, signal) {
82
+ const definition = options.surface.published.find(tool => tool.toolName === name);
83
+ // A tool that is not EXPORTABLE must not be callable either. Looking only for
84
+ // its presence in `published` would let a client invoke by name exactly the
85
+ // tool the export deliberately withheld — defeating MCP-12 through the back
86
+ // door, since a client that guessed the name would get a partial result the
87
+ // export refused to promise.
88
+ if (definition === undefined || definition.notExportableReason !== undefined) {
89
+ return {
90
+ structured: null,
91
+ text: `unknown tool ${JSON.stringify(name)}`,
92
+ isError: true,
93
+ };
94
+ }
95
+ const outcome = await options.surface.execute({
96
+ name,
97
+ arguments: args,
98
+ signal,
99
+ // Server-issued, monotonically increasing. A caller-supplied identity would
100
+ // let a caller forge a receipt (BASE-05).
101
+ callId: `mcp_${Date.now().toString(36)}_${(++counter).toString(36)}`,
102
+ });
103
+ if (outcome.isError) {
104
+ return {
105
+ structured: null,
106
+ // Bounded by the dispatch layer when it becomes a tool-error result.
107
+ text: outcome.message ?? 'the tool failed without reporting a reason',
108
+ isError: true,
109
+ };
110
+ }
111
+ return {
112
+ // The canonical value, post-policy, exactly as the host returned it: a
113
+ // redaction here would be a content-only control, which MCP-11 says is not a
114
+ // confidentiality control at all.
115
+ structured: outcome.value ?? null,
116
+ text: renderBounded(outcome.value),
117
+ };
118
+ },
119
+ };
120
+ }
121
+ /**
122
+ * Render a bounded, model-readable representation of a canonical value.
123
+ *
124
+ * Bounded because a result is copied into a model's context, and an unbounded
125
+ * rendering of a large value would consume it silently.
126
+ * @param value - the canonical value.
127
+ * @returns the text rendering.
128
+ */
129
+ function renderBounded(value) {
130
+ const text = typeof value === 'string' ? value : JSON.stringify(value ?? null);
131
+ return text.length > 100_000 ? `${text.slice(0, 100_000)}…(truncated)` : text;
132
+ }
133
+ //# sourceMappingURL=host-binding.js.map