create-skybridge 0.0.0-dev.eb4bc95 → 0.0.0-dev.eb5abb2
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 +51 -10
- package/package.json +3 -3
- package/template/AGENTS.md +1 -0
- package/template/README.md +40 -18
- package/template/node_modules/.bin/alpic +21 -0
- package/template/node_modules/.bin/sb +2 -2
- package/template/node_modules/.bin/skybridge +2 -2
- package/template/node_modules/.bin/vite +2 -2
- package/template/package.json +7 -7
- package/template/server/src/index.ts +62 -42
- package/template/web/src/helpers.ts +1 -1
- package/template/web/src/index.css +4 -1
- package/template/web/src/widgets/magic-8-ball.tsx +8 -5
- package/template/node_modules/.bin/mcp-inspector +0 -21
- package/template/server/src/middleware.ts +0 -54
- package/template/server/src/server.ts +0 -61
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ export async function init(args = process.argv.slice(2)) {
|
|
|
56
56
|
defaultValue: defaultProjectName,
|
|
57
57
|
placeholder: defaultProjectName,
|
|
58
58
|
validate: (value) => {
|
|
59
|
-
return value
|
|
59
|
+
return !value || sanitizeTargetDir(value).length > 0
|
|
60
60
|
? undefined
|
|
61
61
|
: "Invalid project name";
|
|
62
62
|
},
|
|
@@ -105,8 +105,8 @@ export async function init(args = process.argv.slice(2)) {
|
|
|
105
105
|
emptyDir(targetDir);
|
|
106
106
|
break;
|
|
107
107
|
case "no":
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
prompts.log.error("Target directory is not empty.");
|
|
109
|
+
process.exit(1);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
const root = path.join(process.cwd(), targetDir);
|
|
@@ -153,7 +153,29 @@ export async function init(args = process.argv.slice(2)) {
|
|
|
153
153
|
}
|
|
154
154
|
const userAgent = process.env.npm_config_user_agent;
|
|
155
155
|
const pkgManager = userAgent?.split(" ")[0]?.split("/")[0] || "npm";
|
|
156
|
-
// 4. Ask about
|
|
156
|
+
// 4. Ask about skills installation
|
|
157
|
+
if (interactive) {
|
|
158
|
+
const skillsResult = await prompts.confirm({
|
|
159
|
+
message: "Install the coding agents skills? (recommended)",
|
|
160
|
+
initialValue: true,
|
|
161
|
+
});
|
|
162
|
+
if (prompts.isCancel(skillsResult)) {
|
|
163
|
+
return cancel();
|
|
164
|
+
}
|
|
165
|
+
if (skillsResult) {
|
|
166
|
+
run([
|
|
167
|
+
...getPkgExecCmd(pkgManager, "skills"),
|
|
168
|
+
"add",
|
|
169
|
+
"alpic-ai/skybridge",
|
|
170
|
+
"-s",
|
|
171
|
+
"chatgpt-app-builder",
|
|
172
|
+
], {
|
|
173
|
+
stdio: "inherit",
|
|
174
|
+
cwd: targetDir,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 5. Ask about immediate installation
|
|
157
179
|
let immediate = argImmediate;
|
|
158
180
|
if (immediate === undefined) {
|
|
159
181
|
if (interactive) {
|
|
@@ -225,18 +247,37 @@ function sanitizeTargetDir(targetDir) {
|
|
|
225
247
|
// Remove leading/trailing slashes
|
|
226
248
|
.replace(/^\/+|\/+$/g, ""));
|
|
227
249
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return
|
|
250
|
+
// Skip user's SPEC.md and IDE/agent preferences (.idea, .claude, etc.)
|
|
251
|
+
function isSkippedEntry(entry) {
|
|
252
|
+
return ((entry.name.startsWith(".") && entry.isDirectory()) ||
|
|
253
|
+
entry.name === "SPEC.md");
|
|
254
|
+
}
|
|
255
|
+
function isEmpty(dirPath) {
|
|
256
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
257
|
+
return entries.every(isSkippedEntry);
|
|
231
258
|
}
|
|
232
259
|
function emptyDir(dir) {
|
|
233
260
|
if (!fs.existsSync(dir)) {
|
|
234
261
|
return;
|
|
235
262
|
}
|
|
236
|
-
for (const
|
|
237
|
-
if (
|
|
263
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
264
|
+
if (isSkippedEntry(entry)) {
|
|
238
265
|
continue;
|
|
239
266
|
}
|
|
240
|
-
fs.rmSync(path.
|
|
267
|
+
fs.rmSync(path.join(dir, entry.name), { recursive: true, force: true });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function getPkgExecCmd(pkgManager, cmd) {
|
|
271
|
+
switch (pkgManager) {
|
|
272
|
+
case "yarn":
|
|
273
|
+
return ["yarn", "dlx", cmd];
|
|
274
|
+
case "pnpm":
|
|
275
|
+
return ["pnpm", "dlx", cmd];
|
|
276
|
+
case "bun":
|
|
277
|
+
return ["bunx", cmd];
|
|
278
|
+
case "deno":
|
|
279
|
+
return ["deno", "run", "-A", `npm:${cmd}`];
|
|
280
|
+
default:
|
|
281
|
+
return ["npx", cmd];
|
|
241
282
|
}
|
|
242
283
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-skybridge",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.eb5abb2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alpic",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"template"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@clack/prompts": "^0.
|
|
21
|
-
"giget": "^
|
|
20
|
+
"@clack/prompts": "^1.0.0",
|
|
21
|
+
"giget": "^3.1.2",
|
|
22
22
|
"mri": "^1.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Before writing code, first explore the project structure, then invoke the chatgpt-app-builder skill for documentation.
|
package/template/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Skybridge Starter
|
|
2
2
|
|
|
3
|
-
A minimal TypeScript template for building
|
|
3
|
+
A minimal TypeScript template for building MCP and ChatGPT Apps with the [Skybridge](https://docs.skybridge.tech/home) framework.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
7
7
|
### Prerequisites
|
|
8
8
|
|
|
9
9
|
- Node.js 24+
|
|
10
|
-
- HTTP tunnel such as [ngrok](https://ngrok.com/download)
|
|
10
|
+
- HTTP tunnel such as [ngrok](https://ngrok.com/download) if you want to test with remote MCP hosts like ChatGPT or Claude.ai.
|
|
11
11
|
|
|
12
12
|
### Local Development
|
|
13
13
|
|
|
@@ -37,41 +37,63 @@ pnpm dev
|
|
|
37
37
|
bun dev
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
This command starts
|
|
40
|
+
This command starts:
|
|
41
|
+
- Your MCP server at `http://localhost:3000/mcp`.
|
|
42
|
+
- Skybridge DevTools UI at `http://localhost:3000/`.
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
- a React application on Vite HMR dev server (the UI elements to be displayed in the host)
|
|
44
|
+
#### 3. Project structure
|
|
44
45
|
|
|
45
|
-
#### 3. Connect to ChatGPT
|
|
46
|
-
|
|
47
|
-
- ChatGPT requires connectors to be publicly accessible. To expose your server on the Internet, run:
|
|
48
|
-
```bash
|
|
49
|
-
ngrok http 3000
|
|
50
46
|
```
|
|
51
|
-
|
|
47
|
+
├── server/
|
|
48
|
+
│ └── src/
|
|
49
|
+
│ ├── index.ts # Entry point
|
|
50
|
+
│ ├── middleware.ts # MCP middleware
|
|
51
|
+
│ └── server.ts # Widget registry & routes
|
|
52
|
+
├── web/
|
|
53
|
+
│ ├── src/
|
|
54
|
+
│ │ ├── widgets/ # React components (one per widget)
|
|
55
|
+
│ │ ├── helpers.ts # Shared utilities
|
|
56
|
+
│ │ └── index.css # Global styles
|
|
57
|
+
│ └── vite.config.ts
|
|
58
|
+
├── alpic.json # Deployment config
|
|
59
|
+
├── nodemon.json # Dev server config
|
|
60
|
+
└── package.json
|
|
61
|
+
```
|
|
52
62
|
|
|
53
63
|
### Create your first widget
|
|
54
64
|
|
|
55
65
|
#### 1. Add a new widget
|
|
56
66
|
|
|
57
|
-
- Register a widget in `server/server.ts` with a unique name (e.g., `my-widget`)
|
|
58
|
-
- Create a matching React component at `web/src/widgets/my-widget.tsx`. The file name must match the widget name exactly
|
|
67
|
+
- Register a widget in `server/src/server.ts` with a unique name (e.g., `my-widget`) using [`registerWidget`](https://docs.skybridge.tech/api-reference/register-widget)
|
|
68
|
+
- Create a matching React component at `web/src/widgets/my-widget.tsx`. **The file name must match the widget name exactly**.
|
|
59
69
|
|
|
60
70
|
#### 2. Edit widgets with Hot Module Replacement (HMR)
|
|
61
71
|
|
|
62
|
-
Edit and save components in `web/src/widgets/` — changes appear instantly
|
|
72
|
+
Edit and save components in `web/src/widgets/` — changes will appear instantly inside your App.
|
|
63
73
|
|
|
64
74
|
#### 3. Edit server code
|
|
65
75
|
|
|
66
|
-
Modify files in `server/` and
|
|
76
|
+
Modify files in `server/` and refresh the connection with your testing MCP Client to see the changes.
|
|
77
|
+
|
|
78
|
+
### Testing your App
|
|
79
|
+
|
|
80
|
+
You can test your App locally by using our DevTools UI on `localhost:3000` while running the `pnpm dev` command.
|
|
81
|
+
|
|
82
|
+
To test your app with other MCP Clients like ChatGPT, Claude or VSCode, see [Testing Your App](https://docs.skybridge.tech/quickstart/test-your-app).
|
|
83
|
+
|
|
67
84
|
|
|
68
85
|
## Deploy to Production
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
- In ChatGPT, navigate to **Settings → Connectors → Create** and add your MCP server URL (e.g., `https://your-app-name.alpic.live`)
|
|
87
|
+
Skybridge is infrastructure vendor agnostic, and your app can be deployed on any cloud platform supporting MCP.
|
|
72
88
|
|
|
73
|
-
|
|
89
|
+
The simplest way to deploy your App in minutes is [Alpic](https://alpic.ai/).
|
|
90
|
+
1. Create an account on [Alpic platform](https://app.alpic.ai/).
|
|
91
|
+
2. Connect your GitHub repository to automatically deploy at each commit.
|
|
92
|
+
3. Use your remote App URL to connect it to MCP Clients, or use the Alpic Playground to easily test your App.
|
|
74
93
|
|
|
94
|
+
## Resources
|
|
95
|
+
- [Skybridge Documentation](https://docs.skybridge.tech/)
|
|
75
96
|
- [Apps SDK Documentation](https://developers.openai.com/apps-sdk)
|
|
97
|
+
- [MCP Apps Documentation](https://github.com/modelcontextprotocol/ext-apps/tree/main)
|
|
76
98
|
- [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
|
|
77
99
|
- [Alpic Documentation](https://docs.alpic.ai/)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules/alpic/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules/alpic/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules/alpic/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules/alpic/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/alpic@1.85.0_@opentelemetry+api@1.9.0/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../alpic/bin/run.js" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../alpic/bin/run.js" "$@"
|
|
21
|
+
fi
|
|
@@ -10,9 +10,9 @@ case `uname` in
|
|
|
10
10
|
esac
|
|
11
11
|
|
|
12
12
|
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.
|
|
13
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules"
|
|
14
14
|
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.
|
|
15
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
16
|
fi
|
|
17
17
|
if [ -x "$basedir/node" ]; then
|
|
18
18
|
exec "$basedir/node" "$basedir/../skybridge/bin/run.js" "$@"
|
|
@@ -10,9 +10,9 @@ case `uname` in
|
|
|
10
10
|
esac
|
|
11
11
|
|
|
12
12
|
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.
|
|
13
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules"
|
|
14
14
|
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.
|
|
15
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules/skybridge/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/skybridge@0.29.1_@modelcontextprotocol+sdk@1.26.0_zod@4.3.6__@types+node@25.2.2_@types+_034bba0111fd9b60db9ed73a8e849a6a/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
16
|
fi
|
|
17
17
|
if [ -x "$basedir/node" ]; then
|
|
18
18
|
exec "$basedir/node" "$basedir/../skybridge/bin/run.js" "$@"
|
|
@@ -10,9 +10,9 @@ case `uname` in
|
|
|
10
10
|
esac
|
|
11
11
|
|
|
12
12
|
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@
|
|
13
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules"
|
|
14
14
|
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@
|
|
15
|
+
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.2_jiti@2.6.1_lightningcss@1.30.2_terser@5.44.1_tsx@4.21.0_yaml@2.8.2/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
16
|
fi
|
|
17
17
|
if [ -x "$basedir/node" ]; then
|
|
18
18
|
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
|
package/template/package.json
CHANGED
|
@@ -8,31 +8,31 @@
|
|
|
8
8
|
"dev": "skybridge dev",
|
|
9
9
|
"build": "skybridge build",
|
|
10
10
|
"start": "skybridge start",
|
|
11
|
-
"
|
|
11
|
+
"deploy": "alpic deploy"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
14
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
15
15
|
"cors": "^2.8.6",
|
|
16
16
|
"express": "^5.2.1",
|
|
17
17
|
"react": "^19.2.4",
|
|
18
18
|
"react-dom": "^19.2.4",
|
|
19
|
-
"skybridge": ">=0.
|
|
19
|
+
"skybridge": ">=0.29.1 <1.0.0",
|
|
20
20
|
"vite": "^7.3.1",
|
|
21
21
|
"zod": "^4.3.6"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@modelcontextprotocol/inspector": "^0.19.0",
|
|
25
24
|
"@skybridge/devtools": ">=0.26.1 <1.0.0",
|
|
26
25
|
"@types/cors": "^2.8.19",
|
|
27
26
|
"@types/express": "^5.0.6",
|
|
28
|
-
"@types/react": "^19.2.
|
|
27
|
+
"@types/react": "^19.2.14",
|
|
29
28
|
"@types/react-dom": "^19.2.3",
|
|
30
|
-
"@vitejs/plugin-react": "^5.1.
|
|
29
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
30
|
+
"alpic": "^1.85.0",
|
|
31
31
|
"nodemon": "^3.1.11",
|
|
32
32
|
"tsx": "^4.21.0",
|
|
33
33
|
"typescript": "^5.9.3"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": ">=24.13.
|
|
36
|
+
"node": ">=24.13.1"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -1,42 +1,62 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
import { McpServer } from "skybridge/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
const Answers = [
|
|
5
|
+
"As I see it, yes",
|
|
6
|
+
"Don't count on it",
|
|
7
|
+
"It is certain",
|
|
8
|
+
"It is decidedly so",
|
|
9
|
+
"Most likely",
|
|
10
|
+
"My reply is no",
|
|
11
|
+
"My sources say no",
|
|
12
|
+
"Outlook good",
|
|
13
|
+
"Outlook not so good",
|
|
14
|
+
"Signs point to yes",
|
|
15
|
+
"Very doubtful",
|
|
16
|
+
"Without a doubt",
|
|
17
|
+
"Yes definitely",
|
|
18
|
+
"Yes",
|
|
19
|
+
"You may rely on it",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const server = new McpServer(
|
|
23
|
+
{
|
|
24
|
+
name: "alpic-openai-app",
|
|
25
|
+
version: "0.0.1",
|
|
26
|
+
},
|
|
27
|
+
{ capabilities: {} },
|
|
28
|
+
).registerWidget(
|
|
29
|
+
"magic-8-ball",
|
|
30
|
+
{
|
|
31
|
+
description: "Magic 8 Ball",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
description: "For fortune-telling or seeking advice.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
question: z.string().describe("The user question."),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
async ({ question }) => {
|
|
40
|
+
try {
|
|
41
|
+
// deterministic answer
|
|
42
|
+
const hash = question
|
|
43
|
+
.split("")
|
|
44
|
+
.reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
45
|
+
const answer = Answers[hash % Answers.length];
|
|
46
|
+
return {
|
|
47
|
+
structuredContent: { answer },
|
|
48
|
+
content: [],
|
|
49
|
+
isError: false,
|
|
50
|
+
};
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: `Error: ${error}` }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
server.run();
|
|
61
|
+
|
|
62
|
+
export type AppType = typeof server;
|
|
@@ -5,15 +5,18 @@ import { useToolInfo } from "../helpers";
|
|
|
5
5
|
|
|
6
6
|
function Magic8Ball() {
|
|
7
7
|
const { input, output } = useToolInfo<"magic-8-ball">();
|
|
8
|
-
if (!output) {
|
|
9
|
-
return <div>Shaking...</div>;
|
|
10
|
-
}
|
|
11
8
|
|
|
12
9
|
return (
|
|
13
10
|
<div className="container">
|
|
14
11
|
<div className="ball">
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
{output ? (
|
|
13
|
+
<>
|
|
14
|
+
<div className="question">{input.question}</div>
|
|
15
|
+
<div className="answer">{output.answer}</div>
|
|
16
|
+
</>
|
|
17
|
+
) : (
|
|
18
|
+
<div className="question">Shaking...</div>
|
|
19
|
+
)}
|
|
17
20
|
</div>
|
|
18
21
|
</div>
|
|
19
22
|
);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/cli/build/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/cli/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/cli/build/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/cli/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/inspector/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules/@modelcontextprotocol/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.19.0_@types+node@24.10.9_@types+react-dom@19.2.3_@typ_90a4933ac32d445296d880cafbf4dfc1/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../@modelcontextprotocol/inspector/cli/build/cli.js" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../@modelcontextprotocol/inspector/cli/build/cli.js" "$@"
|
|
21
|
-
fi
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
-
import type { NextFunction, Request, Response } from "express";
|
|
3
|
-
|
|
4
|
-
import type { McpServer } from "skybridge/server";
|
|
5
|
-
|
|
6
|
-
export const mcp =
|
|
7
|
-
(server: McpServer) =>
|
|
8
|
-
async (req: Request, res: Response, next: NextFunction) => {
|
|
9
|
-
// Only handle requests to the /mcp path
|
|
10
|
-
if (req.path !== "/mcp") {
|
|
11
|
-
return next();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (req.method === "POST") {
|
|
15
|
-
try {
|
|
16
|
-
const transport = new StreamableHTTPServerTransport({
|
|
17
|
-
sessionIdGenerator: undefined,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
res.on("close", () => {
|
|
21
|
-
transport.close();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
await server.connect(transport);
|
|
25
|
-
|
|
26
|
-
await transport.handleRequest(req, res, req.body);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error("Error handling MCP request:", error);
|
|
29
|
-
if (!res.headersSent) {
|
|
30
|
-
res.status(500).json({
|
|
31
|
-
jsonrpc: "2.0",
|
|
32
|
-
error: {
|
|
33
|
-
code: -32603,
|
|
34
|
-
message: "Internal server error",
|
|
35
|
-
},
|
|
36
|
-
id: null,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else if (req.method === "GET" || req.method === "DELETE") {
|
|
41
|
-
res.writeHead(405).end(
|
|
42
|
-
JSON.stringify({
|
|
43
|
-
jsonrpc: "2.0",
|
|
44
|
-
error: {
|
|
45
|
-
code: -32000,
|
|
46
|
-
message: "Method not allowed.",
|
|
47
|
-
},
|
|
48
|
-
id: null,
|
|
49
|
-
}),
|
|
50
|
-
);
|
|
51
|
-
} else {
|
|
52
|
-
next();
|
|
53
|
-
}
|
|
54
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "skybridge/server";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
|
|
4
|
-
const Answers = [
|
|
5
|
-
"As I see it, yes",
|
|
6
|
-
"Don't count on it",
|
|
7
|
-
"It is certain",
|
|
8
|
-
"It is decidedly so",
|
|
9
|
-
"Most likely",
|
|
10
|
-
"My reply is no",
|
|
11
|
-
"My sources say no",
|
|
12
|
-
"Outlook good",
|
|
13
|
-
"Outlook not so good",
|
|
14
|
-
"Signs point to yes",
|
|
15
|
-
"Very doubtful",
|
|
16
|
-
"Without a doubt",
|
|
17
|
-
"Yes definitely",
|
|
18
|
-
"Yes",
|
|
19
|
-
"You may rely on it",
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const server = new McpServer(
|
|
23
|
-
{
|
|
24
|
-
name: "alpic-openai-app",
|
|
25
|
-
version: "0.0.1",
|
|
26
|
-
},
|
|
27
|
-
{ capabilities: {} },
|
|
28
|
-
).registerWidget(
|
|
29
|
-
"magic-8-ball",
|
|
30
|
-
{
|
|
31
|
-
description: "Magic 8 Ball",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
description: "For fortune-telling or seeking advice.",
|
|
35
|
-
inputSchema: {
|
|
36
|
-
question: z.string().describe("The user question."),
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
async ({ question }) => {
|
|
40
|
-
try {
|
|
41
|
-
// deterministic answer
|
|
42
|
-
const hash = question
|
|
43
|
-
.split("")
|
|
44
|
-
.reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
45
|
-
const answer = Answers[hash % Answers.length];
|
|
46
|
-
return {
|
|
47
|
-
structuredContent: { answer },
|
|
48
|
-
content: [],
|
|
49
|
-
isError: false,
|
|
50
|
-
};
|
|
51
|
-
} catch (error) {
|
|
52
|
-
return {
|
|
53
|
-
content: [{ type: "text", text: `Error: ${error}` }],
|
|
54
|
-
isError: true,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
export default server;
|
|
61
|
-
export type AppType = typeof server;
|