nitrostack 1.0.0 → 1.0.2
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/CHANGELOG.md +30 -0
- package/dist/cli/index.js +4 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/src/studio/README.md +140 -0
- package/src/studio/app/api/auth/fetch-metadata/route.ts +71 -0
- package/src/studio/app/api/auth/register-client/route.ts +67 -0
- package/src/studio/app/api/chat/route.ts +123 -0
- package/src/studio/app/api/health/checks/route.ts +42 -0
- package/src/studio/app/api/health/route.ts +13 -0
- package/src/studio/app/api/init/route.ts +85 -0
- package/src/studio/app/api/ping/route.ts +13 -0
- package/src/studio/app/api/prompts/[name]/route.ts +21 -0
- package/src/studio/app/api/prompts/route.ts +13 -0
- package/src/studio/app/api/resources/[...uri]/route.ts +18 -0
- package/src/studio/app/api/resources/route.ts +13 -0
- package/src/studio/app/api/roots/route.ts +13 -0
- package/src/studio/app/api/sampling/route.ts +14 -0
- package/src/studio/app/api/tools/[name]/call/route.ts +41 -0
- package/src/studio/app/api/tools/route.ts +23 -0
- package/src/studio/app/api/widget-examples/route.ts +44 -0
- package/src/studio/app/auth/callback/page.tsx +160 -0
- package/src/studio/app/auth/page.tsx +543 -0
- package/src/studio/app/chat/page.tsx +530 -0
- package/src/studio/app/chat/page.tsx.backup +390 -0
- package/src/studio/app/globals.css +410 -0
- package/src/studio/app/health/page.tsx +177 -0
- package/src/studio/app/layout.tsx +48 -0
- package/src/studio/app/page.tsx +337 -0
- package/src/studio/app/page.tsx.backup +346 -0
- package/src/studio/app/ping/page.tsx +204 -0
- package/src/studio/app/prompts/page.tsx +228 -0
- package/src/studio/app/resources/page.tsx +313 -0
- package/src/studio/components/EnlargeModal.tsx +116 -0
- package/src/studio/components/Sidebar.tsx +133 -0
- package/src/studio/components/ToolCard.tsx +108 -0
- package/src/studio/components/WidgetRenderer.tsx +99 -0
- package/src/studio/lib/api.ts +207 -0
- package/src/studio/lib/llm-service.ts +361 -0
- package/src/studio/lib/mcp-client.ts +168 -0
- package/src/studio/lib/store.ts +192 -0
- package/src/studio/lib/theme-provider.tsx +50 -0
- package/src/studio/lib/types.ts +107 -0
- package/src/studio/lib/widget-loader.ts +90 -0
- package/src/studio/middleware.ts +27 -0
- package/src/studio/next.config.js +16 -0
- package/src/studio/package-lock.json +2696 -0
- package/src/studio/package.json +34 -0
- package/src/studio/postcss.config.mjs +10 -0
- package/src/studio/tailwind.config.ts +67 -0
- package/src/studio/tsconfig.json +41 -0
- package/templates/typescript-auth/.env.example +23 -0
- package/templates/typescript-auth/src/app.module.ts +103 -0
- package/templates/typescript-auth/src/db/database.ts +163 -0
- package/templates/typescript-auth/src/db/seed.ts +374 -0
- package/templates/typescript-auth/src/db/setup.ts +87 -0
- package/templates/typescript-auth/src/events/analytics.service.ts +52 -0
- package/templates/typescript-auth/src/events/notification.service.ts +40 -0
- package/templates/typescript-auth/src/filters/global-exception.filter.ts +28 -0
- package/templates/typescript-auth/src/guards/README.md +75 -0
- package/templates/typescript-auth/src/guards/jwt.guard.ts +105 -0
- package/templates/typescript-auth/src/health/database.health.ts +41 -0
- package/templates/typescript-auth/src/index.ts +26 -0
- package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +24 -0
- package/templates/typescript-auth/src/middleware/logging.middleware.ts +42 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +16 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +114 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +40 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +241 -0
- package/templates/typescript-auth/src/modules/auth/auth.module.ts +16 -0
- package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +147 -0
- package/templates/typescript-auth/src/modules/auth/auth.resources.ts +84 -0
- package/templates/typescript-auth/src/modules/auth/auth.tools.ts +139 -0
- package/templates/typescript-auth/src/modules/cart/cart.module.ts +16 -0
- package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +95 -0
- package/templates/typescript-auth/src/modules/cart/cart.resources.ts +44 -0
- package/templates/typescript-auth/src/modules/cart/cart.tools.ts +281 -0
- package/templates/typescript-auth/src/modules/orders/orders.module.ts +16 -0
- package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +88 -0
- package/templates/typescript-auth/src/modules/orders/orders.resources.ts +48 -0
- package/templates/typescript-auth/src/modules/orders/orders.tools.ts +281 -0
- package/templates/typescript-auth/src/modules/products/products.module.ts +16 -0
- package/templates/typescript-auth/src/modules/products/products.prompts.ts +146 -0
- package/templates/typescript-auth/src/modules/products/products.resources.ts +98 -0
- package/templates/typescript-auth/src/modules/products/products.tools.ts +266 -0
- package/templates/typescript-auth/src/pipes/validation.pipe.ts +42 -0
- package/templates/typescript-auth/src/services/database.service.ts +90 -0
- package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +122 -0
- package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +116 -0
- package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +105 -0
- package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +139 -0
- package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +153 -0
- package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +86 -0
- package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +116 -0
- package/templates/typescript-auth/src/widgets/app/categories/page.tsx +134 -0
- package/templates/typescript-auth/src/widgets/app/layout.tsx +21 -0
- package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +129 -0
- package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +206 -0
- package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +225 -0
- package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +218 -0
- package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +121 -0
- package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +173 -0
- package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +187 -0
- package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +165 -0
- package/templates/typescript-auth/src/widgets/next.config.js +38 -0
- package/templates/typescript-auth/src/widgets/package.json +18 -0
- package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +169 -0
- package/templates/typescript-auth/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-auth/src/widgets/types/tool-data.ts +141 -0
- package/templates/typescript-auth/src/widgets/widget-manifest.json +464 -0
- package/templates/typescript-auth/tsconfig.json +27 -0
- package/templates/typescript-auth-api-key/.env +15 -0
- package/templates/typescript-auth-api-key/.env.example +4 -0
- package/templates/typescript-auth-api-key/src/app.module.ts +38 -0
- package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +47 -0
- package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +157 -0
- package/templates/typescript-auth-api-key/src/health/system.health.ts +55 -0
- package/templates/typescript-auth-api-key/src/index.ts +47 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +12 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +73 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +60 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +71 -0
- package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +18 -0
- package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +155 -0
- package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +123 -0
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-auth-api-key/src/widgets/next.config.js +37 -0
- package/templates/typescript-auth-api-key/src/widgets/package.json +24 -0
- package/templates/typescript-auth-api-key/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-auth-api-key/tsconfig.json +23 -0
- package/templates/typescript-oauth/.env.example +91 -0
- package/templates/typescript-oauth/src/app.module.ts +89 -0
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +127 -0
- package/templates/typescript-oauth/src/index.ts +74 -0
- package/templates/typescript-oauth/src/modules/demo/demo.module.ts +16 -0
- package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +190 -0
- package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-oauth/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-oauth/src/widgets/next.config.js +37 -0
- package/templates/typescript-oauth/src/widgets/package.json +24 -0
- package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-oauth/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-oauth/tsconfig.json +23 -0
- package/templates/typescript-starter/.env.example +4 -0
- package/templates/typescript-starter/src/app.module.ts +34 -0
- package/templates/typescript-starter/src/health/system.health.ts +55 -0
- package/templates/typescript-starter/src/index.ts +27 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +60 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +71 -0
- package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-starter/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-starter/src/widgets/next.config.js +37 -0
- package/templates/typescript-starter/src/widgets/package.json +24 -0
- package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-starter/tsconfig.json +23 -0
- package/LICENSE_URLS_UPDATE_COMPLETE.md +0 -388
package/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.2] - 2025-10-27
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Critical**: Fixed CLI `--version` command to read version dynamically from `package.json`
|
|
14
|
+
- Was showing hardcoded `1.0.0` instead of actual package version
|
|
15
|
+
- Now correctly displays the installed version
|
|
16
|
+
- **Critical**: Fixed `src/studio` not being included in npm package
|
|
17
|
+
- Studio files are now properly included (47 files)
|
|
18
|
+
- Users can now run `nitrostack dev` without Studio installation errors
|
|
19
|
+
- Changed `.npmignore` to exclude specific `/src/` subdirectories while keeping `/src/studio/`
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Updated `.npmignore` to specifically exclude `/src/auth/`, `/src/cli/`, `/src/core/`, etc. instead of blanket `/src/` exclusion
|
|
23
|
+
- CLI now uses `createRequire` to load `package.json` for dynamic version reading
|
|
24
|
+
|
|
25
|
+
## [1.0.1] - 2025-10-27
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- **Critical**: Fixed `.npmignore` to include template `src/` folders
|
|
29
|
+
- Changed `src/` to `/src/` to only exclude root source files
|
|
30
|
+
- Template source files are now properly included in the package
|
|
31
|
+
- Users can now successfully generate projects with all necessary files
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- Updated `.npmignore` patterns to use leading slashes for root-only exclusions
|
|
35
|
+
- Keep template `.env.example` files by excluding only root `.env` files
|
|
36
|
+
|
|
37
|
+
## [1.0.0] - 2025-10-27
|
|
38
|
+
|
|
10
39
|
### Changed
|
|
11
40
|
- **License**: Changed from MIT to Apache License 2.0
|
|
12
41
|
- **Copyright**: Copyright holder is Abhishek Pandit
|
|
13
42
|
- **Author**: Updated author to Abhishek Pandit
|
|
43
|
+
- **Package Name**: Renamed from hypermcp to nitrostack
|
|
14
44
|
- Updated all documentation links to official website (https://nitrostack.vercel.app/) and docs (https://nitrostack-docs.vercel.app/)
|
|
15
45
|
- Added NOTICE file for Apache 2.0 compliance with dependency attributions
|
|
16
46
|
- Updated CONTRIBUTING.md with Apache 2.0 license headers and contributor agreement
|
package/dist/cli/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { createRequire } from 'module';
|
|
3
4
|
import { initCommand } from './commands/init.js';
|
|
4
5
|
import { devCommand } from './commands/dev.js';
|
|
5
6
|
import { buildCommand } from './commands/build.js';
|
|
6
7
|
import { startCommand } from './commands/start.js';
|
|
7
8
|
import { generate } from './commands/generate.js';
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const packageJson = require('../../package.json');
|
|
8
11
|
const program = new Command();
|
|
9
12
|
program
|
|
10
13
|
.name('nitrostack')
|
|
11
14
|
.description('NitroStack - Build MCP servers with ease')
|
|
12
|
-
.version(
|
|
15
|
+
.version(packageJson.version);
|
|
13
16
|
program
|
|
14
17
|
.command('init')
|
|
15
18
|
.description('Initialize a new NitroStack project')
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAEhC,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,qCAAqC,CAAC;KAClD,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;KACjD,MAAM,CAAC,uBAAuB,EAAE,+CAA+C,EAAE,YAAY,CAAC;KAC9F,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,eAAe,EAAE,iBAAiB,EAAE,MAAM,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;KACxD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,CAAC;KACrD,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,eAAe,EAAE,iBAAiB,EAAE,MAAM,CAAC;KAClD,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,KAAK,CAAC,GAAG,CAAC;KACV,WAAW,CAAC,oCAAoC,CAAC;KACjD,QAAQ,CAAC,QAAQ,EAAE,6HAA6H,CAAC;KACjJ,QAAQ,CAAC,QAAQ,EAAE,8CAA8C,CAAC;KAClE,MAAM,CAAC,mBAAmB,EAAE,8CAA8C,CAAC;KAC3E,MAAM,CAAC,iBAAiB,EAAE,oCAAoC,CAAC;KAC/D,MAAM,CAAC,SAAS,EAAE,0BAA0B,CAAC;KAC7C,MAAM,CAAC,gBAAgB,EAAE,6CAA6C,CAAC;KACvE,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# NitroStack Studio 🎨
|
|
2
|
+
|
|
3
|
+
Modern, React-based visual inspector for MCP servers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ⚡ **Tools Browser** - Execute tools with auto-generated forms
|
|
8
|
+
- 🎨 **Widget Rendering** - Preview UI components in dev and prod
|
|
9
|
+
- 🤖 **AI Chat** - Chat with tool integration (OpenAI/Gemini)
|
|
10
|
+
- 📦 **Resources** - Browse MCP resources and schemas
|
|
11
|
+
- 💬 **Prompts** - Execute MCP prompts
|
|
12
|
+
- 🔐 **Auth** - OAuth 2.1, JWT, and API key support
|
|
13
|
+
- 💚 **Health** - System health monitoring
|
|
14
|
+
- 📡 **Ping** - Latency testing
|
|
15
|
+
- 🎲 **Sampling** - Text completion testing
|
|
16
|
+
- 🌳 **Roots** - MCP server roots
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
src/studio/
|
|
22
|
+
├── app/ # Next.js App Router pages
|
|
23
|
+
│ ├── page.tsx # Tools (default)
|
|
24
|
+
│ ├── chat/ # AI Chat
|
|
25
|
+
│ ├── resources/ # Resources browser
|
|
26
|
+
│ ├── prompts/ # Prompts executor
|
|
27
|
+
│ ├── auth/ # Authentication
|
|
28
|
+
│ ├── health/ # Health checks
|
|
29
|
+
│ ├── ping/ # Ping testing
|
|
30
|
+
│ ├── sampling/ # Sampling API
|
|
31
|
+
│ └── roots/ # Roots browser
|
|
32
|
+
├── components/ # Reusable React components
|
|
33
|
+
│ ├── Sidebar.tsx # Navigation sidebar
|
|
34
|
+
│ ├── ToolCard.tsx # Tool display card
|
|
35
|
+
│ ├── WidgetRenderer.tsx # Widget iframe loader
|
|
36
|
+
│ └── EnlargeModal.tsx # Full-screen widget viewer
|
|
37
|
+
├── lib/ # Utilities and shared logic
|
|
38
|
+
│ ├── api.ts # API client
|
|
39
|
+
│ ├── store.ts # Zustand state management
|
|
40
|
+
│ ├── types.ts # TypeScript types
|
|
41
|
+
│ ├── widget-loader.ts # Dev/prod widget loading
|
|
42
|
+
│ └── dummy-data.ts # Preview data generator
|
|
43
|
+
└── next.config.ts # Next.js configuration
|
|
44
|
+
|
|
45
|
+
## Development
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Install dependencies
|
|
49
|
+
cd src/studio
|
|
50
|
+
npm install
|
|
51
|
+
|
|
52
|
+
# Run dev server
|
|
53
|
+
npm run dev
|
|
54
|
+
|
|
55
|
+
# Build static export
|
|
56
|
+
npm run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Widget Rendering
|
|
60
|
+
|
|
61
|
+
The Studio supports two modes:
|
|
62
|
+
|
|
63
|
+
### Dev Mode (Port 3001)
|
|
64
|
+
- Widgets load from Next.js dev server
|
|
65
|
+
- Hot reload enabled
|
|
66
|
+
- URL: `http://localhost:3001/widget-name`
|
|
67
|
+
|
|
68
|
+
### Production Mode
|
|
69
|
+
- Widgets compile to static HTML
|
|
70
|
+
- Bundled with server
|
|
71
|
+
- Served from `/widgets/*`
|
|
72
|
+
|
|
73
|
+
## Static Export
|
|
74
|
+
|
|
75
|
+
Studio builds to static HTML/CSS/JS for easy deployment:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm run build
|
|
79
|
+
# Output: ../../dist/studio/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Deploy to:
|
|
83
|
+
- Vercel
|
|
84
|
+
- Netlify
|
|
85
|
+
- Cloudflare Pages
|
|
86
|
+
- GitHub Pages
|
|
87
|
+
- S3 + CloudFront
|
|
88
|
+
- Any static hosting
|
|
89
|
+
|
|
90
|
+
## State Management
|
|
91
|
+
|
|
92
|
+
Uses Zustand for global state:
|
|
93
|
+
- Connection status
|
|
94
|
+
- Tools, resources, prompts
|
|
95
|
+
- Chat messages
|
|
96
|
+
- Auth tokens
|
|
97
|
+
- Modal state
|
|
98
|
+
|
|
99
|
+
## API Integration
|
|
100
|
+
|
|
101
|
+
All API calls go through the unified `StudioAPI` client in `lib/api.ts`:
|
|
102
|
+
- Tools: `api.getTools()`, `api.callTool()`
|
|
103
|
+
- Resources: `api.getResources()`, `api.getResource()`
|
|
104
|
+
- Chat: `api.chat()`
|
|
105
|
+
- Auth: `api.discoverAuth()`, `api.registerClient()`
|
|
106
|
+
- Health: `api.getHealth()`
|
|
107
|
+
|
|
108
|
+
## Styling
|
|
109
|
+
|
|
110
|
+
- **Tailwind CSS** - Utility-first styling
|
|
111
|
+
- **Dark Theme** - Optimized for developer experience
|
|
112
|
+
- **Custom CSS** - Global styles in `app/globals.css`
|
|
113
|
+
- **Animations** - Fade-in, slide-in, pulse, skeleton loading
|
|
114
|
+
|
|
115
|
+
## Integration with NitroStack
|
|
116
|
+
|
|
117
|
+
When you run `nitrostack dev`, it starts:
|
|
118
|
+
1. **MCP Server** (your project on stdio)
|
|
119
|
+
2. **Widget Dev Server** (Next.js on port 3001)
|
|
120
|
+
3. **Studio** (Next.js on port 3000)
|
|
121
|
+
|
|
122
|
+
Studio proxies API calls to the MCP server and loads widgets from the widget dev server.
|
|
123
|
+
|
|
124
|
+
## Browser Support
|
|
125
|
+
|
|
126
|
+
- Modern browsers (Chrome, Firefox, Safari, Edge)
|
|
127
|
+
- ES2022+ JavaScript
|
|
128
|
+
- CSS Grid & Flexbox
|
|
129
|
+
|
|
130
|
+
## Performance
|
|
131
|
+
|
|
132
|
+
- **Static Export** - Pre-rendered HTML
|
|
133
|
+
- **Code Splitting** - Automatic by Next.js
|
|
134
|
+
- **Tree Shaking** - Unused code removed
|
|
135
|
+
- **Lazy Loading** - Components load on demand
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT - Part of NitroStack
|
|
140
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch OAuth 2.1 Protected Resource Metadata
|
|
3
|
+
*
|
|
4
|
+
* This endpoint fetches OAuth metadata from an MCP server's
|
|
5
|
+
* /.well-known/oauth-protected-resource endpoint (RFC 9728)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
|
|
10
|
+
export async function POST(request: NextRequest) {
|
|
11
|
+
try {
|
|
12
|
+
const { url, type } = await request.json();
|
|
13
|
+
|
|
14
|
+
if (!url) {
|
|
15
|
+
return NextResponse.json(
|
|
16
|
+
{ error: 'url is required' },
|
|
17
|
+
{ status: 400 }
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let metadataUrl: string;
|
|
22
|
+
|
|
23
|
+
if (type === 'resource') {
|
|
24
|
+
// Fetch Protected Resource Metadata (RFC 9728)
|
|
25
|
+
metadataUrl = new URL('/.well-known/oauth-protected-resource', url).toString();
|
|
26
|
+
} else if (type === 'auth-server') {
|
|
27
|
+
// Fetch Authorization Server Metadata (RFC 8414)
|
|
28
|
+
metadataUrl = new URL('/.well-known/oauth-authorization-server', url).toString();
|
|
29
|
+
} else {
|
|
30
|
+
return NextResponse.json(
|
|
31
|
+
{ error: 'type must be "resource" or "auth-server"' },
|
|
32
|
+
{ status: 400 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Fetch the metadata
|
|
37
|
+
const response = await fetch(metadataUrl, {
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: {
|
|
40
|
+
'Accept': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
signal: AbortSignal.timeout(5000), // 5 second timeout
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
return NextResponse.json(
|
|
47
|
+
{ error: `Failed to fetch metadata: ${response.statusText}` },
|
|
48
|
+
{ status: response.status }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const metadata = await response.json();
|
|
53
|
+
|
|
54
|
+
// Basic validation
|
|
55
|
+
if (type === 'resource' && (!metadata.resource || !metadata.authorization_servers)) {
|
|
56
|
+
return NextResponse.json(
|
|
57
|
+
{ error: 'Invalid OAuth resource metadata format' },
|
|
58
|
+
{ status: 400 }
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return NextResponse.json(metadata);
|
|
63
|
+
} catch (error: any) {
|
|
64
|
+
console.error('Error fetching OAuth metadata:', error);
|
|
65
|
+
return NextResponse.json(
|
|
66
|
+
{ error: error.message || 'Failed to fetch OAuth metadata' },
|
|
67
|
+
{ status: 500 }
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Client Registration (RFC 7591)
|
|
3
|
+
*
|
|
4
|
+
* This endpoint handles OAuth 2.1 Dynamic Client Registration
|
|
5
|
+
* by proxying requests to the authorization server's registration endpoint.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
|
|
10
|
+
export async function POST(request: NextRequest) {
|
|
11
|
+
try {
|
|
12
|
+
const { endpoint, metadata } = await request.json();
|
|
13
|
+
|
|
14
|
+
if (!endpoint) {
|
|
15
|
+
return NextResponse.json(
|
|
16
|
+
{ error: 'endpoint is required' },
|
|
17
|
+
{ status: 400 }
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!metadata) {
|
|
22
|
+
return NextResponse.json(
|
|
23
|
+
{ error: 'metadata is required' },
|
|
24
|
+
{ status: 400 }
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Register the client with the authorization server
|
|
29
|
+
const response = await fetch(endpoint, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'Accept': 'application/json',
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(metadata),
|
|
36
|
+
signal: AbortSignal.timeout(10000), // 10 second timeout
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errorText = await response.text();
|
|
41
|
+
console.error('Client registration failed:', response.status, errorText);
|
|
42
|
+
return NextResponse.json(
|
|
43
|
+
{ error: `Registration failed: ${response.statusText}`, details: errorText },
|
|
44
|
+
{ status: response.status }
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const registrationResponse = await response.json();
|
|
49
|
+
|
|
50
|
+
// Validate the response contains required fields
|
|
51
|
+
if (!registrationResponse.client_id) {
|
|
52
|
+
return NextResponse.json(
|
|
53
|
+
{ error: 'Invalid registration response: missing client_id' },
|
|
54
|
+
{ status: 400 }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return NextResponse.json(registrationResponse);
|
|
59
|
+
} catch (error: any) {
|
|
60
|
+
console.error('Error during client registration:', error);
|
|
61
|
+
return NextResponse.json(
|
|
62
|
+
{ error: error.message || 'Failed to register client' },
|
|
63
|
+
{ status: 500 }
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
import { LLMService, type ChatMessage, type LLMProvider } from '@/lib/llm-service';
|
|
4
|
+
|
|
5
|
+
const llmService = new LLMService();
|
|
6
|
+
|
|
7
|
+
export async function POST(request: NextRequest) {
|
|
8
|
+
try {
|
|
9
|
+
const { provider, messages, apiKey, jwtToken, mcpApiKey } = await request.json() as {
|
|
10
|
+
provider: LLMProvider;
|
|
11
|
+
messages: ChatMessage[];
|
|
12
|
+
apiKey: string; // LLM API key
|
|
13
|
+
jwtToken?: string; // MCP server JWT
|
|
14
|
+
mcpApiKey?: string; // MCP server API key
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
console.log('Received chat request:', {
|
|
18
|
+
provider,
|
|
19
|
+
messagesCount: messages?.length,
|
|
20
|
+
messages: JSON.stringify(messages),
|
|
21
|
+
hasApiKey: !!apiKey
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (!provider || !messages || !apiKey) {
|
|
25
|
+
return NextResponse.json(
|
|
26
|
+
{ error: 'Missing required fields' },
|
|
27
|
+
{ status: 400 }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (messages.length === 0) {
|
|
32
|
+
return NextResponse.json(
|
|
33
|
+
{ error: 'Messages array is empty' },
|
|
34
|
+
{ status: 400 }
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Get available tools from MCP server
|
|
39
|
+
const client = getMcpClient();
|
|
40
|
+
const toolsList = await client.listTools();
|
|
41
|
+
const tools = toolsList.tools?.map((tool: any) => ({
|
|
42
|
+
name: tool.name,
|
|
43
|
+
description: tool.description || '',
|
|
44
|
+
inputSchema: tool.inputSchema || {},
|
|
45
|
+
})) || [];
|
|
46
|
+
|
|
47
|
+
// Call LLM
|
|
48
|
+
const response = await llmService.chat(provider, messages, tools, apiKey);
|
|
49
|
+
|
|
50
|
+
// If LLM wants to call tools, execute them
|
|
51
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
52
|
+
const toolResults: ChatMessage[] = [];
|
|
53
|
+
|
|
54
|
+
for (const toolCall of response.toolCalls) {
|
|
55
|
+
try {
|
|
56
|
+
// Inject auth tokens into tool arguments if available
|
|
57
|
+
const toolArgs = { ...toolCall.arguments };
|
|
58
|
+
if (jwtToken || mcpApiKey) {
|
|
59
|
+
toolArgs._meta = {
|
|
60
|
+
...(toolArgs._meta || {}),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (jwtToken) {
|
|
64
|
+
toolArgs._meta._jwt = jwtToken;
|
|
65
|
+
toolArgs._meta.authorization = `Bearer ${jwtToken}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (mcpApiKey) {
|
|
69
|
+
toolArgs._meta.apiKey = mcpApiKey;
|
|
70
|
+
toolArgs._meta['x-api-key'] = mcpApiKey;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Execute tool via MCP client
|
|
75
|
+
const result = await client.executeTool(toolCall.name, toolArgs);
|
|
76
|
+
|
|
77
|
+
// Extract content from MCP result
|
|
78
|
+
let toolContent = '';
|
|
79
|
+
if (result.content && Array.isArray(result.content)) {
|
|
80
|
+
toolContent = result.content
|
|
81
|
+
.map((c: any) => c.text || JSON.stringify(c))
|
|
82
|
+
.join('\n');
|
|
83
|
+
} else {
|
|
84
|
+
toolContent = JSON.stringify(result);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Store tool result with both ID and NAME (Gemini needs the name!)
|
|
88
|
+
toolResults.push({
|
|
89
|
+
role: 'tool',
|
|
90
|
+
content: toolContent,
|
|
91
|
+
toolCallId: toolCall.id,
|
|
92
|
+
toolName: toolCall.name, // Add tool name for Gemini function responses
|
|
93
|
+
});
|
|
94
|
+
} catch (error: any) {
|
|
95
|
+
toolResults.push({
|
|
96
|
+
role: 'tool',
|
|
97
|
+
content: JSON.stringify({ error: error.message }),
|
|
98
|
+
toolCallId: toolCall.id,
|
|
99
|
+
toolName: toolCall.name, // Add tool name for Gemini function responses
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Return response with tool results
|
|
105
|
+
return NextResponse.json({
|
|
106
|
+
message: response.message,
|
|
107
|
+
toolCalls: response.toolCalls,
|
|
108
|
+
toolResults,
|
|
109
|
+
finishReason: response.finishReason,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// No tool calls, just return the message
|
|
114
|
+
return NextResponse.json({
|
|
115
|
+
message: response.message,
|
|
116
|
+
finishReason: response.finishReason,
|
|
117
|
+
});
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
console.error('Chat error:', error);
|
|
120
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
|
|
8
|
+
if (!client.isConnected()) {
|
|
9
|
+
return NextResponse.json({
|
|
10
|
+
error: 'MCP client not connected',
|
|
11
|
+
checks: []
|
|
12
|
+
}, { status: 500 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Read health checks from MCP server as a resource
|
|
16
|
+
try {
|
|
17
|
+
const result = await client.readResource('health://checks');
|
|
18
|
+
|
|
19
|
+
// Parse the health checks data
|
|
20
|
+
const healthData = JSON.parse(result.contents[0].text);
|
|
21
|
+
|
|
22
|
+
return NextResponse.json({
|
|
23
|
+
checks: healthData.checks || [],
|
|
24
|
+
count: healthData.checks?.length || 0
|
|
25
|
+
});
|
|
26
|
+
} catch (resourceError: any) {
|
|
27
|
+
// Health checks resource not available or no checks registered
|
|
28
|
+
console.log('No health checks resource available');
|
|
29
|
+
return NextResponse.json({
|
|
30
|
+
checks: [],
|
|
31
|
+
count: 0
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
} catch (error: any) {
|
|
35
|
+
console.error('❌ Error in /api/health/checks:', error.message);
|
|
36
|
+
return NextResponse.json(
|
|
37
|
+
{ error: 'Failed to fetch health checks', checks: [] },
|
|
38
|
+
{ status: 500 }
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
const client = getMcpClient();
|
|
6
|
+
|
|
7
|
+
return NextResponse.json({
|
|
8
|
+
status: 'ok',
|
|
9
|
+
connected: client.isConnected(),
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Initialize MCP client connection
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
function loadEnvFile(projectPath: string): Record<string, string> {
|
|
8
|
+
const envPath = path.join(projectPath, '.env');
|
|
9
|
+
const envVars: Record<string, string> = {};
|
|
10
|
+
|
|
11
|
+
if (fs.existsSync(envPath)) {
|
|
12
|
+
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
13
|
+
envContent.split('\n').forEach(line => {
|
|
14
|
+
line = line.trim();
|
|
15
|
+
if (line && !line.startsWith('#')) {
|
|
16
|
+
const [key, ...valueParts] = line.split('=');
|
|
17
|
+
if (key && valueParts.length > 0) {
|
|
18
|
+
envVars[key.trim()] = valueParts.join('=').trim().replace(/^["']|["']$/g, '');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return envVars;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function POST() {
|
|
28
|
+
try {
|
|
29
|
+
const client = getMcpClient();
|
|
30
|
+
|
|
31
|
+
// Get MCP server config from environment
|
|
32
|
+
const command = process.env.MCP_COMMAND || 'node';
|
|
33
|
+
const argsString = process.env.MCP_ARGS || '';
|
|
34
|
+
|
|
35
|
+
// Parse MCP_ARGS - it can be a JSON array string or a single path
|
|
36
|
+
let args: string[] = [];
|
|
37
|
+
if (argsString) {
|
|
38
|
+
try {
|
|
39
|
+
// Try to parse as JSON array
|
|
40
|
+
args = JSON.parse(argsString);
|
|
41
|
+
} catch {
|
|
42
|
+
// If not JSON, treat as a single argument
|
|
43
|
+
args = [argsString];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!client.isConnected()) {
|
|
48
|
+
// Get project directory from the MCP server path
|
|
49
|
+
// If using wrapper, the actual server path is the second argument
|
|
50
|
+
const serverPath = args.length > 1 ? args[1] : args[0];
|
|
51
|
+
const projectPath = serverPath ? path.dirname(path.dirname(serverPath)) : process.cwd();
|
|
52
|
+
|
|
53
|
+
// Load environment variables from project's .env file
|
|
54
|
+
const projectEnv = loadEnvFile(projectPath);
|
|
55
|
+
|
|
56
|
+
console.log(`📂 Project path: ${projectPath}`);
|
|
57
|
+
console.log(`🔧 Loaded ${Object.keys(projectEnv).length} env vars from ${projectPath}/.env`);
|
|
58
|
+
console.log(`🔑 JWT_SECRET present: ${projectEnv.JWT_SECRET ? 'YES' : 'NO'}`);
|
|
59
|
+
console.log(`📝 Command: ${command} ${args.join(' ')}`);
|
|
60
|
+
|
|
61
|
+
await client.connect({
|
|
62
|
+
command,
|
|
63
|
+
args,
|
|
64
|
+
env: {
|
|
65
|
+
...projectEnv,
|
|
66
|
+
NODE_ENV: 'development',
|
|
67
|
+
},
|
|
68
|
+
cwd: projectPath, // Set working directory to project root
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log('✅ MCP client connected successfully');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return NextResponse.json({
|
|
75
|
+
success: true,
|
|
76
|
+
message: 'MCP client connected',
|
|
77
|
+
});
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
console.error('Failed to connect MCP client:', error);
|
|
80
|
+
return NextResponse.json(
|
|
81
|
+
{ error: error.message },
|
|
82
|
+
{ status: 500 }
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
const result = await client.ping();
|
|
8
|
+
return NextResponse.json(result);
|
|
9
|
+
} catch (error: any) {
|
|
10
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function POST(
|
|
5
|
+
request: NextRequest,
|
|
6
|
+
{ params }: { params: { name: string } }
|
|
7
|
+
) {
|
|
8
|
+
try {
|
|
9
|
+
const client = getMcpClient();
|
|
10
|
+
const args = await request.json();
|
|
11
|
+
console.log('🔍 Executing prompt:', params.name, 'with args:', args);
|
|
12
|
+
const result = await client.getPrompt(params.name, args);
|
|
13
|
+
console.log('✅ Prompt result:', result);
|
|
14
|
+
return NextResponse.json(result);
|
|
15
|
+
} catch (error: any) {
|
|
16
|
+
console.error('❌ Prompt execution error:', error);
|
|
17
|
+
console.error('Error stack:', error.stack);
|
|
18
|
+
return NextResponse.json({ error: error.message, stack: error.stack }, { status: 500 });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
const result = await client.listPrompts();
|
|
8
|
+
return NextResponse.json(result);
|
|
9
|
+
} catch (error: any) {
|
|
10
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|