create-mcp-use-app 2.0.0-beta.3 → 2.0.0-beta.5
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 +68 -37
- package/dist/index.js +10 -8
- package/dist/templates/blank/README.md +1 -1
- package/dist/templates/blank/tsconfig.json +2 -1
- package/dist/templates/mcp-apps/README.md +1 -1
- package/dist/templates/mcp-apps/index.ts +71 -101
- package/dist/templates/mcp-apps/mcp-env.d.ts +1 -1
- package/dist/templates/mcp-apps/public/logo-mcp-use.svg +8 -0
- package/dist/templates/mcp-apps/tsconfig.json +2 -1
- package/dist/templates/mcp-apps/views/my-view/MeshGradient.tsx +299 -0
- package/dist/templates/mcp-apps/views/my-view/Tooltip.tsx +75 -0
- package/dist/templates/mcp-apps/views/my-view/icons.tsx +142 -0
- package/dist/templates/mcp-apps/views/my-view/view.css +5 -0
- package/dist/templates/mcp-apps/views/my-view/view.tsx +396 -0
- package/dist/templates/{starter → mcp-server}/README.md +2 -2
- package/dist/templates/{starter → mcp-server}/index.ts +0 -18
- package/dist/templates/{starter → mcp-server}/tsconfig.json +2 -1
- package/package.json +2 -2
- package/dist/templates/mcp-apps/public/fruits/apple.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/apricot.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/avocado.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/banana.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/blueberry.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/cherries.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/coconut.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/grapes.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/lemon.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/mango.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/orange.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/pear.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/pineapple.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/plum.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/strawberry.webp +0 -0
- package/dist/templates/mcp-apps/public/fruits/watermelon.webp +0 -0
- package/dist/templates/mcp-apps/views/product-search-result/components/Accordion.tsx +0 -35
- package/dist/templates/mcp-apps/views/product-search-result/components/AccordionItem.tsx +0 -35
- package/dist/templates/mcp-apps/views/product-search-result/components/Carousel.tsx +0 -52
- package/dist/templates/mcp-apps/views/product-search-result/components/CarouselItem.tsx +0 -91
- package/dist/templates/mcp-apps/views/product-search-result/components/CarouselSkeleton.tsx +0 -18
- package/dist/templates/mcp-apps/views/product-search-result/hooks/useCarouselAnimation.ts +0 -72
- package/dist/templates/mcp-apps/views/product-search-result/view.css +0 -81
- package/dist/templates/mcp-apps/views/product-search-result/view.tsx +0 -371
- /package/dist/templates/{starter → mcp-server}/gitignore +0 -0
- /package/dist/templates/{starter → mcp-server}/package.json +0 -0
- /package/dist/templates/{starter → mcp-server}/public/icon.svg +0 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/** MCP App starter view — edit this file to build your UI. */
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
ModelContext,
|
|
5
|
+
ThemeProvider,
|
|
6
|
+
useCallTool,
|
|
7
|
+
useDisplayMode,
|
|
8
|
+
useHostContext,
|
|
9
|
+
useOpenExternal,
|
|
10
|
+
useSendFollowUp,
|
|
11
|
+
useToolContext,
|
|
12
|
+
useViewTheme,
|
|
13
|
+
useViewTool,
|
|
14
|
+
} from "mcp-use/react";
|
|
15
|
+
import { useState } from "react";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
CloseIcon,
|
|
20
|
+
ExpandIcon,
|
|
21
|
+
ExternalLinkIcon,
|
|
22
|
+
MonitorIcon,
|
|
23
|
+
MoonIcon,
|
|
24
|
+
PipIcon,
|
|
25
|
+
SmartphoneIcon,
|
|
26
|
+
SunIcon,
|
|
27
|
+
} from "./icons.js";
|
|
28
|
+
import { HeroMeshOrb } from "./MeshGradient.js";
|
|
29
|
+
import { Tooltip } from "./Tooltip.js";
|
|
30
|
+
import "./view.css";
|
|
31
|
+
|
|
32
|
+
export default function McpApp() {
|
|
33
|
+
// useToolContext — tool lifecycle (pending / error / result)
|
|
34
|
+
const view = useToolContext<"show-app">();
|
|
35
|
+
// useHostContext — locale, timezone, platform, capabilities
|
|
36
|
+
const { hostCapabilities, platform, displayMode, locale, timeZone } =
|
|
37
|
+
useHostContext();
|
|
38
|
+
const theme = useViewTheme();
|
|
39
|
+
// useDisplayMode — request pip / fullscreen / inline
|
|
40
|
+
const { availableDisplayModes, requestDisplayMode } = useDisplayMode();
|
|
41
|
+
// useOpenExternal — open URLs via the host
|
|
42
|
+
const openExternal = useOpenExternal();
|
|
43
|
+
// useSendFollowUp — send a prompt back to the host
|
|
44
|
+
const sendFollowUp = useSendFollowUp();
|
|
45
|
+
// useCallTool — invoke server tools from the view
|
|
46
|
+
const sayHello = useCallTool("say-hello");
|
|
47
|
+
|
|
48
|
+
const [count, setCount] = useState(0);
|
|
49
|
+
const [highlighted, setHighlighted] = useState(false);
|
|
50
|
+
|
|
51
|
+
// useViewTool — register a tool callable from the host
|
|
52
|
+
useViewTool(
|
|
53
|
+
{
|
|
54
|
+
name: "set-counter",
|
|
55
|
+
description: "Set the counter displayed in the MCP App card",
|
|
56
|
+
inputSchema: z.object({
|
|
57
|
+
value: z.number().int().min(0).describe("Counter value to display"),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
async ({ value }) => {
|
|
61
|
+
setCount(value);
|
|
62
|
+
setHighlighted(true);
|
|
63
|
+
window.setTimeout(() => setHighlighted(false), 1200);
|
|
64
|
+
return { content: [{ type: "text", text: `Counter set to ${value}` }] };
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const isMobile = platform === "mobile";
|
|
69
|
+
const isFullscreen = displayMode === "fullscreen";
|
|
70
|
+
const isPip = displayMode === "pip";
|
|
71
|
+
const pending = view.status === "pending";
|
|
72
|
+
const canOpenExternal = hostCapabilities?.openLinks !== undefined;
|
|
73
|
+
const canSendFollowUp = hostCapabilities?.message !== undefined;
|
|
74
|
+
const callResult = sayHello.data?.structuredContent?.greeting;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<ThemeProvider>
|
|
78
|
+
<div
|
|
79
|
+
data-card-shell
|
|
80
|
+
className={
|
|
81
|
+
isFullscreen
|
|
82
|
+
? "relative flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden rounded-none border-0 bg-white dark:bg-black"
|
|
83
|
+
: `relative overflow-hidden rounded-3xl border border-zinc-200 bg-white dark:border-white/10 dark:bg-black${
|
|
84
|
+
!pending && highlighted
|
|
85
|
+
? " ring-2 ring-blue-500 ring-offset-2 dark:ring-offset-black"
|
|
86
|
+
: ""
|
|
87
|
+
}`
|
|
88
|
+
}
|
|
89
|
+
>
|
|
90
|
+
{!isMobile && <HeroMeshOrb />}
|
|
91
|
+
{!isFullscreen && (
|
|
92
|
+
<div className="absolute inset-x-4 top-4 z-20 flex items-center justify-between">
|
|
93
|
+
<div className="flex items-center gap-2">
|
|
94
|
+
<Tooltip label={`MCP Host sending: Theme: ${theme}`} multiline>
|
|
95
|
+
<span
|
|
96
|
+
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium tracking-wide text-neutral-500 dark:text-neutral-400"
|
|
97
|
+
aria-label={`Theme: ${theme}`}
|
|
98
|
+
>
|
|
99
|
+
{theme === "dark" ? <MoonIcon /> : <SunIcon />}
|
|
100
|
+
</span>
|
|
101
|
+
</Tooltip>
|
|
102
|
+
<Tooltip
|
|
103
|
+
label={`MCP Host sending: Platform: ${isMobile ? "mobile" : "web"}`}
|
|
104
|
+
multiline
|
|
105
|
+
>
|
|
106
|
+
<span
|
|
107
|
+
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium tracking-wide text-neutral-500 dark:text-neutral-400"
|
|
108
|
+
aria-label={`Platform: ${isMobile ? "mobile" : "web"}`}
|
|
109
|
+
>
|
|
110
|
+
{isMobile ? <SmartphoneIcon /> : <MonitorIcon />}
|
|
111
|
+
</span>
|
|
112
|
+
</Tooltip>
|
|
113
|
+
<Tooltip label={`MCP Host sending: Locale: ${locale}`} multiline>
|
|
114
|
+
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium tracking-wide text-neutral-500 dark:text-neutral-400">
|
|
115
|
+
{locale}
|
|
116
|
+
</span>
|
|
117
|
+
</Tooltip>
|
|
118
|
+
<Tooltip
|
|
119
|
+
label={`MCP Host sending: Timezone: ${timeZone}`}
|
|
120
|
+
multiline
|
|
121
|
+
>
|
|
122
|
+
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium tracking-wide text-neutral-500 dark:text-neutral-400">
|
|
123
|
+
{timeZone.split("/").pop()?.replace(/_/g, " ") ?? timeZone}
|
|
124
|
+
</span>
|
|
125
|
+
</Tooltip>
|
|
126
|
+
</div>
|
|
127
|
+
<div className="flex items-center gap-2">
|
|
128
|
+
{!isFullscreen && !isPip && (
|
|
129
|
+
<>
|
|
130
|
+
{availableDisplayModes.includes("pip") && (
|
|
131
|
+
<Tooltip
|
|
132
|
+
label="MCP Apps display mode: picture-in-picture"
|
|
133
|
+
multiline
|
|
134
|
+
>
|
|
135
|
+
<button
|
|
136
|
+
type="button"
|
|
137
|
+
className="cursor-pointer rounded-full border border-neutral-300 p-2 text-neutral-900 transition-colors hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-100 dark:hover:bg-neutral-800"
|
|
138
|
+
aria-label="Picture-in-picture"
|
|
139
|
+
onClick={() => void requestDisplayMode({ mode: "pip" })}
|
|
140
|
+
>
|
|
141
|
+
<PipIcon />
|
|
142
|
+
</button>
|
|
143
|
+
</Tooltip>
|
|
144
|
+
)}
|
|
145
|
+
{availableDisplayModes.includes("fullscreen") && (
|
|
146
|
+
<Tooltip
|
|
147
|
+
label="MCP Apps display mode: fullscreen"
|
|
148
|
+
multiline
|
|
149
|
+
>
|
|
150
|
+
<button
|
|
151
|
+
type="button"
|
|
152
|
+
className="cursor-pointer rounded-full border border-neutral-300 p-2 text-neutral-900 transition-colors hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-100 dark:hover:bg-neutral-800"
|
|
153
|
+
aria-label="Fullscreen"
|
|
154
|
+
onClick={() =>
|
|
155
|
+
void requestDisplayMode({ mode: "fullscreen" })
|
|
156
|
+
}
|
|
157
|
+
>
|
|
158
|
+
<ExpandIcon />
|
|
159
|
+
</button>
|
|
160
|
+
</Tooltip>
|
|
161
|
+
)}
|
|
162
|
+
</>
|
|
163
|
+
)}
|
|
164
|
+
{(isFullscreen || isPip) && (
|
|
165
|
+
<Tooltip
|
|
166
|
+
label="MCP Apps display mode: return to inline"
|
|
167
|
+
multiline
|
|
168
|
+
>
|
|
169
|
+
<button
|
|
170
|
+
type="button"
|
|
171
|
+
className="cursor-pointer rounded-full border border-neutral-300 p-2 text-neutral-900 transition-colors hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-100 dark:hover:bg-neutral-800"
|
|
172
|
+
aria-label="Exit"
|
|
173
|
+
onClick={() => void requestDisplayMode({ mode: "inline" })}
|
|
174
|
+
>
|
|
175
|
+
<CloseIcon />
|
|
176
|
+
</button>
|
|
177
|
+
</Tooltip>
|
|
178
|
+
)}
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
{!isMobile && (
|
|
183
|
+
<button
|
|
184
|
+
type="button"
|
|
185
|
+
className="absolute bottom-6 left-1/2 z-20 flex -translate-x-1/2 cursor-pointer flex-col items-center gap-1 border-0 bg-transparent p-0 text-neutral-900 transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
|
|
186
|
+
disabled={!canOpenExternal}
|
|
187
|
+
title="mcp-use on GitHub"
|
|
188
|
+
onClick={() =>
|
|
189
|
+
void openExternal({ url: "https://github.com/mcp-use/mcp-use" })
|
|
190
|
+
}
|
|
191
|
+
>
|
|
192
|
+
<span className="text-[10px] font-medium tracking-wide uppercase">
|
|
193
|
+
Built with
|
|
194
|
+
</span>
|
|
195
|
+
<Image
|
|
196
|
+
src="/logo-mcp-use.svg"
|
|
197
|
+
alt="mcp-use"
|
|
198
|
+
className="h-[1.4rem] w-auto max-w-[115px] object-contain"
|
|
199
|
+
/>
|
|
200
|
+
</button>
|
|
201
|
+
)}
|
|
202
|
+
<div
|
|
203
|
+
className={`relative z-10 flex flex-col items-center text-center ${
|
|
204
|
+
isFullscreen
|
|
205
|
+
? "min-h-0 flex-1 justify-center overflow-y-auto px-6 py-8"
|
|
206
|
+
: isMobile
|
|
207
|
+
? "px-6 py-10"
|
|
208
|
+
: "min-h-[400px] px-8 py-8 pb-16 sm:min-h-[440px] sm:px-10 sm:py-10 sm:pb-16"
|
|
209
|
+
}`}
|
|
210
|
+
>
|
|
211
|
+
{view.status === "error" ? (
|
|
212
|
+
<>
|
|
213
|
+
<h1 className="m-0 text-2xl font-semibold tracking-tight text-neutral-900 dark:text-neutral-100">
|
|
214
|
+
Failed to load MCP App
|
|
215
|
+
</h1>
|
|
216
|
+
<p className="mt-4 mb-0 text-sm text-neutral-600 dark:text-neutral-400">
|
|
217
|
+
{view.error.message}
|
|
218
|
+
</p>
|
|
219
|
+
</>
|
|
220
|
+
) : (
|
|
221
|
+
<>
|
|
222
|
+
{/* ModelContext — push state the host model can read */}
|
|
223
|
+
{!pending && (
|
|
224
|
+
<ModelContext content={`MCP App counter: ${count}`} />
|
|
225
|
+
)}
|
|
226
|
+
<div
|
|
227
|
+
className={`relative z-10 mb-0 flex flex-col items-center gap-3 ${isMobile ? "mt-10" : "mt-3"}`}
|
|
228
|
+
>
|
|
229
|
+
{pending ? (
|
|
230
|
+
<span
|
|
231
|
+
aria-hidden
|
|
232
|
+
className="inline-block h-7 w-[4.75rem] animate-pulse rounded-full bg-zinc-200 dark:bg-zinc-800"
|
|
233
|
+
/>
|
|
234
|
+
) : (
|
|
235
|
+
<button
|
|
236
|
+
type="button"
|
|
237
|
+
className="inline-flex cursor-pointer items-center gap-1 rounded-full border border-neutral-300 bg-transparent px-3 py-1 text-xs font-medium text-neutral-600 transition-colors hover:bg-neutral-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-600 dark:text-neutral-300 dark:hover:bg-neutral-800"
|
|
238
|
+
disabled={!canOpenExternal}
|
|
239
|
+
onClick={() =>
|
|
240
|
+
void openExternal({
|
|
241
|
+
url: "https://mcp-use.com/docs/typescript",
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
>
|
|
245
|
+
Docs
|
|
246
|
+
<ExternalLinkIcon />
|
|
247
|
+
</button>
|
|
248
|
+
)}
|
|
249
|
+
<h1
|
|
250
|
+
className={`hero-title relative z-10 mx-auto mb-0 max-w-md text-center font-medium leading-tight text-neutral-900 dark:text-neutral-100 ${
|
|
251
|
+
isMobile ? "text-2xl" : "text-4xl sm:text-5xl"
|
|
252
|
+
}`}
|
|
253
|
+
>
|
|
254
|
+
{pending ? (
|
|
255
|
+
<span className="inline-block animate-pulse rounded-sm text-transparent select-none bg-zinc-200 dark:bg-zinc-800">
|
|
256
|
+
{view.toolInput?.appName?.trim() || "MCP App"}
|
|
257
|
+
</span>
|
|
258
|
+
) : (
|
|
259
|
+
view.toolInput?.appName?.trim() || "MCP App"
|
|
260
|
+
)}
|
|
261
|
+
</h1>
|
|
262
|
+
</div>
|
|
263
|
+
<p
|
|
264
|
+
className={`relative z-10 mx-auto mt-4 mb-6 max-w-md text-center leading-relaxed text-neutral-600 dark:text-neutral-400 ${isMobile ? "text-sm" : "text-base"}`}
|
|
265
|
+
>
|
|
266
|
+
{pending ? (
|
|
267
|
+
<span className="inline-block animate-pulse rounded-sm text-transparent select-none bg-zinc-200 dark:bg-zinc-800">
|
|
268
|
+
Get started by editing{" "}
|
|
269
|
+
<code className="inline-flex align-middle rounded-md bg-zinc-100 px-1.5 py-0.5 font-mono text-[13px] leading-none text-transparent dark:bg-zinc-800">
|
|
270
|
+
views/my-view/view.tsx
|
|
271
|
+
</code>
|
|
272
|
+
</span>
|
|
273
|
+
) : (
|
|
274
|
+
<>
|
|
275
|
+
Get started by editing{" "}
|
|
276
|
+
<code className="inline-flex align-middle rounded-md bg-zinc-100 px-1.5 py-0.5 font-mono text-[13px] leading-none text-neutral-700 dark:bg-zinc-800 dark:text-neutral-200">
|
|
277
|
+
views/my-view/view.tsx
|
|
278
|
+
</code>
|
|
279
|
+
</>
|
|
280
|
+
)}
|
|
281
|
+
</p>
|
|
282
|
+
<div
|
|
283
|
+
className={`relative z-10 flex w-full flex-wrap items-center justify-center ${isMobile ? "gap-1.5" : "gap-2"}`}
|
|
284
|
+
>
|
|
285
|
+
<Tooltip
|
|
286
|
+
label="Widget state: updates UI and Model Context for the host"
|
|
287
|
+
multiline
|
|
288
|
+
>
|
|
289
|
+
<button
|
|
290
|
+
type="button"
|
|
291
|
+
disabled={pending}
|
|
292
|
+
aria-hidden={pending}
|
|
293
|
+
tabIndex={pending ? -1 : 0}
|
|
294
|
+
className={`inline-flex cursor-pointer items-center gap-1.5 rounded-full bg-black font-normal text-white transition-colors hover:bg-black/90 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-white dark:text-black dark:hover:bg-white/90 ${
|
|
295
|
+
isMobile ? "px-3 py-1.5 text-xs" : "px-4 py-2 text-sm"
|
|
296
|
+
} ${pending ? "animate-pulse opacity-70" : ""}`}
|
|
297
|
+
onClick={() => setCount((c) => c + 1)}
|
|
298
|
+
>
|
|
299
|
+
<span className={pending ? "text-transparent" : undefined}>
|
|
300
|
+
Update State
|
|
301
|
+
</span>
|
|
302
|
+
<span
|
|
303
|
+
className={`rounded-full border tabular-nums ${
|
|
304
|
+
isMobile
|
|
305
|
+
? "px-1 py-0.5 text-[10px]"
|
|
306
|
+
: "px-1.5 py-0.5 text-xs"
|
|
307
|
+
} border-white/35 dark:border-black/25 ${pending ? "text-transparent" : ""}`}
|
|
308
|
+
>
|
|
309
|
+
{count}
|
|
310
|
+
</span>
|
|
311
|
+
</button>
|
|
312
|
+
</Tooltip>
|
|
313
|
+
<Tooltip
|
|
314
|
+
label="In-app tool calls: invoke MCP tools from the view"
|
|
315
|
+
multiline
|
|
316
|
+
>
|
|
317
|
+
<button
|
|
318
|
+
type="button"
|
|
319
|
+
disabled={pending || sayHello.isPending}
|
|
320
|
+
aria-hidden={pending}
|
|
321
|
+
tabIndex={pending ? -1 : 0}
|
|
322
|
+
className={`inline-flex cursor-pointer items-center gap-1.5 rounded-full border border-neutral-300 bg-transparent font-normal text-neutral-900 transition-colors hover:bg-neutral-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-600 dark:text-neutral-100 dark:hover:bg-neutral-800 ${
|
|
323
|
+
isMobile ? "px-3 py-1.5 text-xs" : "px-4 py-2 text-sm"
|
|
324
|
+
} ${pending ? "animate-pulse opacity-70" : ""}`}
|
|
325
|
+
onClick={() => void sayHello.callTool({ name: "mcp-use" })}
|
|
326
|
+
>
|
|
327
|
+
<span className={pending ? "text-transparent" : undefined}>
|
|
328
|
+
{sayHello.isPending ? "Saying…" : "Say Hello"}
|
|
329
|
+
</span>
|
|
330
|
+
</button>
|
|
331
|
+
</Tooltip>
|
|
332
|
+
<Tooltip
|
|
333
|
+
label="Follow-up messages: send a prompt back to the MCP host"
|
|
334
|
+
multiline
|
|
335
|
+
>
|
|
336
|
+
<button
|
|
337
|
+
type="button"
|
|
338
|
+
disabled={pending || !canSendFollowUp}
|
|
339
|
+
aria-hidden={pending}
|
|
340
|
+
tabIndex={pending ? -1 : 0}
|
|
341
|
+
className={`inline-flex cursor-pointer items-center gap-1.5 rounded-full border border-neutral-300 bg-transparent font-normal text-neutral-900 transition-colors hover:bg-neutral-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-600 dark:text-neutral-100 dark:hover:bg-neutral-800 ${
|
|
342
|
+
isMobile ? "px-3 py-1.5 text-xs" : "px-4 py-2 text-sm"
|
|
343
|
+
} ${pending ? "animate-pulse opacity-70" : ""}`}
|
|
344
|
+
onClick={() =>
|
|
345
|
+
void sendFollowUp({
|
|
346
|
+
prompt:
|
|
347
|
+
"Tell me more about MCP Apps and views in mcp-use",
|
|
348
|
+
}).catch(() => {})
|
|
349
|
+
}
|
|
350
|
+
>
|
|
351
|
+
<span className={pending ? "text-transparent" : undefined}>
|
|
352
|
+
Send Followup
|
|
353
|
+
</span>
|
|
354
|
+
</button>
|
|
355
|
+
</Tooltip>
|
|
356
|
+
</div>
|
|
357
|
+
{!pending && callResult !== undefined && (
|
|
358
|
+
<p className="mx-auto mt-4 mb-0 text-center text-sm text-neutral-600 dark:text-neutral-400">
|
|
359
|
+
Tool Response: {callResult}
|
|
360
|
+
</p>
|
|
361
|
+
)}
|
|
362
|
+
{!pending && sayHello.error !== undefined && (
|
|
363
|
+
<p className="mt-4 mb-0 text-sm text-red-500" role="alert">
|
|
364
|
+
{sayHello.error.message}
|
|
365
|
+
</p>
|
|
366
|
+
)}
|
|
367
|
+
</>
|
|
368
|
+
)}
|
|
369
|
+
</div>
|
|
370
|
+
{isMobile && !isFullscreen && (
|
|
371
|
+
<div className="relative w-full">
|
|
372
|
+
<HeroMeshOrb flow />
|
|
373
|
+
<button
|
|
374
|
+
type="button"
|
|
375
|
+
className="absolute bottom-3 left-1/2 z-20 flex -translate-x-1/2 cursor-pointer flex-col items-center gap-1 border-0 bg-transparent p-0 text-neutral-900 transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
|
|
376
|
+
disabled={!canOpenExternal}
|
|
377
|
+
title="mcp-use on GitHub"
|
|
378
|
+
onClick={() =>
|
|
379
|
+
void openExternal({ url: "https://github.com/mcp-use/mcp-use" })
|
|
380
|
+
}
|
|
381
|
+
>
|
|
382
|
+
<span className="text-[10px] font-medium tracking-wide uppercase">
|
|
383
|
+
Built with
|
|
384
|
+
</span>
|
|
385
|
+
<Image
|
|
386
|
+
src="/logo-mcp-use.svg"
|
|
387
|
+
alt="mcp-use"
|
|
388
|
+
className="h-[1.15rem] w-auto max-w-[98px] object-contain"
|
|
389
|
+
/>
|
|
390
|
+
</button>
|
|
391
|
+
</div>
|
|
392
|
+
)}
|
|
393
|
+
</div>
|
|
394
|
+
</ThemeProvider>
|
|
395
|
+
);
|
|
396
|
+
}
|
|
@@ -11,9 +11,9 @@ npm install
|
|
|
11
11
|
npm run dev
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Open [http://localhost:3000/inspector](http://localhost:3000/inspector) with your browser to test your server.
|
|
14
|
+
Open [http://localhost:3000/mcp/inspector](http://localhost:3000/mcp/inspector) with your browser to test your server.
|
|
15
15
|
|
|
16
|
-
You can start building by editing the entry file. Add tools
|
|
16
|
+
You can start building by editing the entry file. Add tools and prompts — the server auto-reloads as you edit.
|
|
17
17
|
|
|
18
18
|
## Learn More
|
|
19
19
|
|
|
@@ -29,24 +29,6 @@ server.tool(
|
|
|
29
29
|
}
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
server.resource(
|
|
33
|
-
{
|
|
34
|
-
name: "settings",
|
|
35
|
-
uri: "config://settings",
|
|
36
|
-
description: "Example application settings",
|
|
37
|
-
mimeType: "application/json",
|
|
38
|
-
},
|
|
39
|
-
async (uri) => ({
|
|
40
|
-
contents: [
|
|
41
|
-
{
|
|
42
|
-
uri: uri.href,
|
|
43
|
-
mimeType: "application/json",
|
|
44
|
-
text: JSON.stringify({ theme: "dark", language: "en" }),
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
})
|
|
48
|
-
);
|
|
49
|
-
|
|
50
32
|
server.prompt(
|
|
51
33
|
{
|
|
52
34
|
name: "review-code",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-mcp-use-app",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Create MCP-Use apps with one command",
|
|
6
6
|
"author": "mcp-use, Inc.",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scaffold",
|
|
23
23
|
"cli",
|
|
24
24
|
"init",
|
|
25
|
-
"
|
|
25
|
+
"mcp-server",
|
|
26
26
|
"template"
|
|
27
27
|
],
|
|
28
28
|
"bin": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import { AccordionItem } from "./AccordionItem.js";
|
|
3
|
-
|
|
4
|
-
export interface AccordionItemData {
|
|
5
|
-
question: string;
|
|
6
|
-
answer: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface AccordionProps {
|
|
10
|
-
items: AccordionItemData[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function Accordion({ items }: AccordionProps) {
|
|
14
|
-
const [openAccordionIndex, setOpenAccordionIndex] = useState<number | null>(
|
|
15
|
-
null
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="mt-4 border-t border-neutral-200 p-8 pt-4 dark:border-neutral-700">
|
|
20
|
-
<div className="overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-700">
|
|
21
|
-
{items.map((item, index) => (
|
|
22
|
-
<AccordionItem
|
|
23
|
-
key={index}
|
|
24
|
-
question={item.question}
|
|
25
|
-
answer={item.answer}
|
|
26
|
-
isOpen={openAccordionIndex === index}
|
|
27
|
-
onToggle={() =>
|
|
28
|
-
setOpenAccordionIndex(openAccordionIndex === index ? null : index)
|
|
29
|
-
}
|
|
30
|
-
/>
|
|
31
|
-
))}
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export interface AccordionItemProps {
|
|
2
|
-
question: string;
|
|
3
|
-
answer: string;
|
|
4
|
-
isOpen: boolean;
|
|
5
|
-
onToggle: () => void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function AccordionItem({
|
|
9
|
-
question,
|
|
10
|
-
answer,
|
|
11
|
-
isOpen,
|
|
12
|
-
onToggle,
|
|
13
|
-
}: AccordionItemProps) {
|
|
14
|
-
return (
|
|
15
|
-
<div className="border-b border-neutral-200 last:border-b-0 dark:border-neutral-700">
|
|
16
|
-
<button
|
|
17
|
-
type="button"
|
|
18
|
-
onClick={onToggle}
|
|
19
|
-
className="flex w-full items-center justify-between p-4 text-left transition-colors hover:bg-neutral-50 dark:hover:bg-neutral-900"
|
|
20
|
-
>
|
|
21
|
-
<span className="font-medium text-neutral-900 dark:text-neutral-100">
|
|
22
|
-
{question}
|
|
23
|
-
</span>
|
|
24
|
-
<span className="text-xl text-neutral-500 transition-transform duration-200 dark:text-neutral-400">
|
|
25
|
-
{isOpen ? "−" : "+"}
|
|
26
|
-
</span>
|
|
27
|
-
</button>
|
|
28
|
-
{isOpen && (
|
|
29
|
-
<div className="px-4 pb-4 text-neutral-600 dark:text-neutral-400">
|
|
30
|
-
{answer}
|
|
31
|
-
</div>
|
|
32
|
-
)}
|
|
33
|
-
</div>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { useRef } from "react";
|
|
2
|
-
import { CarouselItem } from "./CarouselItem.js";
|
|
3
|
-
import { useCarouselAnimation } from "../hooks/useCarouselAnimation.js";
|
|
4
|
-
|
|
5
|
-
interface CarouselProps {
|
|
6
|
-
results: Array<{ fruit: string; color: string }>;
|
|
7
|
-
favorites?: string[];
|
|
8
|
-
highlighted?: string | null;
|
|
9
|
-
onSelectFruit: (fruit: string) => void;
|
|
10
|
-
onToggleFavorite?: (fruit: string) => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function Carousel({
|
|
14
|
-
results,
|
|
15
|
-
favorites = [],
|
|
16
|
-
highlighted = null,
|
|
17
|
-
onSelectFruit,
|
|
18
|
-
onToggleFavorite,
|
|
19
|
-
}: CarouselProps) {
|
|
20
|
-
const carouselContainerRef = useRef<HTMLDivElement>(null);
|
|
21
|
-
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
22
|
-
|
|
23
|
-
useCarouselAnimation(carouselContainerRef, scrollContainerRef);
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<div
|
|
27
|
-
ref={scrollContainerRef}
|
|
28
|
-
className="carousel-scroll-container w-full overflow-x-auto overflow-y-visible pl-8"
|
|
29
|
-
>
|
|
30
|
-
<div ref={carouselContainerRef} className="overflow-visible">
|
|
31
|
-
<div className="flex gap-4">
|
|
32
|
-
{results.map((item, index) => {
|
|
33
|
-
const fruit = item.fruit;
|
|
34
|
-
return (
|
|
35
|
-
<CarouselItem
|
|
36
|
-
key={`${fruit}-${index}`}
|
|
37
|
-
fruit={fruit}
|
|
38
|
-
color={item.color}
|
|
39
|
-
isFavorite={favorites.includes(fruit)}
|
|
40
|
-
isHighlighted={highlighted === fruit}
|
|
41
|
-
onClick={() => onSelectFruit(fruit)}
|
|
42
|
-
{...(onToggleFavorite !== undefined && {
|
|
43
|
-
onToggleFavorite: () => onToggleFavorite(fruit),
|
|
44
|
-
})}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
})}
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
}
|