@epic-web/workshop-mcp 5.13.4 → 5.13.6

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/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  Configure the MCP for your project with `npx -y @epic-web/workshop-mcp`.
4
4
 
5
- Ask your LLM what it can do.
5
+ Ask your LLM what it can do. And it'll tell you.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
+ import { z } from 'zod';
7
+ // Create server instance
8
+ const server = new McpServer({
9
+ name: 'epicshop',
10
+ version: '1.0.0',
11
+ capabilities: {
12
+ tools: {},
13
+ },
14
+ }, {
15
+ instructions: `
16
+ This is intended to be used within a workshop using the Epic Workshop App
17
+ (@epic-web/workshop-app) to help learners in the process of completing the
18
+ workshop exercises and understanding the learning outcomes.
19
+
20
+ The user's work in progress is in the \`playground\` directory. Any changes they
21
+ ask you to make should be in this directory.
22
+ `.trim(),
23
+ });
24
+ server.tool('get_exercise_step_progress_diff', `
25
+ Intended to help a student understand what work they still have to complete.
26
+
27
+ This returns a git diff of the playground directory as BASE (their work in
28
+ progress) against the solution directory as HEAD (the final state they're trying
29
+ to achieve). Meaning, if there are lines removed, it means they still need to
30
+ add those lines and if they are added, it means they still need to remove them.
31
+
32
+ If there's a diff with significant changes, you should explain what the changes
33
+ are and their significance. Be brief. Let them tell you whether they need you to
34
+ elaborate.
35
+
36
+ For additional context, you can use the \`get_exercise_step_instructions\` tool
37
+ to get the instructions for the current exercise step to help explain the
38
+ significance of changes.
39
+ `.trim(), {
40
+ workshopDirectory: z
41
+ .string()
42
+ .describe('The workshop directory (the root directory of the workshop repo. Best to not bother asking the user and just use the project root path).'),
43
+ }, async ({ workshopDirectory }) => {
44
+ if (workshopDirectory.endsWith('playground')) {
45
+ workshopDirectory = path.join(workshopDirectory, '..');
46
+ }
47
+ process.env.EPICSHOP_CONTEXT_CWD = workshopDirectory;
48
+ const { getApps, isPlaygroundApp, findSolutionDir, getFullPathFromAppName, init, } = await import('@epic-web/workshop-utils/apps.server');
49
+ await init();
50
+ const { getDiffOutputWithRelativePaths } = await import('@epic-web/workshop-utils/diff.server');
51
+ const apps = await getApps();
52
+ const playgroundApp = apps.find(isPlaygroundApp);
53
+ if (!playgroundApp) {
54
+ return {
55
+ content: [{ type: 'text', text: 'No playground app found' }],
56
+ isError: true,
57
+ };
58
+ }
59
+ const baseApp = playgroundApp;
60
+ const solutionDir = await findSolutionDir({
61
+ fullPath: await getFullPathFromAppName(playgroundApp.appName),
62
+ });
63
+ const headApp = apps.find((a) => a.fullPath === solutionDir);
64
+ if (!headApp) {
65
+ return {
66
+ content: [{ type: 'text', text: 'No playground solution app found' }],
67
+ isError: true,
68
+ };
69
+ }
70
+ const diffCode = await getDiffOutputWithRelativePaths(baseApp, headApp);
71
+ if (!diffCode) {
72
+ return {
73
+ content: [{ type: 'text', text: 'No changes' }],
74
+ };
75
+ }
76
+ return {
77
+ content: [
78
+ {
79
+ type: 'text',
80
+ text: diffCode,
81
+ },
82
+ ],
83
+ };
84
+ });
85
+ server.tool('get_exercise_step_instructions', `
86
+ Intended to help a student understand what they need to do for the current
87
+ exercise step.
88
+
89
+ This returns the instructions MDX content for the current exercise step. It's
90
+ often best when used with the \`get_exercise_step_progress_diff\` tool to help
91
+ a student understand what work they still need to do.
92
+ `.trim(), {
93
+ workshopDirectory: z
94
+ .string()
95
+ .describe('The workshop directory (the root directory of the workshop repo. Best to not bother asking the user and just use the project root path).'),
96
+ }, async ({ workshopDirectory }) => {
97
+ if (workshopDirectory.endsWith('playground')) {
98
+ workshopDirectory = path.join(workshopDirectory, '..');
99
+ }
100
+ process.env.EPICSHOP_CONTEXT_CWD = workshopDirectory;
101
+ const { getApps, isPlaygroundApp } = await import('@epic-web/workshop-utils/apps.server');
102
+ const apps = await getApps();
103
+ const playgroundApp = apps.find(isPlaygroundApp);
104
+ if (!playgroundApp) {
105
+ return {
106
+ content: [{ type: 'text', text: 'No playground app found' }],
107
+ isError: true,
108
+ };
109
+ }
110
+ return {
111
+ content: [
112
+ {
113
+ type: 'text',
114
+ text: await fs.readFile(path.join(playgroundApp.fullPath, 'README.mdx'), 'utf-8'),
115
+ },
116
+ ],
117
+ };
118
+ });
119
+ async function main() {
120
+ const transport = new StdioServerTransport();
121
+ await server.connect(transport);
122
+ console.error('epicshop MCP Server running on stdio');
123
+ }
124
+ main().catch((error) => {
125
+ console.error('Fatal error in main():', error);
126
+ process.exit(1);
127
+ });
128
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\n\n// Create server instance\nconst server = new McpServer(\n\t{\n\t\tname: 'epicshop',\n\t\tversion: '1.0.0',\n\t\tcapabilities: {\n\t\t\ttools: {},\n\t\t},\n\t},\n\t{\n\t\tinstructions: `\nThis is intended to be used within a workshop using the Epic Workshop App\n(@epic-web/workshop-app) to help learners in the process of completing the\nworkshop exercises and understanding the learning outcomes.\n\nThe user's work in progress is in the \\`playground\\` directory. Any changes they\nask you to make should be in this directory.\n\t\t`.trim(),\n\t},\n)\n\nserver.tool(\n\t'get_exercise_step_progress_diff',\n\t`\nIntended to help a student understand what work they still have to complete.\n\nThis returns a git diff of the playground directory as BASE (their work in\nprogress) against the solution directory as HEAD (the final state they're trying\nto achieve). Meaning, if there are lines removed, it means they still need to\nadd those lines and if they are added, it means they still need to remove them.\n\nIf there's a diff with significant changes, you should explain what the changes\nare and their significance. Be brief. Let them tell you whether they need you to\nelaborate.\n\nFor additional context, you can use the \\`get_exercise_step_instructions\\` tool\nto get the instructions for the current exercise step to help explain the\nsignificance of changes.\n\t`.trim(),\n\t{\n\t\tworkshopDirectory: z\n\t\t\t.string()\n\t\t\t.describe(\n\t\t\t\t'The workshop directory (the root directory of the workshop repo. Best to not bother asking the user and just use the project root path).',\n\t\t\t),\n\t},\n\tasync ({ workshopDirectory }) => {\n\t\tif (workshopDirectory.endsWith('playground')) {\n\t\t\tworkshopDirectory = path.join(workshopDirectory, '..')\n\t\t}\n\t\tprocess.env.EPICSHOP_CONTEXT_CWD = workshopDirectory\n\n\t\tconst {\n\t\t\tgetApps,\n\t\t\tisPlaygroundApp,\n\t\t\tfindSolutionDir,\n\t\t\tgetFullPathFromAppName,\n\t\t\tinit,\n\t\t} = await import('@epic-web/workshop-utils/apps.server')\n\t\tawait init()\n\n\t\tconst { getDiffOutputWithRelativePaths } = await import(\n\t\t\t'@epic-web/workshop-utils/diff.server'\n\t\t)\n\n\t\tconst apps = await getApps()\n\t\tconst playgroundApp = apps.find(isPlaygroundApp)\n\n\t\tif (!playgroundApp) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: 'text', text: 'No playground app found' }],\n\t\t\t\tisError: true,\n\t\t\t}\n\t\t}\n\n\t\tconst baseApp = playgroundApp\n\t\tconst solutionDir = await findSolutionDir({\n\t\t\tfullPath: await getFullPathFromAppName(playgroundApp.appName),\n\t\t})\n\t\tconst headApp = apps.find((a) => a.fullPath === solutionDir)\n\n\t\tif (!headApp) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: 'text', text: 'No playground solution app found' }],\n\t\t\t\tisError: true,\n\t\t\t}\n\t\t}\n\n\t\tconst diffCode = await getDiffOutputWithRelativePaths(baseApp, headApp)\n\n\t\tif (!diffCode) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: 'text', text: 'No changes' }],\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: diffCode,\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t},\n)\n\nserver.tool(\n\t'get_exercise_step_instructions',\n\t`\nIntended to help a student understand what they need to do for the current\nexercise step.\n\nThis returns the instructions MDX content for the current exercise step. It's\noften best when used with the \\`get_exercise_step_progress_diff\\` tool to help\na student understand what work they still need to do.\n\t`.trim(),\n\t{\n\t\tworkshopDirectory: z\n\t\t\t.string()\n\t\t\t.describe(\n\t\t\t\t'The workshop directory (the root directory of the workshop repo. Best to not bother asking the user and just use the project root path).',\n\t\t\t),\n\t},\n\tasync ({ workshopDirectory }) => {\n\t\tif (workshopDirectory.endsWith('playground')) {\n\t\t\tworkshopDirectory = path.join(workshopDirectory, '..')\n\t\t}\n\t\tprocess.env.EPICSHOP_CONTEXT_CWD = workshopDirectory\n\n\t\tconst { getApps, isPlaygroundApp } = await import(\n\t\t\t'@epic-web/workshop-utils/apps.server'\n\t\t)\n\t\tconst apps = await getApps()\n\t\tconst playgroundApp = apps.find(isPlaygroundApp)\n\t\tif (!playgroundApp) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: 'text', text: 'No playground app found' }],\n\t\t\t\tisError: true,\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: await fs.readFile(\n\t\t\t\t\t\tpath.join(playgroundApp.fullPath, 'README.mdx'),\n\t\t\t\t\t\t'utf-8',\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t},\n)\n\nasync function main() {\n\tconst transport = new StdioServerTransport()\n\tawait server.connect(transport)\n\tconsole.error('epicshop MCP Server running on stdio')\n}\n\nmain().catch((error) => {\n\tconsole.error('Fatal error in main():', error)\n\tprocess.exit(1)\n})\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epic-web/workshop-mcp",
3
- "version": "5.13.4",
3
+ "version": "5.13.6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -12,11 +12,13 @@
12
12
  "esm"
