create-mcp-use-app 2.0.0-beta.1 → 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 +3 -3
- package/dist/index.js +38 -66
- package/dist/templates/blank/package.json +14 -7
- 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 +16 -14
- 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 +14 -10
- package/dist/templates/starter/tsconfig.json +13 -10
- package/package.json +2 -2
- 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
package/README.md
CHANGED
|
@@ -156,8 +156,8 @@ Perfect for getting started with all available features or building full-feature
|
|
|
156
156
|
The mcp-apps template includes:
|
|
157
157
|
|
|
158
158
|
- MCP server setup focused on OpenAI Apps SDK integration
|
|
159
|
-
- OpenAI Apps SDK compatible
|
|
160
|
-
- Example
|
|
159
|
+
- OpenAI Apps SDK compatible views under `views/<name>/view.tsx`
|
|
160
|
+
- Example `product-search-result` view with carousel UI
|
|
161
161
|
- Optimized for OpenAI assistant integration
|
|
162
162
|
|
|
163
163
|
Ideal for building MCP servers that integrate with OpenAI's Apps SDK.
|
|
@@ -433,7 +433,7 @@ server.prompt("code_review", {
|
|
|
433
433
|
**Command not found:**
|
|
434
434
|
|
|
435
435
|
```bash
|
|
436
|
-
# Make sure you have Node.js
|
|
436
|
+
# Make sure you have Node.js 22.22.2+ installed
|
|
437
437
|
node --version
|
|
438
438
|
|
|
439
439
|
# Try with npx
|
package/dist/index.js
CHANGED
|
@@ -1321,7 +1321,7 @@ function updatePackageJson(projectPath, projectName) {
|
|
|
1321
1321
|
const packageJsonPath = join2(projectPath, "package.json");
|
|
1322
1322
|
const packageJsonContent = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1323
1323
|
packageJsonContent.name = projectName;
|
|
1324
|
-
packageJsonContent.description =
|
|
1324
|
+
packageJsonContent.description = `${projectName}: an mcp-use server`;
|
|
1325
1325
|
writeFileSync(packageJsonPath, JSON.stringify(packageJsonContent, null, 2));
|
|
1326
1326
|
}
|
|
1327
1327
|
function updateIndexTs(projectPath, projectName) {
|
|
@@ -1346,7 +1346,7 @@ function parseCli(argv) {
|
|
|
1346
1346
|
install: { type: "boolean" },
|
|
1347
1347
|
skills: { type: "boolean" },
|
|
1348
1348
|
dev: { type: "boolean" },
|
|
1349
|
-
|
|
1349
|
+
"sdk-version": { type: "string" },
|
|
1350
1350
|
yarn: { type: "boolean" },
|
|
1351
1351
|
npm: { type: "boolean" },
|
|
1352
1352
|
pnpm: { type: "boolean" },
|
|
@@ -1366,7 +1366,7 @@ function parseCli(argv) {
|
|
|
1366
1366
|
install,
|
|
1367
1367
|
skills,
|
|
1368
1368
|
dev: values.dev,
|
|
1369
|
-
|
|
1369
|
+
sdkVersion: values["sdk-version"],
|
|
1370
1370
|
yarn: values.yarn,
|
|
1371
1371
|
npm: values.npm,
|
|
1372
1372
|
pnpm: values.pnpm
|
|
@@ -1539,32 +1539,13 @@ function renderLogo() {
|
|
|
1539
1539
|
var packageJson = JSON.parse(
|
|
1540
1540
|
readFileSync2(join3(__dirname, "../package.json"), "utf-8")
|
|
1541
1541
|
);
|
|
1542
|
-
function getCurrentPackageVersions(isDevelopment = false,
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
if (isDevelopment) {
|
|
1546
|
-
versions["mcp-use"] = "workspace:*";
|
|
1547
|
-
} else if (useCanary) {
|
|
1548
|
-
versions["mcp-use"] = "canary";
|
|
1549
|
-
} else {
|
|
1550
|
-
versions["mcp-use"] = "latest";
|
|
1551
|
-
}
|
|
1552
|
-
} catch (error) {
|
|
1553
|
-
if (process.env.NODE_ENV === "development") {
|
|
1554
|
-
console.warn(
|
|
1555
|
-
"\u26A0\uFE0F Could not read workspace package versions, using defaults"
|
|
1556
|
-
);
|
|
1557
|
-
console.warn(
|
|
1558
|
-
` Error: ${error instanceof Error ? error.message : String(error)}`
|
|
1559
|
-
);
|
|
1560
|
-
if (error instanceof Error && error.stack) {
|
|
1561
|
-
console.warn(` Stack: ${error.stack}`);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1542
|
+
function getCurrentPackageVersions(isDevelopment = false, sdkVersion) {
|
|
1543
|
+
if (isDevelopment) {
|
|
1544
|
+
return { "mcp-use": "workspace:*" };
|
|
1564
1545
|
}
|
|
1565
|
-
return
|
|
1546
|
+
return { "mcp-use": sdkVersion ?? "latest" };
|
|
1566
1547
|
}
|
|
1567
|
-
function processTemplateFile(filePath, versions, isDevelopment = false
|
|
1548
|
+
function processTemplateFile(filePath, versions, isDevelopment = false) {
|
|
1568
1549
|
const content = readFileSync2(filePath, "utf-8");
|
|
1569
1550
|
let processedContent = content;
|
|
1570
1551
|
for (const [packageName, version] of Object.entries(versions)) {
|
|
@@ -1574,24 +1555,20 @@ function processTemplateFile(filePath, versions, isDevelopment = false, useCanar
|
|
|
1574
1555
|
version
|
|
1575
1556
|
);
|
|
1576
1557
|
}
|
|
1558
|
+
const mcpUseVersion = isDevelopment ? "workspace:*" : versions["mcp-use"] || "latest";
|
|
1577
1559
|
if (isDevelopment) {
|
|
1578
1560
|
processedContent = processedContent.replace(
|
|
1579
1561
|
/"mcp-use": "\^[^"]+"/,
|
|
1580
1562
|
'"mcp-use": "workspace:*"'
|
|
1581
1563
|
);
|
|
1582
|
-
} else
|
|
1564
|
+
} else {
|
|
1583
1565
|
processedContent = processedContent.replace(
|
|
1584
1566
|
/"mcp-use": "workspace:\*"/,
|
|
1585
|
-
`"mcp-use": "
|
|
1567
|
+
`"mcp-use": "${mcpUseVersion}"`
|
|
1586
1568
|
);
|
|
1587
1569
|
processedContent = processedContent.replace(
|
|
1588
1570
|
/"mcp-use": "\^[^"]+"/,
|
|
1589
|
-
`"mcp-use": "
|
|
1590
|
-
);
|
|
1591
|
-
} else {
|
|
1592
|
-
processedContent = processedContent.replace(
|
|
1593
|
-
/"mcp-use": "workspace:\*"/,
|
|
1594
|
-
`"mcp-use": "${versions["mcp-use"] || "latest"}"`
|
|
1571
|
+
`"mcp-use": "${mcpUseVersion}"`
|
|
1595
1572
|
);
|
|
1596
1573
|
}
|
|
1597
1574
|
return processedContent;
|
|
@@ -1779,7 +1756,7 @@ function validateTemplateName(template) {
|
|
|
1779
1756
|
}
|
|
1780
1757
|
return resolvedTemplate;
|
|
1781
1758
|
}
|
|
1782
|
-
async function copyTemplate(projectPath, template, versions, isDevelopment = false
|
|
1759
|
+
async function copyTemplate(projectPath, template, versions, isDevelopment = false) {
|
|
1783
1760
|
const repoInfo = parseGitHubRepoUrl(template);
|
|
1784
1761
|
if (repoInfo) {
|
|
1785
1762
|
const tempDir = mkdtempSync(join3(tmpdir(), "create-mcp-use-app-"));
|
|
@@ -1789,8 +1766,7 @@ async function copyTemplate(projectPath, template, versions, isDevelopment = fal
|
|
|
1789
1766
|
tempDir,
|
|
1790
1767
|
projectPath,
|
|
1791
1768
|
versions,
|
|
1792
|
-
isDevelopment
|
|
1793
|
-
useCanary
|
|
1769
|
+
isDevelopment
|
|
1794
1770
|
);
|
|
1795
1771
|
} finally {
|
|
1796
1772
|
try {
|
|
@@ -1832,11 +1808,10 @@ async function copyTemplate(projectPath, template, versions, isDevelopment = fal
|
|
|
1832
1808
|
templatePath,
|
|
1833
1809
|
projectPath,
|
|
1834
1810
|
versions,
|
|
1835
|
-
isDevelopment
|
|
1836
|
-
useCanary
|
|
1811
|
+
isDevelopment
|
|
1837
1812
|
);
|
|
1838
1813
|
}
|
|
1839
|
-
function copyDirectoryWithProcessing(src, dest, versions, isDevelopment
|
|
1814
|
+
function copyDirectoryWithProcessing(src, dest, versions, isDevelopment) {
|
|
1840
1815
|
const entries = readdirSync3(src, { withFileTypes: true });
|
|
1841
1816
|
for (const entry of entries) {
|
|
1842
1817
|
if (entry.name === ".git") {
|
|
@@ -1847,19 +1822,12 @@ function copyDirectoryWithProcessing(src, dest, versions, isDevelopment, useCana
|
|
|
1847
1822
|
const destPath = join3(dest, destName);
|
|
1848
1823
|
if (entry.isDirectory()) {
|
|
1849
1824
|
mkdirSync(destPath, { recursive: true });
|
|
1850
|
-
copyDirectoryWithProcessing(
|
|
1851
|
-
srcPath,
|
|
1852
|
-
destPath,
|
|
1853
|
-
versions,
|
|
1854
|
-
isDevelopment,
|
|
1855
|
-
useCanary
|
|
1856
|
-
);
|
|
1825
|
+
copyDirectoryWithProcessing(srcPath, destPath, versions, isDevelopment);
|
|
1857
1826
|
} else if (entry.name === "package.json" || entry.name.endsWith(".json")) {
|
|
1858
1827
|
const processedContent = processTemplateFile(
|
|
1859
1828
|
srcPath,
|
|
1860
1829
|
versions,
|
|
1861
|
-
isDevelopment
|
|
1862
|
-
useCanary
|
|
1830
|
+
isDevelopment
|
|
1863
1831
|
);
|
|
1864
1832
|
writeFileSync2(destPath, processedContent);
|
|
1865
1833
|
} else {
|
|
@@ -1946,7 +1914,7 @@ Options:
|
|
|
1946
1914
|
--no-skills Skip installing skills
|
|
1947
1915
|
--no-git Skip initializing a git repository
|
|
1948
1916
|
--dev Use workspace dependencies for development
|
|
1949
|
-
--
|
|
1917
|
+
--sdk-version <version> Pin mcp-use to an npm version or dist-tag (e.g. canary, 1.34.0)
|
|
1950
1918
|
--yarn Use yarn as package manager
|
|
1951
1919
|
--npm Use npm as package manager
|
|
1952
1920
|
--pnpm Use pnpm as package manager
|
|
@@ -1968,11 +1936,15 @@ async function main() {
|
|
|
1968
1936
|
listTemplates();
|
|
1969
1937
|
return;
|
|
1970
1938
|
}
|
|
1971
|
-
if (options.dev && options.
|
|
1972
|
-
console.error(red("\u274C Cannot use --dev and --
|
|
1939
|
+
if (options.dev && options.sdkVersion) {
|
|
1940
|
+
console.error(red("\u274C Cannot use --dev and --sdk-version together"));
|
|
1973
1941
|
console.error(yellow(" Please choose only one dependency mode"));
|
|
1974
1942
|
process.exit(1);
|
|
1975
1943
|
}
|
|
1944
|
+
if (options.sdkVersion !== void 0 && !options.sdkVersion.trim()) {
|
|
1945
|
+
console.error(red("\u274C --sdk-version requires a non-empty value"));
|
|
1946
|
+
process.exit(1);
|
|
1947
|
+
}
|
|
1976
1948
|
let projectName = initialProjectName;
|
|
1977
1949
|
let selectedTemplate = options.template;
|
|
1978
1950
|
const interactive = isInteractive();
|
|
@@ -2059,14 +2031,8 @@ async function main() {
|
|
|
2059
2031
|
}
|
|
2060
2032
|
console.log(cyan(`\u{1F680} Creating MCP server "${displayName}"...`));
|
|
2061
2033
|
const validatedTemplate = validateTemplateName(selectedTemplate);
|
|
2062
|
-
const versions = getCurrentPackageVersions(options.dev, options.
|
|
2063
|
-
await copyTemplate(
|
|
2064
|
-
projectPath,
|
|
2065
|
-
validatedTemplate,
|
|
2066
|
-
versions,
|
|
2067
|
-
options.dev,
|
|
2068
|
-
options.canary
|
|
2069
|
-
);
|
|
2034
|
+
const versions = getCurrentPackageVersions(options.dev, options.sdkVersion);
|
|
2035
|
+
await copyTemplate(projectPath, validatedTemplate, versions, options.dev);
|
|
2070
2036
|
updatePackageJson(projectPath, packageName);
|
|
2071
2037
|
updateIndexTs(projectPath, packageName);
|
|
2072
2038
|
let install = options.install;
|
|
@@ -2168,8 +2134,8 @@ async function main() {
|
|
|
2168
2134
|
console.log(
|
|
2169
2135
|
yellow("\u{1F527} Development mode: Using workspace dependencies")
|
|
2170
2136
|
);
|
|
2171
|
-
} else if (options.
|
|
2172
|
-
console.log(cyan(
|
|
2137
|
+
} else if (options.sdkVersion) {
|
|
2138
|
+
console.log(cyan(`\u{1F4CC} Using mcp-use@${options.sdkVersion}`));
|
|
2173
2139
|
}
|
|
2174
2140
|
console.log("");
|
|
2175
2141
|
console.log(bold("\u{1F4C1} Project structure:"));
|
|
@@ -2186,10 +2152,16 @@ async function main() {
|
|
|
2186
2152
|
console.log(" \u251C\u2500\u2500 tsconfig.json");
|
|
2187
2153
|
console.log(" \u2514\u2500\u2500 README.md");
|
|
2188
2154
|
} else if (validatedTemplate === "mcp-apps") {
|
|
2189
|
-
console.log(" \u251C\u2500\u2500
|
|
2155
|
+
console.log(" \u251C\u2500\u2500 public/");
|
|
2156
|
+
console.log(" \u2502 \u251C\u2500\u2500 icon.svg");
|
|
2157
|
+
console.log(" \u2502 \u2514\u2500\u2500 fruits/ (16 WebP assets)");
|
|
2158
|
+
console.log(" \u251C\u2500\u2500 views/");
|
|
2190
2159
|
console.log(" \u2502 \u2514\u2500\u2500 product-search-result/");
|
|
2191
|
-
console.log(" \u2502 \
|
|
2192
|
-
console.log(" \u251C\u2500\u2500
|
|
2160
|
+
console.log(" \u2502 \u251C\u2500\u2500 view.tsx");
|
|
2161
|
+
console.log(" \u2502 \u251C\u2500\u2500 view.css");
|
|
2162
|
+
console.log(" \u2502 \u251C\u2500\u2500 components/");
|
|
2163
|
+
console.log(" \u2502 \u2514\u2500\u2500 hooks/");
|
|
2164
|
+
console.log(" \u251C\u2500\u2500 mcp-env.d.ts");
|
|
2193
2165
|
console.log(" \u251C\u2500\u2500 index.ts (server entry point)");
|
|
2194
2166
|
console.log(" \u251C\u2500\u2500 package.json");
|
|
2195
2167
|
console.log(" \u251C\u2500\u2500 tsconfig.json");
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-use server",
|
|
3
3
|
"type": "module",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=22.22.2"
|
|
6
|
+
},
|
|
4
7
|
"version": "1.0.0",
|
|
5
|
-
"description": "
|
|
6
|
-
"author": "",
|
|
8
|
+
"description": "an mcp-use server",
|
|
9
|
+
"author": "mcp-use",
|
|
7
10
|
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/mcp-use/mcp-use",
|
|
8
12
|
"keywords": [
|
|
9
13
|
"mcp",
|
|
10
|
-
"server",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
14
|
+
"mcp-server",
|
|
15
|
+
"chatgpt plugins",
|
|
16
|
+
"claude connector",
|
|
17
|
+
"mcp-app",
|
|
18
|
+
"mcp-use",
|
|
19
|
+
"manufact"
|
|
13
20
|
],
|
|
14
21
|
"main": "dist/index.js",
|
|
15
22
|
"scripts": {
|
|
@@ -23,7 +30,7 @@
|
|
|
23
30
|
"mcp-use": "workspace:*"
|
|
24
31
|
},
|
|
25
32
|
"devDependencies": {
|
|
26
|
-
"@types/node": "^
|
|
27
|
-
"typescript": "7.0.
|
|
33
|
+
"@types/node": "^22.20.0",
|
|
34
|
+
"typescript": "^7.0.2"
|
|
28
35
|
}
|
|
29
36
|
}
|
|
@@ -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
|
}
|
|
@@ -1,43 +1,147 @@
|
|
|
1
1
|
import { MCPServer } from "mcp-use";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
-
const fruits = [
|
|
4
|
+
const fruits = [
|
|
5
|
+
{ fruit: "mango", color: "bg-[#FBF1E1] dark:bg-[#FBF1E1]/10" },
|
|
6
|
+
{ fruit: "pineapple", color: "bg-[#f8f0d9] dark:bg-[#f8f0d9]/10" },
|
|
7
|
+
{ fruit: "cherries", color: "bg-[#E2EDDC] dark:bg-[#E2EDDC]/10" },
|
|
8
|
+
{ fruit: "coconut", color: "bg-[#fbedd3] dark:bg-[#fbedd3]/10" },
|
|
9
|
+
{ fruit: "apricot", color: "bg-[#fee6ca] dark:bg-[#fee6ca]/10" },
|
|
10
|
+
{ fruit: "blueberry", color: "bg-[#e0e6e6] dark:bg-[#e0e6e6]/10" },
|
|
11
|
+
{ fruit: "grapes", color: "bg-[#f4ebe2] dark:bg-[#f4ebe2]/10" },
|
|
12
|
+
{ fruit: "watermelon", color: "bg-[#e6eddb] dark:bg-[#e6eddb]/10" },
|
|
13
|
+
{ fruit: "orange", color: "bg-[#fdebdf] dark:bg-[#fdebdf]/10" },
|
|
14
|
+
{ fruit: "avocado", color: "bg-[#ecefda] dark:bg-[#ecefda]/10" },
|
|
15
|
+
{ fruit: "apple", color: "bg-[#F9E7E4] dark:bg-[#F9E7E4]/10" },
|
|
16
|
+
{ fruit: "pear", color: "bg-[#f1f1cf] dark:bg-[#f1f1cf]/10" },
|
|
17
|
+
{ fruit: "plum", color: "bg-[#ece5ec] dark:bg-[#ece5ec]/10" },
|
|
18
|
+
{ fruit: "banana", color: "bg-[#fdf0dd] dark:bg-[#fdf0dd]/10" },
|
|
19
|
+
{ fruit: "strawberry", color: "bg-[#f7e6df] dark:bg-[#f7e6df]/10" },
|
|
20
|
+
{ fruit: "lemon", color: "bg-[#feeecd] dark:bg-[#feeecd]/10" },
|
|
21
|
+
];
|
|
5
22
|
|
|
6
|
-
const
|
|
23
|
+
const fruitRowSchema = z.object({
|
|
24
|
+
fruit: z.string(),
|
|
25
|
+
color: z.string(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const searchOutputSchema = z.object({
|
|
7
29
|
query: z.string(),
|
|
8
|
-
|
|
30
|
+
results: z.array(fruitRowSchema),
|
|
9
31
|
});
|
|
10
32
|
|
|
33
|
+
const detailsOutputSchema = z.object({
|
|
34
|
+
fruit: z.string(),
|
|
35
|
+
color: z.string(),
|
|
36
|
+
facts: z.array(z.string()),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function renderAsMarkdownTable(
|
|
40
|
+
results: Array<{ fruit: string; color: string }>
|
|
41
|
+
): string {
|
|
42
|
+
const header = "| Fruit | Color |\n| --- | --- |";
|
|
43
|
+
const rows = results.map((r) => `| ${r.fruit} | ${r.color} |`).join("\n");
|
|
44
|
+
return `${header}\n${rows}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
11
47
|
const server = new MCPServer({
|
|
12
48
|
name: "{{PROJECT_NAME}}",
|
|
13
49
|
title: "{{PROJECT_NAME}}",
|
|
14
50
|
version: "1.0.0",
|
|
15
|
-
description: "
|
|
51
|
+
description: "MCP Apps server with a fruit shop view",
|
|
52
|
+
instructions:
|
|
53
|
+
"Use search-fruits to find fruit matches before calling get-fruit-details. Prefer the view result when the user wants to browse or compare options visually.",
|
|
54
|
+
websiteUrl: "https://mcp-use.com",
|
|
55
|
+
icons: [
|
|
56
|
+
{
|
|
57
|
+
src: "icon.svg",
|
|
58
|
+
mimeType: "image/svg+xml",
|
|
59
|
+
sizes: ["512x512"],
|
|
60
|
+
},
|
|
61
|
+
],
|
|
16
62
|
});
|
|
17
63
|
|
|
18
64
|
export const searchFruits = server.tool(
|
|
19
65
|
{
|
|
20
66
|
name: "search-fruits",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
67
|
+
title: "Search fruits",
|
|
68
|
+
description: "Search for fruits and display the results in a view",
|
|
69
|
+
inputSchema: z.object({
|
|
70
|
+
query: z.string().optional().describe("Search query to filter fruits"),
|
|
71
|
+
}),
|
|
72
|
+
outputSchema: searchOutputSchema,
|
|
24
73
|
view: {
|
|
25
74
|
name: "product-search-result",
|
|
26
|
-
description: "
|
|
75
|
+
description: "Product search results with carousel and details",
|
|
27
76
|
prefersBorder: true,
|
|
28
77
|
},
|
|
29
|
-
annotations: {
|
|
78
|
+
annotations: {
|
|
79
|
+
readOnlyHint: true,
|
|
80
|
+
destructiveHint: false,
|
|
81
|
+
openWorldHint: false,
|
|
82
|
+
},
|
|
30
83
|
},
|
|
31
|
-
async ({ query = "" }) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
84
|
+
async ({ query = "" }, ctx) => {
|
|
85
|
+
const results = fruits.filter(
|
|
86
|
+
(f) => query === "" || f.fruit.toLowerCase().includes(query.toLowerCase())
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Emulate a delay to show the loading state in the view
|
|
90
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
91
|
+
|
|
92
|
+
const data = { query, results };
|
|
93
|
+
|
|
94
|
+
if (!ctx.client.supportsViews()) {
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: renderAsMarkdownTable(results) }],
|
|
97
|
+
structuredContent: data,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
36
101
|
return {
|
|
37
|
-
content: [
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: `Found ${results.length} fruits matching "${query || "all"}"`,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
38
108
|
structuredContent: data,
|
|
39
109
|
};
|
|
40
110
|
}
|
|
41
111
|
);
|
|
42
112
|
|
|
113
|
+
export const getFruitDetails = server.tool(
|
|
114
|
+
{
|
|
115
|
+
name: "get-fruit-details",
|
|
116
|
+
title: "Get fruit details",
|
|
117
|
+
description: "Get detailed information about a specific fruit",
|
|
118
|
+
inputSchema: z.object({
|
|
119
|
+
fruit: z.string().describe("The fruit name"),
|
|
120
|
+
}),
|
|
121
|
+
outputSchema: detailsOutputSchema,
|
|
122
|
+
annotations: {
|
|
123
|
+
readOnlyHint: true,
|
|
124
|
+
destructiveHint: false,
|
|
125
|
+
openWorldHint: false,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
async ({ fruit }) => {
|
|
129
|
+
const found = fruits.find(
|
|
130
|
+
(f) => f.fruit.toLowerCase() === fruit.toLowerCase()
|
|
131
|
+
);
|
|
132
|
+
const details = {
|
|
133
|
+
fruit: found?.fruit ?? fruit,
|
|
134
|
+
color: found?.color ?? "unknown",
|
|
135
|
+
facts: [
|
|
136
|
+
`${fruit} is a delicious fruit`,
|
|
137
|
+
`Color: ${found?.color ?? "unknown"}`,
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: "text", text: JSON.stringify(details) }],
|
|
142
|
+
structuredContent: details,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
43
147
|
export default server;
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-use server",
|
|
3
3
|
"type": "module",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=22.22.2"
|
|
6
|
+
},
|
|
4
7
|
"version": "1.0.0",
|
|
5
|
-
"description": "
|
|
6
|
-
"author": "",
|
|
8
|
+
"description": "an mcp-use server",
|
|
9
|
+
"author": "mcp-use",
|
|
7
10
|
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/mcp-use/mcp-use",
|
|
8
12
|
"keywords": [
|
|
9
13
|
"mcp",
|
|
10
|
-
"server",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"react",
|
|
17
|
-
"mcp-apps"
|
|
14
|
+
"mcp-server",
|
|
15
|
+
"chatgpt plugins",
|
|
16
|
+
"claude connector",
|
|
17
|
+
"mcp-app",
|
|
18
|
+
"mcp-use",
|
|
19
|
+
"manufact"
|
|
18
20
|
],
|
|
19
21
|
"main": "dist/index.js",
|
|
20
22
|
"scripts": {
|
|
@@ -26,14 +28,14 @@
|
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
30
|
"mcp-use": "workspace:*",
|
|
29
|
-
"react": "^19.2.
|
|
30
|
-
"react-dom": "^19.2.
|
|
31
|
+
"react": "^19.2.7",
|
|
32
|
+
"react-dom": "^19.2.7",
|
|
31
33
|
"zod": "^4.4.3"
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
|
-
"@types/node": "^
|
|
36
|
+
"@types/node": "^22.20.0",
|
|
35
37
|
"@types/react": "^19.2.17",
|
|
36
38
|
"@types/react-dom": "^19.2.3",
|
|
37
|
-
"typescript": "7.0.
|
|
39
|
+
"typescript": "^7.0.2"
|
|
38
40
|
}
|
|
39
41
|
}
|
|
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
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
"esModuleInterop": true,
|
|
10
10
|
"forceConsistentCasingInFileNames": true,
|
|
11
11
|
"skipLibCheck": true,
|
|
12
|
-
"noEmit": true
|
|
13
|
-
"noUncheckedIndexedAccess": true,
|
|
14
|
-
"exactOptionalPropertyTypes": true
|
|
12
|
+
"noEmit": true
|
|
15
13
|
},
|
|
16
|
-
"include": [
|
|
14
|
+
"include": [
|
|
15
|
+
"index.ts",
|
|
16
|
+
"mcp-env.d.ts",
|
|
17
|
+
"src/**/*",
|
|
18
|
+
"views/**/*",
|
|
19
|
+
"server.ts",
|
|
20
|
+
".mcp-use/**/*.d.ts"
|
|
21
|
+
],
|
|
17
22
|
"exclude": ["node_modules", "dist"]
|
|
18
23
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
}
|