create-skybridge 0.0.0-dev.e205b05 → 0.0.0-dev.e210492
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/LICENSE +21 -0
- package/dist/index.js +101 -28
- package/dist/index.test.js +13 -1
- package/package.json +13 -14
- package/template/.dockerignore +4 -0
- package/template/AGENTS.md +1 -0
- package/template/Dockerfile +53 -0
- package/template/README.md +41 -24
- package/template/_gitignore +3 -1
- package/template/alpic.json +1 -2
- package/template/node_modules/.bin/alpic +21 -0
- package/template/node_modules/.bin/sb +21 -0
- package/template/node_modules/.bin/skybridge +21 -0
- package/template/node_modules/.bin/tsc +2 -2
- package/template/node_modules/.bin/tsserver +2 -2
- package/template/node_modules/.bin/tsx +2 -2
- package/template/node_modules/.bin/vite +2 -2
- package/template/package.json +28 -26
- package/template/src/helpers.ts +4 -0
- package/template/src/index.css +38 -0
- package/template/src/server.ts +44 -0
- package/template/src/views/components/intro.tsx +43 -0
- package/template/src/views/images/mascot/beret.png +0 -0
- package/template/src/views/images/mascot/chapka.png +0 -0
- package/template/src/views/images/mascot/classic.png +0 -0
- package/template/src/views/images/mascot/conical.png +0 -0
- package/template/src/views/images/mascot/cownboy.png +0 -0
- package/template/src/views/images/mascot/fez.png +0 -0
- package/template/src/views/images/mascot/formal.png +0 -0
- package/template/src/views/images/mascot/jester.png +0 -0
- package/template/src/views/images/mascot/mitre.png +0 -0
- package/template/src/views/images/mascot/propeller.png +0 -0
- package/template/src/views/images/mascot/sombrero.png +0 -0
- package/template/src/views/images/mascot/viking.png +0 -0
- package/template/src/views/start.tsx +87 -0
- package/template/src/vite-manifest.d.ts +4 -0
- package/template/tsconfig.json +7 -19
- package/template/{web/vite.config.ts → vite.config.ts} +3 -4
- package/template/node_modules/.bin/mcp-inspector +0 -21
- package/template/node_modules/.bin/nodemon +0 -21
- package/template/node_modules/.bin/shx +0 -21
- package/template/nodemon.json +0 -5
- package/template/server/src/index.ts +0 -35
- package/template/server/src/middleware.ts +0 -54
- package/template/server/src/server.ts +0 -61
- package/template/tsconfig.server.json +0 -11
- package/template/web/src/helpers.ts +0 -4
- package/template/web/src/index.css +0 -31
- package/template/web/src/widgets/magic-8-ball.tsx +0 -24
package/template/package.json
CHANGED
|
@@ -5,35 +5,37 @@
|
|
|
5
5
|
"description": "Alpic MCP Server Template",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"dev": "
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"server:start": "node server/dist/index.js",
|
|
14
|
-
"web:build": "tsc -b web && vite build -c web/vite.config.ts",
|
|
15
|
-
"web:preview": "vite preview -c web/vite.config.ts"
|
|
8
|
+
"dev": "skybridge dev",
|
|
9
|
+
"dev:tunnel": "skybridge dev --tunnel",
|
|
10
|
+
"build": "skybridge build",
|
|
11
|
+
"start": "skybridge start",
|
|
12
|
+
"deploy": "alpic deploy"
|
|
16
13
|
},
|
|
17
14
|
"dependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"
|
|
20
|
-
"react": "^
|
|
21
|
-
"react
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
15
|
+
"@alpic-ai/ui": "^1.122.0",
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
17
|
+
"lucide-react": "^1.14.0",
|
|
18
|
+
"react": "^19.2.4",
|
|
19
|
+
"react-dom": "^19.2.4",
|
|
20
|
+
"skybridge": ">=0.0.0-dev.e210492",
|
|
21
|
+
"sonner": "^2.0.7",
|
|
22
|
+
"tw-animate-css": "^1.4.0",
|
|
23
|
+
"vite": "^8.0.3",
|
|
24
|
+
"zod": "^4.3.6"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
29
|
-
"@types/node": "^
|
|
30
|
-
"@types/react": "^19.
|
|
31
|
-
"@types/react-dom": "^19.
|
|
32
|
-
"@vitejs/plugin-react": "^
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"tsx": "^4.
|
|
36
|
-
"typescript": "^
|
|
27
|
+
"@skybridge/devtools": "workspace:*",
|
|
28
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
29
|
+
"@types/node": "^24.12.0",
|
|
30
|
+
"@types/react": "^19.2.14",
|
|
31
|
+
"@types/react-dom": "^19.2.3",
|
|
32
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
33
|
+
"alpic": "^1.104.1",
|
|
34
|
+
"tailwindcss": "^4.2.4",
|
|
35
|
+
"tsx": "^4.21.0",
|
|
36
|
+
"typescript": "^6.0.2"
|
|
37
37
|
},
|
|
38
|
-
"
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=24.14.1"
|
|
40
|
+
}
|
|
39
41
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Mozilla+Text:wght@400..700&display=swap");
|
|
2
|
+
@import "tailwindcss";
|
|
3
|
+
@import "tw-animate-css";
|
|
4
|
+
@import "@alpic-ai/ui/theme";
|
|
5
|
+
|
|
6
|
+
@source "../node_modules/@alpic-ai/ui/src";
|
|
7
|
+
|
|
8
|
+
@theme {
|
|
9
|
+
--font-mozilla: "Mozilla Text", serif;
|
|
10
|
+
--animate-float: float 3s ease-in-out infinite;
|
|
11
|
+
--animate-twirl: twirl 20s ease-in-out infinite;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@keyframes float {
|
|
15
|
+
0%,
|
|
16
|
+
100% {
|
|
17
|
+
transform: translateY(0);
|
|
18
|
+
}
|
|
19
|
+
50% {
|
|
20
|
+
transform: translateY(-6px);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@keyframes twirl {
|
|
25
|
+
0%,
|
|
26
|
+
80% {
|
|
27
|
+
transform: rotateY(0deg);
|
|
28
|
+
}
|
|
29
|
+
85% {
|
|
30
|
+
transform: rotateY(180deg);
|
|
31
|
+
}
|
|
32
|
+
95% {
|
|
33
|
+
transform: rotateY(180deg);
|
|
34
|
+
}
|
|
35
|
+
100% {
|
|
36
|
+
transform: rotateY(360deg);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { McpServer } from "skybridge/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
const server = new McpServer(
|
|
5
|
+
{
|
|
6
|
+
name: "alpic-openai-app",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
},
|
|
9
|
+
{ capabilities: {} },
|
|
10
|
+
).registerTool(
|
|
11
|
+
{
|
|
12
|
+
name: "start",
|
|
13
|
+
description: "Onboard Skybridge",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
name: z.string().describe("The user name."),
|
|
16
|
+
},
|
|
17
|
+
view: {
|
|
18
|
+
component: "start",
|
|
19
|
+
description: "Onboarding deck",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async ({ name }) => {
|
|
23
|
+
try {
|
|
24
|
+
return {
|
|
25
|
+
structuredContent: { name },
|
|
26
|
+
isError: false,
|
|
27
|
+
};
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text: `Error: ${error}` }],
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (process.env.NODE_ENV === "production") {
|
|
38
|
+
const { default: manifest } = await import("./vite-manifest.js");
|
|
39
|
+
server.setViteManifest(manifest);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default await server.run();
|
|
43
|
+
|
|
44
|
+
export type AppType = typeof server;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Button } from "@alpic-ai/ui/components/button";
|
|
2
|
+
import { CheckCheck, ChevronsRight, Info } from "lucide-react";
|
|
3
|
+
import { useToolInfo } from "@/helpers.js";
|
|
4
|
+
|
|
5
|
+
export default function Intro({ onNext }: { onNext: () => void }) {
|
|
6
|
+
const { input } = useToolInfo<"start">();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<div className="flex flex-col gap-3">
|
|
11
|
+
<h1 className="type-display-xs font-mozilla font-semibold">
|
|
12
|
+
Howdy, <span className="text-primary">{input?.name} !</span>
|
|
13
|
+
</h1>
|
|
14
|
+
<p className="">
|
|
15
|
+
You're wondering how the view displays your name, don't you? Well,
|
|
16
|
+
it's because it can read <strong>tool output</strong>. The LLM also
|
|
17
|
+
knows about it.
|
|
18
|
+
</p>
|
|
19
|
+
</div>
|
|
20
|
+
<p className="flex items-start gap-2 type-text-xs text-muted-foreground">
|
|
21
|
+
<Info className="size-4 shrink-0" />
|
|
22
|
+
<span>
|
|
23
|
+
The{" "}
|
|
24
|
+
<a
|
|
25
|
+
href="https://docs.skybridge.tech"
|
|
26
|
+
target="_blank"
|
|
27
|
+
rel="noreferrer"
|
|
28
|
+
className="underline underline-offset-4"
|
|
29
|
+
>
|
|
30
|
+
useToolInfo
|
|
31
|
+
</a>{" "}
|
|
32
|
+
hook hydrates the view with tool input, output and metadata.
|
|
33
|
+
</span>
|
|
34
|
+
</p>
|
|
35
|
+
<div className="flex justify-end gap-2">
|
|
36
|
+
<Button variant="cta" onClick={onNext}>
|
|
37
|
+
<CheckCheck />
|
|
38
|
+
Sharing view state
|
|
39
|
+
</Button>
|
|
40
|
+
</div>
|
|
41
|
+
</>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import "@/index.css";
|
|
2
|
+
|
|
3
|
+
import { Card, CardContent } from "@alpic-ai/ui/components/card";
|
|
4
|
+
import {
|
|
5
|
+
Tooltip,
|
|
6
|
+
TooltipContent,
|
|
7
|
+
TooltipTrigger,
|
|
8
|
+
} from "@alpic-ai/ui/components/tooltip";
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
import { useLayout, useViewState } from "skybridge/web";
|
|
11
|
+
import Intro from "./components/intro.js";
|
|
12
|
+
import classic from "./images/mascot/classic.png";
|
|
13
|
+
|
|
14
|
+
const STEPS = [
|
|
15
|
+
"Reading tool output",
|
|
16
|
+
"Sharing view state",
|
|
17
|
+
"Calling tools",
|
|
18
|
+
] as const;
|
|
19
|
+
const TOTAL_STEPS = STEPS.length;
|
|
20
|
+
|
|
21
|
+
export default function Start() {
|
|
22
|
+
const [state] = useViewState({ mascot: "classic" });
|
|
23
|
+
const { theme } = useLayout();
|
|
24
|
+
const [step, setStep] = useState(0);
|
|
25
|
+
|
|
26
|
+
let mascot: string;
|
|
27
|
+
switch (state.mascot) {
|
|
28
|
+
case "classic":
|
|
29
|
+
mascot = classic;
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
throw new Error("cannot find mascot");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
className={`${theme === "dark" ? "dark" : ""} flex min-h-full items-center justify-center p-6 `}
|
|
38
|
+
>
|
|
39
|
+
<Card className="w-full max-w-2xl">
|
|
40
|
+
<CardContent>
|
|
41
|
+
<div className="flex flex-col items-center gap-6 md:flex-row md:items-stretch">
|
|
42
|
+
<div className="shrink-0 self-center animate-float">
|
|
43
|
+
<img
|
|
44
|
+
src={mascot}
|
|
45
|
+
alt="Skybridge mascot"
|
|
46
|
+
className="h-40 w-40 object-contain animate-twirl"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="flex flex-1 flex-col justify-between gap-6">
|
|
50
|
+
<div className="flex gap-1.5">
|
|
51
|
+
{STEPS.map((label, i) => (
|
|
52
|
+
<Tooltip key={label}>
|
|
53
|
+
<TooltipTrigger asChild>
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
onClick={() => setStep(i)}
|
|
57
|
+
className={`h-1 flex-1 rounded-full ${
|
|
58
|
+
i <= step ? "bg-primary" : "bg-muted"
|
|
59
|
+
}`}
|
|
60
|
+
aria-label={label}
|
|
61
|
+
/>
|
|
62
|
+
</TooltipTrigger>
|
|
63
|
+
<TooltipContent>{label}</TooltipContent>
|
|
64
|
+
</Tooltip>
|
|
65
|
+
))}
|
|
66
|
+
</div>
|
|
67
|
+
{(() => {
|
|
68
|
+
const onNext = () =>
|
|
69
|
+
setStep((s) => Math.min(s + 1, TOTAL_STEPS - 1));
|
|
70
|
+
switch (step) {
|
|
71
|
+
case 0:
|
|
72
|
+
return <Intro onNext={onNext} />;
|
|
73
|
+
case 1:
|
|
74
|
+
return <div>step 2 placeholder</div>;
|
|
75
|
+
case 2:
|
|
76
|
+
return <div>step 3 placeholder</div>;
|
|
77
|
+
default:
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
})()}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</CardContent>
|
|
84
|
+
</Card>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
package/template/tsconfig.json
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
|
|
9
|
-
"strict": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"noFallthroughCasesInSwitch": true,
|
|
2
|
+
"extends": "skybridge/tsconfig",
|
|
18
3
|
|
|
19
|
-
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"paths": {
|
|
6
|
+
"@/*": ["./src/*"]
|
|
7
|
+
}
|
|
20
8
|
},
|
|
21
|
-
|
|
22
|
-
"
|
|
9
|
+
|
|
10
|
+
"include": ["src", ".skybridge/**/*.d.ts"]
|
|
23
11
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
2
3
|
import react from "@vitejs/plugin-react";
|
|
3
|
-
import { skybridge } from "skybridge/
|
|
4
|
+
import { skybridge } from "skybridge/vite";
|
|
4
5
|
import { defineConfig } from "vite";
|
|
5
6
|
|
|
6
|
-
// https://vite.dev/config/
|
|
7
7
|
export default defineConfig({
|
|
8
|
-
plugins: [skybridge(), react()],
|
|
9
|
-
root: __dirname,
|
|
8
|
+
plugins: [skybridge(), react(), tailwindcss()],
|
|
10
9
|
resolve: {
|
|
11
10
|
alias: {
|
|
12
11
|
"@": path.resolve(__dirname, "./src"),
|
|
@@ -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.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/cli/build/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/cli/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/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.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/cli/build/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/cli/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/inspector/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/node_modules/@modelcontextprotocol/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/@modelcontextprotocol+inspector@0.17.5_@types+node@22.18.12_@types+react-dom@19.2.3_@ty_960011790b33063d7255347351a0cc44/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,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/nodemon@3.1.11/node_modules/nodemon/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/nodemon@3.1.11/node_modules/nodemon/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/nodemon@3.1.11/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/nodemon@3.1.11/node_modules/nodemon/bin/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/nodemon@3.1.11/node_modules/nodemon/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/nodemon@3.1.11/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/../nodemon/bin/nodemon.js" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../nodemon/bin/nodemon.js" "$@"
|
|
21
|
-
fi
|
|
@@ -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/shx@0.3.4/node_modules/shx/lib/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/shx@0.3.4/node_modules/shx/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/shx@0.3.4/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/shx@0.3.4/node_modules/shx/lib/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/shx@0.3.4/node_modules/shx/node_modules:/home/runner/work/skybridge/skybridge/node_modules/.pnpm/shx@0.3.4/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/../shx/lib/cli.js" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../shx/lib/cli.js" "$@"
|
|
21
|
-
fi
|
package/template/nodemon.json
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import express, { type Express } from "express";
|
|
2
|
-
|
|
3
|
-
import { widgetsDevServer } from "skybridge/server";
|
|
4
|
-
import type { ViteDevServer } from "vite";
|
|
5
|
-
import { mcp } from "./middleware.js";
|
|
6
|
-
import server from "./server.js";
|
|
7
|
-
|
|
8
|
-
const app = express() as Express & { vite: ViteDevServer };
|
|
9
|
-
|
|
10
|
-
app.use(express.json());
|
|
11
|
-
|
|
12
|
-
app.use(mcp(server));
|
|
13
|
-
|
|
14
|
-
const env = process.env.NODE_ENV || "development";
|
|
15
|
-
|
|
16
|
-
if (env !== "production") {
|
|
17
|
-
app.use(await widgetsDevServer());
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
app.listen(3000, (error) => {
|
|
21
|
-
if (error) {
|
|
22
|
-
console.error("Failed to start server:", error);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log(`Server listening on port 3000 - ${env}`);
|
|
27
|
-
console.log(
|
|
28
|
-
"Make your local server accessible with 'ngrok http 3000' and connect to ChatGPT with URL https://xxxxxx.ngrok-free.app/mcp",
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
process.on("SIGINT", async () => {
|
|
33
|
-
console.log("Server shutdown complete");
|
|
34
|
-
process.exit(0);
|
|
35
|
-
});
|
|
@@ -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;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
.container {
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: center;
|
|
4
|
-
align-items: center;
|
|
5
|
-
height: 100%;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.ball {
|
|
9
|
-
background-color: black;
|
|
10
|
-
border-radius: 50%;
|
|
11
|
-
width: 12rem;
|
|
12
|
-
height: 12rem;
|
|
13
|
-
display: flex;
|
|
14
|
-
flex-direction: column;
|
|
15
|
-
align-items: center;
|
|
16
|
-
justify-content: center;
|
|
17
|
-
font-family: monospace;
|
|
18
|
-
text-align: center;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.question {
|
|
22
|
-
font-size: 0.75rem;
|
|
23
|
-
color: lightgrey;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.answer {
|
|
27
|
-
font-size: 1.125rem;
|
|
28
|
-
font-weight: bold;
|
|
29
|
-
margin-top: 0.5rem;
|
|
30
|
-
color: aqua;
|
|
31
|
-
}
|