create-mcp-use-app 2.0.0-beta.2 → 2.0.0-beta.3
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 +2 -2
- package/dist/index.js +10 -4
- package/dist/templates/blank/package.json +9 -5
- package/dist/templates/blank/tsconfig.json +13 -10
- package/dist/templates/mcp-apps/index.ts +119 -15
- package/dist/templates/mcp-apps/{tools.d.ts → mcp-env.d.ts} +3 -1
- package/dist/templates/mcp-apps/package.json +9 -10
- 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/tsconfig.json +9 -4
- package/dist/templates/mcp-apps/views/product-search-result/components/Accordion.tsx +35 -0
- package/dist/templates/mcp-apps/views/product-search-result/components/AccordionItem.tsx +35 -0
- package/dist/templates/mcp-apps/views/product-search-result/components/Carousel.tsx +52 -0
- package/dist/templates/mcp-apps/views/product-search-result/components/CarouselItem.tsx +91 -0
- package/dist/templates/mcp-apps/views/product-search-result/components/CarouselSkeleton.tsx +18 -0
- package/dist/templates/mcp-apps/views/product-search-result/hooks/useCarouselAnimation.ts +72 -0
- package/dist/templates/mcp-apps/views/product-search-result/view.css +81 -0
- package/dist/templates/mcp-apps/views/product-search-result/view.tsx +371 -0
- package/dist/templates/starter/package.json +9 -8
- package/dist/templates/starter/tsconfig.json +13 -10
- package/package.json +1 -1
- package/dist/templates/blank/public/favicon.ico +0 -0
- package/dist/templates/mcp-apps/public/favicon.ico +0 -0
- package/dist/templates/mcp-apps/public/fruits/apple.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/apricot.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/avocado.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/banana.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/blueberry.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/cherries.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/coconut.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/grapes.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/lemon.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/mango.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/orange.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/pear.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/pineapple.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/plum.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/strawberry.png +0 -0
- package/dist/templates/mcp-apps/public/fruits/watermelon.png +0 -0
- package/dist/templates/mcp-apps/resources/product-search-result/view.tsx +0 -25
- package/dist/templates/starter/public/favicon.ico +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* Carousel scroll container with padding for blur effect */
|
|
2
|
+
.carousel-scroll-container {
|
|
3
|
+
padding-bottom: 2rem;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/* Hover effect styles for carousel items */
|
|
7
|
+
.carousel-item {
|
|
8
|
+
position: relative;
|
|
9
|
+
container-type: size;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
transition-property: translate, scale;
|
|
12
|
+
transition-duration: 0.12s;
|
|
13
|
+
transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
14
|
+
-webkit-tap-highlight-color: transparent;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
border-radius: 12px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.carousel-item:active {
|
|
20
|
+
translate: 0 1px;
|
|
21
|
+
scale: 0.99;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.carousel-item-content {
|
|
25
|
+
position: relative;
|
|
26
|
+
z-index: 2;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.carousel-item-bg {
|
|
35
|
+
position: absolute;
|
|
36
|
+
inset: 0;
|
|
37
|
+
display: grid;
|
|
38
|
+
place-items: center;
|
|
39
|
+
transform: translateZ(0);
|
|
40
|
+
filter: blur(28px) saturate(5) brightness(1.3);
|
|
41
|
+
translate: calc(var(--pointer-x, -10) * 50cqi)
|
|
42
|
+
calc(var(--pointer-y, -10) * 50cqh);
|
|
43
|
+
scale: var(--icon-scale, 3.4);
|
|
44
|
+
opacity: var(--icon-opacity, 0.25);
|
|
45
|
+
will-change: transform, filter, opacity;
|
|
46
|
+
pointer-events: none;
|
|
47
|
+
z-index: 1;
|
|
48
|
+
transition:
|
|
49
|
+
opacity 0.26s ease-out,
|
|
50
|
+
scale 0.26s ease-out;
|
|
51
|
+
border-radius: inherit;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.carousel-item-bg img {
|
|
55
|
+
width: 100px;
|
|
56
|
+
-webkit-user-select: none;
|
|
57
|
+
user-select: none;
|
|
58
|
+
-webkit-user-drag: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.carousel-item::after {
|
|
62
|
+
content: "";
|
|
63
|
+
position: absolute;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
inset: 0px;
|
|
66
|
+
border-radius: inherit;
|
|
67
|
+
border: 3px solid transparent;
|
|
68
|
+
backdrop-filter: blur(0px) saturate(4.2) brightness(2.5) contrast(2.5);
|
|
69
|
+
-webkit-backdrop-filter: blur(0px) saturate(4.2) brightness(2.5) contrast(2.5);
|
|
70
|
+
mask:
|
|
71
|
+
linear-gradient(#fff 0 100%) border-box,
|
|
72
|
+
linear-gradient(#fff 0 100%) padding-box;
|
|
73
|
+
mask-composite: exclude;
|
|
74
|
+
z-index: 3;
|
|
75
|
+
transform: translateZ(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.carousel-item-highlighted {
|
|
79
|
+
outline: 2px solid rgb(37 99 235);
|
|
80
|
+
outline-offset: 2px;
|
|
81
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Image,
|
|
3
|
+
ModelContext,
|
|
4
|
+
ThemeProvider,
|
|
5
|
+
ViewControls,
|
|
6
|
+
useCallTool,
|
|
7
|
+
useDisplayMode,
|
|
8
|
+
useHostContext,
|
|
9
|
+
useOpenExternal,
|
|
10
|
+
useSendFollowUp,
|
|
11
|
+
useToolContext,
|
|
12
|
+
useViewTheme,
|
|
13
|
+
useViewTool,
|
|
14
|
+
} from "mcp-use/react";
|
|
15
|
+
import { useCallback, useState } from "react";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
import { Accordion } from "./components/Accordion.js";
|
|
19
|
+
import { Carousel } from "./components/Carousel.js";
|
|
20
|
+
import { CarouselSkeleton } from "./components/CarouselSkeleton.js";
|
|
21
|
+
import "./view.css";
|
|
22
|
+
|
|
23
|
+
const shellClass =
|
|
24
|
+
"relative rounded-3xl border border-neutral-200 bg-white dark:border-neutral-700 dark:bg-neutral-900";
|
|
25
|
+
|
|
26
|
+
const iconButtonClass =
|
|
27
|
+
"rounded-full border border-neutral-300 p-2 transition-colors hover:bg-neutral-100 dark:border-neutral-600 dark:hover:bg-neutral-800";
|
|
28
|
+
|
|
29
|
+
function HeartIcon({ filled }: { filled: boolean }) {
|
|
30
|
+
if (filled) {
|
|
31
|
+
return (
|
|
32
|
+
<svg
|
|
33
|
+
width="14"
|
|
34
|
+
height="14"
|
|
35
|
+
viewBox="0 0 24 24"
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
aria-hidden
|
|
38
|
+
>
|
|
39
|
+
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return (
|
|
44
|
+
<svg
|
|
45
|
+
width="14"
|
|
46
|
+
height="14"
|
|
47
|
+
viewBox="0 0 24 24"
|
|
48
|
+
fill="none"
|
|
49
|
+
stroke="currentColor"
|
|
50
|
+
strokeWidth="2"
|
|
51
|
+
aria-hidden
|
|
52
|
+
>
|
|
53
|
+
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
|
|
54
|
+
</svg>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function ExpandIcon() {
|
|
59
|
+
return (
|
|
60
|
+
<svg
|
|
61
|
+
width="14"
|
|
62
|
+
height="14"
|
|
63
|
+
viewBox="0 0 24 24"
|
|
64
|
+
fill="none"
|
|
65
|
+
stroke="currentColor"
|
|
66
|
+
strokeWidth="2"
|
|
67
|
+
aria-hidden
|
|
68
|
+
>
|
|
69
|
+
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
|
|
70
|
+
</svg>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function PipIcon() {
|
|
75
|
+
return (
|
|
76
|
+
<svg
|
|
77
|
+
width="14"
|
|
78
|
+
height="14"
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
strokeWidth="2"
|
|
83
|
+
aria-hidden
|
|
84
|
+
>
|
|
85
|
+
<rect x="2" y="4" width="20" height="14" rx="2" />
|
|
86
|
+
<rect x="13" y="11" width="7" height="5" rx="1" fill="currentColor" />
|
|
87
|
+
</svg>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function CloseIcon() {
|
|
92
|
+
return (
|
|
93
|
+
<svg
|
|
94
|
+
width="14"
|
|
95
|
+
height="14"
|
|
96
|
+
viewBox="0 0 24 24"
|
|
97
|
+
fill="none"
|
|
98
|
+
stroke="currentColor"
|
|
99
|
+
strokeWidth="2"
|
|
100
|
+
aria-hidden
|
|
101
|
+
>
|
|
102
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
103
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
104
|
+
</svg>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function ProductSearchResultContent() {
|
|
109
|
+
const view = useToolContext<"search-fruits">();
|
|
110
|
+
const theme = useViewTheme();
|
|
111
|
+
const { locale, hostCapabilities } = useHostContext();
|
|
112
|
+
const { displayMode, availableDisplayModes, requestDisplayMode } =
|
|
113
|
+
useDisplayMode();
|
|
114
|
+
const sendFollowUp = useSendFollowUp();
|
|
115
|
+
const openExternal = useOpenExternal();
|
|
116
|
+
|
|
117
|
+
const [favorites, setFavorites] = useState<string[]>([]);
|
|
118
|
+
const [highlighted, setHighlighted] = useState<string | null>(null);
|
|
119
|
+
|
|
120
|
+
const details = useCallTool("get-fruit-details");
|
|
121
|
+
|
|
122
|
+
useViewTool(
|
|
123
|
+
{
|
|
124
|
+
name: "highlight-fruit",
|
|
125
|
+
description: "Highlight a visible result in the carousel",
|
|
126
|
+
inputSchema: z.object({ id: z.string() }),
|
|
127
|
+
},
|
|
128
|
+
async ({ id }) => {
|
|
129
|
+
setHighlighted(id);
|
|
130
|
+
return { content: [{ type: "text", text: `Highlighted ${id}` }] };
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const toggleFavorite = useCallback((fruit: string) => {
|
|
135
|
+
setFavorites((current) =>
|
|
136
|
+
current.includes(fruit)
|
|
137
|
+
? current.filter((f) => f !== fruit)
|
|
138
|
+
: [...current, fruit]
|
|
139
|
+
);
|
|
140
|
+
}, []);
|
|
141
|
+
|
|
142
|
+
const accordionItems = [
|
|
143
|
+
{
|
|
144
|
+
question: "Demo of the autosize feature",
|
|
145
|
+
answer:
|
|
146
|
+
"This is a demo of the autosize feature. The view will automatically resize to fit the content, as supported by the MCP Apps specification.",
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
const root = theme === "dark" ? "dark" : "";
|
|
151
|
+
const lang = locale?.split("-")[0] ?? "en";
|
|
152
|
+
const isFullscreen = displayMode === "fullscreen";
|
|
153
|
+
const isPip = displayMode === "pip";
|
|
154
|
+
|
|
155
|
+
if (view.status === "error") {
|
|
156
|
+
return (
|
|
157
|
+
<div className={`${root} ${shellClass} p-8`} role="alert">
|
|
158
|
+
<p className="m-0 font-medium text-neutral-900 dark:text-neutral-100">
|
|
159
|
+
Search failed
|
|
160
|
+
</p>
|
|
161
|
+
<p className="mt-2 mb-0 text-sm text-neutral-600 dark:text-neutral-400">
|
|
162
|
+
{view.error.message}
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (view.status === "pending") {
|
|
169
|
+
return (
|
|
170
|
+
<div className={`${root} ${shellClass}`}>
|
|
171
|
+
<div className="p-8 pb-4">
|
|
172
|
+
<h5 className="mb-1 text-sm text-neutral-500 dark:text-neutral-400">
|
|
173
|
+
MCP-Apps Template
|
|
174
|
+
</h5>
|
|
175
|
+
<h2 className="mb-3 text-2xl font-semibold text-neutral-900 dark:text-neutral-100">
|
|
176
|
+
Lovely Little Fruit Shop
|
|
177
|
+
</h2>
|
|
178
|
+
<div className="h-5 w-48 animate-pulse rounded-md bg-neutral-100 dark:bg-neutral-800" />
|
|
179
|
+
</div>
|
|
180
|
+
<CarouselSkeleton />
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const { query, results } = view.toolOutput;
|
|
186
|
+
const selectedFruit = details.data?.structuredContent;
|
|
187
|
+
const isLoadingDetails = details.isPending;
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div className={`${root} ${shellClass}`}>
|
|
191
|
+
<ModelContext
|
|
192
|
+
content={`User is viewing results for "${query}"; favorites: ${favorites.join(", ") || "none"}`}
|
|
193
|
+
/>
|
|
194
|
+
|
|
195
|
+
<div className="absolute top-4 right-4 z-10 flex items-center gap-2">
|
|
196
|
+
<span className="rounded-full px-2.5 py-1 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">
|
|
197
|
+
{lang}
|
|
198
|
+
</span>
|
|
199
|
+
|
|
200
|
+
{favorites.length > 0 && (
|
|
201
|
+
<span className="flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium text-red-500">
|
|
202
|
+
<HeartIcon filled />
|
|
203
|
+
{favorites.length}
|
|
204
|
+
</span>
|
|
205
|
+
)}
|
|
206
|
+
|
|
207
|
+
{!isFullscreen && !isPip && (
|
|
208
|
+
<>
|
|
209
|
+
{availableDisplayModes.includes("pip") && (
|
|
210
|
+
<button
|
|
211
|
+
type="button"
|
|
212
|
+
className={iconButtonClass}
|
|
213
|
+
title="Picture-in-picture"
|
|
214
|
+
onClick={() => {
|
|
215
|
+
void requestDisplayMode({ mode: "pip" });
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
218
|
+
<PipIcon />
|
|
219
|
+
</button>
|
|
220
|
+
)}
|
|
221
|
+
{availableDisplayModes.includes("fullscreen") && (
|
|
222
|
+
<button
|
|
223
|
+
type="button"
|
|
224
|
+
className={iconButtonClass}
|
|
225
|
+
title="Fullscreen"
|
|
226
|
+
onClick={() => {
|
|
227
|
+
void requestDisplayMode({ mode: "fullscreen" });
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
<ExpandIcon />
|
|
231
|
+
</button>
|
|
232
|
+
)}
|
|
233
|
+
</>
|
|
234
|
+
)}
|
|
235
|
+
|
|
236
|
+
{(isFullscreen || isPip) && (
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
className={iconButtonClass}
|
|
240
|
+
title="Exit"
|
|
241
|
+
onClick={() => {
|
|
242
|
+
void requestDisplayMode({ mode: "inline" });
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
<CloseIcon />
|
|
246
|
+
</button>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<div className="p-8 pb-4">
|
|
251
|
+
<h5 className="mb-1 text-sm text-neutral-500 dark:text-neutral-400">
|
|
252
|
+
MCP-Apps Template
|
|
253
|
+
</h5>
|
|
254
|
+
<h2 className="mb-1 text-2xl font-semibold text-neutral-900 dark:text-neutral-100">
|
|
255
|
+
Lovely Little Fruit Shop
|
|
256
|
+
</h2>
|
|
257
|
+
<p className="text-base text-neutral-600 dark:text-neutral-400">
|
|
258
|
+
{query
|
|
259
|
+
? `Showing results for "${query}"`
|
|
260
|
+
: "Tap a fruit to see details"}
|
|
261
|
+
</p>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<Carousel
|
|
265
|
+
results={results}
|
|
266
|
+
favorites={favorites}
|
|
267
|
+
highlighted={highlighted}
|
|
268
|
+
onSelectFruit={(fruit: string) => {
|
|
269
|
+
void details.callTool({ fruit });
|
|
270
|
+
}}
|
|
271
|
+
onToggleFavorite={toggleFavorite}
|
|
272
|
+
/>
|
|
273
|
+
|
|
274
|
+
{selectedFruit && (
|
|
275
|
+
<div className="mx-8 my-6 flex items-center gap-6 rounded-2xl border border-neutral-200 bg-neutral-50 p-5 dark:border-neutral-700 dark:bg-neutral-950">
|
|
276
|
+
<div
|
|
277
|
+
className={`shrink-0 rounded-xl p-4 ${
|
|
278
|
+
results.find((r) => r.fruit === selectedFruit.fruit)?.color ?? ""
|
|
279
|
+
}`}
|
|
280
|
+
>
|
|
281
|
+
<Image
|
|
282
|
+
src={`/fruits/${selectedFruit.fruit}.webp`}
|
|
283
|
+
alt={selectedFruit.fruit}
|
|
284
|
+
className="h-24 w-24 object-contain"
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
<div className="flex-1">
|
|
288
|
+
{isLoadingDetails ? (
|
|
289
|
+
<div className="h-4 w-32 animate-pulse rounded bg-neutral-200 dark:bg-neutral-800" />
|
|
290
|
+
) : (
|
|
291
|
+
<>
|
|
292
|
+
<div className="mb-2 flex items-center gap-2">
|
|
293
|
+
<h3 className="text-lg font-semibold capitalize">
|
|
294
|
+
{selectedFruit.fruit}
|
|
295
|
+
</h3>
|
|
296
|
+
<button
|
|
297
|
+
type="button"
|
|
298
|
+
onClick={() => toggleFavorite(selectedFruit.fruit)}
|
|
299
|
+
className={`rounded-full p-1 transition-colors hover:bg-neutral-100 dark:hover:bg-neutral-800 ${
|
|
300
|
+
favorites.includes(selectedFruit.fruit)
|
|
301
|
+
? "text-red-500"
|
|
302
|
+
: "text-neutral-500"
|
|
303
|
+
}`}
|
|
304
|
+
title={
|
|
305
|
+
favorites.includes(selectedFruit.fruit)
|
|
306
|
+
? "Remove from favorites"
|
|
307
|
+
: "Add to favorites"
|
|
308
|
+
}
|
|
309
|
+
>
|
|
310
|
+
<HeartIcon
|
|
311
|
+
filled={favorites.includes(selectedFruit.fruit)}
|
|
312
|
+
/>
|
|
313
|
+
</button>
|
|
314
|
+
</div>
|
|
315
|
+
<ul className="space-y-1">
|
|
316
|
+
{selectedFruit.facts.map((fact: string) => (
|
|
317
|
+
<li
|
|
318
|
+
key={fact}
|
|
319
|
+
className="flex items-start gap-2 text-sm text-neutral-600 dark:text-neutral-400"
|
|
320
|
+
>
|
|
321
|
+
<span className="mt-0.5 text-blue-600">•</span>
|
|
322
|
+
{fact}
|
|
323
|
+
</li>
|
|
324
|
+
))}
|
|
325
|
+
</ul>
|
|
326
|
+
<div className="mt-3 flex flex-wrap gap-2">
|
|
327
|
+
{hostCapabilities?.message !== undefined && (
|
|
328
|
+
<button
|
|
329
|
+
type="button"
|
|
330
|
+
onClick={() => {
|
|
331
|
+
void sendFollowUp({
|
|
332
|
+
prompt: `Tell me more interesting facts about ${selectedFruit.fruit}`,
|
|
333
|
+
}).catch(() => {});
|
|
334
|
+
}}
|
|
335
|
+
className="cursor-pointer rounded-lg bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 transition-colors hover:bg-blue-100 dark:bg-blue-950 dark:text-blue-300 dark:hover:bg-blue-900"
|
|
336
|
+
>
|
|
337
|
+
Ask the AI for more about {selectedFruit.fruit}
|
|
338
|
+
</button>
|
|
339
|
+
)}
|
|
340
|
+
<button
|
|
341
|
+
type="button"
|
|
342
|
+
onClick={() => {
|
|
343
|
+
void openExternal({
|
|
344
|
+
url: `https://images.example.com/producers/${selectedFruit.fruit}`,
|
|
345
|
+
});
|
|
346
|
+
}}
|
|
347
|
+
className="cursor-pointer rounded-lg border border-neutral-300 px-3 py-1.5 text-xs font-medium text-neutral-700 transition-colors hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-300 dark:hover:bg-neutral-800"
|
|
348
|
+
>
|
|
349
|
+
View producer
|
|
350
|
+
</button>
|
|
351
|
+
</div>
|
|
352
|
+
</>
|
|
353
|
+
)}
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
|
|
358
|
+
<Accordion items={accordionItems} />
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export default function ProductSearchResult() {
|
|
364
|
+
return (
|
|
365
|
+
<ThemeProvider>
|
|
366
|
+
<ViewControls>
|
|
367
|
+
<ProductSearchResultContent />
|
|
368
|
+
</ViewControls>
|
|
369
|
+
</ThemeProvider>
|
|
370
|
+
);
|
|
371
|
+
}
|
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
"node": ">=22.22.2"
|
|
6
6
|
},
|
|
7
7
|
"version": "1.0.0",
|
|
8
|
-
"description": "
|
|
9
|
-
"author": "",
|
|
8
|
+
"description": "an mcp-use server",
|
|
9
|
+
"author": "mcp-use",
|
|
10
10
|
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/mcp-use/mcp-use",
|
|
11
12
|
"keywords": [
|
|
12
13
|
"mcp",
|
|
13
|
-
"server",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
14
|
+
"mcp-server",
|
|
15
|
+
"chatgpt plugins",
|
|
16
|
+
"claude connector",
|
|
17
|
+
"mcp-app",
|
|
18
|
+
"mcp-use",
|
|
19
|
+
"manufact"
|
|
19
20
|
],
|
|
20
21
|
"main": "dist/index.js",
|
|
21
22
|
"scripts": {
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
3
|
+
"target": "ES2024",
|
|
4
4
|
"jsx": "react-jsx",
|
|
5
|
-
"module": "
|
|
6
|
-
"moduleResolution": "
|
|
7
|
-
"
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"lib": ["ES2024", "DOM", "DOM.Iterable"],
|
|
8
8
|
"strict": true,
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"allowSyntheticDefaultImports": true,
|
|
12
9
|
"esModuleInterop": true,
|
|
13
10
|
"forceConsistentCasingInFileNames": true,
|
|
14
11
|
"skipLibCheck": true,
|
|
15
|
-
"
|
|
16
|
-
"tsBuildInfoFile": "./dist/.tsbuildinfo"
|
|
12
|
+
"noEmit": true
|
|
17
13
|
},
|
|
18
|
-
"include": [
|
|
14
|
+
"include": [
|
|
15
|
+
"index.ts",
|
|
16
|
+
"mcp-env.d.ts",
|
|
17
|
+
"src/**/*",
|
|
18
|
+
"views/**/*",
|
|
19
|
+
"server.ts",
|
|
20
|
+
".mcp-use/**/*.d.ts"
|
|
21
|
+
],
|
|
19
22
|
"exclude": ["node_modules", "dist"]
|
|
20
23
|
}
|
package/package.json
CHANGED
|
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
|
|
Binary file
|
|
Binary file
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { useToolContext } from "mcp-use/react";
|
|
2
|
-
|
|
3
|
-
export default function ProductSearchResult() {
|
|
4
|
-
const view = useToolContext<"search-fruits">();
|
|
5
|
-
|
|
6
|
-
if (view.status === "pending") {
|
|
7
|
-
return (
|
|
8
|
-
<p>
|
|
9
|
-
Searching{view.toolInput?.query ? ` for ${view.toolInput.query}` : ""}…
|
|
10
|
-
</p>
|
|
11
|
-
);
|
|
12
|
-
}
|
|
13
|
-
if (view.status === "error") return <p>{view.error.message}</p>;
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<main>
|
|
17
|
-
<h1>Fruit results</h1>
|
|
18
|
-
<ul>
|
|
19
|
-
{view.toolOutput.items.map((item) => (
|
|
20
|
-
<li key={item.id}>{item.name}</li>
|
|
21
|
-
))}
|
|
22
|
-
</ul>
|
|
23
|
-
</main>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
Binary file
|