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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.js +101 -28
  3. package/dist/index.test.js +13 -1
  4. package/package.json +13 -14
  5. package/template/.dockerignore +4 -0
  6. package/template/AGENTS.md +1 -0
  7. package/template/Dockerfile +53 -0
  8. package/template/README.md +41 -24
  9. package/template/_gitignore +3 -1
  10. package/template/alpic.json +1 -2
  11. package/template/node_modules/.bin/alpic +21 -0
  12. package/template/node_modules/.bin/sb +21 -0
  13. package/template/node_modules/.bin/skybridge +21 -0
  14. package/template/node_modules/.bin/tsc +2 -2
  15. package/template/node_modules/.bin/tsserver +2 -2
  16. package/template/node_modules/.bin/tsx +2 -2
  17. package/template/node_modules/.bin/vite +2 -2
  18. package/template/package.json +28 -26
  19. package/template/src/helpers.ts +4 -0
  20. package/template/src/index.css +38 -0
  21. package/template/src/server.ts +44 -0
  22. package/template/src/views/components/intro.tsx +43 -0
  23. package/template/src/views/images/mascot/beret.png +0 -0
  24. package/template/src/views/images/mascot/chapka.png +0 -0
  25. package/template/src/views/images/mascot/classic.png +0 -0
  26. package/template/src/views/images/mascot/conical.png +0 -0
  27. package/template/src/views/images/mascot/cownboy.png +0 -0
  28. package/template/src/views/images/mascot/fez.png +0 -0
  29. package/template/src/views/images/mascot/formal.png +0 -0
  30. package/template/src/views/images/mascot/jester.png +0 -0
  31. package/template/src/views/images/mascot/mitre.png +0 -0
  32. package/template/src/views/images/mascot/propeller.png +0 -0
  33. package/template/src/views/images/mascot/sombrero.png +0 -0
  34. package/template/src/views/images/mascot/viking.png +0 -0
  35. package/template/src/views/start.tsx +87 -0
  36. package/template/src/vite-manifest.d.ts +4 -0
  37. package/template/tsconfig.json +7 -19
  38. package/template/{web/vite.config.ts → vite.config.ts} +3 -4
  39. package/template/node_modules/.bin/mcp-inspector +0 -21
  40. package/template/node_modules/.bin/nodemon +0 -21
  41. package/template/node_modules/.bin/shx +0 -21
  42. package/template/nodemon.json +0 -5
  43. package/template/server/src/index.ts +0 -35
  44. package/template/server/src/middleware.ts +0 -54
  45. package/template/server/src/server.ts +0 -61
  46. package/template/tsconfig.server.json +0 -11
  47. package/template/web/src/helpers.ts +0 -4
  48. package/template/web/src/index.css +0 -31
  49. package/template/web/src/widgets/magic-8-ball.tsx +0 -24
@@ -5,35 +5,37 @@
5
5
  "description": "Alpic MCP Server Template",
6
6
  "type": "module",
7
7
  "scripts": {
8
- "dev": "nodemon",
9
- "build": "vite build -c web/vite.config.ts && shx rm -rf server/dist && tsc -p tsconfig.server.json && shx cp -r web/dist server/dist/assets",
10
- "start": "node server/dist/index.js",
11
- "inspector": "mcp-inspector http://localhost:3000/mcp",
12
- "server:build": "tsc -p tsconfig.server.json",
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
- "@modelcontextprotocol/sdk": "^1.24.3",
19
- "express": "^5.1.0",
20
- "react": "^19.1.1",
21
- "react-dom": "^19.1.1",
22
- "skybridge": ">=0.16.0 <1.0.0",
23
- "vite": "^7.1.11",
24
- "zod": "^4.1.13"
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
- "@modelcontextprotocol/inspector": "^0.17.5",
28
- "@types/express": "^5.0.3",
29
- "@types/node": "^22.15.30",
30
- "@types/react": "^19.1.16",
31
- "@types/react-dom": "^19.1.9",
32
- "@vitejs/plugin-react": "^5.0.4",
33
- "nodemon": "^3.1.10",
34
- "shx": "^0.3.4",
35
- "tsx": "^4.19.4",
36
- "typescript": "^5.7.2"
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
- "workspaces": []
38
+ "engines": {
39
+ "node": ">=24.14.1"
40
+ }
39
41
  }
@@ -0,0 +1,4 @@
1
+ import { generateHelpers } from "skybridge/web";
2
+ import type { AppType } from "./server.js";
3
+
4
+ export const { useToolInfo, useCallTool } = generateHelpers<AppType>();
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ // Typed shim for the Vite manifest emitted by `skybridge build`. The actual
2
+ // `vite-manifest.js` is generated alongside this file and gitignored.
3
+ declare const manifest: Record<string, { file: string }>;
4
+ export default manifest;
@@ -1,23 +1,11 @@
1
1
  {
2
- "compilerOptions": {
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
- "noEmit": true
4
+ "compilerOptions": {
5
+ "paths": {
6
+ "@/*": ["./src/*"]
7
+ }
20
8
  },
21
- "include": ["server/src", "web/src", "web/vite.config.ts"],
22
- "exclude": ["dist", "node_modules"]
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/web";
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
@@ -1,5 +0,0 @@
1
- {
2
- "watch": ["server/src"],
3
- "ext": "ts,json",
4
- "exec": "tsx server/src/index.ts"
5
- }
@@ -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,11 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "noEmit": false,
5
- "outDir": "server/dist",
6
- "sourceMap": true,
7
- "declaration": true
8
- },
9
- "include": ["server/src"],
10
- "exclude": ["dist", "node_modules"]
11
- }
@@ -1,4 +0,0 @@
1
- import { generateHelpers } from "skybridge/web";
2
- import type { AppType } from "../../server/src/server";
3
-
4
- export const { useToolInfo } = generateHelpers<AppType>();
@@ -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
- }