@decocms/bindings 1.0.1-alpha.20 → 1.0.1-alpha.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/bindings",
3
- "version": "1.0.1-alpha.20",
3
+ "version": "1.0.1-alpha.22",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",
@@ -129,7 +129,7 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
129
129
  };
130
130
  };
131
131
 
132
- export type MCPBindingClient<T extends ReturnType<typeof bindingClient>> =
132
+ export type MCPBindingClient<T extends ReturnType<typeof bindingClient<any>>> =
133
133
  ReturnType<T["forConnection"]>;
134
134
 
135
135
  /**
@@ -59,6 +59,16 @@ export type MCPClientStub<TDefinition extends readonly ToolBinder[]> = {
59
59
  };
60
60
 
61
61
  export type MCPClientFetchStub<TDefinition extends readonly ToolBinder[]> = {
62
+ listTools: () => Promise<
63
+ {
64
+ id: string;
65
+ inputSchema: z.ZodType;
66
+ outputSchema: z.ZodType;
67
+ description: string;
68
+ execute: (params: any) => Promise<any>;
69
+ }[]
70
+ >;
71
+ } & {
62
72
  [K in TDefinition[number] as K["name"]]: K["streamable"] extends true
63
73
  ? K extends ToolBinder<string, infer TInput, any, true>
64
74
  ? (params: TInput, init?: RequestInit) => Promise<Response>
@@ -11,18 +11,33 @@ const safeParse = (content: string) => {
11
11
  }
12
12
  };
13
13
 
14
- const toolsMap = new Map<
15
- string,
16
- Promise<
17
- Array<{
18
- name: string;
19
- inputSchema: any;
20
- outputSchema?: any;
21
- description: string;
22
- }>
23
- >
24
- >();
14
+ type Tool = {
15
+ name: string;
16
+ inputSchema: any;
17
+ outputSchema?: any;
18
+ description: string;
19
+ };
25
20
 
21
+ const toolsMap = new Map<string, Promise<Array<Tool>>>();
22
+
23
+ const mapTool = (
24
+ tool: Tool,
25
+ callToolFn: (input: any, toolName?: string) => Promise<any>,
26
+ ) => {
27
+ return {
28
+ ...tool,
29
+ id: tool.name,
30
+ inputSchema: tool.inputSchema
31
+ ? convertJsonSchemaToZod(tool.inputSchema)
32
+ : undefined,
33
+ outputSchema: tool.outputSchema
34
+ ? convertJsonSchemaToZod(tool.outputSchema)
35
+ : undefined,
36
+ execute: (input: any) => {
37
+ return callToolFn(input.context, tool.name);
38
+ },
39
+ };
40
+ };
26
41
  /**
27
42
  * The base fetcher used to fetch the MCP from API.
28
43
  */
@@ -47,7 +62,13 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
47
62
  if (typeof name !== "string") {
48
63
  throw new Error("Name must be a string");
49
64
  }
