@decocms/runtime 1.0.0-alpha.41 → 1.0.0-alpha.42

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/runtime",
3
- "version": "1.0.0-alpha.41",
3
+ "version": "1.0.0-alpha.42",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",
package/src/index.ts CHANGED
@@ -14,6 +14,15 @@ import {
14
14
  type CreateMCPServerOptions,
15
15
  MCPServer,
16
16
  } from "./tools.ts";
17
+ export {
18
+ createPrompt,
19
+ createPublicPrompt,
20
+ type Prompt,
21
+ type PromptArgsRawShape,
22
+ type PromptExecutionContext,
23
+ type CreatedPrompt,
24
+ type GetPromptResult,
25
+ } from "./tools.ts";
17
26
  import type { Binding } from "./wrangler.ts";
18
27
  export { proxyConnectionForId, BindingOf } from "./bindings.ts";
19
28
  export { type CORSOptions, type CORSOrigin } from "./cors.ts";
package/src/tools.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  type EventBusBindingClient,
8
8
  } from "@decocms/bindings";
9
9
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
10
11
  import { z } from "zod";
11
12
  import { zodToJsonSchema } from "zod-to-json-schema";
12
13
  import { BindingRegistry } from "./bindings.ts";
@@ -81,6 +82,58 @@ export type CreatedTool = {
81
82
  }): Promise<unknown>;
82
83
  };
83
84
 
85
+ // Re-export GetPromptResult for external use
86
+ export type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
87
+
88
+ /**
89
+ * Prompt argument schema shape - must be string types per MCP specification.
90
+ * Unlike tool arguments, prompt arguments are always strings.
91
+ */
92
+ export type PromptArgsRawShape = {
93
+ [k: string]:
94
+ | z.ZodType<string, z.ZodTypeDef, string>
95
+ | z.ZodOptional<z.ZodType<string, z.ZodTypeDef, string>>;
96
+ };
97
+
98
+ /**
99
+ * Context passed to prompt execute functions.
100
+ */
101
+ export interface PromptExecutionContext<
102
+ TArgs extends PromptArgsRawShape = PromptArgsRawShape,
103
+ > {
104
+ args: z.objectOutputType<TArgs, z.ZodTypeAny>;
105
+ runtimeContext: AppContext;
106
+ }
107
+
108
+ /**
109
+ * Prompt interface with generic argument types for type-safe prompt creation.
110
+ */
111
+ export interface Prompt<TArgs extends PromptArgsRawShape = PromptArgsRawShape> {
112
+ name: string;
113
+ title?: string;
114
+ description?: string;
115
+ argsSchema?: TArgs;
116
+ execute(
117
+ context: PromptExecutionContext<TArgs>,
118
+ ): Promise<GetPromptResult> | GetPromptResult;
119
+ }
120
+
121
+ /**
122
+ * CreatedPrompt is a permissive type that any Prompt can be assigned to.
123
+ * Uses a structural type with relaxed execute signature to allow prompts with any schema.
124
+ */
125
+ export type CreatedPrompt = {
126
+ name: string;
127
+ title?: string;
128
+ description?: string;
129
+ argsSchema?: PromptArgsRawShape;
130
+ // Use a permissive execute signature - accepts any args shape
131
+ execute(context: {
132
+ args: Record<string, string | undefined>;
133
+ runtimeContext: AppContext;
134
+ }): Promise<GetPromptResult> | GetPromptResult;
135
+ };
136
+
84
137
  /**
85
138
  * creates a private tool that always ensure for athentication before being executed
86
139
  */
@@ -134,6 +187,43 @@ export function createTool<
134
187
  };
135
188
  }
136
189
 
190
+ /**
191
+ * Creates a public prompt that does not require authentication.
192
+ */
193
+ export function createPublicPrompt<TArgs extends PromptArgsRawShape>(
194
+ opts: Prompt<TArgs>,
195
+ ): Prompt<TArgs> {
196
+ return {
197
+ ...opts,
198
+ execute: (input: PromptExecutionContext<TArgs>) => {
199
+ return opts.execute({
200
+ ...input,
201
+ runtimeContext: createRuntimeContext(input.runtimeContext),
202
+ });
203
+ },
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Creates a prompt that always ensures authentication before being executed.
209
+ * This is the default and recommended way to create prompts.
210
+ */
211
+ export function createPrompt<TArgs extends PromptArgsRawShape>(
212
+ opts: Prompt<TArgs>,
213
+ ): Prompt<TArgs> {
214
+ const execute = opts.execute;
215
+ return createPublicPrompt({
216
+ ...opts,
217
+ execute: (input: PromptExecutionContext<TArgs>) => {
218
+ const env = input.runtimeContext.env;
219
+ if (env) {
220
+ env.MESH_REQUEST_CONTEXT?.ensureAuthenticated();
221
+ }
222
+ return execute(input);
223
+ },
224
+ });
225
+ }
226
+
137
227
  export interface ViewExport {
138
228
  title: string;
139
229
  icon: string;
@@ -260,6 +350,17 @@ export interface CreateMCPServerOptions<
260
350
  | Promise<CreatedTool[]>
261
351
  >
262
352
  | ((env: TEnv) => CreatedTool[] | Promise<CreatedTool[]>);
353
+ prompts?:
354
+ | Array<
355
+ (
356
+ env: TEnv,
357
+ ) =>
358
+ | Promise<CreatedPrompt>
359
+ | CreatedPrompt
360
+ | CreatedPrompt[]
361
+ | Promise<CreatedPrompt[]>
362
+ >
363
+ | ((env: TEnv) => CreatedPrompt[] | Promise<CreatedPrompt[]>);
263
364
  }
264
365
 
265
366
  export type Fetch<TEnv = unknown> = (
@@ -399,7 +500,7 @@ export const createMCPServer = <
399
500
 
400
501
  const server = new McpServer(
401
502
  { name: "@deco/mcp-api", version: "1.0.0" },
402
- { capabilities: { tools: {} } },
503
+ { capabilities: { tools: {}, prompts: {} } },
403
504
  );
404
505
 
405
506
  const toolsFn =
@@ -466,7 +567,45 @@ export const createMCPServer = <
466
567
  );
467
568
  }
468
569
 
469
- return { server, tools };
570
+ // Resolve and register prompts
571
+ const promptsFn =
572
+ typeof options.prompts === "function"
573
+ ? options.prompts
574
+ : async (bindings: TEnv) => {
575
+ if (typeof options.prompts === "function") {
576
+ return await options.prompts(bindings);
577
+ }
578
+ return await Promise.all(
579
+ options.prompts?.flatMap(async (prompt) => {
580
+ const promptResult = prompt(bindings);
581
+ const awaited = await promptResult;
582
+ if (Array.isArray(awaited)) {
583
+ return awaited;
584
+ }
585
+ return [awaited];
586
+ }) ?? [],
587
+ ).then((p) => p.flat());
588
+ };
589
+ const prompts = await promptsFn(bindings);
590
+
591
+ for (const prompt of prompts) {
592
+ server.registerPrompt(
593
+ prompt.name,
594
+ {
595
+ title: prompt.title,
596
+ description: prompt.description,
597
+ argsSchema: prompt.argsSchema,
598
+ },
599
+ async (args) => {
600
+ return await prompt.execute({
601
+ args: args as Record<string, string | undefined>,
602
+ runtimeContext: createRuntimeContext(),
603
+ });
604
+ },
605
+ );
606
+ }
607
+
608
+ return { server, tools, prompts };
470
609
  };
471
610
 
472
611
  const fetch = async (req: Request, env: TEnv) => {