@decocms/bindings 1.4.1 → 1.4.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/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@decocms/bindings",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",
7
7
  "test": "bun test"
8
8
  },
9
9
  "dependencies": {
10
- "@modelcontextprotocol/sdk": "1.27.1",
11
- "@tanstack/react-router": "1.139.7",
12
- "react": "^19.2.0",
10
+ "@modelcontextprotocol/sdk": "1.29.0",
11
+ "@tanstack/react-router": "1.169.2",
12
+ "react": "^19.2.6",
13
13
  "zod": "^4.0.0",
14
14
  "zod-from-json-schema": "^0.5.2"
15
15
  },
@@ -32,7 +32,8 @@
32
32
  "./plugin-router": "./src/core/plugin-router.tsx",
33
33
  "./ai-gateway": "./src/well-known/ai-gateway.ts",
34
34
  "./server-plugin": "./src/core/server-plugin.ts",
35
- "./trigger": "./src/well-known/trigger.ts"
35
+ "./trigger": "./src/well-known/trigger.ts",
36
+ "./brand": "./src/well-known/brand.ts"
36
37
  },
37
38
  "engines": {
38
39
  "node": ">=24.0.0"
@@ -24,7 +24,6 @@ export interface ToolBinder<
24
24
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
25
  TInput = any,
26
26
  TReturn extends object | null | boolean = object,
27
- TStreamable extends boolean = boolean,
28
27
  > {
29
28
  /** The name of the tool (e.g., "DECO_CHAT_CHANNELS_JOIN") */
30
29
  name: TName;
@@ -33,12 +32,7 @@ export interface ToolBinder<
33
32
  inputSchema: ZodType<TInput>;
34
33
 
35
34
  /** Optional Zod schema for validating tool output */
36
- outputSchema?: TStreamable extends true ? never : ZodType<TReturn>;
37
-
38
- /**
39
- * Whether this tool is streamable.
40
- */
41
- streamable?: TStreamable;
35
+ outputSchema?: ZodType<TReturn>;
42
36
 
43
37
  /**
44
38
  * Whether this tool is optional in the binding.
@@ -103,13 +97,6 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
103
97
  forClient: (client: ServerClient): MCPClientFetchStub<TDefinition> => {
104
98
  return createMCPFetchStub<TDefinition>({
105
99
  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
100
  });
114
101
  },
115
102
  forConnection: (
@@ -117,13 +104,6 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
117
104
  ): MCPClientFetchStub<TDefinition> => {
118
105
  return createMCPFetchStub<TDefinition>({
119
106
  connection: mcpConnection,
120
- streamable: binder.reduce(
121
- (acc, tool) => {
122
- acc[tool.name] = tool.streamable === true;
123
- return acc;
124
- },
125
- {} as Record<string, boolean>,
126
- ),
127
107
  });
128
108
  },
129
109
  };
@@ -1,7 +1,6 @@
1
1
  export { HTTPClientTransport } from "./http-client-transport";
2
2
  export {
3
3
  createMCPFetchStub,
4
- isStreamableToolBinder,
5
4
  MCPClient,
6
5
  type CreateStubAPIOptions,
7
6
  type MCPClientFetchStub,
@@ -47,11 +47,6 @@ export interface ServerClient {
47
47
  callTool: Client["callTool"];
48
48
  listTools: () => Promise<ListToolsResult>;
49
49
  };
50
- callStreamableTool?: (
51
- tool: string,
52
- args: Record<string, unknown>,
53
- signal?: AbortSignal,
54
- ) => Promise<Response>;
55
50
  }
56
51
  export const createServerClient = async (
57
52
  mcpServer: { connection: MCPConnection; name?: string },
@@ -73,36 +68,6 @@ export const createServerClient = async (
73
68
 
74
69
  return {
75
70
  client,
76
- callStreamableTool: (tool, args, signal) => {
77
- if (mcpServer.connection.type !== "HTTP") {
78
- throw new Error("HTTP connection required");
79
- }
80
-
81
- const headers = new Headers(extraHeaders);
82
-
83
- if (!headers.has("Authorization")) {
84
- headers.set("Authorization", `Bearer ${mcpServer.connection.token}`);
85
- }
86
-
87
- for (const [key, value] of Object.entries(
88
- mcpServer.connection.headers ?? {},
89
- )) {
90
- headers.set(key, value);
91
- }
92
-
93
- const url = new URL(mcpServer.connection.url);
94
- // Trim trailing slashes from pathname, ensuring it starts with '/'
95
- const trimmedPath = url.pathname.replace(/\/+$/, "") || "/";
96
- url.pathname = `${trimmedPath}/call-tool/${encodeURIComponent(tool)}`;
97
-
98
- return fetch(url.href, {
99
- method: "POST",
100
- redirect: "manual",
101
- body: JSON.stringify(args),
102
- headers,
103
- signal,
104
- });
105
- },
106
71
  };
107
72
  };
108
73
 
@@ -3,12 +3,6 @@ import { z } from "zod";
3
3
  import type { MCPConnection } from "../connection";
4
4
  import { createMCPClientProxy } from "./proxy";
5
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
- };
11
-
12
6
  // Default fetcher instance with API_SERVER_URL and API_HEADERS
13
7
  export const MCPClient = new Proxy(
14
8
  {} as {
@@ -69,13 +63,13 @@ export type MCPClientFetchStub<TDefinition extends readonly ToolBinder[]> = {
69
63
  }[]
70
64
  >;
71
65
  } & {
72
- [K in TDefinition[number] as K["name"]]: K["streamable"] extends true
73
- ? K extends ToolBinder<string, infer TInput, any, true>
74
- ? (params: TInput, init?: RequestInit) => Promise<Response>
75
- : never
76
- : K extends ToolBinder<string, infer TInput, infer TReturn, any>
77
- ? (params: TInput, init?: RequestInit) => Promise<Awaited<TReturn>>
78
- : never;
66
+ [K in TDefinition[number] as K["name"]]: K extends ToolBinder<
67
+ string,
68
+ infer TInput,
69
+ infer TReturn
70
+ >
71
+ ? (params: TInput, init?: RequestInit) => Promise<Awaited<TReturn>>
72
+ : never;
79
73
  };
80
74
 
81
75
  export interface MCPClientRaw {
@@ -93,7 +87,6 @@ export type JSONSchemaToZodConverter = (jsonSchema: any) => z.ZodTypeAny;
93
87
 
94
88
  export interface CreateStubForClientAPIOptions {
95
89
  client: ServerClient;
96
- streamable?: Record<string, boolean>;
97
90
  debugId?: () => string;
98
91
  getErrorByStatusCode?: (
99
92
  statusCode: number,
@@ -105,7 +98,6 @@ export interface CreateStubForClientAPIOptions {
105
98
 
106
99
  export interface CreateStubForConnectionAPIOptions {
107
100
  connection: MCPConnection;
108
- streamable?: Record<string, boolean>;
109
101
  debugId?: () => string;
110
102
  createServerClient?: (
111
103
  mcpServer: { connection: MCPConnection; name?: string },
@@ -74,16 +74,7 @@ export function createMCPClientProxy<T extends Record<string, unknown>>(
74
74
  ? { "x-trace-debug-id": debugId }
75
75
  : undefined;
76
76
 
77
- const { client, callStreamableTool } = await createClient(extraHeaders);
78
-
79
- if (options?.streamable?.[String(toolName)]) {
80
- if (!callStreamableTool) {
81
- throw new Error(
82
- `Tool ${String(toolName)} requires streaming support but client doesn't provide callStreamableTool`,
83
- );
84
- }
85
- return await callStreamableTool(String(toolName), args);
86
- }
77
+ const { client } = await createClient(extraHeaders);
87
78
 
88
79
  const { structuredContent, isError, content } = await client.callTool({
89
80
  name: String(toolName),
@@ -16,9 +16,9 @@ import type { Hono } from "hono";
16
16
  import type { Kysely } from "kysely";
17
17
 
18
18
  /**
19
- * Subset of MeshContext exposed to server plugin tool handlers.
19
+ * Subset of StudioContext exposed to server plugin tool handlers.
20
20
  *
21
- * Plugins receive the full MeshContext at runtime but should only depend on
21
+ * Plugins receive the full StudioContext at runtime but should only depend on
22
22
  * these properties. This keeps the plugin contract stable and avoids coupling
23
23
  * plugins to Mesh internals (db, vault, tracer, etc.).
24
24
  */
package/src/index.ts CHANGED
@@ -123,3 +123,25 @@ export {
123
123
 
124
124
  // Re-export workflow binding types
125
125
  export { WORKFLOWS_COLLECTION_BINDING } from "./well-known/workflow";
126
+
127
+ // Re-export brand binding types (for reading org brand context)
128
+ export {
129
+ BrandColorsSchema,
130
+ type BrandColors,
131
+ BrandFontsSchema,
132
+ type BrandFonts,
133
+ BrandAssetsSchema,
134
+ type BrandAssets,
135
+ BrandSchema,
136
+ type Brand,
137
+ BrandGetInputSchema,
138
+ type BrandGetInput,
139
+ type BrandGetOutput,
140
+ BrandListInputSchema,
141
+ type BrandListInput,
142
+ BrandListOutputSchema,
143
+ type BrandListOutput,
144
+ BRAND_BINDING,
145
+ BrandBinding,
146
+ type BrandBindingClient,
147
+ } from "./well-known/brand";
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Brand Well-Known Binding
3
+ *
4
+ * Defines the interface for reading brand context (colors, fonts, assets,
5
+ * voice) from an organization. External MCPs that need brand awareness
6
+ * can declare a dependency on this binding and call BRAND_GET / BRAND_LIST
7
+ * to pull structured brand data on demand.
8
+ *
9
+ * This binding includes:
10
+ * - BRAND_GET: Get a brand by ID (or the org default)
11
+ * - BRAND_LIST: List all active brands (optional)
12
+ */
13
+
14
+ import { z } from "zod";
15
+ import { bindingClient, type ToolBinder } from "../core/binder";
16
+
17
+ // ============================================================================
18
+ // Brand Sub-Schemas
19
+ // ============================================================================
20
+
21
+ export const BrandColorsSchema = z.object({
22
+ primary: z.string().optional().describe("Primary brand color (hex)"),
23
+ secondary: z.string().optional().describe("Secondary brand color (hex)"),
24
+ accent: z.string().optional().describe("Accent / highlight color (hex)"),
25
+ background: z.string().optional().describe("Background color (hex)"),
26
+ foreground: z.string().optional().describe("Foreground / text color (hex)"),
27
+ });
28
+
29
+ export type BrandColors = z.infer<typeof BrandColorsSchema>;
30
+
31
+ export const BrandFontsSchema = z.object({
32
+ heading: z.string().optional().describe("Font family for headings"),
33
+ body: z.string().optional().describe("Font family for body text"),
34
+ code: z.string().optional().describe("Font family for code / monospace"),
35
+ });
36
+
37
+ export type BrandFonts = z.infer<typeof BrandFontsSchema>;
38
+
39
+ export const BrandAssetsSchema = z.object({
40
+ logo: z.string().optional().describe("Logo URL"),
41
+ favicon: z.string().optional().describe("Favicon URL"),
42
+ ogImage: z.string().optional().describe("Open Graph image URL"),
43
+ });
44
+
45
+ export type BrandAssets = z.infer<typeof BrandAssetsSchema>;
46
+
47
+ // ============================================================================
48
+ // Brand Schema
49
+ // ============================================================================
50
+
51
+ export const BrandSchema = z.object({
52
+ id: z.string(),
53
+ name: z.string().describe("Brand / company name"),
54
+ domain: z.string().optional().describe("Company domain (e.g. example.com)"),
55
+ colors: BrandColorsSchema.optional().describe("Semantic color palette"),
56
+ fonts: BrandFontsSchema.optional().describe("Font families by role"),
57
+ assets: BrandAssetsSchema.optional().describe("Visual identity assets"),
58
+ overview: z.string().optional().describe("Company overview / description"),
59
+ tagline: z.string().optional().describe("Brand tagline"),
60
+ tone: z.string().optional().describe("Tone of voice description"),
61
+ metadata: z
62
+ .record(z.string(), z.unknown())
63
+ .optional()
64
+ .describe("Extra design tokens and metadata"),
65
+ });
66
+
67
+ export type Brand = z.infer<typeof BrandSchema>;
68
+
69
+ // ============================================================================
70
+ // BRAND_GET Schemas
71
+ // ============================================================================
72
+
73
+ export const BrandGetInputSchema = z.object({
74
+ id: z
75
+ .string()
76
+ .optional()
77
+ .describe("Brand ID. Omit to get the default brand."),
78
+ });
79
+
80
+ export type BrandGetInput = z.infer<typeof BrandGetInputSchema>;
81
+
82
+ export type BrandGetOutput = z.infer<typeof BrandSchema>;
83
+
84
+ // ============================================================================
85
+ // BRAND_LIST Schemas
86
+ // ============================================================================
87
+
88
+ export const BrandListInputSchema = z.object({});
89
+
90
+ export type BrandListInput = z.infer<typeof BrandListInputSchema>;
91
+
92
+ export const BrandListOutputSchema = z.object({
93
+ items: z.array(BrandSchema),
94
+ });
95
+
96
+ export type BrandListOutput = z.infer<typeof BrandListOutputSchema>;
97
+
98
+ // ============================================================================
99
+ // Brand Binding
100
+ // ============================================================================
101
+
102
+ /**
103
+ * Brand Binding
104
+ *
105
+ * Defines the interface for reading brand context from an organization.
106
+ *
107
+ * Required tools:
108
+ * - BRAND_GET: Get a single brand by ID, or the default brand when no ID
109
+ *
110
+ * Optional tools:
111
+ * - BRAND_LIST: List all active brands
112
+ */
113
+ export const BRAND_BINDING = [
114
+ {
115
+ name: "BRAND_GET" as const,
116
+ inputSchema: BrandGetInputSchema,
117
+ outputSchema: BrandSchema,
118
+ },
119
+ {
120
+ name: "BRAND_LIST" as const,
121
+ inputSchema: BrandListInputSchema,
122
+ outputSchema: BrandListOutputSchema,
123
+ opt: true,
124
+ },
125
+ ] satisfies ToolBinder[];
126
+
127
+ /**
128
+ * Brand Binding Client
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * import { BrandBinding } from "@decocms/bindings/brand";
133
+ *
134
+ * const client = BrandBinding.forConnection(connection);
135
+ *
136
+ * // Get the default brand
137
+ * const brand = await client.BRAND_GET({});
138
+ *
139
+ * // Get a specific brand
140
+ * const brand = await client.BRAND_GET({ id: "acme-corp" });
141
+ *
142
+ * // List all brands
143
+ * const { items } = await client.BRAND_LIST({});
144
+ * ```
145
+ */
146
+ export const BrandBinding = bindingClient(BRAND_BINDING);
147
+
148
+ /**
149
+ * Type helper for the Brand binding client
150
+ */
151
+ export type BrandBindingClient = ReturnType<typeof BrandBinding.forConnection>;
@@ -712,7 +712,6 @@ export const LANGUAGE_MODEL_BINDING = [
712
712
  {
713
713
  name: "LLM_DO_STREAM" as const,
714
714
  inputSchema: LanguageModelInputSchema,
715
- streamable: true,
716
715
  },
717
716
  {
718
717
  name: "LLM_DO_GENERATE" as const,