50
- async function callToolFn(args: Record<string, unknown>) {
65
+ if (name === "listTools") {
66
+ return asCallableTools;
67
+ }
68
+ async function callToolFn(
69
+ args: Record<string, unknown>,
70
+ toolName = name,
71
+ ) {
51
72
  const debugId = options?.debugId?.();
52
73
  const extraHeaders = debugId
53
74
  ? { "x-trace-debug-id": debugId }
@@ -55,12 +76,12 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
55
76
 
56
77
  const { client, callStreamableTool } = await createClient(extraHeaders);
57
78
 
58
- if (options?.streamable?.[String(name)]) {
59
- return callStreamableTool(String(name), args);
79
+ if (options?.streamable?.[String(toolName)]) {
80
+ return callStreamableTool(String(toolName), args);
60
81
  }
61
82
 
62
83
  const { structuredContent, isError, content } = await client.callTool({
63
- name: String(name),
84
+ name: String(toolName),
64
85
  arguments: args as Record<string, unknown>,
65
86
  });
66
87
 
@@ -85,7 +106,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
85
106
  }
86
107
 
87
108
  throw new Error(
88
- `Tool ${String(name)} returned an error: ${JSON.stringify(
109
+ `Tool ${String(toolName)} returned an error: ${JSON.stringify(
89
110
  structuredContent ?? content,
90
111
  )}`,
91
112
  );
@@ -93,7 +114,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
93
114
  return structuredContent;
94
115
  }
95
116
 
96
- const listToolsFn = async () => {
117
+ async function listToolsFn() {
97
118
  const { client } = await createClient();
98
119
  const { tools } = await client.listTools();
99
120
 
@@ -103,7 +124,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
103
124
  outputSchema?: any;
104
125
  description: string;
105
126
  }[];
106
- };
127
+ }
107
128
 
108
129
  async function listToolsOnce() {
109
130
  if (!("connection" in options)) {
@@ -125,6 +146,12 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
125
146
  return;
126
147
  }
127
148
  }
149
+
150
+ async function asCallableTools() {
151
+ const tools = (await listToolsOnce()) ?? [];
152
+ return tools.map((tool) => mapTool(tool, callToolFn));
153
+ }
154
+
128
155
  callToolFn.asTool = async () => {
129
156
  const tools = (await listToolsOnce()) ?? [];
130
157
  const tool = tools.find((t) => t.name === name);
@@ -132,19 +159,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
132
159
  throw new Error(`Tool ${name} not found`);
133
160
  }
134
161
 
135
- return {
136
- ...tool,
137
- id: tool.name,
138
- inputSchema: tool.inputSchema
139
- ? convertJsonSchemaToZod(tool.inputSchema)
140
- : undefined,
141
- outputSchema: tool.outputSchema
142
- ? convertJsonSchemaToZod(tool.outputSchema)
143
- : undefined,
144
- execute: (input: any) => {
145
- return callToolFn(input.context);
146
- },
147
- };
162
+ return mapTool(tool, callToolFn);
148
163
  };
149
164
  return callToolFn;
150
165
  },
@@ -260,7 +260,7 @@ export interface CollectionBindingOptions {
260
260
  * ```
261
261
  */
262
262
  export function createCollectionBindings<
263
- TEntitySchema extends z.AnyZodObject,
263
+ TEntitySchema extends z.ZodObject<z.ZodRawShape>,
264
264
  TName extends string,
265
265
  >(
266
266
  collectionName: TName,
@@ -329,9 +329,11 @@ type ToolBinding<
329
329
  * Type helper to extract the collection binding type
330
330
  */
331
331
  export type CollectionBinding<
332
- TEntitySchema extends z.AnyZodObject,
332
+ TEntitySchema,
333
333
  TUpperName extends Uppercase<string> = Uppercase<string>,
334
- TEntity = z.infer<TEntitySchema>,
334
+ TEntity = TEntitySchema extends z.AnyZodObject
335
+ ? z.infer<TEntitySchema>
336
+ : TEntitySchema,
335
337
  > = [
336
338
  ToolBinding<
337
339
  `COLLECTION_${TUpperName}_LIST`,
@@ -107,11 +107,17 @@ export type OnEventsInput = z.infer<typeof OnEventsInputSchema>;
107
107
  /**
108
108
  * Per-event result schema
109
109
  * Allows granular control over each event in a batch
110
+ *
111
+ * Three modes:
112
+ * - `{ success: true }` - Event processed successfully
113
+ * - `{ success: false, error: "..." }` - Event failed permanently
114
+ * - `{ retryAfter: 60000 }` - Retry later (success not yet determined)
110
115
  */
111
116
  export const EventResultSchema = z.object({
112
117
  /** Whether this specific event was processed successfully */
113
118
  success: z
114
119
  .boolean()
120
+ .optional()
115
121
  .describe("Whether this event was processed successfully"),
116
122
 
117
123
  /** Error message if success=false */
@@ -120,6 +126,7 @@ export const EventResultSchema = z.object({
120
126
  /**
121
127
  * Request re-delivery of this event after this many milliseconds.
122
128
  * Does not count toward max retry attempts.
129
+ * When present without success, indicates the event should be retried.
123
130
  */
124
131
  retryAfter: z
125
132
  .number()