@yaklabs-ai/plugin-sdk 0.54.2 → 0.55.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/README.md CHANGED
@@ -13,7 +13,7 @@ it under the name your plugin code actually imports:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.54.2"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.55.0"
17
17
  }
18
18
  }
19
19
  ```
@@ -62,7 +62,7 @@ Every tool the entrypoint registers is declared in the manifest too:
62
62
  "description": "Greets people by name.",
63
63
  "version": "0.1.0",
64
64
  "namespace": "widgets",
65
- "compatibility": { "sdk": "^0.54.2" },
65
+ "compatibility": { "sdk": "^0.55.0" },
66
66
  "targets": {
67
67
  "kay": {
68
68
  "agent": {
@@ -153,7 +153,7 @@ naming both versions, instead of loading it and finding no `activate`.
153
153
  | `@bonsai/plugin-sdk/system-one` | The types and error class for `api.systemOne` / `app.systemOne`, from 0.13.8 |
154
154
  | `@bonsai/plugin-sdk/zod` | `z` (the host's in the daemon), on an entry with no other import, from 0.13.9 |
155
155
 
156
- A plugin that imports these subpaths declares the current supported SDK range (`^0.54.2`).
156
+ A plugin that imports these subpaths declares the current supported SDK range (`^0.55.0`).
157
157
  The rows record when each subpath appeared, not retained runtime compatibility. `vendored-mcp` builds the plugin's URI module (its link cards and help); hosting the
158
158
  vendor's MCP server itself is a separate host decision: Bonsai hosts it once a person approves
159
159
  the plugin's `mcp.host-server` grant for that server's name and URL. A server that needs an OAuth
@@ -161,7 +161,7 @@ sign-in names one of the plugin's auth services in `authService`; that service m
161
161
  one `delegated` scheme, which Bonsai uses to sign the person in to the server. Bonsai declares that
162
162
  scheme at runtime; the plugin's code must not declare it again. From 0.16.2 a plugin's code can also
163
163
  call the server's tools through `api.vendoredMcp.port(<server>)`, typed by this subpath's
164
- `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.54.2`).
164
+ `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.55.0`).
165
165
 
166
166
  From 0.13.10 the manifest schema carries two facts Bonsai reads for its own plugins only; another
167
167
  plugin's are ignored, with a load diagnostic. An `external-cli` auth scheme's `cli` says how Bonsai
@@ -243,7 +243,7 @@ Provider schemas remain authoritative; declaring a dependency grants no authorit
243
243
  through `app.uri`, parse returned Markdown in the consuming plugin, and retain the read's
244
244
  revision (or `contentDigest` from `/uri`) for edits. The old `memory.read` and `memory.write`
245
245
  grants do not authorize the replacement scheme-and-verb calls. Contracts before 0.49.0 are
246
- refused; migrate and declare `^0.54.2`. The current host also serves the 0.49.0 resource contract.
246
+ refused; migrate and declare `^0.55.0`. The current host also serves the 0.49.0 resource contract.
247
247
 
248
248
  ## What this package is, and is not, at runtime
249
249
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.54.2",
4
+ "version": "0.55.0",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -2673,8 +2673,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2673
2673
  * optional `attachments`: each file's name, media type, size and the address its bytes are read
2674
2674
  * from, never the bytes. Gmail lists a mail's attachments there, so Flows can file them. Additive:
2675
2675
  * a plugin that publishes attachments declares ^0.54.2.
2676
+ *
2677
+ * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
2678
+ * Existing agent and background MCP call shapes remain supported.
2676
2679
  */
2677
- declare const KAY_PLUGIN_SDK_VERSION: "0.54.2";
2680
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
2678
2681
 
2679
2682
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2680
2683
 
@@ -3132,13 +3135,8 @@ declare interface KayAgentVendoredMcp {
3132
3135
  * The port to `server`, a name this plugin declares in its `kay.app` target's
3133
3136
  * `contributes.mcpServers`. Throws when the plugin declares no server of that name. A declared
3134
3137
  * server that Bonsai does not host for this plugin still returns a port; each call then answers
3135
- * `unknown-server`. Its message names the plugin that holds the name, or else lists the possible
3136
- * reasons (no approved `mcp.host-server` grant, a sign-in the server cannot use, or a name that
3137
- * a plugin Bonsai ships or another installed plugin also claims) and points at the plugin's load
3138
- * diagnostic.
3139
- *
3140
- * A port reaches this plugin's own server only. To use another plugin's data, declare that
3141
- * plugin in the manifest's `dependencies.plugins`; a later SDK surface reaches it.
3138
+ * `unknown-server`. Each invocation uses the resource caller's exact `kay.agent` `uri.call`
3139
+ * grant for `mcp` / `write`; MCP checks the host-stamped caller against server ownership.
3142
3140
  */
3143
3141
  port<TTool extends string = string>(server: string): VendoredMcpPort<TTool>;
3144
3142
  }
@@ -10639,7 +10637,7 @@ declare interface Usage {
10639
10637
  /**
10640
10638
  * ---
10641
10639
  * responsibility: The one interface through which a vendored-MCP plugin's code calls a tool on its
10642
- * own vendored MCP server, so every read-through plugin and the daemon that implements the port
10640
+ * own vendored MCP server, so every read-through plugin and the SDK that implements the port
10643
10641
  * agree on the same shape by construction.
10644
10642
  * owns:
10645
10643
  * - {@link VendoredMcpPort} - what a plugin's URI module and tools call.
@@ -10647,8 +10645,8 @@ declare interface Usage {
10647
10645
  * must surface to the agent rather than swallow.
10648
10646
  * does_not_own:
10649
10647
  * - The implementation. A plugin never dials MCP itself: it takes the port from
10650
- * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the daemon binds to the
10651
- * plugin's own hosted server over its MCP host. Plugin source stays host-free, and a plugin
10648
+ * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the SDK binds through
10649
+ * resource calls to the plugin's own hosted server. Plugin source stays host-free, and a plugin
10652
10650
  * under test substitutes a fake port.
10653
10651
  * - Which tool names exist. `TTool` is the plugin's own union of the vendor tools it calls; the
10654
10652
  * port is generic so a typo in a tool name fails typecheck inside the plugin.
@@ -10684,8 +10682,8 @@ declare type VendoredMcpOutcome =
10684
10682
 
10685
10683
  /**
10686
10684
  * One vendored MCP server, as the plugin that declares it calls it. `invoke` calls any tool the
10687
- * server has, whether it reads or writes. The port checks no permission of its own: a call is as
10688
- * permitted as the plugin tool or URI verb that makes it.
10685
+ * server has, whether it reads or writes. The resource caller checks the target's exact
10686
+ * `uri.call` grant, and MCP checks the host-stamped caller against server ownership.
10689
10687
  */
10690
10688
  declare interface VendoredMcpPort<TTool extends string = string> {
10691
10689
  invoke(input: {
@@ -2727,8 +2727,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2727
2727
  * optional `attachments`: each file's name, media type, size and the address its bytes are read
2728
2728
  * from, never the bytes. Gmail lists a mail's attachments there, so Flows can file them. Additive:
2729
2729
  * a plugin that publishes attachments declares ^0.54.2.
2730
+ *
2731
+ * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
2732
+ * Existing agent and background MCP call shapes remain supported.
2730
2733
  */
2731
- declare const KAY_PLUGIN_SDK_VERSION: "0.54.2";
2734
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
2732
2735
 
2733
2736
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2734
2737
 
@@ -3183,13 +3186,8 @@ declare interface KayAgentVendoredMcp {
3183
3186
  * The port to `server`, a name this plugin declares in its `kay.app` target's
3184
3187
  * `contributes.mcpServers`. Throws when the plugin declares no server of that name. A declared
3185
3188
  * server that Bonsai does not host for this plugin still returns a port; each call then answers
3186
- * `unknown-server`. Its message names the plugin that holds the name, or else lists the possible
3187
- * reasons (no approved `mcp.host-server` grant, a sign-in the server cannot use, or a name that
3188
- * a plugin Bonsai ships or another installed plugin also claims) and points at the plugin's load
3189
- * diagnostic.
3190
- *
3191
- * A port reaches this plugin's own server only. To use another plugin's data, declare that
3192
- * plugin in the manifest's `dependencies.plugins`; a later SDK surface reaches it.
3189
+ * `unknown-server`. Each invocation uses the resource caller's exact `kay.agent` `uri.call`
3190
+ * grant for `mcp` / `write`; MCP checks the host-stamped caller against server ownership.
3193
3191
  */
3194
3192
  port<TTool extends string = string>(server: string): VendoredMcpPort<TTool>;
3195
3193
  }
@@ -12044,7 +12042,7 @@ declare interface Usage {
12044
12042
  /**
12045
12043
  * ---
12046
12044
  * responsibility: The one interface through which a vendored-MCP plugin's code calls a tool on its
12047
- * own vendored MCP server, so every read-through plugin and the daemon that implements the port
12045
+ * own vendored MCP server, so every read-through plugin and the SDK that implements the port
12048
12046
  * agree on the same shape by construction.
12049
12047
  * owns:
12050
12048
  * - {@link VendoredMcpPort} - what a plugin's URI module and tools call.
@@ -12052,8 +12050,8 @@ declare interface Usage {
12052
12050
  * must surface to the agent rather than swallow.
12053
12051
  * does_not_own:
12054
12052
  * - The implementation. A plugin never dials MCP itself: it takes the port from
12055
- * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the daemon binds to the
12056
- * plugin's own hosted server over its MCP host. Plugin source stays host-free, and a plugin
12053
+ * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the SDK binds through
12054
+ * resource calls to the plugin's own hosted server. Plugin source stays host-free, and a plugin
12057
12055
  * under test substitutes a fake port.
12058
12056
  * - Which tool names exist. `TTool` is the plugin's own union of the vendor tools it calls; the
12059
12057
  * port is generic so a typo in a tool name fails typecheck inside the plugin.
@@ -12089,8 +12087,8 @@ declare type VendoredMcpOutcome =
12089
12087
 
12090
12088
  /**
12091
12089
  * One vendored MCP server, as the plugin that declares it calls it. `invoke` calls any tool the
12092
- * server has, whether it reads or writes. The port checks no permission of its own: a call is as
12093
- * permitted as the plugin tool or URI verb that makes it.
12090
+ * server has, whether it reads or writes. The resource caller checks the target's exact
12091
+ * `uri.call` grant, and MCP checks the host-stamped caller against server ownership.
12094
12092
  */
12095
12093
  declare interface VendoredMcpPort<TTool extends string = string> {
12096
12094
  invoke(input: {
@@ -3081,8 +3081,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
3081
3081
  * optional `attachments`: each file's name, media type, size and the address its bytes are read
3082
3082
  * from, never the bytes. Gmail lists a mail's attachments there, so Flows can file them. Additive:
3083
3083
  * a plugin that publishes attachments declares ^0.54.2.
3084
+ *
3085
+ * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
3086
+ * Existing agent and background MCP call shapes remain supported.
3084
3087
  */
3085
- declare const KAY_PLUGIN_SDK_VERSION: "0.54.2";
3088
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
3086
3089
 
3087
3090
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
3088
3091
 
@@ -3580,13 +3583,8 @@ export declare interface KayAgentVendoredMcp {
3580
3583
  * The port to `server`, a name this plugin declares in its `kay.app` target's
3581
3584
  * `contributes.mcpServers`. Throws when the plugin declares no server of that name. A declared
3582
3585
  * server that Bonsai does not host for this plugin still returns a port; each call then answers
3583
- * `unknown-server`. Its message names the plugin that holds the name, or else lists the possible
3584
- * reasons (no approved `mcp.host-server` grant, a sign-in the server cannot use, or a name that
3585
- * a plugin Bonsai ships or another installed plugin also claims) and points at the plugin's load
3586
- * diagnostic.
3587
- *
3588
- * A port reaches this plugin's own server only. To use another plugin's data, declare that
3589
- * plugin in the manifest's `dependencies.plugins`; a later SDK surface reaches it.
3586
+ * `unknown-server`. Each invocation uses the resource caller's exact `kay.agent` `uri.call`
3587
+ * grant for `mcp` / `write`; MCP checks the host-stamped caller against server ownership.
3590
3588
  */
3591
3589
  port<TTool extends string = string>(server: string): VendoredMcpPort<TTool>;
3592
3590
  }
@@ -11852,6 +11850,7 @@ export declare class UriProviderError extends UriError {
11852
11850
  readonly uri: string;
11853
11851
  readonly status?: number;
11854
11852
  readonly providerCode?: string;
11853
+ readonly serviceId?: string;
11855
11854
  readonly retryable?: boolean;
11856
11855
  /** Provider-directed delay before retrying, in milliseconds. */
11857
11856
  readonly retryAfterMs?: number;
@@ -11869,6 +11868,8 @@ export declare interface UriProviderErrorOptions {
11869
11868
  readonly message: string;
11870
11869
  readonly status?: number;
11871
11870
  readonly providerCode?: string;
11871
+ /** Service to reconnect when the provider requires sign-in. */
11872
+ readonly serviceId?: string;
11872
11873
  readonly retryable?: boolean;
11873
11874
  /** Provider-directed delay before retrying, in milliseconds. */
11874
11875
  readonly retryAfterMs?: number;
@@ -12340,7 +12341,7 @@ declare interface Usage {
12340
12341
  /**
12341
12342
  * ---
12342
12343
  * responsibility: The one interface through which a vendored-MCP plugin's code calls a tool on its
12343
- * own vendored MCP server, so every read-through plugin and the daemon that implements the port
12344
+ * own vendored MCP server, so every read-through plugin and the SDK that implements the port
12344
12345
  * agree on the same shape by construction.
12345
12346
  * owns:
12346
12347
  * - {@link VendoredMcpPort} - what a plugin's URI module and tools call.
@@ -12348,8 +12349,8 @@ declare interface Usage {
12348
12349
  * must surface to the agent rather than swallow.
12349
12350
  * does_not_own:
12350
12351
  * - The implementation. A plugin never dials MCP itself: it takes the port from
12351
- * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the daemon binds to the
12352
- * plugin's own hosted server over its MCP host. Plugin source stays host-free, and a plugin
12352
+ * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the SDK binds through
12353
+ * resource calls to the plugin's own hosted server. Plugin source stays host-free, and a plugin
12353
12354
  * under test substitutes a fake port.
12354
12355
  * - Which tool names exist. `TTool` is the plugin's own union of the vendor tools it calls; the
12355
12356
  * port is generic so a typo in a tool name fails typecheck inside the plugin.
@@ -12385,8 +12386,8 @@ declare type VendoredMcpOutcome =
12385
12386
 
12386
12387
  /**
12387
12388
  * One vendored MCP server, as the plugin that declares it calls it. `invoke` calls any tool the
12388
- * server has, whether it reads or writes. The port checks no permission of its own: a call is as
12389
- * permitted as the plugin tool or URI verb that makes it.
12389
+ * server has, whether it reads or writes. The resource caller checks the target's exact
12390
+ * `uri.call` grant, and MCP checks the host-stamped caller against server ownership.
12390
12391
  */
12391
12392
  declare interface VendoredMcpPort<TTool extends string = string> {
12392
12393
  invoke(input: {
package/dist/kay-agent.js CHANGED
@@ -422,6 +422,7 @@ var UriProviderError = class extends UriError {
422
422
  uri;
423
423
  status;
424
424
  providerCode;
425
+ serviceId;
425
426
  retryable;
426
427
  /** Provider-directed delay before retrying, in milliseconds. */
427
428
  retryAfterMs;
@@ -439,6 +440,8 @@ var UriProviderError = class extends UriError {
439
440
  this.status = options.status;
440
441
  if (options.providerCode !== void 0)
441
442
  this.providerCode = options.providerCode;
443
+ if (options.serviceId !== void 0)
444
+ this.serviceId = options.serviceId;
442
445
  if (options.retryable !== void 0)
443
446
  this.retryable = options.retryable;
444
447
  if (options.retryAfterMs !== void 0) {
package/dist/kay-app.d.ts CHANGED
@@ -4309,8 +4309,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
4309
4309
  * optional `attachments`: each file's name, media type, size and the address its bytes are read
4310
4310
  * from, never the bytes. Gmail lists a mail's attachments there, so Flows can file them. Additive:
4311
4311
  * a plugin that publishes attachments declares ^0.54.2.
4312
+ *
4313
+ * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
4314
+ * Existing agent and background MCP call shapes remain supported.
4312
4315
  */
4313
- declare const KAY_PLUGIN_SDK_VERSION: "0.54.2";
4316
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
4314
4317
 
4315
4318
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
4316
4319
 
@@ -18270,6 +18273,7 @@ export declare class UriProviderError extends UriError {
18270
18273
  readonly uri: string;
18271
18274
  readonly status?: number;
18272
18275
  readonly providerCode?: string;
18276
+ readonly serviceId?: string;
18273
18277
  readonly retryable?: boolean;
18274
18278
  /** Provider-directed delay before retrying, in milliseconds. */
18275
18279
  readonly retryAfterMs?: number;
@@ -18287,6 +18291,8 @@ export declare interface UriProviderErrorOptions {
18287
18291
  readonly message: string;
18288
18292
  readonly status?: number;
18289
18293
  readonly providerCode?: string;
18294
+ /** Service to reconnect when the provider requires sign-in. */
18295
+ readonly serviceId?: string;
18290
18296
  readonly retryable?: boolean;
18291
18297
  /** Provider-directed delay before retrying, in milliseconds. */
18292
18298
  readonly retryAfterMs?: number;
@@ -18799,7 +18805,7 @@ declare type UserShellCommandMessage = CustomMessage<UserShellCommandDetails> &
18799
18805
  /**
18800
18806
  * ---
18801
18807
  * responsibility: The one interface through which a vendored-MCP plugin's code calls a tool on its
18802
- * own vendored MCP server, so every read-through plugin and the daemon that implements the port
18808
+ * own vendored MCP server, so every read-through plugin and the SDK that implements the port
18803
18809
  * agree on the same shape by construction.
18804
18810
  * owns:
18805
18811
  * - {@link VendoredMcpPort} - what a plugin's URI module and tools call.
@@ -18807,8 +18813,8 @@ declare type UserShellCommandMessage = CustomMessage<UserShellCommandDetails> &
18807
18813
  * must surface to the agent rather than swallow.
18808
18814
  * does_not_own:
18809
18815
  * - The implementation. A plugin never dials MCP itself: it takes the port from
18810
- * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the daemon binds to the
18811
- * plugin's own hosted server over its MCP host. Plugin source stays host-free, and a plugin
18816
+ * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the SDK binds through
18817
+ * resource calls to the plugin's own hosted server. Plugin source stays host-free, and a plugin
18812
18818
  * under test substitutes a fake port.
18813
18819
  * - Which tool names exist. `TTool` is the plugin's own union of the vendor tools it calls; the
18814
18820
  * port is generic so a typo in a tool name fails typecheck inside the plugin.
package/dist/kay-app.js CHANGED
@@ -55,6 +55,7 @@ var UriProviderError = class extends UriError {
55
55
  uri;
56
56
  status;
57
57
  providerCode;
58
+ serviceId;
58
59
  retryable;
59
60
  /** Provider-directed delay before retrying, in milliseconds. */
60
61
  retryAfterMs;
@@ -72,6 +73,8 @@ var UriProviderError = class extends UriError {
72
73
  this.status = options.status;
73
74
  if (options.providerCode !== void 0)
74
75
  this.providerCode = options.providerCode;
76
+ if (options.serviceId !== void 0)
77
+ this.serviceId = options.serviceId;
75
78
  if (options.retryable !== void 0)
76
79
  this.retryable = options.retryable;
77
80
  if (options.retryAfterMs !== void 0) {
@@ -1,3 +1,9 @@
1
+ export declare function createKayAgentVendoredMcp(pluginId: string, servers: readonly string[], uri: PluginUriCaller): KayAgentVendoredMcp;
2
+
3
+ export declare function createKayAppMcp(pluginId: string, servers: readonly string[], uri: PluginUriCaller): KayAppMcp;
4
+
5
+ export declare function createVendoredMcpPort(server: string, uri: PluginUriCaller): VendoredMcpPort;
6
+
1
7
  /**
2
8
  * The URI module for one vendored-MCP integration plugin.
3
9
  *
@@ -44,6 +50,35 @@ declare type JsonValue = JsonPrimitive | {
44
50
  readonly [key: string]: JsonValue;
45
51
  } | readonly JsonValue[];
46
52
 
53
+ /**
54
+ * Calls tools on the plugin's own vendored MCP servers. See {@link KayAgentPluginApi.vendoredMcp}.
55
+ */
56
+ declare interface KayAgentVendoredMcp {
57
+ /**
58
+ * The port to `server`, a name this plugin declares in its `kay.app` target's
59
+ * `contributes.mcpServers`. Throws when the plugin declares no server of that name. A declared
60
+ * server that Bonsai does not host for this plugin still returns a port; each call then answers
61
+ * `unknown-server`. Each invocation uses the resource caller's exact `kay.agent` `uri.call`
62
+ * grant for `mcp` / `write`; MCP checks the host-stamped caller against server ownership.
63
+ */
64
+ port<TTool extends string = string>(server: string): VendoredMcpPort<TTool>;
65
+ }
66
+
67
+ /** Calls tools on this plugin's manifest-declared MCP servers through Bonsai's managed connection. */
68
+ declare interface KayAppMcp {
69
+ /**
70
+ * Uses the current app-wide server set, without a session or working directory.
71
+ * Refuses undeclared or no-longer-hosted servers. Sign-in and tool failures return typed outcomes;
72
+ * credentials remain with the host. Like the agent-side vendored MCP API, calls can read or write
73
+ * and do not use the agent's per-tool approval path.
74
+ */
75
+ callTool(input: {
76
+ readonly server: string;
77
+ readonly tool: string;
78
+ readonly args: Readonly<Record<string, unknown>>;
79
+ }): Promise<VendoredMcpOutcome>;
80
+ }
81
+
47
82
  declare interface LineRange {
48
83
  readonly start: number;
49
84
  readonly end: number;
@@ -127,6 +162,38 @@ declare interface ObservationMaterial {
127
162
  readonly retainForMs?: number;
128
163
  }
129
164
 
165
+ /**
166
+ * Sessionless resource calls. Each call checks the calling target's exact scheme and verb grant.
167
+ * Results retain provider bytes, metadata and revisions; provider failures retain their URI tags.
168
+ * A cancellation or lost response does not prove a mutation was not applied.
169
+ */
170
+ declare interface PluginUriCaller {
171
+ read(input: string, options?: PluginUriReadOptions): Promise<RawResource>;
172
+ list(input: string, params?: UriListParams, options?: PluginUriCallOptions): Promise<UriListResult>;
173
+ search(input: string, params: UriSearchParams, options?: PluginUriCallOptions): Promise<UriSearchResult>;
174
+ write(input: string, content?: UriPayload | Uint8Array, options?: PluginUriWriteOptions): Promise<UriMutationResult | void>;
175
+ edit(input: string, payload: UriPayload, options?: PluginUriMutationOptions): Promise<UriMutationResult>;
176
+ delete(input: string, options?: PluginUriMutationOptions): Promise<UriMutationResult>;
177
+ }
178
+
179
+ declare interface PluginUriCallOptions {
180
+ readonly cwd?: string;
181
+ readonly signal?: AbortSignal;
182
+ }
183
+
184
+ declare interface PluginUriMutationOptions extends PluginUriCallOptions {
185
+ readonly expectedRevision?: string;
186
+ }
187
+
188
+ declare interface PluginUriReadOptions extends PluginUriCallOptions {
189
+ readonly knownRevision?: string;
190
+ }
191
+
192
+ declare interface PluginUriWriteOptions extends PluginUriMutationOptions {
193
+ readonly sources?: readonly UriWriteSource[];
194
+ readonly writeSource?: UriSourceDescriptor;
195
+ }
196
+
130
197
  declare interface RawResource {
131
198
  readonly uri: string;
132
199
  readonly content: string | Uint8Array;
@@ -1246,7 +1313,7 @@ declare type VendoredMcpFactClaim = {
1246
1313
  /**
1247
1314
  * ---
1248
1315
  * responsibility: The one interface through which a vendored-MCP plugin's code calls a tool on its
1249
- * own vendored MCP server, so every read-through plugin and the daemon that implements the port
1316
+ * own vendored MCP server, so every read-through plugin and the SDK that implements the port
1250
1317
  * agree on the same shape by construction.
1251
1318
  * owns:
1252
1319
  * - {@link VendoredMcpPort} - what a plugin's URI module and tools call.
@@ -1254,8 +1321,8 @@ declare type VendoredMcpFactClaim = {
1254
1321
  * must surface to the agent rather than swallow.
1255
1322
  * does_not_own:
1256
1323
  * - The implementation. A plugin never dials MCP itself: it takes the port from
1257
- * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the daemon binds to the
1258
- * plugin's own hosted server over its MCP host. Plugin source stays host-free, and a plugin
1324
+ * `api.vendoredMcp.port(server)` (`@bonsai/plugin-sdk/kay-agent`), which the SDK binds through
1325
+ * resource calls to the plugin's own hosted server. Plugin source stays host-free, and a plugin
1259
1326
  * under test substitutes a fake port.
1260
1327
  * - Which tool names exist. `TTool` is the plugin's own union of the vendor tools it calls; the
1261
1328
  * port is generic so a typo in a tool name fails typecheck inside the plugin.
@@ -1291,8 +1358,8 @@ export declare type VendoredMcpOutcome =
1291
1358
 
1292
1359
  /**
1293
1360
  * One vendored MCP server, as the plugin that declares it calls it. `invoke` calls any tool the
1294
- * server has, whether it reads or writes. The port checks no permission of its own: a call is as
1295
- * permitted as the plugin tool or URI verb that makes it.
1361
+ * server has, whether it reads or writes. The resource caller checks the target's exact
1362
+ * `uri.call` grant, and MCP checks the host-stamped caller against server ownership.
1296
1363
  */
1297
1364
  export declare interface VendoredMcpPort<TTool extends string = string> {
1298
1365
  invoke(input: {
@@ -480,6 +480,30 @@ var UriPayloadContractSchema = z2.strictObject({
480
480
  examples: z2.array(z2.unknown()).optional()
481
481
  });
482
482
 
483
+ // packages/herd-uri/dist/payloads.js
484
+ function isJsonPrimitive(value) {
485
+ return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
486
+ }
487
+ function isJsonValue(value) {
488
+ return isJsonValueInner(value, /* @__PURE__ */ new WeakSet());
489
+ }
490
+ function isJsonValueInner(value, seen) {
491
+ if (isJsonPrimitive(value))
492
+ return true;
493
+ if (typeof value !== "object" || value === null)
494
+ return false;
495
+ if (seen.has(value))
496
+ return false;
497
+ seen.add(value);
498
+ if (Array.isArray(value)) {
499
+ return value.every((item) => isJsonValueInner(item, seen));
500
+ }
501
+ const prototype = Object.getPrototypeOf(value);
502
+ if (prototype !== Object.prototype && prototype !== null)
503
+ return false;
504
+ return Object.values(value).every((item) => isJsonValueInner(item, seen));
505
+ }
506
+
483
507
  // packages/herd-uri/dist/text-edit.js
484
508
  import { z as z3 } from "zod";
485
509
  var findReplaceArm = z3.strictObject({
@@ -664,7 +688,70 @@ function createVendoredMcpUriModule(descriptor) {
664
688
  }
665
689
  };
666
690
  }
691
+
692
+ // packages/plugin-sdk/dist/vendored-mcp.js
693
+ function createVendoredMcpPort(server, uri) {
694
+ return {
695
+ async invoke({ cwd, tool, args }) {
696
+ try {
697
+ if (!isJsonValue(args)) {
698
+ return {
699
+ ok: false,
700
+ reason: "failed",
701
+ message: "MCP tool arguments must be JSON-compatible."
702
+ };
703
+ }
704
+ const result = await uri.write(`mcp://${encodeURIComponent(server)}/tools/${encodeURIComponent(tool)}`, args, { cwd });
705
+ if (result === void 0 || result.resource === void 0) {
706
+ return {
707
+ ok: false,
708
+ reason: "failed",
709
+ message: `MCP server '${server}' returned no tool result.`
710
+ };
711
+ }
712
+ return { ok: true, value: result.resource };
713
+ } catch (error) {
714
+ const failure = error;
715
+ const code = failure?.providerCode;
716
+ const reason = failure?._tag === "UriProviderError" && failure.moduleId === "mcp.servers" && (code === "needs-auth" || code === "unknown-server" || code === "unknown-tool" || code === "failed") ? code : "failed";
717
+ return {
718
+ ok: false,
719
+ reason,
720
+ message: error instanceof Error ? error.message : String(error),
721
+ ...typeof failure?.serviceId === "string" ? { serviceId: failure.serviceId } : {}
722
+ };
723
+ }
724
+ }
725
+ };
726
+ }
727
+ function createKayAgentVendoredMcp(pluginId, servers, uri) {
728
+ return {
729
+ port(server) {
730
+ if (!servers.includes(server)) {
731
+ throw new Error(`Plugin '${pluginId}' declares no MCP server '${server}' in its kay.app target's contributes.mcpServers, so api.vendoredMcp has no port to it.`);
732
+ }
733
+ return createVendoredMcpPort(server, uri);
734
+ }
735
+ };
736
+ }
737
+ function createKayAppMcp(pluginId, servers, uri) {
738
+ return {
739
+ async callTool({ server, tool, args }) {
740
+ if (!servers.includes(server)) {
741
+ return {
742
+ ok: false,
743
+ reason: "unknown-server",
744
+ message: `Plugin '${pluginId}' does not declare MCP server '${server}'.`
745
+ };
746
+ }
747
+ return createVendoredMcpPort(server, uri).invoke({ cwd: "", tool, args });
748
+ }
749
+ };
750
+ }
667
751
  export {
752
+ createKayAgentVendoredMcp,
753
+ createKayAppMcp,
754
+ createVendoredMcpPort,
668
755
  createVendoredMcpUriModule,
669
756
  vendoredMcpUriModuleFacts
670
757
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaklabs-ai/plugin-sdk",
3
- "version": "0.54.2",
3
+ "version": "0.55.0",
4
4
  "description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
5
5
  "author": "YakLabs",
6
6
  "type": "module",