@decocms/runtime 1.0.0-alpha.37 → 1.0.0-alpha.38

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.
@@ -447,6 +447,10 @@
447
447
  "name": {
448
448
  "type": "string"
449
449
  },
450
+ "array": {
451
+ "type": "boolean",
452
+ "const": true
453
+ },
450
454
  "type": {
451
455
  "type": "string",
452
456
  "const": "mcp"
@@ -469,6 +473,10 @@
469
473
  "name": {
470
474
  "type": "string"
471
475
  },
476
+ "array": {
477
+ "type": "boolean",
478
+ "const": true
479
+ },
472
480
  "type": {
473
481
  "type": "string",
474
482
  "const": "mcp"
@@ -479,7 +487,6 @@
479
487
  }
480
488
  },
481
489
  "required": [
482
- "app_name",
483
490
  "name",
484
491
  "type"
485
492
  ],
@@ -491,6 +498,10 @@
491
498
  "name": {
492
499
  "type": "string"
493
500
  },
501
+ "array": {
502
+ "type": "boolean",
503
+ "const": true
504
+ },
494
505
  "type": {
495
506
  "type": "string",
496
507
  "const": "contract"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/runtime",
3
- "version": "1.0.0-alpha.37",
3
+ "version": "1.0.0-alpha.38",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit"
@@ -88,7 +88,7 @@ export const bindingClient = <TDefinition extends readonly ToolBinder[]>(
88
88
  };
89
89
  };
90
90
 
91
- export type MCPBindingClient<T extends ReturnType<typeof bindingClient>> =
91
+ export type MCPBindingClient<T extends ReturnType<typeof bindingClient<any>>> =
92
92
  ReturnType<T["forConnection"]>;
93
93
 
94
94
  export const ChannelBinding = bindingClient(CHANNEL_BINDING);
package/src/bindings.ts CHANGED
@@ -1,18 +1,96 @@
1
+ import { CollectionBinding } from "packages/bindings/src/well-known/collections.ts";
1
2
  import type { MCPConnection } from "./connection.ts";
2
- import type { DefaultEnv, RequestContext } from "./index.ts";
3
- import { MCPClient } from "./mcp.ts";
4
- import type {
5
- BindingBase,
6
- ContractBinding,
7
- MCPAppBinding,
8
- MCPBinding,
9
- } from "./wrangler.ts";
3
+ import type { RequestContext } from "./index.ts";
4
+ import { type MCPClientFetchStub, MCPClient, type ToolBinder } from "./mcp.ts";
5
+ import { z } from "zod";
10
6
 
11
7
  type ClientContext = Omit<
12
8
  RequestContext,
13
9
  "ensureAuthenticated" | "state" | "fetchIntegrationMetadata"
14
10
  >;
15
11
 
