@decocms/runtime 1.0.0-alpha.2 → 1.0.0-alpha.21
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/config-schema.json +553 -0
- package/package.json +5 -14
- package/src/bindings/binder.ts +1 -4
- package/src/bindings/index.ts +0 -33
- package/src/bindings/language-model/utils.ts +0 -91
- package/src/bindings.ts +31 -110
- package/src/client.ts +1 -145
- package/src/cors.ts +140 -0
- package/src/index.ts +84 -167
- package/src/mcp.ts +7 -166
- package/src/proxy.ts +3 -54
- package/src/state.ts +3 -31
- package/src/tools.ts +372 -0
- package/src/wrangler.ts +5 -5
- package/tsconfig.json +1 -1
- package/src/admin.ts +0 -16
- package/src/auth.ts +0 -233
- package/src/bindings/deconfig/helpers.ts +0 -107
- package/src/bindings/deconfig/index.ts +0 -1
- package/src/bindings/deconfig/resources.ts +0 -689
- package/src/bindings/deconfig/types.ts +0 -106
- package/src/bindings/language-model/ai-sdk.ts +0 -90
- package/src/bindings/language-model/index.ts +0 -4
- package/src/bindings/resources/bindings.ts +0 -99
- package/src/bindings/resources/helpers.ts +0 -95
- package/src/bindings/resources/schemas.ts +0 -265
- package/src/bindings/views.ts +0 -14
- package/src/drizzle.ts +0 -201
- package/src/mastra.ts +0 -670
- package/src/resources.ts +0 -168
- package/src/views.ts +0 -26
- package/src/well-known.ts +0 -20
package/src/mastra.ts
DELETED
|
@@ -1,670 +0,0 @@
|
|
|
1
|
-
/* oxlint-disable no-explicit-any */
|
|
2
|
-
/* oxlint-disable ban-types */
|
|
3
|
-
import { HttpServerTransport } from "@deco/mcp/http";
|
|
4
|
-
import {
|
|
5
|
-
createTool as mastraCreateTool,
|
|
6
|
-
Tool,
|
|
7
|
-
type ToolAction,
|
|
8
|
-
type ToolExecutionContext,
|
|
9
|
-
} from "@mastra/core";
|
|
10
|
-
import { RuntimeContext } from "@mastra/core/di";
|
|
11
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
-
import { z } from "zod";
|
|
13
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
14
|
-
import type { DefaultEnv } from "./index.ts";
|
|
15
|
-
import {
|
|
16
|
-
ResourceCreateInputSchema,
|
|
17
|
-
ResourceCreateOutputSchema,
|
|
18
|
-
ResourceDeleteInputSchema,
|
|
19
|
-
ResourceDeleteOutputSchema,
|
|
20
|
-
ResourceSearchInputSchema,
|
|
21
|
-
ResourceSearchOutputSchema,
|
|
22
|
-
ResourcesListOutputSchema,
|
|
23
|
-
ResourcesReadInputSchema,
|
|
24
|
-
ResourcesReadOutputSchema,
|
|
25
|
-
ResourceUpdateInputSchema,
|
|
26
|
-
ResourceUpdateOutputSchema,
|
|
27
|
-
} from "./resources.ts";
|
|
28
|
-
import { createStateValidationTool, State } from "./state.ts";
|
|
29
|
-
import { ViewsListOutputSchema } from "./views.ts";
|
|
30
|
-
|
|
31
|
-
export const createRuntimeContext = (prev?: RuntimeContext<AppContext>) => {
|
|
32
|
-
const runtimeContext = new RuntimeContext<AppContext>();
|
|
33
|
-
const store = State.getStore();
|
|
34
|
-
if (!store) {
|
|
35
|
-
if (prev) {
|
|
36
|
-
return prev;
|
|
37
|
-
}
|
|
38
|
-
throw new Error("Missing context, did you forget to call State.bind?");
|
|
39
|
-
}
|
|
40
|
-
const { env, ctx, req } = store;
|
|
41
|
-
runtimeContext.set("env", env);
|
|
42
|
-
runtimeContext.set("ctx", ctx);
|
|
43
|
-
runtimeContext.set("req", req);
|
|
44
|
-
return runtimeContext;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* creates a private tool that always ensure for athentication before being executed
|
|
49
|
-
*/
|
|
50
|
-
export function createPrivateTool<
|
|
51
|
-
TSchemaIn extends z.ZodSchema = z.ZodSchema,
|
|
52
|
-
TSchemaOut extends z.ZodSchema | undefined = undefined,
|
|
53
|
-
TSuspendSchema extends z.ZodSchema = z.ZodSchema,
|
|
54
|
-
TResumeSchema extends z.ZodSchema = z.ZodSchema,
|
|
55
|
-
TContext extends
|
|
56
|
-
ToolExecutionContext<TSchemaIn> = ToolExecutionContext<TSchemaIn>,
|
|
57
|
-
TExecute extends ToolAction<
|
|
58
|
-
TSchemaIn,
|
|
59
|
-
TSchemaOut,
|
|
60
|
-
any,
|
|
61
|
-
any,
|
|
62
|
-
TContext
|
|
63
|
-
>["execute"] = ToolAction<
|
|
64
|
-
TSchemaIn,
|
|
65
|
-
TSchemaOut,
|
|
66
|
-
any,
|
|
67
|
-
any,
|
|
68
|
-
TContext
|
|
69
|
-
>["execute"],
|
|
70
|
-
>(
|
|
71
|
-
opts: ToolAction<
|
|
72
|
-
TSchemaIn,
|
|
73
|
-
TSchemaOut,
|
|
74
|
-
TSuspendSchema,
|
|
75
|
-
TResumeSchema,
|
|
76
|
-
TContext
|
|
77
|
-
> & {
|
|
78
|
-
execute?: TExecute;
|
|
79
|
-
},
|
|
80
|
-
): [TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TExecute] extends [
|
|
81
|
-
z.ZodSchema,
|
|
82
|
-
z.ZodSchema,
|
|
83
|
-
z.ZodSchema,
|
|
84
|
-
z.ZodSchema,
|
|
85
|
-
Function,
|
|
86
|
-
]
|
|
87
|
-
? Tool<TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TContext> & {
|
|
88
|
-
inputSchema: TSchemaIn;
|
|
89
|
-
outputSchema: TSchemaOut;
|
|
90
|
-
execute: (context: TContext) => Promise<any>;
|
|
91
|
-
}
|
|
92
|
-
: Tool<TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TContext> {
|
|
93
|
-
const execute = opts.execute;
|
|
94
|
-
if (typeof execute === "function") {
|
|
95
|
-
opts.execute = ((input, options) => {
|
|
96
|
-
const env = input.runtimeContext.get("env") as DefaultEnv;
|
|
97
|
-
if (env) {
|
|
98
|
-
env.DECO_REQUEST_CONTEXT.ensureAuthenticated();
|
|
99
|
-
}
|
|
100
|
-
return execute(input, options);
|
|
101
|
-
}) as TExecute;
|
|
102
|
-
}
|
|
103
|
-
return createTool(opts);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface StreamableTool<TSchemaIn extends z.ZodSchema = z.ZodSchema> {
|
|
107
|
-
id: string;
|
|
108
|
-
inputSchema: TSchemaIn;
|
|
109
|
-
streamable?: true;
|
|
110
|
-
description?: string;
|
|
111
|
-
execute: (input: ToolExecutionContext<TSchemaIn>) => Promise<Response>;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function createStreamableTool<
|
|
115
|
-
TSchemaIn extends z.ZodSchema = z.ZodSchema,
|
|
116
|
-
>(streamableTool: StreamableTool<TSchemaIn>): StreamableTool<TSchemaIn> {
|
|
117
|
-
return {
|
|
118
|
-
...streamableTool,
|
|
119
|
-
execute: (input: ToolExecutionContext<TSchemaIn>) => {
|
|
120
|
-
const env = input.runtimeContext.get("env") as DefaultEnv;
|
|
121
|
-
if (env) {
|
|
122
|
-
env.DECO_REQUEST_CONTEXT.ensureAuthenticated();
|
|
123
|
-
}
|
|
124
|
-
return streamableTool.execute({
|
|
125
|
-
...input,
|
|
126
|
-
runtimeContext: createRuntimeContext(input.runtimeContext),
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function createTool<
|
|
133
|
-
TSchemaIn extends z.ZodSchema | undefined = undefined,
|
|
134
|
-
TSchemaOut extends z.ZodSchema | undefined = undefined,
|
|
135
|
-
TSuspendSchema extends z.ZodSchema = z.ZodSchema,
|
|
136
|
-
TResumeSchema extends z.ZodSchema = z.ZodSchema,
|
|
137
|
-
TContext extends ToolExecutionContext<
|
|
138
|
-
TSchemaIn,
|
|
139
|
-
TSuspendSchema,
|
|
140
|
-
TResumeSchema
|
|
141
|
-
> = ToolExecutionContext<TSchemaIn, TSuspendSchema, TResumeSchema>,
|
|
142
|
-
TExecute extends ToolAction<
|
|
143
|
-
TSchemaIn,
|
|
144
|
-
TSchemaOut,
|
|
145
|
-
TSuspendSchema,
|
|
146
|
-
TResumeSchema,
|
|
147
|
-
TContext
|
|
148
|
-
>["execute"] = ToolAction<
|
|
149
|
-
TSchemaIn,
|
|
150
|
-
TSchemaOut,
|
|
151
|
-
TSuspendSchema,
|
|
152
|
-
TResumeSchema,
|
|
153
|
-
TContext
|
|
154
|
-
>["execute"],
|
|
155
|
-
>(
|
|
156
|
-
opts: ToolAction<
|
|
157
|
-
TSchemaIn,
|
|
158
|
-
TSchemaOut,
|
|
159
|
-
TSuspendSchema,
|
|
160
|
-
TResumeSchema,
|
|
161
|
-
TContext
|
|
162
|
-
> & {
|
|
163
|
-
execute?: TExecute;
|
|
164
|
-
},
|
|
165
|
-
): [TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TExecute] extends [
|
|
166
|
-
z.ZodSchema,
|
|
167
|
-
z.ZodSchema,
|
|
168
|
-
z.ZodSchema,
|
|
169
|
-
z.ZodSchema,
|
|
170
|
-
Function,
|
|
171
|
-
]
|
|
172
|
-
? Tool<TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TContext> & {
|
|
173
|
-
inputSchema: TSchemaIn;
|
|
174
|
-
outputSchema: TSchemaOut;
|
|
175
|
-
execute: (context: TContext) => Promise<any>;
|
|
176
|
-
}
|
|
177
|
-
: Tool<TSchemaIn, TSchemaOut, TSuspendSchema, TResumeSchema, TContext> {
|
|
178
|
-
// @ts-expect-error - TSchemaIn is not a ZodType
|
|
179
|
-
return mastraCreateTool({
|
|
180
|
-
...opts,
|
|
181
|
-
execute:
|
|
182
|
-
typeof opts?.execute === "function"
|
|
183
|
-
? (((input) => {
|
|
184
|
-
return opts.execute!({
|
|
185
|
-
...input,
|
|
186
|
-
runtimeContext: createRuntimeContext(input.runtimeContext),
|
|
187
|
-
});
|
|
188
|
-
}) as TExecute)
|
|
189
|
-
: opts.execute,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export type ExecWithContext<TF extends (...args: any[]) => any> = (
|
|
194
|
-
input: Omit<Parameters<TF>[0], "runtimeContext"> & {
|
|
195
|
-
runtimeContext: RuntimeContext<AppContext>;
|
|
196
|
-
},
|
|
197
|
-
) => ReturnType<TF>;
|
|
198
|
-
|
|
199
|
-
export interface ViewExport {
|
|
200
|
-
title: string;
|
|
201
|
-
icon: string;
|
|
202
|
-
url: string;
|
|
203
|
-
tools?: string[];
|
|
204
|
-
rules?: string[];
|
|
205
|
-
installBehavior?: "none" | "open" | "autoPin";
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export type Resources<Env = any, TSchema extends z.ZodTypeAny = never> = Array<
|
|
209
|
-
(env: Env & DefaultEnv<TSchema>) => {
|
|
210
|
-
name: string;
|
|
211
|
-
icon: string;
|
|
212
|
-
title: string;
|
|
213
|
-
description?: string;
|
|
214
|
-
tools: {
|
|
215
|
-
read: (args: { uri: string }) => Promise<unknown>;
|
|
216
|
-
search: (args: {
|
|
217
|
-
term: string;
|
|
218
|
-
cursor?: string;
|
|
219
|
-
limit?: number;
|
|
220
|
-
}) => Promise<unknown>;
|
|
221
|
-
create?: (
|
|
222
|
-
args: z.infer<typeof ResourceCreateInputSchema>,
|
|
223
|
-
) => Promise<unknown>;
|
|
224
|
-
update?: (
|
|
225
|
-
args: z.infer<typeof ResourceUpdateInputSchema>,
|
|
226
|
-
) => Promise<unknown>;
|
|
227
|
-
delete?: (
|
|
228
|
-
args: z.infer<typeof ResourceDeleteInputSchema>,
|
|
229
|
-
) => Promise<unknown>;
|
|
230
|
-
};
|
|
231
|
-
views?: {
|
|
232
|
-
list?: { url?: string; tools?: string[]; rules?: string[] };
|
|
233
|
-
detail?: {
|
|
234
|
-
url?: string;
|
|
235
|
-
mimeTypePattern?: string;
|
|
236
|
-
resourceName?: string;
|
|
237
|
-
tools?: string[];
|
|
238
|
-
rules?: string[];
|
|
239
|
-
};
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
>;
|
|
243
|
-
export interface Integration {
|
|
244
|
-
id: string;
|
|
245
|
-
appId: string;
|
|
246
|
-
}
|
|
247
|
-
export type CreatedTool =
|
|
248
|
-
| ReturnType<typeof createTool>
|
|
249
|
-
| ReturnType<typeof createStreamableTool>;
|
|
250
|
-
export function isStreamableTool(tool: CreatedTool): tool is StreamableTool {
|
|
251
|
-
return tool && "streamable" in tool && tool.streamable === true;
|
|
252
|
-
}
|
|
253
|
-
export interface CreateMCPServerOptions<
|
|
254
|
-
Env = any,
|
|
255
|
-
TSchema extends z.ZodTypeAny = never,
|
|
256
|
-
> {
|
|
257
|
-
before?: (env: Env & DefaultEnv<TSchema>) => Promise<void> | void;
|
|
258
|
-
oauth?: {
|
|
259
|
-
state?: TSchema;
|
|
260
|
-
scopes?: string[];
|
|
261
|
-
};
|
|
262
|
-
views?: (
|
|
263
|
-
env: Env & DefaultEnv<TSchema>,
|
|
264
|
-
) => Promise<ViewExport[]> | ViewExport[];
|
|
265
|
-
resources?: Resources<Env, TSchema>;
|
|
266
|
-
tools?:
|
|
267
|
-
| Array<
|
|
268
|
-
(
|
|
269
|
-
env: Env & DefaultEnv<TSchema>,
|
|
270
|
-
) =>
|
|
271
|
-
| Promise<CreatedTool>
|
|
272
|
-
| CreatedTool
|
|
273
|
-
| CreatedTool[]
|
|
274
|
-
| Promise<CreatedTool[]>
|
|
275
|
-
>
|
|
276
|
-
| ((
|
|
277
|
-
env: Env & DefaultEnv<TSchema>,
|
|
278
|
-
) => CreatedTool[] | Promise<CreatedTool[]>);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
export type Fetch<TEnv = any> = (
|
|
282
|
-
req: Request,
|
|
283
|
-
env: TEnv,
|
|
284
|
-
ctx: ExecutionContext,
|
|
285
|
-
) => Promise<Response> | Response;
|
|
286
|
-
|
|
287
|
-
export interface AppContext<TEnv = any> {
|
|
288
|
-
env: TEnv;
|
|
289
|
-
ctx: { waitUntil: (promise: Promise<any>) => void };
|
|
290
|
-
req?: Request;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const decoChatOAuthToolsFor = <TSchema extends z.ZodTypeAny = never>({
|
|
294
|
-
state: schema,
|
|
295
|
-
scopes,
|
|
296
|
-
}: CreateMCPServerOptions<any, TSchema>["oauth"] = {}) => {
|
|
297
|
-
const jsonSchema = schema
|
|
298
|
-
? zodToJsonSchema(schema)
|
|
299
|
-
: { type: "object", properties: {} };
|
|
300
|
-
return [
|
|
301
|
-
createTool({
|
|
302
|
-
id: "DECO_CHAT_OAUTH_START",
|
|
303
|
-
description: "OAuth for Deco Chat",
|
|
304
|
-
inputSchema: z.object({
|
|
305
|
-
returnUrl: z.string(),
|
|
306
|
-
}),
|
|
307
|
-
outputSchema: z.object({
|
|
308
|
-
stateSchema: z.any(),
|
|
309
|
-
scopes: z.array(z.string()).optional(),
|
|
310
|
-
}),
|
|
311
|
-
execute: () => {
|
|
312
|
-
return Promise.resolve({
|
|
313
|
-
stateSchema: jsonSchema,
|
|
314
|
-
scopes,
|
|
315
|
-
});
|
|
316
|
-
},
|
|
317
|
-
}),
|
|
318
|
-
];
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
type CallTool = (opts: {
|
|
322
|
-
toolCallId: string;
|
|
323
|
-
toolCallInput: any;
|
|
324
|
-
}) => Promise<any>;
|
|
325
|
-
|
|
326
|
-
export type MCPServer<TEnv = any, TSchema extends z.ZodTypeAny = never> = {
|
|
327
|
-
fetch: Fetch<TEnv & DefaultEnv<TSchema>>;
|
|
328
|
-
callTool: CallTool;
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
export const createMCPServer = <
|
|
332
|
-
TEnv = any,
|
|
333
|
-
TSchema extends z.ZodTypeAny = never,
|
|
334
|
-
>(
|
|
335
|
-
options: CreateMCPServerOptions<TEnv, TSchema>,
|
|
336
|
-
): MCPServer<TEnv, TSchema> => {
|
|
337
|
-
const createServer = async (bindings: TEnv & DefaultEnv<TSchema>) => {
|
|
338
|
-
await options.before?.(bindings);
|
|
339
|
-
|
|
340
|
-
const server = new McpServer(
|
|
341
|
-
{ name: "@deco/mcp-api", version: "1.0.0" },
|
|
342
|
-
{ capabilities: { tools: {} } },
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
// Resolve resources first; build resource tools; append later
|
|
346
|
-
const resolvedResources = await Promise.all(
|
|
347
|
-
options.resources?.map((r) => r(bindings)) ?? [],
|
|
348
|
-
);
|
|
349
|
-
const readHandlers = new Map<
|
|
350
|
-
string,
|
|
351
|
-
(a: { uri: string }) => Promise<any>
|
|
352
|
-
>();
|
|
353
|
-
const searchHandlers = new Map<
|
|
354
|
-
string,
|
|
355
|
-
(a: { term: string; cursor?: string; limit?: number }) => Promise<any>
|
|
356
|
-
>();
|
|
357
|
-
const createHandlers = new Map<string, (a: any) => Promise<any>>();
|
|
358
|
-
const updateHandlers = new Map<string, (a: any) => Promise<any>>();
|
|
359
|
-
const deleteHandlers = new Map<string, (a: any) => Promise<any>>();
|
|
360
|
-
for (const r of resolvedResources) {
|
|
361
|
-
if (r?.tools?.read) readHandlers.set(r.name, r.tools.read);
|
|
362
|
-
if (r?.tools?.search) searchHandlers.set(r.name, r.tools.search);
|
|
363
|
-
if (r?.tools?.create) createHandlers.set(r.name, r.tools.create);
|
|
364
|
-
if (r?.tools?.update) updateHandlers.set(r.name, r.tools.update);
|
|
365
|
-
if (r?.tools?.delete) deleteHandlers.set(r.name, r.tools.delete);
|
|
366
|
-
}
|
|
367
|
-
const resourceTools: ReturnType<typeof createTool>[] = [];
|
|
368
|
-
if (resolvedResources.length > 0) {
|
|
369
|
-
resourceTools.push(
|
|
370
|
-
createTool({
|
|
371
|
-
id: "DECO_CHAT_RESOURCES_READ",
|
|
372
|
-
description: "Read a resource by uri (name + uri)",
|
|
373
|
-
inputSchema: ResourcesReadInputSchema,
|
|
374
|
-
outputSchema: ResourcesReadOutputSchema,
|
|
375
|
-
execute: (input) => {
|
|
376
|
-
// @ts-expect-error - input.name is not a string
|
|
377
|
-
const fn = readHandlers.get(input.name);
|
|
378
|
-
if (!fn) {
|
|
379
|
-
// @ts-expect-error - input.name is not a string
|
|
380
|
-
throw new Error(`READ not implemented for ${input.name}`);
|
|
381
|
-
}
|
|
382
|
-
// @ts-expect-error - input.name is not a string
|
|
383
|
-
return fn({ uri: input.uri });
|
|
384
|
-
},
|
|
385
|
-
}),
|
|
386
|
-
);
|
|
387
|
-
resourceTools.push(
|
|
388
|
-
createTool({
|
|
389
|
-
id: "DECO_CHAT_RESOURCES_SEARCH",
|
|
390
|
-
description: "Search resources (name + term)",
|
|
391
|
-
inputSchema: ResourceSearchInputSchema,
|
|
392
|
-
outputSchema: ResourceSearchOutputSchema,
|
|
393
|
-
execute: (input) => {
|
|
394
|
-
// @ts-expect-error - input.name is not a string
|
|
395
|
-
const fn = searchHandlers.get(input.name);
|
|
396
|
-
if (!fn) {
|
|
397
|
-
// @ts-expect-error - input.name is not a string
|
|
398
|
-
throw new Error(`SEARCH not implemented for ${input.name}`);
|
|
399
|
-
}
|
|
400
|
-
// @ts-expect-error - input.name is not a string
|
|
401
|
-
const { term, cursor, limit } = input;
|
|
402
|
-
return fn({ term, cursor, limit });
|
|
403
|
-
},
|
|
404
|
-
}),
|
|
405
|
-
);
|
|
406
|
-
resourceTools.push(
|
|
407
|
-
createTool({
|
|
408
|
-
id: "DECO_CHAT_RESOURCES_CREATE",
|
|
409
|
-
description: "Create a resource (name + content)",
|
|
410
|
-
inputSchema: ResourceCreateInputSchema,
|
|
411
|
-
outputSchema: ResourceCreateOutputSchema,
|
|
412
|
-
execute: (input) => {
|
|
413
|
-
// @ts-expect-error - input.name is not a string
|
|
414
|
-
const fn = createHandlers.get(input.name);
|
|
415
|
-
if (!fn) {
|
|
416
|
-
// @ts-expect-error - input.name is not a string
|
|
417
|
-
throw new Error(`CREATE not implemented for ${input.name}`);
|
|
418
|
-
}
|
|
419
|
-
return fn(input);
|
|
420
|
-
},
|
|
421
|
-
}),
|
|
422
|
-
);
|
|
423
|
-
resourceTools.push(
|
|
424
|
-
createTool({
|
|
425
|
-
id: "DECO_CHAT_RESOURCES_UPDATE",
|
|
426
|
-
description: "Update a resource (name + uri)",
|
|
427
|
-
inputSchema: ResourceUpdateInputSchema,
|
|
428
|
-
outputSchema: ResourceUpdateOutputSchema,
|
|
429
|
-
execute: (input) => {
|
|
430
|
-
// @ts-expect-error - input.name is not a string
|
|
431
|
-
const fn = updateHandlers.get(input.name);
|
|
432
|
-
if (!fn) {
|
|
433
|
-
// @ts-expect-error - input.name is not a string
|
|
434
|
-
throw new Error(`UPDATE not implemented for ${input.name}`);
|
|
435
|
-
}
|
|
436
|
-
return fn(input);
|
|
437
|
-
},
|
|
438
|
-
}),
|
|
439
|
-
);
|
|
440
|
-
resourceTools.push(
|
|
441
|
-
createTool({
|
|
442
|
-
id: "DECO_CHAT_RESOURCES_DELETE",
|
|
443
|
-
description: "Delete a resource (name + uri)",
|
|
444
|
-
inputSchema: ResourceDeleteInputSchema,
|
|
445
|
-
outputSchema: ResourceDeleteOutputSchema,
|
|
446
|
-
execute: (input) => {
|
|
447
|
-
// @ts-expect-error - input.name is not a string
|
|
448
|
-
const fn = deleteHandlers.get(input.name);
|
|
449
|
-
if (!fn) {
|
|
450
|
-
// @ts-expect-error - input.name is not a string
|
|
451
|
-
throw new Error(`DELETE not implemented for ${input.name}`);
|
|
452
|
-
}
|
|
453
|
-
return fn(input);
|
|
454
|
-
},
|
|
455
|
-
}),
|
|
456
|
-
);
|
|
457
|
-
resourceTools.push(
|
|
458
|
-
createTool({
|
|
459
|
-
id: "DECO_CHAT_RESOURCES_LIST",
|
|
460
|
-
description: "List resource types",
|
|
461
|
-
inputSchema: z.object({}),
|
|
462
|
-
outputSchema: ResourcesListOutputSchema,
|
|
463
|
-
execute: () =>
|
|
464
|
-
Promise.resolve({
|
|
465
|
-
resources: resolvedResources.map((r) => ({
|
|
466
|
-
name: r.name,
|
|
467
|
-
icon: r.icon,
|
|
468
|
-
title: r.title,
|
|
469
|
-
description: r.description ?? "",
|
|
470
|
-
hasCreate: Boolean(createHandlers.get(r.name)),
|
|
471
|
-
hasUpdate: Boolean(updateHandlers.get(r.name)),
|
|
472
|
-
hasDelete: Boolean(deleteHandlers.get(r.name)),
|
|
473
|
-
})),
|
|
474
|
-
}),
|
|
475
|
-
}),
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
const toolsFn =
|
|
480
|
-
typeof options.tools === "function"
|
|
481
|
-
? options.tools
|
|
482
|
-
: async (bindings: TEnv & DefaultEnv<TSchema>) => {
|
|
483
|
-
if (typeof options.tools === "function") {
|
|
484
|
-
return await options.tools(bindings);
|
|
485
|
-
}
|
|
486
|
-
return await Promise.all(
|
|
487
|
-
options.tools?.flatMap(async (tool) => {
|
|
488
|
-
const toolResult = tool(bindings);
|
|
489
|
-
const awaited = await toolResult;
|
|
490
|
-
if (Array.isArray(awaited)) {
|
|
491
|
-
return awaited;
|
|
492
|
-
}
|
|
493
|
-
return [awaited];
|
|
494
|
-
}) ?? [],
|
|
495
|
-
).then((t) => t.flat());
|
|
496
|
-
};
|
|
497
|
-
const tools = await toolsFn(bindings);
|
|
498
|
-
|
|
499
|
-
tools.push(...decoChatOAuthToolsFor<TSchema>(options.oauth));
|
|
500
|
-
tools.push(createStateValidationTool(options.oauth?.state));
|
|
501
|
-
|
|
502
|
-
tools.push(
|
|
503
|
-
createTool({
|
|
504
|
-
id: `DECO_CHAT_VIEWS_LIST`,
|
|
505
|
-
description: "List views exposed by this MCP",
|
|
506
|
-
inputSchema: z.any(),
|
|
507
|
-
outputSchema: ViewsListOutputSchema,
|
|
508
|
-
execute: async () => {
|
|
509
|
-
const base = ((await options.views?.(bindings)) ?? []).map((v) => ({
|
|
510
|
-
id: undefined,
|
|
511
|
-
// Stable machine name for routing: UPPERCASE + underscores
|
|
512
|
-
name: v.title.toUpperCase().replace(/[^A-Z0-9]/g, "_"),
|
|
513
|
-
title: v.title,
|
|
514
|
-
description: undefined,
|
|
515
|
-
icon: v.icon,
|
|
516
|
-
url: v.url,
|
|
517
|
-
tools: v.tools ?? [],
|
|
518
|
-
rules: v.rules ?? [],
|
|
519
|
-
installBehavior: v.installBehavior ?? "none",
|
|
520
|
-
}));
|
|
521
|
-
const resourceViews = resolvedResources
|
|
522
|
-
.map((r) => {
|
|
523
|
-
const listUrl =
|
|
524
|
-
r.views?.list?.url ??
|
|
525
|
-
`internal://resource/list?name=${encodeURIComponent(r.name)}`;
|
|
526
|
-
|
|
527
|
-
// Default CRUD tool ids for resources
|
|
528
|
-
const defaultListTools: string[] = (() => {
|
|
529
|
-
const base = [
|
|
530
|
-
"DECO_CHAT_RESOURCES_LIST",
|
|
531
|
-
"DECO_CHAT_RESOURCES_READ",
|
|
532
|
-
"DECO_CHAT_RESOURCES_SEARCH",
|
|
533
|
-
];
|
|
534
|
-
const canCreate = Boolean(createHandlers.get(r.name));
|
|
535
|
-
const canUpdate = Boolean(updateHandlers.get(r.name));
|
|
536
|
-
const canDelete = Boolean(deleteHandlers.get(r.name));
|
|
537
|
-
if (canCreate) base.push("DECO_CHAT_RESOURCES_CREATE");
|
|
538
|
-
if (canUpdate) base.push("DECO_CHAT_RESOURCES_UPDATE");
|
|
539
|
-
if (canDelete) base.push("DECO_CHAT_RESOURCES_DELETE");
|
|
540
|
-
return base;
|
|
541
|
-
})();
|
|
542
|
-
|
|
543
|
-
const defaultListRules: string[] = [
|
|
544
|
-
`You are viewing the ${
|
|
545
|
-
r.title ?? r.name
|
|
546
|
-
} resources list. Resources are changeable via Resource tools (DECO_CHAT_RESOURCES_*). Use the appropriate tools to read, search, create, update, or delete items; do not fabricate data.`,
|
|
547
|
-
];
|
|
548
|
-
|
|
549
|
-
const list = [
|
|
550
|
-
{
|
|
551
|
-
name: `${r.name.toUpperCase()}_LIST`,
|
|
552
|
-
title: `${r.name} List`,
|
|
553
|
-
description: r.description,
|
|
554
|
-
icon: r.icon,
|
|
555
|
-
url: listUrl,
|
|
556
|
-
tools: r.views?.list?.tools ?? defaultListTools,
|
|
557
|
-
rules: r.views?.list?.rules ?? defaultListRules,
|
|
558
|
-
},
|
|
559
|
-
];
|
|
560
|
-
const detailUrl =
|
|
561
|
-
r.views?.detail?.url ??
|
|
562
|
-
`internal://resource/detail?name=${encodeURIComponent(r.name)}`;
|
|
563
|
-
const detail = [
|
|
564
|
-
{
|
|
565
|
-
name: `${r.name.toUpperCase()}_DETAIL`,
|
|
566
|
-
title: `${r.name} Detail`,
|
|
567
|
-
description: r.description,
|
|
568
|
-
icon: r.icon,
|
|
569
|
-
url: detailUrl,
|
|
570
|
-
mimeTypePattern: r.views?.detail?.mimeTypePattern,
|
|
571
|
-
resourceName: r.views?.detail?.resourceName ?? r.name,
|
|
572
|
-
tools: r.views?.detail?.tools ?? [],
|
|
573
|
-
rules: r.views?.detail?.rules ?? [],
|
|
574
|
-
},
|
|
575
|
-
];
|
|
576
|
-
return [...list, ...detail];
|
|
577
|
-
})
|
|
578
|
-
.flat();
|
|
579
|
-
|
|
580
|
-
return { views: [...base, ...resourceViews] };
|
|
581
|
-
},
|
|
582
|
-
}),
|
|
583
|
-
);
|
|
584
|
-
|
|
585
|
-
for (const tool of tools) {
|
|
586
|
-
server.registerTool(
|
|
587
|
-
tool.id,
|
|
588
|
-
{
|
|
589
|
-
_meta: {
|
|
590
|
-
streamable: isStreamableTool(tool),
|
|
591
|
-
},
|
|
592
|
-
description: tool.description,
|
|
593
|
-
inputSchema:
|
|
594
|
-
tool.inputSchema && "shape" in tool.inputSchema
|
|
595
|
-
? (tool.inputSchema.shape as z.ZodRawShape)
|
|
596
|
-
: z.object({}).shape,
|
|
597
|
-
outputSchema: isStreamableTool(tool)
|
|
598
|
-
? z.object({ bytes: z.record(z.string(), z.number()) }).shape
|
|
599
|
-
: tool.outputSchema &&
|
|
600
|
-
typeof tool.outputSchema === "object" &&
|
|
601
|
-
"shape" in tool.outputSchema
|
|
602
|
-
? (tool.outputSchema.shape as z.ZodRawShape)
|
|
603
|
-
: z.object({}).shape,
|
|
604
|
-
},
|
|
605
|
-
async (args) => {
|
|
606
|
-
let result = await tool.execute!({
|
|
607
|
-
context: args,
|
|
608
|
-
runId: crypto.randomUUID(),
|
|
609
|
-
runtimeContext: createRuntimeContext(),
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
if (isStreamableTool(tool) && result instanceof Response) {
|
|
613
|
-
result = { bytes: await result.bytes() };
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
structuredContent: result,
|
|
617
|
-
content: [
|
|
618
|
-
{
|
|
619
|
-
type: "text",
|
|
620
|
-
text: JSON.stringify(result),
|
|
621
|
-
},
|
|
622
|
-
],
|
|
623
|
-
};
|
|
624
|
-
},
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
return { server, tools };
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
const fetch = async (
|
|
632
|
-
req: Request,
|
|
633
|
-
env: TEnv & DefaultEnv<TSchema>,
|
|
634
|
-
_ctx: ExecutionContext,
|
|
635
|
-
) => {
|
|
636
|
-
const { server } = await createServer(env);
|
|
637
|
-
const transport = new HttpServerTransport();
|
|
638
|
-
|
|
639
|
-
await server.connect(transport);
|
|
640
|
-
|
|
641
|
-
return await transport.handleMessage(req);
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
const callTool: CallTool = async ({ toolCallId, toolCallInput }) => {
|
|
645
|
-
const currentState = State.getStore();
|
|
646
|
-
if (!currentState) {
|
|
647
|
-
throw new Error("Missing state, did you forget to call State.bind?");
|
|
648
|
-
}
|
|
649
|
-
const env = currentState?.env;
|
|
650
|
-
const { tools } = await createServer(env);
|
|
651
|
-
const tool = tools.find((t) => t.id === toolCallId);
|
|
652
|
-
const execute = tool?.execute;
|
|
653
|
-
if (!execute) {
|
|
654
|
-
throw new Error(
|
|
655
|
-
`Tool ${toolCallId} not found or does not have an execute function`,
|
|
656
|
-
);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
return execute({
|
|
660
|
-
context: toolCallInput,
|
|
661
|
-
runId: crypto.randomUUID(),
|
|
662
|
-
runtimeContext: createRuntimeContext(),
|
|
663
|
-
});
|
|
664
|
-
};
|
|
665
|
-
|
|
666
|
-
return {
|
|
667
|
-
fetch,
|
|
668
|
-
callTool,
|
|
669
|
-
};
|
|
670
|
-
};
|