holon-ui 0.0.1-dev.2 → 0.0.1-dev.3
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 +6 -7
- package/package.json +2 -2
- package/runtime.mjs +3 -4
package/README.md
CHANGED
|
@@ -62,17 +62,16 @@ const order = await apps.orders.tools.lookup({ id: "A-1" }, { timeout: 5000 });
|
|
|
62
62
|
|
|
63
63
|
An endpoint binding takes `endpoint`, and optionally `authProvider`, `fetch`, and `scoped: true` to close the session after every call. Otherwise a client keeps one session open; call `close()` when the page no longer needs it.
|
|
64
64
|
|
|
65
|
-
A tool can stop and ask for input through an MCP elicitation.
|
|
65
|
+
A tool can stop and ask for input through an MCP elicitation. Pass `elicit` to answer it, and the call returns its usual typed output:
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
endpoint: "https://orders.example.com/mcp",
|
|
71
|
-
elicit: async ({ params }) => ({ action: "accept", content: await showForm(params) }),
|
|
72
|
-
},
|
|
68
|
+
const { shipped } = await apps.orders.tools.ship({ id: "A-1" }, {
|
|
69
|
+
elicit: async params => ({ action: "accept", content: await showForm(params) }),
|
|
73
70
|
});
|
|
74
71
|
```
|
|
75
72
|
|
|
73
|
+
Without `elicit`, the call throws `ToolCallError` with the question on `.result`.
|
|
74
|
+
|
|
76
75
|
## Read and watch resources
|
|
77
76
|
|
|
78
77
|
A server types a JSON resource by registering it with `mimeType: "application/json"` and an `"sh.holon/outputSchema"` JSON Schema in its `_meta`:
|
|
@@ -88,7 +87,7 @@ await apps.orders.resources["orders://summary"].watch(value => render(value.open
|
|
|
88
87
|
|
|
89
88
|
## Give tools to the page's agent
|
|
90
89
|
|
|
91
|
-
`exposeTools` registers the tools of an endpoint-bound client with the page's WebMCP context (`navigator.modelContext`), except those whose `_meta.ui.visibility` omits `"model"`. Calls from the agent go through the client, so they are validated. An agent can only supply arguments, so a question
|
|
90
|
+
`exposeTools` registers the tools of an endpoint-bound client with the page's WebMCP context (`navigator.modelContext`), except those whose `_meta.ui.visibility` omits `"model"`. Calls from the agent go through the client, so they are validated. An agent can only supply arguments, so a question reaches it as a failed call naming the question; to answer for it, pass an `execute` that calls `callTool` with `elicit`. It returns `false` when the browser has no WebMCP context.
|
|
92
91
|
|
|
93
92
|
```typescript
|
|
94
93
|
await exposeTools(apps.orders, { signal: lifetime.signal });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holon-ui",
|
|
3
|
-
"version": "0.0.1-dev.
|
|
3
|
+
"version": "0.0.1-dev.3",
|
|
4
4
|
"description": "Typed MCP clients for browser views: MCP Apps host bindings and WebMCP tool exposure.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"fixtures": "node scripts/fixtures.mjs"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"holon-sh": "^0.0.1-dev.
|
|
42
|
+
"holon-sh": "^0.0.1-dev.6"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@modelcontextprotocol/ext-apps": ">=1.0.0"
|
package/runtime.mjs
CHANGED
|
@@ -33,10 +33,9 @@ export async function exposeTools(app, options = {}) {
|
|
|
33
33
|
const { signal } = options;
|
|
34
34
|
const execute = options.execute ?? (async (name, args) => {
|
|
35
35
|
const result = await app.callTool({ name, arguments: args }, { signal });
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return { isError: true, content: [{ type: "text", text: [`${name} needs input this page cannot provide`, ...questions].join(": ") }] };
|
|
36
|
+
// An agent can only supply arguments, so it cannot answer. A custom execute can.
|
|
37
|
+
if (result.resultType === "input_required") throw new ToolCallError("page", name, result);
|
|
38
|
+
return result;
|
|
40
39
|
});
|
|
41
40
|
const { tools } = await app.listTools({ signal });
|
|
42
41
|
for (const tool of tools) {
|