13
13
  ],
14
14
  "exports": {
15
- "./package.json": "./package.json"
15
+ "./package.json": "./package.json",
16
+ ".": "./dist/esm/cli.js"
16
17
  }
17
18
  },
18
19
  "exports": {
19
- "./package.json": "./package.json"
20
+ "./package.json": "./package.json",
21
+ ".": "./dist/esm/cli.js"
20
22
  },
21
23
  "files": [
22
24
  "dist"
@@ -27,7 +29,7 @@
27
29
  "build:watch": "nx watch --projects=@epic-web/workshop-mcp -- nx run \\$NX_PROJECT_NAME:build"
28
30
  },
29
31
  "dependencies": {
30
- "@epic-web/workshop-utils": "5.13.4",
32
+ "@epic-web/workshop-utils": "5.13.6",
31
33
  "@modelcontextprotocol/sdk": "^1.9.0",
32
34
  "zod": "^3.24.2"
33
35
  },
@@ -40,5 +42,7 @@
40
42
  "type": "git",
41
43
  "url": "https://github.com/epicweb-dev/epicshop.git",
42
44
  "directory": "packages/workshop-mcp"
43
- }
45
+ },
46
+ "main": "./dist/esm/cli.js",
47
+ "module": "./dist/esm/cli.js"
44
48
  }