@decocms/bindings 1.0.1-alpha.4 → 1.0.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.
package/README.md CHANGED
@@ -621,14 +621,14 @@ This will generate ESM output in the `dist/` directory with TypeScript declarati
621
621
 
622
622
  ### Testing
623
623
 
624
- Tests are written with [Vitest](https://vitest.dev/):
624
+ Tests are written with [Bun](https://bun.com/docs/test):
625
625
 
626
626
  ```bash
627
627
  # Run tests once
628
- bun run test
628
+ bun test
629
629
 
630
630
  # Watch mode
631
- bun run test:watch
631
+ bun test --watch
632
632
  ```
633
633
 
634
634
  ## Publishing
package/package.json CHANGED
@@ -1,29 +1,26 @@
1
1
  {
2
2
  "name": "@decocms/bindings",
3
- "version": "1.0.1-alpha.4",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
- "test": "vitest run",
7
- "test:watch": "vitest"
6
+ "check": "tsc --noEmit",
7
+ "test": "bun test"
8
8
  },
9
9
  "dependencies": {
10
- "@modelcontextprotocol/sdk": "^1.20.2",
10
+ "@modelcontextprotocol/sdk": "1.20.2",
11
11
  "zod": "^3.25.76",
12
- "zod-from-json-schema": "^0.0.5",
13
- "zod-to-json-schema": "3.25.0"
12
+ "zod-from-json-schema": "^0.0.5"
14
13
  },
15
14
  "exports": {
16
15
  ".": "./src/index.ts",
17
- "./models": "./src/well-known/models.ts",
18
16
  "./collections": "./src/well-known/collections.ts",
19
17
  "./llm": "./src/well-known/language-model.ts",
20
18
  "./connection": "./src/core/connection.ts",
21
19
  "./client": "./src/core/client/index.ts",
22
20
  "./mcp": "./src/well-known/mcp.ts",
23
- "./agent": "./src/well-known/agent.ts"
24
- },
25
- "devDependencies": {
26
- "vitest": "3.2.4"
21
+ "./assistant": "./src/well-known/assistant.ts",
22
+ "./prompt": "./src/well-known/prompt.ts",
23
+ "./workflow": "./src/well-known/workflow.ts"
27
24
  },
28
25
  "engines": {
29
26
  "node": ">=24.0.0"
@@ -6,47 +6,9 @@
6
6
  */
7
7
 
8
8
  import type { ZodType } from "zod";
9
- import { zodToJsonSchema } from "zod-to-json-schema";
10
9
  import { createMCPFetchStub, MCPClientFetchStub } from "./client/mcp";
10
+ import { ServerClient } from "./client/mcp-client";
11
11
  import { MCPConnection } from "./connection";
12
- import { isSubset } from "./subset";
13
-
14
- type JsonSchema = Record<string, unknown>;
15
-
16
- /**
17
- * Checks if a value is a Zod schema by looking for the _def property
18
- */
19
- function isZodSchema(value: unknown): value is ZodType<unknown> {
20
- return (
21
- value !== null &&
22
- typeof value === "object" &&
23
- "_def" in value &&
24
- typeof (value as Record<string, unknown>)._def === "object"
25
- );
26
- }
27
-
28
- /**
29
- * Normalizes a schema to JSON Schema format.
30
- * Accepts either a Zod schema or a JSON schema and returns a JSON schema.
31
- *
32
- * @param schema - A Zod schema or JSON schema
33
- * @returns The JSON schema representation, or null if input is null/undefined
34
- */
35
- export function normalizeToJsonSchema(
36
- schema: ZodType<unknown> | JsonSchema | null | undefined,
37
- ): JsonSchema | null {
38
- if (schema == null) {
39
- return null;
40
- }
41
-
42
- if (isZodSchema(schema)) {
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- return zodToJsonSchema(schema as any) as JsonSchema;
45
- }
46
-
47
- // Already a JSON schema
48
- return schema as JsonSchema;
49
- }
50
12
 
51
13
  /**
52
14
  * ToolBinder defines a single tool within a binding.
@@ -138,6 +100,18 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
138
100
  ) => {
139
101
  return {
140
102
  ...createBindingChecker(binder),
103
+ forClient: (client: ServerClient): MCPClientFetchStub<TDefinition> => {
104
+ return createMCPFetchStub<TDefinition>({
105
+ client,
106
+ streamable: binder.reduce(
107
+ (acc, tool) => {
108
+ acc[tool.name] = tool.streamable === true;
109
+ return acc;
110
+ },
111
+ {} as Record<string, boolean>,
112
+ ),
113
+ });
114
+ },
141
115
  forConnection: (
142
116
  mcpConnection: MCPConnection,
143
117
  ): MCPClientFetchStub<TDefinition> => {
@@ -155,7 +129,7 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
155
129
  };
156
130
  };
157
131
 
158
- export type MCPBindingClient<T extends ReturnType<typeof bindingClient>> =
132
+ export type MCPBindingClient<T extends ReturnType<typeof bindingClient<any>>> =
159
133
  ReturnType<T["forConnection"]>;
160
134
 
161
135
  /**
@@ -197,42 +171,7 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
197
171
  if (!matchedTool) {
198
172
  return false;
199
173
  }
200
-
201
- // === INPUT SCHEMA VALIDATION ===
202
- // Tool must accept what binder requires
203
- // Check: isSubset(binder, tool) - every value valid under binder is valid under tool
204
- const binderInputSchema = normalizeToJsonSchema(binderTool.inputSchema);
205
- const toolInputSchema = normalizeToJsonSchema(matchedTool.inputSchema);
206
-
207
- if (binderInputSchema && toolInputSchema) {
208
- // Check if binder input is a subset of tool input (tool accepts what binder requires)
209
- if (!isSubset(binderInputSchema, toolInputSchema)) {
210
- return false;
211
- }
212
- } else if (binderInputSchema && !toolInputSchema) {
213
- // Binder requires input schema but tool doesn't have one
214
- return false;
215
- }
216
-
217
- // === OUTPUT SCHEMA VALIDATION ===
218
- // Tool must provide what binder expects (but can provide more)
219
- // Check: isSubset(binder, tool) - tool provides at least what binder expects
220
- const binderOutputSchema = normalizeToJsonSchema(
221
- binderTool.outputSchema,
222
- );
223
- const toolOutputSchema = normalizeToJsonSchema(
224
- matchedTool.outputSchema,
225
- );
226
-
227
- if (binderOutputSchema && toolOutputSchema) {
228
- // Check if binder output is a subset of tool output (tool provides what binder expects)
229
- if (!isSubset(binderOutputSchema, toolOutputSchema)) {
230
- return false;
231
- }
232
- } else if (binderOutputSchema && !toolOutputSchema) {
233
- // Binder expects output schema but tool doesn't have one
234
- return false;
235
- }
174
+ // FIXME @mcandeia Zod to JSONSchema converstion is creating inconsistent schemas
236
175
  }
237
176
  return true;
238
177
  },
@@ -1 +1,11 @@
1
1
  export { HTTPClientTransport } from "./http-client-transport";
2
+ export {
3
+ createMCPFetchStub,
4
+ isStreamableToolBinder,
5
+ MCPClient,
6
+ type CreateStubAPIOptions,
7
+ type MCPClientFetchStub,
8
+ type MCPClientStub,
9
+ type ServerClient,
10
+ } from "./mcp";
11
+ export { bindingClient } from "../binder";
@@ -9,8 +9,10 @@ import {
9
9
  import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
10
10
  import { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
11
11
  import {
12
+ CallToolRequest,
12
13
  Implementation,
13
14
  ListToolsRequest,
15
+ ListToolsResult,
14
16
  ListToolsResultSchema,
15
17
  } from "@modelcontextprotocol/sdk/types.js";
16
18
  import { MCPConnection } from "../connection";
@@ -41,10 +43,16 @@ class Client extends BaseClient {
41
43
  return result;
42
44
  }
43
45
  }
44
-
46
+ type CallToolResponse = Awaited<ReturnType<Client["callTool"]>>;
45
47
  export interface ServerClient {
46
- client: Client;
47
- callStreamableTool: (tool: string, args: unknown) => Promise<Response>;
48
+ client: {
49
+ callTool: (params: CallToolRequest["params"]) => Promise<CallToolResponse>;
50
+ listTools: () => Promise<ListToolsResult>;
51
+ };
52
+ callStreamableTool: (
53
+ tool: string,
54
+ args: Record<string, unknown>,
55
+ ) => Promise<Response>;
48
56
  }
49
57
  export const createServerClient = async (
50
58
  mcpServer: { connection: MCPConnection; name?: string },
@@ -83,7 +91,12 @@ export const createServerClient = async (
83
91
  headers.set(key, value);
84
92
  }
85
93
 
86
- return fetch(mcpServer.connection.url + `/call-tool/${tool}`, {
94
+ const url = new URL(mcpServer.connection.url);
95
+ // Trim trailing slashes from pathname, ensuring it starts with '/'
96
+ const trimmedPath = url.pathname.replace(/\/+$/, "") || "/";
97
+ url.pathname = `${trimmedPath}/call-tool/${encodeURIComponent(tool)}`;
98
+
99
+ return fetch(url.href, {
87
100
  method: "POST",
88
101
  redirect: "manual",
89
102
  body: JSON.stringify(args),
@@ -93,7 +106,7 @@ export const createServerClient = async (
93
106
  };
94
107
  };
95
108
 
96
- export const createTransport = (
109
+ const createTransport = (
97
110
  connection: MCPConnection,
98
111
  signal?: AbortSignal,
99
112
  extraHeaders?: Record<string, string>,
@@ -2,15 +2,19 @@
2
2
  import { z } from "zod";
3
3
  import type { MCPConnection } from "../connection";
4
4
  import { createMCPClientProxy } from "./proxy";
5
-
6
- export interface FetchOptions extends RequestInit {
7
- path?: string;
8
- segments?: string[];
9
- }
5
+ export type { ServerClient } from "./mcp-client";
6
+ export const isStreamableToolBinder = (
7
+ toolBinder: ToolBinder,
8
+ ): toolBinder is ToolBinder<string, any, any, true> => {
9
+ return toolBinder.streamable === true;
10
+ };
10
11
 
11
12
  // Default fetcher instance with API_SERVER_URL and API_HEADERS
12
13
  export const MCPClient = new Proxy(
13
14
  {} as {
15
+ forClient: <TDefinition extends readonly ToolBinder[]>(
16
+ client: ServerClient,
17
+ ) => MCPClientFetchStub<TDefinition>;
14
18
  forConnection: <TDefinition extends readonly ToolBinder[]>(
15
19
  connection: MCPConnection,
16
20
  ) => MCPClientFetchStub<TDefinition>;
@@ -34,14 +38,16 @@ export const MCPClient = new Proxy(
34
38
  },
35
39
  );
36
40
 
41
+ export interface FetchOptions extends RequestInit {
42
+ path?: string;
43
+ segments?: string[];
44
+ }
45
+
46
+ // Default fetcher instance with API_SERVER_URL and API_HEADERS
37
47
  import type { ToolBinder } from "../binder";
48
+ import { ServerClient } from "./mcp-client";
38
49
  export type { ToolBinder };
39
50
 
40
- export const isStreamableToolBinder = (
41
- toolBinder: ToolBinder,
42
- ): toolBinder is ToolBinder<string, any, any, true> => {
43
- return toolBinder.streamable === true;
44
- };
45
51
  export type MCPClientStub<TDefinition extends readonly ToolBinder[]> = {
46
52
  [K in TDefinition[number] as K["name"]]: K extends ToolBinder<
47
53
  string,
@@ -53,6 +59,16 @@ export type MCPClientStub<TDefinition extends readonly ToolBinder[]> = {
53
59
  };
54
60
 
55
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
+ } & {
56
72
  [K in TDefinition[number] as K["name"]]: K["streamable"] extends true
57
73
  ? K extends ToolBinder<string, infer TInput, any, true>
58
74
  ? (params: TInput, init?: RequestInit) => Promise<Response>
@@ -74,10 +90,28 @@ export interface MCPClientRaw {
74
90
  >;
75
91
  }
76
92
  export type JSONSchemaToZodConverter = (jsonSchema: any) => z.ZodTypeAny;
77
- export interface CreateStubAPIOptions {
93
+
94
+ export interface CreateStubForClientAPIOptions {
95
+ client: ServerClient;
96
+ streamable?: Record<string, boolean>;
97
+ debugId?: () => string;
98
+ getErrorByStatusCode?: (
99
+ statusCode: number,
100
+ message?: string,
101
+ traceId?: string,
102
+ errorObject?: unknown,
103
+ ) => Error;
104
+ }
105
+
106
+ export interface CreateStubForConnectionAPIOptions {
78
107
  connection: MCPConnection;
79
108
  streamable?: Record<string, boolean>;
80
109
  debugId?: () => string;
110
+ createServerClient?: (
111
+ mcpServer: { connection: MCPConnection; name?: string },
112
+ signal?: AbortSignal,
113
+ extraHeaders?: Record<string, string>,
114
+ ) => ServerClient;
81
115
  getErrorByStatusCode?: (
82
116
  statusCode: number,
83
117
  message?: string,
@@ -85,6 +119,9 @@ export interface CreateStubAPIOptions {
85
119
  errorObject?: unknown,
86
120
  ) => Error;
87
121
  }
122
+ export type CreateStubAPIOptions =
123
+ | CreateStubForClientAPIOptions
124
+ | CreateStubForConnectionAPIOptions;
88
125
 
89
126
  export function createMCPFetchStub<TDefinition extends readonly ToolBinder[]>(
90
127
  options: CreateStubAPIOptions,
@@ -11,24 +11,49 @@ 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
  */
29
44
  export function createMCPClientProxy<T extends Record<string, unknown>>(
30
45
  options: CreateStubAPIOptions,
31
46
  ): T {
47
+ const createClient = (extraHeaders?: Record<string, string>) => {
48
+ if ("connection" in options) {
49
+ return createServerClient(
50
+ { connection: options.connection },
51
+ undefined,
52
+ extraHeaders,
53
+ );
54
+ }
55
+ return options.client;
56
+ };
32
57
  return new Proxy<T>({} as T, {
33
58
  get(_, name) {
34
59
  if (name === "toJSON") {
@@ -37,32 +62,28 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
37
62
  if (typeof name !== "string") {
38
63
  throw new Error("Name must be a string");
39
64
  }
40
- async function callToolFn(args: unknown) {
65
+ if (name === "listTools") {
66
+ return asCallableTools;
67
+ }
68
+ async function callToolFn(
69
+ args: Record<string, unknown>,
70
+ toolName = name,
71
+ ) {
41
72
  const debugId = options?.debugId?.();
42
73
  const extraHeaders = debugId
43
74
  ? { "x-trace-debug-id": debugId }
44
75
  : undefined;
45
76
 
46
- const { client, callStreamableTool } = await createServerClient(
47
- { connection: options.connection },
48
- undefined,
49
- extraHeaders,
50
- );
77
+ const { client, callStreamableTool } = await createClient(extraHeaders);
51
78
 
52
- if (options?.streamable?.[String(name)]) {
53
- return callStreamableTool(String(name), args);
79
+ if (options?.streamable?.[String(toolName)]) {
80
+ return callStreamableTool(String(toolName), args);
54
81
  }
55
82
 
56
- const { structuredContent, isError, content } = await client.callTool(
57
- {
58
- name: String(name),
59
- arguments: args as Record<string, unknown>,
60
- },
61
- undefined,
62
- {
63
- timeout: 3000000,
64
- },
65
- );
83
+ const { structuredContent, isError, content } = await client.callTool({
84
+ name: String(toolName),
85
+ arguments: args as Record<string, unknown>,
86
+ });
66
87
 
67
88
  if (isError) {
68
89
  const maybeErrorMessage = (content as { text: string }[])?.[0]?.text;
@@ -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,10 +114,8 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
93
114
  return structuredContent;
94
115
  }
95
116
 
96
- const listToolsFn = async () => {
97
- const { client } = await createServerClient({
98
- connection: options.connection,
99
- });
117
+ async function listToolsFn() {
118
+ const { client } = await createClient();
100
119
  const { tools } = await client.listTools();
101
120
 
102
121
  return tools as {
@@ -105,9 +124,12 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
105
124
  outputSchema?: any;
106
125
  description: string;
107
126
  }[];
108
- };
127
+ }
109
128
 
110
129
  async function listToolsOnce() {
130
+ if (!("connection" in options)) {
131
+ return listToolsFn();
132
+ }
111
133
  const conn = options.connection;
112
134
  const key = JSON.stringify(conn);
113
135
 
@@ -124,6 +146,12 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
124
146
  return;
125
147
  }
126
148
  }
149
+
150
+ async function asCallableTools() {
151
+ const tools = (await listToolsOnce()) ?? [];
152
+ return tools.map((tool) => mapTool(tool, callToolFn));
153
+ }
154
+
127
155
  callToolFn.asTool = async () => {
128
156
  const tools = (await listToolsOnce()) ?? [];
129
157
  const tool = tools.find((t) => t.name === name);
@@ -131,19 +159,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
131
159
  throw new Error(`Tool ${name} not found`);
132
160
  }
133
161
 
134
- return {
135
- ...tool,
136
- id: tool.name,
137
- inputSchema: tool.inputSchema
138
- ? convertJsonSchemaToZod(tool.inputSchema)
139
- : undefined,
140
- outputSchema: tool.outputSchema
141
- ? convertJsonSchemaToZod(tool.outputSchema)
142
- : undefined,
143
- execute: (input: any) => {
144
- return callToolFn(input.context);
145
- },
146
- };
162
+ return mapTool(tool, callToolFn);
147
163
  };
148
164
  return callToolFn;
149
165
  },
package/src/index.ts CHANGED
@@ -13,3 +13,60 @@ export {
13
13
  type ToolBinder,
14
14
  type ToolWithSchemas,
15
15
  } from "./core/binder";
16
+
17
+ // Re-export registry binding types
18
+ export {
19
+ MCPRegistryServerSchema,
20
+ type RegistryAppCollectionEntity,
21
+ REGISTRY_APP_BINDING,
22
+ } from "./well-known/registry";
23
+
24
+ // Re-export event subscriber binding types (for connections that receive events)
25
+ export {
26
+ CloudEventSchema,
27
+ type CloudEvent,
28
+ EventResultSchema,
29
+ type EventResult,
30
+ OnEventsInputSchema,
31
+ type OnEventsInput,
32
+ OnEventsOutputSchema,
33
+ type OnEventsOutput,
34
+ EVENT_SUBSCRIBER_BINDING,
35
+ EventSubscriberBinding,
36
+ type EventSubscriberBindingClient,
37
+ } from "./well-known/event-subscriber";
38
+
39
+ // Re-export event bus binding types (for interacting with an event bus)
40
+ export {
41
+ EventPublishInputSchema,
42
+ type EventPublishInput,
43
+ EventPublishOutputSchema,
44
+ type EventPublishOutput,
45
+ EventSubscribeInputSchema,
46
+ type EventSubscribeInput,
47
+ EventSubscribeOutputSchema,
48
+ type EventSubscribeOutput,
49
+ EventUnsubscribeInputSchema,
50
+ type EventUnsubscribeInput,
51
+ EventUnsubscribeOutputSchema,
52
+ type EventUnsubscribeOutput,
53
+ EventCancelInputSchema,
54
+ type EventCancelInput,
55
+ EventCancelOutputSchema,
56
+ type EventCancelOutput,
57
+ EventAckInputSchema,
58
+ type EventAckInput,
59
+ EventAckOutputSchema,
60
+ type EventAckOutput,
61
+ SubscriptionItemSchema,
62
+ type SubscriptionItem,
63
+ SubscriptionDetailSchema,
64
+ type SubscriptionDetail,
65
+ EventSyncSubscriptionsInputSchema,
66
+ type EventSyncSubscriptionsInput,
67
+ EventSyncSubscriptionsOutputSchema,
68
+ type EventSyncSubscriptionsOutput,
69
+ EVENT_BUS_BINDING,
70
+ EventBusBinding,
71
+ type EventBusBindingClient,
72
+ } from "./well-known/event-bus";
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Assistants Well-Known Binding
3
+ *
4
+ * Defines the interface for AI assistant providers.
5
+ * Any MCP that implements this binding can provide configurable AI assistants
6
+ * with a system prompt and runtime configuration (gateway + model).
7
+ *
8
+ * This binding uses collection bindings for full CRUD operations.
9
+ */
10
+
11
+ import { z } from "zod";
12
+ import type { Binder } from "../core/binder";
13
+ import {
14
+ BaseCollectionEntitySchema,
15
+ createCollectionBindings,
16
+ } from "./collections";
17
+
18
+ /**
19
+ * Assistant entity schema for AI assistants
20
+ * Extends BaseCollectionEntitySchema with assistant-specific fields
21
+ * Base schema already includes: id, title, created_at, updated_at, created_by, updated_by
22
+ */
23
+ export const AssistantSchema = BaseCollectionEntitySchema.extend({
24
+ /**
25
+ * Assistant avatar.
26
+ * Can be a regular URL or a data URI.
27
+ */
28
+ avatar: z
29
+ .string()
30
+ .describe("URL or data URI to the assistant's avatar image"),
31
+
32
+ /**
33
+ * System prompt that defines the assistant's behavior.
34
+ */
35
+ system_prompt: z
36
+ .string()
37
+ .describe("System prompt that defines the assistant's behavior"),
38
+
39
+ /**
40
+ * Selected gateway for this assistant (single gateway).
41
+ * This gateway determines which MCP tools are exposed to chat.
42
+ */
43
+ gateway_id: z.string().describe("Gateway ID to use for this assistant"),
44
+
45
+ /**
46
+ * Selected model for this assistant (model id + the connection where it lives).
47
+ * This allows the UI/runtime to call the correct model provider connection.
48
+ */
49
+ model: z
50
+ .object({
51
+ id: z.string().describe("Model ID"),
52
+ connectionId: z
53
+ .string()
54
+ .describe("Connection ID that provides the model"),
55
+ })
56
+ .describe("Selected model reference for this assistant"),
57
+ });
58
+
59
+ /**
60
+ * ASSISTANT Collection Binding
61
+ *
62
+ * Collection bindings for assistants.
63
+ * Provides full CRUD operations (LIST, GET, CREATE, UPDATE, DELETE) for AI assistants.
64
+ */
65
+ export const ASSISTANTS_COLLECTION_BINDING = createCollectionBindings(
66
+ "assistant",
67
+ AssistantSchema,
68
+ );
69
+
70
+ /**
71
+ * ASSISTANTS Binding
72
+ *
73
+ * Defines the interface for AI assistant providers.
74
+ * Any MCP that implements this binding can provide configurable AI assistants.
75
+ *
76
+ * Required tools:
77
+ * - COLLECTION_ASSISTANT_LIST: List available AI assistants with their configurations
78
+ * - COLLECTION_ASSISTANT_GET: Get a single assistant by ID (includes system_prompt, gateway_id, model)
79
+ *
80
+ * Optional tools:
81
+ * - COLLECTION_ASSISTANT_CREATE: Create a new assistant
82
+ * - COLLECTION_ASSISTANT_UPDATE: Update an existing assistant
83
+ * - COLLECTION_ASSISTANT_DELETE: Delete an assistant
84
+ */
85
+ export const ASSISTANTS_BINDING = [
86
+ ...ASSISTANTS_COLLECTION_BINDING,
87
+ ] as const satisfies Binder;