@epic-web/workshop-mcp 6.54.0 → 6.54.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/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
5
5
  import * as Sentry from '@sentry/node';
6
6
  import { initPrompts } from "./prompts.js";
7
7
  import { initResources } from "./resources.js";
8
+ import { serverInstructions } from "./server-metadata.js";
8
9
  import { initPromptTools, initResourceTools, initTools } from "./tools.js";
9
10
  // Get environment variables
10
11
  const env = getEnv();
@@ -27,16 +28,7 @@ const server = new McpServer({
27
28
  },
28
29
  // TODO: add some common workflows to the instructions
29
30
  {
30
- instructions: `
31
- This is intended to be used within a workshop using the Epic Workshop App
32
- (@epic-web/workshop-app) to help learners in the process of completing the
33
- workshop exercises and understanding the learning outcomes.
34
-
35
- The user's work in progress is in the \`playground\` directory. Any changes they
36
- ask you to make should be in this directory.
37
-
38
- Most of the time you should use the \`get_what_is_next\` tool to get the next step the user needs to complete.
39
- `.trim(),
31
+ instructions: serverInstructions,
40
32
  });
41
33
  // Wrap with Sentry if enabled
42
34
  const monitoredServer = env.EPICSHOP_IS_PUBLISHED && env.SENTRY_DSN
package/dist/prompts.js CHANGED
@@ -2,13 +2,14 @@ import { getExercises } from '@epic-web/workshop-utils/apps.server';
2
2
  import { getWorkshopConfig } from '@epic-web/workshop-utils/config.server';
3
3
  import { z } from 'zod';
4
4
  import { exerciseContextResource } from "./resources.js";
5
+ import { formatPromptDescription, promptDocs } from "./server-metadata.js";
5
6
  import { handleWorkshopDirectory, workshopDirectoryInputSchema, } from "./utils.js";
6
7
  export const quizMeInputSchema = {
7
8
  workshopDirectory: workshopDirectoryInputSchema,
8
9
  exerciseNumber: z
9
10
  .string()
10
11
  .optional()
11
- .describe(`The exercise number to get quizzed on (e.g., \`4\`). Leave blank for a random exercise.`),
12
+ .describe('Exercise number to quiz on (e.g., "4"). Omit for a random exercise.'),
12
13
  };
13
14
  export async function quizMe({ workshopDirectory, exerciseNumber: providedExerciseNumber, }) {
14
15
  const workshopRoot = await handleWorkshopDirectory(workshopDirectory);
@@ -49,8 +50,8 @@ Please use this context to provide quiz questions, one at a time, to me to help
49
50
  }
50
51
  export function initPrompts(server) {
51
52
  server.registerPrompt('quiz_me', {
52
- title: 'Quiz Me',
53
- description: 'Have the LLM quiz you on topics from the workshop exercises',
53
+ title: promptDocs.quiz_me.title,
54
+ description: formatPromptDescription(promptDocs.quiz_me),
54
55
  argsSchema: quizMeInputSchema,
55
56
  }, quizMe);
56
57
  }
package/dist/resources.js CHANGED
@@ -5,6 +5,7 @@ import { getAuthInfo } from '@epic-web/workshop-utils/db.server';
5
5
  import { getEpicVideoInfos, userHasAccessToWorkshop, getUserInfo, getProgress, } from '@epic-web/workshop-utils/epic-api.server';
6
6
  import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
7
7
  import { z } from 'zod';
8
+ import { resourceDocs } from "./server-metadata.js";
8
9
  import { handleWorkshopDirectory, readInWorkshop, safeReadFile, workshopDirectoryInputSchema, } from "./utils.js";
9
10
  export const getWorkshopContextInputSchema = {
10
11
  workshopDirectory: workshopDirectoryInputSchema,
@@ -82,8 +83,8 @@ export async function getWorkshopContextResource({ workshopDirectory, }) {
82
83
  };
83
84
  }