12
+ export interface Binding<TType extends string = string> {
13
+ __type: TType;
14
+ value: string;
15
+ }
16
+
17
+ /**
18
+ * A registry mapping binding type strings (e.g. "@deco/database") to their ToolBinder definitions.
19
+ * Used by ResolvedBindings to resolve binding types to their corresponding MCP client types.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * type MyBindings = {
24
+ * "@deco/database": typeof DATABASE_BINDING;
25
+ * "@deco/storage": typeof STORAGE_BINDING;
26
+ * };
27
+ * ```
28
+ */
29
+ export type BindingRegistry = Record<string, readonly ToolBinder[]>;
30
+
31
+ /**
32
+ * Function that returns Zod Schema
33
+ */
34
+ export const BindingOf = <TRegistry extends BindingRegistry>(
35
+ name: keyof TRegistry | "*",
36
+ ) => {
37
+ return z.object({
38
+ __type: z.literal(name).default(name as any),
39
+ value: z.string(),
40
+ });
41
+ };
42
+
43
+ /**
44
+ * Recursively transforms a type T by replacing all Binding instances with their
45
+ * corresponding MCPClientFetchStub based on the __type field.
46
+ *
47
+ * @template T - The source type to transform
48
+ * @template TBindings - A registry mapping binding __type strings to ToolBinder definitions
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * interface State {
53
+ * db: Binding<"@deco/database">;
54
+ * items: Array<Binding<"@deco/storage">>;
55
+ * config: { nested: Binding<"@deco/config"> };
56
+ * }
57
+ *
58
+ * type Resolved = ResolvedBindings<State, {
59
+ * "@deco/database": typeof DATABASE_BINDING;
60
+ * "@deco/storage": typeof STORAGE_BINDING;
61
+ * }>;
62
+ * // Result:
63
+ * // {
64
+ * // db: MCPClientFetchStub<typeof DATABASE_BINDING>;
65
+ * // items: Array<MCPClientFetchStub<typeof STORAGE_BINDING>>;
66
+ * // config: { nested: unknown }; // "@deco/config" not in registry
67
+ * // }
68
+ * ```
69
+ */
70
+ export type ResolvedBindings<
71
+ T,
72
+ TBindings extends BindingRegistry,
73
+ > = T extends Binding<infer TType>
74
+ ? TType extends keyof TBindings
75
+ ? MCPClientFetchStub<TBindings[TType]> & { __type: TType; value: string }
76
+ : MCPClientFetchStub<[]> & { __type: string; value: string }
77
+ : T extends Array<infer U>
78
+ ? Array<ResolvedBindings<U, TBindings>>
79
+ : T extends object
80
+ ? { [K in keyof T]: ResolvedBindings<T[K], TBindings> }
81
+ : T;
82
+
83
+ export const isBinding = (v: unknown): v is Binding => {
84
+ return (
85
+ typeof v === "object" &&
86
+ v !== null &&
87
+ "__type" in v &&
88
+ typeof v.__type === "string" &&
89
+ "value" in v &&
90
+ typeof v.value === "string"
91
+ );
92
+ };
93
+
16
94
  export const proxyConnectionForId = (
17
95
  connectionId: string,
18
96
  ctx: Omit<ClientContext, "token"> & {
@@ -36,65 +114,72 @@ export const proxyConnectionForId = (
36
114
  headers,
37
115
  };
38
116
  };
117
+
39
118
  const mcpClientForConnectionId = (
40
119
  connectionId: string,
41
120
  ctx: ClientContext,
42
121
  appName?: string,
43
122
  ) => {
44
123
  const mcpConnection = proxyConnectionForId(connectionId, ctx, appName);
45
-
46
- // TODO(@igorbrasileiro): Switch this proxy to be a proxy that call MCP Client.toolCall from @modelcontextprotocol
47
- return MCPClient.forConnection(mcpConnection);
124
+ return new Proxy(MCPClient.forConnection(mcpConnection), {
125
+ get(target, name) {
126
+ if (name === "value") {
127
+ return connectionId;
128
+ }
129
+ if (name === "__type") {
130
+ return appName;
131
+ }
132
+ return target[name as keyof typeof target];
133
+ },
134
+ });
48
135
  };
49
136
 
50
- function mcpClientFromState(
51
- binding: BindingBase | MCPAppBinding,
52
- env: DefaultEnv,
53
- ) {
54
- const ctx = env.MESH_REQUEST_CONTEXT;
55
- const bindingFromState = ctx?.state?.[binding.name];
56
- const connectionId =
57
- bindingFromState &&
58
- typeof bindingFromState === "object" &&
59
- "value" in bindingFromState
60
- ? bindingFromState.value
61
- : undefined;
62
- if (typeof connectionId !== "string" && "app_name" in binding) {
63
- // in case of a binding to an app name, we need to use the new apps/mcp endpoint which will proxy the request to the app but without any token
64
- return undefined;
137
+ const traverseAndReplace = (obj: unknown, ctx: ClientContext): unknown => {
138
+ // Handle null/undefined
139
+ if (obj === null || obj === undefined) {
140
+ return obj;
65
141
  }
66
- return mcpClientForConnectionId(connectionId, ctx);
67
- }
68
142
 
69
- export const createContractBinding = (
70
- binding: ContractBinding,
71
- env: DefaultEnv,
72
- ) => {
73
- return mcpClientFromState(binding, env);
74
- };
75
-
76
- export const createIntegrationBinding = (
77
- binding: MCPBinding,
78
- env: DefaultEnv,
79
- ) => {
80
- const connectionId =
81
- "connection_id" in binding ? binding.connection_id : undefined;
82
- if (!connectionId) {
83
- return mcpClientFromState(binding, env);
143
+ // Handle arrays
144
+ if (Array.isArray(obj)) {
145
+ return obj.map((item) => traverseAndReplace(item, ctx));
84
146
  }
85
- if (!env.MESH_RUNTIME_TOKEN) {
86
- throw new Error("MESH_RUNTIME_TOKEN is required");
87
- }
88
- if (!env.MESH_URL) {
89
- throw new Error("MESH_URL is required");
147
+
148
+ // Handle objects
149
+ if (typeof obj === "object") {
150
+ // Check if this is a binding
151
+ if (isBinding(obj)) {
152
+ return mcpClientForConnectionId(obj.value, ctx, obj.__type);
153
+ }
154
+
155
+ // Traverse object properties
156
+ const result: Record<string, unknown> = {};
157
+ for (const [key, value] of Object.entries(obj)) {
158
+ result[key] = traverseAndReplace(value, ctx);
159
+ }
160
+ return result;
90
161
  }
91
- // bindings pointed to an specific integration id are binded using the app deployment workspace
92
- return mcpClientForConnectionId(
93
- connectionId,
94
- {
95
- token: env.MESH_RUNTIME_TOKEN,
96
- meshUrl: env.MESH_URL,
97
- },
98
- env.MESH_APP_NAME,
99
- );
162
+
163
+ // Return primitives as-is
164
+ return obj;
100
165
  };
166
+
167
+ export const initializeBindings = <
168
+ T,
169
+ TBindings extends BindingRegistry = BindingRegistry,
170
+ >(
171
+ ctx: RequestContext,
172
+ ): void => {
173
+ // resolves the state in-place
174
+ traverseAndReplace(ctx.state, ctx) as ResolvedBindings<T, TBindings>;
175
+ };
176
+
177
+ interface DefaultRegistry extends BindingRegistry {
178
+ "@deco/mesh": CollectionBinding<{ hello: string }, "MESH">;
179
+ }
180
+
181
+ export interface XPTO {
182
+ MESH: Binding<"@deco/meh">;
183
+ }
184
+
185
+ export type XPTOResolved = ResolvedBindings<XPTO, DefaultRegistry>;
package/src/events.ts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  OnEventsOutput,
5
5
  } from "@decocms/bindings";
6
6
  import z from "zod";
7
+ import { isBinding } from "./bindings.ts";
7
8
 
8
9
  // ============================================================================
9
10
  // Types
@@ -14,11 +15,6 @@ export interface EventSubscription {
14
15
  publisher: string;
15
16
  }
16
17
 
17
- interface Binding {
18
- __type: string;
19
- value: string;
20
- }
21
-
22
18
  /**
23
19
  * Per-event handler - handles events of a specific type
24
20
  * Returns result for each event individually
@@ -118,17 +114,6 @@ export type BindingKeysOf<T> = {
118
114
  // Type Guards
119
115
  // ============================================================================
120
116
 
121
- const isBinding = (v: unknown): v is Binding => {
122
- return (
123
- typeof v === "object" &&
124
- v !== null &&
125
- "__type" in v &&
126
- typeof v.__type === "string" &&
127
- "value" in v &&
128
- typeof v.value === "string"
129
- );
130
- };
131
-
132
117
  /**
133
118
  * Check if handlers is a global batch handler (has handler + events at top level)
134
119
  */
package/src/index.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  /* oxlint-disable no-explicit-any */
2
2
  import { decodeJwt } from "jose";
3
3
  import type { z } from "zod";
4
- import { createContractBinding, createIntegrationBinding } from "./bindings.ts";
4
+ import {
5
+ BindingRegistry,
6
+ initializeBindings,
7
+ ResolvedBindings,
8
+ } from "./bindings.ts";
5
9
  import { type CORSOptions, handlePreflight, withCORS } from "./cors.ts";
6
10
  import { createOAuthHandlers } from "./oauth.ts";
7
11
  import { State } from "./state.ts";
@@ -10,8 +14,8 @@ import {
10
14
  type CreateMCPServerOptions,
11
15
  MCPServer,
12
16
  } from "./tools.ts";
13
- import type { Binding, ContractBinding, MCPBinding } from "./wrangler.ts";
14
- export { proxyConnectionForId } from "./bindings.ts";
17
+ import type { Binding } from "./wrangler.ts";
18
+ export { proxyConnectionForId, BindingOf } from "./bindings.ts";
15
19
  export { type CORSOptions, type CORSOrigin } from "./cors.ts";
16
20
  export {
17
21
  createMCPFetchStub,
@@ -19,9 +23,13 @@ export {
19
23
  type ToolBinder,
20
24
  } from "./mcp.ts";
21
25
 
22
- export interface DefaultEnv<TSchema extends z.ZodTypeAny = any> {
23
- MESH_REQUEST_CONTEXT: RequestContext<TSchema>;
24
- MESH_BINDINGS: string;
26
+ export type { BindingRegistry } from "./bindings.ts";
27
+
28
+ export interface DefaultEnv<
29
+ TSchema extends z.ZodTypeAny = any,
30
+ TBindings extends BindingRegistry = BindingRegistry,
31
+ > {
32
+ MESH_REQUEST_CONTEXT: RequestContext<TSchema, TBindings>;
25
33
  MESH_APP_DEPLOYMENT_ID: string;
26
34
  IS_LOCAL: boolean;
27
35
  MESH_URL?: string;
@@ -51,8 +59,10 @@ export const MCPBindings = {
51
59
  export interface UserDefaultExport<
52
60
  TUserEnv = Record<string, unknown>,
53
61
  TSchema extends z.ZodTypeAny = never,
54
- TEnv = TUserEnv & DefaultEnv<TSchema>,
55
- > extends CreateMCPServerOptions<TEnv, TSchema> {
62
+ TBindings extends BindingRegistry = BindingRegistry,
63
+ TEnv extends TUserEnv & DefaultEnv<TSchema, TBindings> = TUserEnv &
64
+ DefaultEnv<TSchema, TBindings>,
65
+ > extends CreateMCPServerOptions<TEnv, TSchema, TBindings> {
56
66
  fetch?: (req: Request, env: TEnv, ctx: any) => Promise<Response> | Response;
57
67
  /**
58
68
  * CORS configuration options.
@@ -61,12 +71,6 @@ export interface UserDefaultExport<
61
71
  cors?: CORSOptions | false;
62
72
  }
63
73
 
64
- // 1. Map binding type to its interface
65
- interface BindingTypeMap {
66
- mcp: MCPBinding;
67
- contract: ContractBinding;
68
- }
69
-
70
74
  export interface User {
71
75
  id: string;
72
76
  email: string;
@@ -79,8 +83,11 @@ export interface User {
79
83
  };
80
84
  }
81
85
 
82
- export interface RequestContext<TSchema extends z.ZodTypeAny = any> {
83
- state: z.infer<TSchema>;
86
+ export interface RequestContext<
87
+ TSchema extends z.ZodTypeAny = any,
88
+ TBindings extends BindingRegistry = BindingRegistry,
89
+ > {
90
+ state: ResolvedBindings<z.infer<TSchema>, TBindings>;
84
91
  token: string;
85
92
  meshUrl: string;
86
93
  authorization?: string | null;
@@ -91,20 +98,6 @@ export interface RequestContext<TSchema extends z.ZodTypeAny = any> {
91
98
  connectionId?: string;
92
99
  }
93
100
 
94
- // 2. Map binding type to its creator function
95
- type CreatorByType = {
96
- [K in keyof BindingTypeMap]: (
97
- value: BindingTypeMap[K],
98
- env: DefaultEnv,
99
- ) => unknown;
100
- };
101
-
102
- // 3. Strongly type creatorByType
103
- const creatorByType: CreatorByType = {
104
- mcp: createIntegrationBinding,
105
- contract: createContractBinding,
106
- };
107
-
108
101
  const withDefaultBindings = ({
109
102
  env,
110
103
  server,
@@ -159,7 +152,6 @@ export const withBindings = <TEnv>({
159
152
  server,
160
153
  tokenOrContext,
161
154
  url,
162
- bindings: inlineBindings,
163
155
  authToken,
164
156
  }: {
165
157
  env: TEnv;
@@ -169,7 +161,6 @@ export const withBindings = <TEnv>({
169
161
  // authToken is the authorization header
170
162
  authToken?: string | null;
171
163
  url?: string;
172
- bindings?: Binding[];
173
164
  }): TEnv => {
174
165
  const env = _env as DefaultEnv<any>;
175
166
  const authorization = authToken ? authToken.split(" ")[1] : undefined;
@@ -223,11 +214,7 @@ export const withBindings = <TEnv>({
223
214
  }
224
215
 
225
216
  env.MESH_REQUEST_CONTEXT = context;
226
- const bindings = inlineBindings ?? MCPBindings.parse(env.MESH_BINDINGS);
227
-
228
- for (const binding of bindings) {
229
- env[binding.name] = creatorByType[binding.type](binding as any, env);
230
- }
217
+ initializeBindings(context);
231
218
 
232
219
  withDefaultBindings({
233
220
  env,
@@ -252,19 +239,21 @@ const DEFAULT_CORS_OPTIONS = {
252
239
  allowHeaders: ["Content-Type", "Authorization", "mcp-protocol-version"],
253
240
  };
254
241
 
255
- export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
256
- userFns: UserDefaultExport<TEnv, TSchema>,
242
+ export const withRuntime = <
243
+ TUserEnv,
244
+ TSchema extends z.ZodTypeAny = never,
245
+ TBindings extends BindingRegistry = BindingRegistry,
246
+ TEnv extends TUserEnv & DefaultEnv<TSchema, TBindings> = TUserEnv &
247
+ DefaultEnv<TSchema, TBindings>,
248
+ >(
249
+ userFns: UserDefaultExport<TUserEnv, TSchema, TBindings>,
257
250
  ) => {
258
- const server = createMCPServer<TEnv, TSchema>(userFns);
251
+ const server = createMCPServer<TUserEnv, TSchema, TBindings>(userFns);
259
252
  const corsOptions = userFns.cors ?? DEFAULT_CORS_OPTIONS;
260
253
  const oauth = userFns.oauth;
261
254
  const oauthHandlers = oauth ? createOAuthHandlers(oauth) : null;
262
255
 
263
- const fetcher = async (
264
- req: Request,
265
- env: TEnv & DefaultEnv<TSchema>,
266
- ctx: any,
267
- ) => {
256
+ const fetcher = async (req: Request, env: TEnv, ctx: any) => {
268
257
  const url = new URL(req.url);
269
258
 
270
259
  // OAuth routes (when configured)
@@ -359,7 +348,7 @@ export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
359
348
  };
360
349
 
361
350
  return {
362
- fetch: async (req: Request, env: TEnv & DefaultEnv<TSchema>, ctx?: any) => {
351
+ fetch: async (req: Request, env: TEnv, ctx?: any) => {
363
352
  if (new URL(req.url).pathname === "/_healthcheck") {
364
353
  return new Response("OK", { status: 200 });
365
354
  }
@@ -373,7 +362,6 @@ export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
373
362
  authToken: req.headers.get("authorization") ?? null,
374
363
  env: { ...process.env, ...env },
375
364
  server,
376
- bindings: userFns.bindings,
377
365
  tokenOrContext: req.headers.get("x-mesh-token") ?? undefined,
378
366
  url: req.url,
379
367
  });
package/src/tools.ts CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
10
  import { z } from "zod";
11
11
  import { zodToJsonSchema } from "zod-to-json-schema";
12
+ import { BindingRegistry } from "./bindings.ts";
12
13
  import { Event, type EventHandlers } from "./events.ts";
13
14
  import type { DefaultEnv } from "./index.ts";
14
15
  import { State } from "./state.ts";
15
- import { Binding } from "./wrangler.ts";
16
16
 
17
17
  // Re-export EventHandlers type for external use
18
18
  export type { EventHandlers } from "./events.ts";
@@ -154,8 +154,8 @@ export function isStreamableTool(
154
154
  return tool && "streamable" in tool && tool.streamable === true;
155
155
  }
156
156
 
157
- export interface OnChangeCallback<TSchema extends z.ZodTypeAny = never> {
158
- state: z.infer<TSchema>;
157
+ export interface OnChangeCallback<TState> {
158
+ state: TState;
159
159
  scopes: string[];
160
160
  }
161
161
 
@@ -232,35 +232,34 @@ type PickByType<T, Value> = {
232
232
  export interface CreateMCPServerOptions<
233
233
  Env = unknown,
234
234
  TSchema extends z.ZodTypeAny = never,
235
+ TBindings extends BindingRegistry = BindingRegistry,
236
+ TEnv extends Env & DefaultEnv<TSchema, TBindings> = Env &
237
+ DefaultEnv<TSchema, TBindings>,
238
+ State extends
239
+ TEnv["MESH_REQUEST_CONTEXT"]["state"] = TEnv["MESH_REQUEST_CONTEXT"]["state"],
235
240
  > {
236
- before?: (env: Env & DefaultEnv<TSchema>) => Promise<void> | void;
241
+ before?: (env: TEnv) => Promise<void> | void;
237
242
  oauth?: OAuthConfig;
238
243
  events?: {
239
- bus?: keyof PickByType<Env & DefaultEnv<TSchema>, EventBusBindingClient>;
240
- handlers?: EventHandlers<Env & DefaultEnv<TSchema>, TSchema>;
244
+ bus?: keyof PickByType<TEnv, EventBusBindingClient>;
245
+ handlers?: EventHandlers<TEnv, TSchema>;
241
246
  };
242
247
  configuration?: {
243
- onChange?: (
244
- env: Env & DefaultEnv<TSchema>,
245
- cb: OnChangeCallback<TSchema>,
246
- ) => Promise<void>;
248
+ onChange?: (env: TEnv, cb: OnChangeCallback<State>) => Promise<void>;
247
249
  state?: TSchema;
248
250
  scopes?: string[];
249
251
  };
250
- bindings?: Binding[];
251
252
  tools?:
252
253
  | Array<
253
254
  (
254
- env: Env & DefaultEnv<TSchema>,
255
+ env: TEnv,
255
256
  ) =>
256
257
  | Promise<CreatedTool>
257
258
  | CreatedTool
258
259
  | CreatedTool[]
259
260
  | Promise<CreatedTool[]>
260
261
  >
261
- | ((
262
- env: Env & DefaultEnv<TSchema>,
263
- ) => CreatedTool[] | Promise<CreatedTool[]>);
262
+ | ((env: TEnv) => CreatedTool[] | Promise<CreatedTool[]>);
264
263
  }
265
264
 
266
265
  export type Fetch<TEnv = unknown> = (
@@ -361,9 +360,9 @@ const toolsFor = <TSchema extends z.ZodTypeAny = never>({
361
360
  return Promise.resolve({
362
361
  stateSchema: jsonSchema,
363
362
  scopes: [
364
- ...(scopes ?? []),
363
+ ...((scopes as string[]) ?? []),
365
364
  ...Event.scopes(events?.handlers ?? {}),
366
- ...(busProp ? [`${busProp}::EVENT_SYNC_SUBSCRIPTIONS`] : []),
365
+ ...(events ? [`${busProp}::EVENT_SYNC_SUBSCRIPTIONS`] : []),
367
366
  ],
368
367
  });
369
368
  },
@@ -376,18 +375,25 @@ type CallTool = (opts: {
376
375
  toolCallInput: unknown;
377
376
  }) => Promise<unknown>;
378
377
 
379
- export type MCPServer<TEnv = unknown, TSchema extends z.ZodTypeAny = never> = {
380
- fetch: Fetch<TEnv & DefaultEnv<TSchema>>;
378
+ export type MCPServer<
379
+ TEnv = unknown,
380
+ TSchema extends z.ZodTypeAny = never,
381
+ TBindings extends BindingRegistry = BindingRegistry,
382
+ > = {
383
+ fetch: Fetch<TEnv & DefaultEnv<TSchema, TBindings>>;
381
384
  callTool: CallTool;
382
385
  };
383
386
 
384
387
  export const createMCPServer = <
385
- TEnv = unknown,
388
+ Env = unknown,
386
389
  TSchema extends z.ZodTypeAny = never,
390
+ TBindings extends BindingRegistry = BindingRegistry,
391
+ TEnv extends Env & DefaultEnv<TSchema, TBindings> = Env &
392
+ DefaultEnv<TSchema, TBindings>,
387
393
  >(
388
- options: CreateMCPServerOptions<TEnv, TSchema>,
389
- ): MCPServer<TEnv, TSchema> => {
390
- const createServer = async (bindings: TEnv & DefaultEnv<TSchema>) => {
394
+ options: CreateMCPServerOptions<TEnv, TSchema, TBindings>,
395
+ ): MCPServer<TEnv, TSchema, TBindings> => {
396
+ const createServer = async (bindings: TEnv) => {
391
397
  await options.before?.(bindings);
392
398
 
393
399
  const server = new McpServer(
@@ -398,7 +404,7 @@ export const createMCPServer = <
398
404
  const toolsFn =
399
405
  typeof options.tools === "function"
400
406
  ? options.tools
401
- : async (bindings: TEnv & DefaultEnv<TSchema>) => {
407
+ : async (bindings: TEnv) => {
402
408
  if (typeof options.tools === "function") {
403
409
  return await options.tools(bindings);
404
410
  }
@@ -462,7 +468,7 @@ export const createMCPServer = <
462
468
  return { server, tools };
463
469
  };
464
470
 
465
- const fetch = async (req: Request, env: TEnv & DefaultEnv<TSchema>) => {
471
+ const fetch = async (req: Request, env: TEnv) => {
466
472
  const { server } = await createServer(env);
467
473
  const transport = new HttpServerTransport();
468
474
 
package/src/wrangler.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export interface BindingBase {
2
2
  name: string;
3
+ array?: true;
3
4
  }
4
5
 
5
6
  export interface MCPConnectionBinding extends BindingBase {
@@ -15,7 +16,7 @@ export interface MCPAppBinding extends BindingBase {
15
16
  /**
16
17
  * The name of the integration to bind.
17
18
  */
18
- app_name: string;
19
+ app_name?: string;
19
20
  }
20
21
  export interface ContractClause {
21
22
  id: string;