84
85
  export const workshopContextResource = {
85
- name: 'workshop_context',
86
- description: 'The context of the workshop',
86
+ name: resourceDocs.workshop_context.name,
87
+ description: resourceDocs.workshop_context.description,
87
88
  uriTemplate: workshopContextUriTemplate,
88
89
  getResource: getWorkshopContextResource,
89
90
  inputSchema: getWorkshopContextInputSchema,
@@ -93,7 +94,7 @@ const getExerciseContextInputSchema = {
93
94
  exerciseNumber: z.coerce
94
95
  .number()
95
96
  .optional()
96
- .describe(`The exercise number to get the context for (defaults to the exercise number the playground is currently set to)`),
97
+ .describe(`Exercise number to fetch (defaults to the current playground exercise if omitted).`),
97
98
  };
98
99
  async function getExerciseContext({ workshopDirectory, exerciseNumber, }) {
99
100
  const { userHasAccess, authInfo, progress, numbers } = await getCommonContextData(workshopDirectory);
@@ -189,8 +190,8 @@ async function getExerciseContextResource({ workshopDirectory, exerciseNumber, }
189
190
  };
190
191
  }
191
192
  export const exerciseContextResource = {
192
- name: 'exercise_context',
193
- description: 'The context of the exercise',
193
+ name: resourceDocs.exercise_context.name,
194
+ description: resourceDocs.exercise_context.description,
194
195
  uriTemplate: exerciseContextUriTemplate,
195
196
  getResource: getExerciseContextResource,
196
197
  inputSchema: getExerciseContextInputSchema,
@@ -274,10 +275,10 @@ const getExerciseStepContextInputSchema = {
274
275
  workshopDirectory: workshopDirectoryInputSchema,
275
276
  exerciseNumber: z.coerce
276
277
  .number()
277
- .describe('The exercise number to get the context for'),
278
+ .describe('Exercise number to fetch (1-based).'),
278
279
  stepNumber: z.coerce
279
280
  .number()
280
- .describe('The step number to get the context for'),
281
+ .describe('Step number to fetch within the exercise (1-based).'),
281
282
  };
282
283
  async function getExerciseStepContext({ workshopDirectory, exerciseNumber, stepNumber, }) {
283
284
  const { userHasAccess, authInfo, progress, numbers } = await getCommonContextData(workshopDirectory);
@@ -354,16 +355,20 @@ async function getExerciseStepContextResource({ workshopDirectory, exerciseNumbe
354
355
  };
355
356
  }
356
357
  export const exerciseStepContextResource = {
357
- name: 'exercise_step_context',
358
- description: 'The context of a specific exercise step',
358
+ name: resourceDocs.exercise_step_context.name,
359
+ description: resourceDocs.exercise_step_context.description,
359
360
  uriTemplate: exerciseStepContextUriTemplate,
360
361
  getResource: getExerciseStepContextResource,
361
362
  inputSchema: getExerciseStepContextInputSchema,
362
363
  };
363
364
  const diffBetweenAppsInputSchema = {
364
365
  workshopDirectory: workshopDirectoryInputSchema,
365
- app1: z.string().describe('The ID of the first app'),
366
- app2: z.string().describe('The ID of the second app'),
366
+ app1: z
367
+ .string()
368
+ .describe('First app ID (format: "02.03.problem" or "02.03.solution").'),
369
+ app2: z
370
+ .string()
371
+ .describe('Second app ID (format: "02.03.problem" or "02.03.solution").'),
367
372
  };
368
373
  async function getDiffBetweenApps({ workshopDirectory, app1, app2, }) {
369
374
  await handleWorkshopDirectory(workshopDirectory);
@@ -401,8 +406,8 @@ async function getDiffBetweenAppsResource({ workshopDirectory, app1, app2, }) {
401
406
  }
402
407
  const diffBetweenAppsUriTemplate = new ResourceTemplate('epicshop://{workshopDirectory}/diff-between-apps/{app1}__vs___{app2}', { list: undefined });
403
408
  export const diffBetweenAppsResource = {
404
- name: 'diff_between_apps',
405
- description: 'The diff between two apps',
409
+ name: resourceDocs.diff_between_apps.name,
410
+ description: resourceDocs.diff_between_apps.description,
406
411
  uriTemplate: diffBetweenAppsUriTemplate,
407
412
  getResource: getDiffBetweenAppsResource,
408
413
  inputSchema: diffBetweenAppsInputSchema,
@@ -438,8 +443,8 @@ async function getExerciseStepProgressDiffResource({ workshopDirectory, }) {
438
443
  };
439
444
  }
440
445
  export const exerciseStepProgressDiffResource = {
441
- name: 'exercise_step_progress_diff',
442
- description: 'The diff between the current exercise step and the solution',
446
+ name: resourceDocs.exercise_step_progress_diff.name,
447
+ description: resourceDocs.exercise_step_progress_diff.description,
443
448
  uriTemplate: exerciseStepProgressDiffUriTemplate,
444
449
  getResource: getExerciseStepProgressDiffResource,
445
450
  inputSchema: getExerciseStepProgressDiffInputSchema,
@@ -459,8 +464,8 @@ async function getUserInfoResource({ workshopDirectory, }) {
459
464
  };
460
465
  }
461
466
  export const userInfoResource = {
462
- name: 'user_info',
463
- description: 'Information about the current user',
467
+ name: resourceDocs.user_info.name,
468
+ description: resourceDocs.user_info.description,
464
469
  uriTemplate: userInfoUri,
465
470
  getResource: getUserInfoResource,
466
471
  inputSchema: getUserInfoInputSchema,
@@ -480,8 +485,8 @@ async function getUserAccessResource({ workshopDirectory, }) {
480
485
  };
481
486
  }
482
487
  export const userAccessResource = {
483
- name: 'user_access',
484
- description: 'Whether the current user has access to the workshop',
488
+ name: resourceDocs.user_access.name,
489
+ description: resourceDocs.user_access.description,
485
490
  uriTemplate: userAccessUriTemplate,
486
491
  getResource: getUserAccessResource,
487
492
  inputSchema: getUserAccessInputSchema,
@@ -501,8 +506,8 @@ async function getUserProgressResource({ workshopDirectory, }) {
501
506
  };
502
507
  }
503
508
  export const userProgressResource = {
504
- name: 'user_progress',
505
- description: 'The progress of the current user',
509
+ name: resourceDocs.user_progress.name,
510
+ description: resourceDocs.user_progress.description,
506
511
  uriTemplate: userProgressUriTemplate,
507
512
  getResource: getUserProgressResource,
508
513
  inputSchema: userProgressInputSchema,
@@ -0,0 +1,476 @@
1
+ export type ToolAnnotationHints = {
2
+ readOnlyHint: boolean;
3
+ destructiveHint: boolean;
4
+ idempotentHint: boolean;
5
+ openWorldHint: boolean;
6
+ };
7
+ type ToolInputDoc = {
8
+ name: string;
9
+ type: string;
10
+ required: boolean;
11
+ description: string;
12
+ examples?: Array<string>;
13
+ };
14
+ type ToolExampleDoc = {
15
+ description: string;
16
+ params: string;
17
+ };
18
+ export type ToolDoc = {
19
+ title: string;
20
+ summary: string;
21
+ inputs: Array<ToolInputDoc>;
22
+ returns: string;
23
+ examples: Array<ToolExampleDoc>;
24
+ nextSteps: Array<string>;
25
+ errorNextSteps?: Array<string>;
26
+ annotations: ToolAnnotationHints;
27
+ };
28
+ type PromptDoc = {
29
+ title: string;
30
+ description: string;
31
+ examples: Array<string>;
32
+ nextSteps: Array<string>;
33
+ };
34
+ export declare const serverInstructions: string;
35
+ export declare const toolDocs: {
36
+ login: {
37
+ title: string;
38
+ summary: string;
39
+ inputs: {
40
+ name: string;
41
+ type: string;
42
+ required: true;
43
+ description: string;
44
+ examples: string[];
45
+ }[];
46
+ returns: string;
47
+ examples: {
48
+ description: string;
49
+ params: string;
50
+ }[];
51
+ nextSteps: string[];
52
+ errorNextSteps: string[];
53
+ annotations: {
54
+ readOnlyHint: false;
55
+ destructiveHint: false;
56
+ idempotentHint: false;
57
+ openWorldHint: true;
58
+ };
59
+ };
60
+ logout: {
61
+ title: string;
62
+ summary: string;
63
+ inputs: {
64
+ name: string;
65
+ type: string;
66
+ required: true;
67
+ description: string;
68
+ examples: string[];
69
+ }[];
70
+ returns: string;
71
+ examples: {
72
+ description: string;
73
+ params: string;
74
+ }[];
75
+ nextSteps: string[];
76
+ annotations: {
77
+ readOnlyHint: false;
78
+ destructiveHint: false;
79
+ idempotentHint: false;
80
+ openWorldHint: false;
81
+ };
82
+ };
83
+ set_playground: {
84
+ title: string;
85
+ summary: string;
86
+ inputs: ({
87
+ name: string;
88
+ type: string;
89
+ required: true;
90
+ description: string;
91
+ examples: string[];
92
+ } | {
93
+ name: string;
94
+ type: string;
95
+ required: false;
96
+ description: string;
97
+ examples: string[];
98
+ })[];
99
+ returns: string;
100
+ examples: {
101
+ description: string;
102
+ params: string;
103
+ }[];
104
+ nextSteps: string[];
105
+ errorNextSteps: string[];
106
+ annotations: {
107
+ readOnlyHint: false;
108
+ destructiveHint: false;
109
+ idempotentHint: false;
110
+ openWorldHint: false;
111
+ };
112
+ };
113
+ update_progress: {
114
+ title: string;
115
+ summary: string;
116
+ inputs: ({
117
+ name: string;
118
+ type: string;
119
+ required: true;
120
+ description: string;
121
+ examples: string[];
122
+ } | {
123
+ name: string;
124
+ type: string;
125
+ required: false;
126
+ description: string;
127
+ examples: string[];
128
+ })[];
129
+ returns: string;
130
+ examples: {
131
+ description: string;
132
+ params: string;
133
+ }[];
134
+ nextSteps: string[];
135
+ errorNextSteps: string[];
136
+ annotations: {
137
+ readOnlyHint: false;
138
+ destructiveHint: false;
139
+ idempotentHint: false;
140
+ openWorldHint: true;
141
+ };
142
+ };
143
+ get_workshop_context: {
144
+ title: string;
145
+ summary: string;
146
+ inputs: {
147
+ name: string;
148
+ type: string;
149
+ required: true;
150
+ description: string;
151
+ examples: string[];
152
+ }[];
153
+ returns: string;
154
+ examples: {
155
+ description: string;
156
+ params: string;
157
+ }[];
158
+ nextSteps: string[];
159
+ annotations: {
160
+ readOnlyHint: true;
161
+ destructiveHint: false;
162
+ idempotentHint: true;
163
+ openWorldHint: true;
164
+ };
165
+ };
166
+ get_exercise_context: {
167
+ title: string;
168
+ summary: string;
169
+ inputs: ({
170
+ name: string;
171
+ type: string;
172
+ required: true;
173
+ description: string;
174
+ examples: string[];
175
+ } | {
176
+ name: string;
177
+ type: string;
178
+ required: false;
179
+ description: string;
180
+ examples: string[];
181
+ })[];
182
+ returns: string;
183
+ examples: {
184
+ description: string;
185
+ params: string;
186
+ }[];
187
+ nextSteps: string[];
188
+ annotations: {
189
+ readOnlyHint: true;
190
+ destructiveHint: false;
191
+ idempotentHint: true;
192
+ openWorldHint: true;
193
+ };
194
+ };
195
+ get_diff_between_apps: {
196
+ title: string;
197
+ summary: string;
198
+ inputs: {
199
+ name: string;
200
+ type: string;
201
+ required: true;
202
+ description: string;
203
+ examples: string[];
204
+ }[];
205
+ returns: string;
206
+ examples: {
207
+ description: string;
208
+ params: string;
209
+ }[];
210
+ nextSteps: string[];
211
+ annotations: {
212
+ readOnlyHint: true;
213
+ destructiveHint: false;
214
+ idempotentHint: true;
215
+ openWorldHint: false;
216
+ };
217
+ };
218
+ get_exercise_step_progress_diff: {
219
+ title: string;
220
+ summary: string;
221
+ inputs: {
222
+ name: string;
223
+ type: string;
224
+ required: true;
225
+ description: string;
226
+ examples: string[];
227
+ }[];
228
+ returns: string;
229
+ examples: {
230
+ description: string;
231
+ params: string;
232
+ }[];
233
+ nextSteps: string[];
234
+ annotations: {
235
+ readOnlyHint: true;
236
+ destructiveHint: false;
237
+ idempotentHint: true;
238
+ openWorldHint: false;
239
+ };
240
+ };
241
+ get_exercise_step_context: {
242
+ title: string;
243
+ summary: string;
244
+ inputs: {
245
+ name: string;
246
+ type: string;
247
+ required: true;
248
+ description: string;
249
+ examples: string[];
250
+ }[];
251
+ returns: string;
252
+ examples: {
253
+ description: string;
254
+ params: string;
255
+ }[];
256
+ nextSteps: string[];
257
+ annotations: {
258
+ readOnlyHint: true;
259
+ destructiveHint: false;
260
+ idempotentHint: true;
261
+ openWorldHint: true;
262
+ };
263
+ };
264
+ view_video: {
265
+ title: string;
266
+ summary: string;
267
+ inputs: {
268
+ name: string;
269
+ type: string;
270
+ required: true;
271
+ description: string;
272
+ examples: string[];
273
+ }[];
274
+ returns: string;
275
+ examples: {
276
+ description: string;
277
+ params: string;
278
+ }[];
279
+ nextSteps: string[];
280
+ annotations: {
281
+ readOnlyHint: true;
282
+ destructiveHint: false;
283
+ idempotentHint: true;
284
+ openWorldHint: true;
285
+ };
286
+ };
287
+ open_exercise_step_files: {
288
+ title: string;
289
+ summary: string;
290
+ inputs: {
291
+ name: string;
292
+ type: string;
293
+ required: true;
294
+ description: string;
295
+ examples: string[];
296
+ }[];
297
+ returns: string;
298
+ examples: {
299
+ description: string;
300
+ params: string;
301
+ }[];
302
+ nextSteps: string[];
303
+ annotations: {
304
+ readOnlyHint: false;
305
+ destructiveHint: false;
306
+ idempotentHint: false;
307
+ openWorldHint: false;
308
+ };
309
+ };
310
+ get_user_info: {
311
+ title: string;
312
+ summary: string;
313
+ inputs: {
314
+ name: string;
315
+ type: string;
316
+ required: true;
317
+ description: string;
318
+ examples: string[];
319
+ }[];
320
+ returns: string;
321
+ examples: {
322
+ description: string;
323
+ params: string;
324
+ }[];
325
+ nextSteps: string[];
326
+ annotations: {
327
+ readOnlyHint: true;
328
+ destructiveHint: false;
329
+ idempotentHint: true;
330
+ openWorldHint: true;
331
+ };
332
+ };
333
+ get_user_access: {
334
+ title: string;
335
+ summary: string;
336
+ inputs: {
337
+ name: string;
338
+ type: string;
339
+ required: true;
340
+ description: string;
341
+ examples: string[];
342
+ }[];
343
+ returns: string;
344
+ examples: {
345
+ description: string;
346
+ params: string;
347
+ }[];
348
+ nextSteps: string[];
349
+ annotations: {
350
+ readOnlyHint: true;
351
+ destructiveHint: false;
352
+ idempotentHint: true;
353
+ openWorldHint: true;
354
+ };
355
+ };
356
+ get_user_progress: {
357
+ title: string;
358
+ summary: string;
359
+ inputs: {
360
+ name: string;
361
+ type: string;
362
+ required: true;
363
+ description: string;
364
+ examples: string[];
365
+ }[];
366
+ returns: string;
367
+ examples: {
368
+ description: string;
369
+ params: string;
370
+ }[];
371
+ nextSteps: string[];
372
+ annotations: {
373
+ readOnlyHint: true;
374
+ destructiveHint: false;
375
+ idempotentHint: true;
376
+ openWorldHint: true;
377
+ };
378
+ };
379
+ get_quiz_instructions: {
380
+ title: string;
381
+ summary: string;
382
+ inputs: ({
383
+ name: string;
384
+ type: string;
385
+ required: true;
386
+ description: string;
387
+ examples: string[];
388
+ } | {
389
+ name: string;
390
+ type: string;
391
+ required: false;
392
+ description: string;
393
+ examples: string[];
394
+ })[];
395
+ returns: string;
396
+ examples: {
397
+ description: string;
398
+ params: string;
399
+ }[];
400
+ nextSteps: string[];
401
+ annotations: {
402
+ readOnlyHint: true;
403
+ destructiveHint: false;
404
+ idempotentHint: true;
405
+ openWorldHint: false;
406
+ };
407
+ };
408
+ get_what_is_next: {
409
+ title: string;
410
+ summary: string;
411
+ inputs: {
412
+ name: string;
413
+ type: string;
414
+ required: true;
415
+ description: string;
416
+ examples: string[];
417
+ }[];
418
+ returns: string;
419
+ examples: {
420
+ description: string;
421
+ params: string;
422
+ }[];
423
+ nextSteps: string[];
424
+ annotations: {
425
+ readOnlyHint: true;
426
+ destructiveHint: false;
427
+ idempotentHint: false;
428
+ openWorldHint: true;
429
+ };
430
+ };
431
+ };
432
+ export declare const promptDocs: {
433
+ quiz_me: {
434
+ title: string;
435
+ description: string;
436
+ examples: string[];
437
+ nextSteps: string[];
438
+ };
439
+ };
440
+ export declare const resourceDocs: {
441
+ workshop_context: {
442
+ name: string;
443
+ description: string;
444
+ };
445
+ exercise_context: {
446
+ name: string;
447
+ description: string;
448
+ };
449
+ exercise_step_context: {
450
+ name: string;
451
+ description: string;
452
+ };
453
+ diff_between_apps: {
454
+ name: string;
455
+ description: string;
456
+ };
457
+ exercise_step_progress_diff: {
458
+ name: string;
459
+ description: string;
460
+ };
461
+ user_info: {
462
+ name: string;
463
+ description: string;
464
+ };
465
+ user_access: {
466
+ name: string;
467
+ description: string;
468
+ };
469
+ user_progress: {
470
+ name: string;
471
+ description: string;
472
+ };
473
+ };
474
+ export declare function formatToolDescription(doc: ToolDoc): string;
475
+ export declare function formatPromptDescription(doc: PromptDoc): string;
476
+ export {};