@nuxtjs/mcp-toolkit 0.4.0 → 0.5.0

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 CHANGED
@@ -1,5 +1,8 @@
1
1
  ![Nuxt MCP Toolkit](https://raw.githubusercontent.com/nuxt-modules/mcp-toolkit/main/assets/banner.jpg)
2
2
 
3
+ [![Install MCP in Cursor](https://mcp-toolkit.nuxt.dev/mcp/badge.svg)](https://mcp-toolkit.nuxt.dev/mcp/deeplink)
4
+ [![Install MCP in VS Code](https://mcp-toolkit.nuxt.dev/mcp/badge.svg?ide=vscode)](https://mcp-toolkit.nuxt.dev/mcp/deeplink?ide=vscode)
5
+
3
6
  # Nuxt MCP Toolkit
4
7
 
5
8
  <!-- automd:badges color="black" license name="@nuxtjs/mcp-toolkit" -->
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxtjs/mcp-toolkit",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "configKey": "mcp",
5
5
  "docs": "https://mcp-toolkit.nuxt.dev/getting-started/installation",
6
6
  "mcp": "https://mcp-toolkit.nuxt.dev/mcp",
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { logger, createResolver, defineNuxtModule, addServerHandler, addServerImports } from '@nuxt/kit';
1
+ import { logger, createResolver, defineNuxtModule, addComponent, addServerHandler, addServerImports } from '@nuxt/kit';
2
2
  import { defu } from 'defu';
3
3
  import { loadAllDefinitions } from '../dist/runtime/server/mcp/loaders/index.js';
4
4
  import { defaultMcpConfig } from '../dist/runtime/server/mcp/config.js';
@@ -6,7 +6,7 @@ import { ROUTES } from '../dist/runtime/server/mcp/constants.js';
6
6
  import { addDevToolsCustomTabs } from '../dist/runtime/server/mcp/devtools/index.js';
7
7
 
8
8
  const name = "@nuxtjs/mcp-toolkit";
9
- const version = "0.4.0";
9
+ const version = "0.5.0";
10
10
 
11
11
  const log = logger.withTag("@nuxtjs/mcp-toolkit");
12
12
  const { resolve } = createResolver(import.meta.url);
@@ -35,6 +35,10 @@ const module$1 = defineNuxtModule({
35
35
  if (!options.enabled) {
36
36
  return;
37
37
  }
38
+ addComponent({
39
+ name: "InstallButton",
40
+ filePath: resolver.resolve("runtime/components/InstallButton.vue")
41
+ });
38
42
  const mcpDir = options.dir ?? defaultMcpConfig.dir;
39
43
  const paths = {
40
44
  tools: [`${mcpDir}/tools`],
@@ -102,6 +106,14 @@ const module$1 = defineNuxtModule({
102
106
  route: options.route,
103
107
  handler: resolver.resolve("runtime/server/mcp/handler")
104
108
  });
109
+ addServerHandler({
110
+ route: `${options.route}/deeplink`,
111
+ handler: resolver.resolve("runtime/server/mcp/deeplink")
112
+ });
113
+ addServerHandler({
114
+ route: `${options.route}/badge.svg`,
115
+ handler: resolver.resolve("runtime/server/mcp/badge-image")
116
+ });
105
117
  addDevToolsCustomTabs(nuxt, options);
106
118
  }
107
119
  });
@@ -0,0 +1,38 @@
1
+ export type SupportedIDE = 'cursor' | 'vscode';
2
+ export interface InstallButtonProps {
3
+ /**
4
+ * URL of the MCP server endpoint (e.g., 'https://example.com/mcp')
5
+ * The deeplink will be derived as '{url}/deeplink?ide=xxx'
6
+ */
7
+ url: string;
8
+ /**
9
+ * Target IDE
10
+ * @default 'cursor'
11
+ */
12
+ ide?: SupportedIDE;
13
+ /**
14
+ * Button label (auto-generated based on IDE if not provided)
15
+ */
16
+ label?: string;
17
+ /**
18
+ * Show the IDE icon
19
+ * @default true
20
+ */
21
+ showIcon?: boolean;
22
+ }
23
+ declare var __VLS_1: {};
24
+ type __VLS_Slots = {} & {
25
+ default?: (props: typeof __VLS_1) => any;
26
+ };
27
+ declare const __VLS_base: import("@vue/runtime-core").DefineComponent<InstallButtonProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<InstallButtonProps> & Readonly<{}>, {
28
+ ide: SupportedIDE;
29
+ showIcon: boolean;
30
+ }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>;
31
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;
34
+ type __VLS_WithSlots<T, S> = T & {
35
+ new (): {
36
+ $slots: S;
37
+ };
38
+ };
@@ -0,0 +1,172 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ const IDE_CONFIG = {
4
+ cursor: {
5
+ name: "Cursor",
6
+ defaultLabel: "Install MCP in Cursor"
7
+ },
8
+ vscode: {
9
+ name: "VS Code",
10
+ defaultLabel: "Install MCP in VS Code"
11
+ }
12
+ };
13
+ const props = defineProps({
14
+ url: { type: String, required: true },
15
+ ide: { type: String, required: false, default: "cursor" },
16
+ label: { type: String, required: false },
17
+ showIcon: { type: Boolean, required: false, default: true }
18
+ });
19
+ const ideConfig = computed(() => IDE_CONFIG[props.ide]);
20
+ const buttonLabel = computed(() => props.label ?? ideConfig.value.defaultLabel);
21
+ const deeplink = computed(() => {
22
+ const baseUrl = props.url.replace(/\/$/, "");
23
+ return `${baseUrl}/deeplink?ide=${props.ide}`;
24
+ });
25
+ </script>
26
+
27
+ <template>
28
+ <a
29
+ :href="deeplink"
30
+ class="mcp-install-button"
31
+ v-bind="$attrs"
32
+ >
33
+ <!-- Cursor Icon -->
34
+ <svg
35
+ v-if="showIcon && ide === 'cursor'"
36
+ class="mcp-install-button-icon"
37
+ xmlns="http://www.w3.org/2000/svg"
38
+ width="1em"
39
+ height="1em"
40
+ viewBox="0 0 24 24"
41
+ aria-hidden="true"
42
+ >
43
+ <path
44
+ fill="url(#mcp-cursor-fill-0)"
45
+ d="M11.925 24l10.425-6-10.425-6L1.5 18l10.425 6z"
46
+ />
47
+ <path
48
+ fill="url(#mcp-cursor-fill-1)"
49
+ d="M22.35 18V6L11.925 0v12l10.425 6z"
50
+ />
51
+ <path
52
+ fill="url(#mcp-cursor-fill-2)"
53
+ d="M11.925 0L1.5 6v12l10.425-6V0z"
54
+ />
55
+ <path
56
+ fill="#555"
57
+ d="M22.35 6L11.925 24V12L22.35 6z"
58
+ />
59
+ <path
60
+ fill="#000"
61
+ d="M22.35 6l-10.425 6L1.5 6h20.85z"
62
+ />
63
+ <defs>
64
+ <linearGradient
65
+ id="mcp-cursor-fill-0"
66
+ x1="11.925"
67
+ x2="11.925"
68
+ y1="12"
69
+ y2="24"
70
+ gradientUnits="userSpaceOnUse"
71
+ >
72
+ <stop
73
+ offset=".16"
74
+ stop-color="#000"
75
+ stop-opacity=".39"
76
+ />
77
+ <stop
78
+ offset=".658"
79
+ stop-color="#000"
80
+ stop-opacity=".8"
81
+ />
82
+ </linearGradient>
83
+ <linearGradient
84
+ id="mcp-cursor-fill-1"
85
+ x1="22.35"
86
+ x2="11.925"
87
+ y1="6.037"
88
+ y2="12.15"
89
+ gradientUnits="userSpaceOnUse"
90
+ >
91
+ <stop
92
+ offset=".182"
93
+ stop-color="#000"
94
+ stop-opacity=".31"
95
+ />
96
+ <stop
97
+ offset=".715"
98
+ stop-color="#000"
99
+ stop-opacity="0"
100
+ />
101
+ </linearGradient>
102
+ <linearGradient
103
+ id="mcp-cursor-fill-2"
104
+ x1="11.925"
105
+ x2="1.5"
106
+ y1="0"
107
+ y2="18"
108
+ gradientUnits="userSpaceOnUse"
109
+ >
110
+ <stop
111
+ stop-color="#000"
112
+ stop-opacity=".6"
113
+ />
114
+ <stop
115
+ offset=".667"
116
+ stop-color="#000"
117
+ stop-opacity=".22"
118
+ />
119
+ </linearGradient>
120
+ </defs>
121
+ </svg>
122
+
123
+ <!-- VS Code Icon -->
124
+ <svg
125
+ v-if="showIcon && ide === 'vscode'"
126
+ class="mcp-install-button-icon mcp-install-button-icon--vscode"
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ width="1em"
129
+ height="1em"
130
+ viewBox="0 0 100 100"
131
+ aria-hidden="true"
132
+ >
133
+ <mask
134
+ id="mcp-vscode-mask"
135
+ width="100"
136
+ height="100"
137
+ x="0"
138
+ y="0"
139
+ maskUnits="userSpaceOnUse"
140
+ >
141
+ <path
142
+ fill="#fff"
143
+ fill-rule="evenodd"
144
+ d="M70.912 99.317a6.223 6.223 0 0 0 4.96-.19l20.589-9.907A6.25 6.25 0 0 0 100 83.587V16.413a6.25 6.25 0 0 0-3.54-5.632L75.874.874a6.226 6.226 0 0 0-7.104 1.21L29.355 38.04 12.187 25.01a4.162 4.162 0 0 0-5.318.236l-5.506 5.009a4.168 4.168 0 0 0-.004 6.162L16.247 50 1.36 63.583a4.168 4.168 0 0 0 .004 6.162l5.506 5.01a4.162 4.162 0 0 0 5.318.236l17.168-13.032L68.77 97.917a6.217 6.217 0 0 0 2.143 1.4ZM75.015 27.3 45.11 50l29.906 22.701V27.3Z"
145
+ clip-rule="evenodd"
146
+ />
147
+ </mask>
148
+ <g mask="url(#mcp-vscode-mask)">
149
+ <path
150
+ fill="#0065A9"
151
+ d="M96.461 10.796 75.857.876a6.23 6.23 0 0 0-7.107 1.207l-67.451 61.5a4.167 4.167 0 0 0 .004 6.162l5.51 5.009a4.167 4.167 0 0 0 5.32.236l81.228-61.62c2.725-2.067 6.639-.124 6.639 3.297v-.24a6.25 6.25 0 0 0-3.539-5.63Z"
152
+ />
153
+ <path
154
+ fill="#007ACC"
155
+ d="m96.461 89.204-20.604 9.92a6.229 6.229 0 0 1-7.107-1.207l-67.451-61.5a4.167 4.167 0 0 1 .004-6.162l5.51-5.009a4.167 4.167 0 0 1 5.32-.236l81.228 61.62c2.725 2.067 6.639.124 6.639-3.297v.24a6.25 6.25 0 0 1-3.539 5.63Z"
156
+ />
157
+ <path
158
+ fill="#1F9CF0"
159
+ d="M75.858 99.126a6.232 6.232 0 0 1-7.108-1.21c2.306 2.307 6.25.674 6.25-2.588V4.672c0-3.262-3.944-4.895-6.25-2.589a6.232 6.232 0 0 1 7.108-1.21l20.6 9.908A6.25 6.25 0 0 1 100 16.413v67.174a6.25 6.25 0 0 1-3.541 5.633l-20.601 9.906Z"
160
+ />
161
+ </g>
162
+ </svg>
163
+
164
+ <span class="mcp-install-button-label">
165
+ <slot>{{ buttonLabel }}</slot>
166
+ </span>
167
+ </a>
168
+ </template>
169
+
170
+ <style>
171
+ .mcp-install-button{align-items:center;background-color:#171717;border:1px solid #404040;color:#fff;cursor:pointer;display:inline-flex;font-size:.875rem;font-weight:500;gap:.5rem;line-height:1.25rem;padding:.4rem .5rem;text-decoration:none;transition:background-color .15s,border-color .15s}.mcp-install-button:hover{background-color:#262626;border-color:#525252}.mcp-install-button:focus-visible{outline:2px solid #3b82f6;outline-offset:2px}.mcp-install-button-icon{filter:invert(1);flex-shrink:0;height:1.25rem;width:1.25rem}.mcp-install-button-icon--vscode{filter:none}.mcp-install-button-label{white-space:nowrap}
172
+ </style>
@@ -0,0 +1,38 @@
1
+ export type SupportedIDE = 'cursor' | 'vscode';
2
+ export interface InstallButtonProps {
3
+ /**
4
+ * URL of the MCP server endpoint (e.g., 'https://example.com/mcp')
5
+ * The deeplink will be derived as '{url}/deeplink?ide=xxx'
6
+ */
7
+ url: string;
8
+ /**
9
+ * Target IDE
10
+ * @default 'cursor'
11
+ */
12
+ ide?: SupportedIDE;
13
+ /**
14
+ * Button label (auto-generated based on IDE if not provided)
15
+ */
16
+ label?: string;
17
+ /**
18
+ * Show the IDE icon
19
+ * @default true
20
+ */
21
+ showIcon?: boolean;
22
+ }
23
+ declare var __VLS_1: {};
24
+ type __VLS_Slots = {} & {
25
+ default?: (props: typeof __VLS_1) => any;
26
+ };
27
+ declare const __VLS_base: import("@vue/runtime-core").DefineComponent<InstallButtonProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<InstallButtonProps> & Readonly<{}>, {
28
+ ide: SupportedIDE;
29
+ showIcon: boolean;
30
+ }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>;
31
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;
34
+ type __VLS_WithSlots<T, S> = T & {
35
+ new (): {
36
+ $slots: S;
37
+ };
38
+ };
@@ -0,0 +1,3 @@
1
+ export type SupportedIDE = 'cursor' | 'vscode';
2
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
3
+ export default _default;
@@ -0,0 +1,154 @@
1
+ import { defineEventHandler, getQuery, setHeader } from "h3";
2
+ import satori from "satori";
3
+ const IDE_CONFIG = {
4
+ cursor: {
5
+ defaultLabel: "Install MCP in Cursor"
6
+ },
7
+ vscode: {
8
+ defaultLabel: "Install MCP in VS Code"
9
+ }
10
+ };
11
+ function CursorIcon() {
12
+ return {
13
+ type: "svg",
14
+ props: {
15
+ width: 18,
16
+ height: 18,
17
+ viewBox: "0 0 24 24",
18
+ style: { filter: "invert(1)" },
19
+ children: [
20
+ {
21
+ type: "path",
22
+ props: {
23
+ fill: "#666",
24
+ d: "M11.925 24l10.425-6-10.425-6L1.5 18l10.425 6z"
25
+ }
26
+ },
27
+ {
28
+ type: "path",
29
+ props: {
30
+ fill: "#888",
31
+ d: "M22.35 18V6L11.925 0v12l10.425 6z"
32
+ }
33
+ },
34
+ {
35
+ type: "path",
36
+ props: {
37
+ fill: "#777",
38
+ d: "M11.925 0L1.5 6v12l10.425-6V0z"
39
+ }
40
+ },
41
+ {
42
+ type: "path",
43
+ props: {
44
+ fill: "#555",
45
+ d: "M22.35 6L11.925 24V12L22.35 6z"
46
+ }
47
+ },
48
+ {
49
+ type: "path",
50
+ props: {
51
+ fill: "#333",
52
+ d: "M22.35 6l-10.425 6L1.5 6h20.85z"
53
+ }
54
+ }
55
+ ]
56
+ }
57
+ };
58
+ }
59
+ function VSCodeIconSimple() {
60
+ return {
61
+ type: "svg",
62
+ props: {
63
+ width: 18,
64
+ height: 18,
65
+ viewBox: "0 0 24 24",
66
+ children: [
67
+ {
68
+ type: "path",
69
+ props: {
70
+ fill: "#007ACC",
71
+ d: "M23.15 2.587L18.21.21a1.494 1.494 0 0 0-1.705.29l-9.46 8.63l-4.12-3.128a.999.999 0 0 0-1.276.057L.327 7.261A1 1 0 0 0 .326 8.74L3.899 12L.326 15.26a1 1 0 0 0 .001 1.479L1.65 17.94a.999.999 0 0 0 1.276.057l4.12-3.128l9.46 8.63a1.492 1.492 0 0 0 1.704.29l4.942-2.377A1.5 1.5 0 0 0 24 20.06V3.939a1.5 1.5 0 0 0-.85-1.352zm-5.146 14.861L10.826 12l7.178-5.448v10.896z"
72
+ }
73
+ }
74
+ ]
75
+ }
76
+ };
77
+ }
78
+ function getIcon(ide) {
79
+ return ide === "vscode" ? VSCodeIconSimple() : CursorIcon();
80
+ }
81
+ async function generateBadgeSVG(options) {
82
+ const { label, color, textColor, borderColor, showIcon, ide } = options;
83
+ const icon = getIcon(ide);
84
+ const element = {
85
+ type: "div",
86
+ props: {
87
+ style: {
88
+ display: "flex",
89
+ alignItems: "center",
90
+ gap: "8px",
91
+ padding: "6px 8px",
92
+ fontSize: "14px",
93
+ fontWeight: 500,
94
+ color: `#${textColor}`,
95
+ backgroundColor: `#${color}`,
96
+ border: `1px solid #${borderColor}`
97
+ },
98
+ children: showIcon ? [icon, { type: "span", props: { children: label } }] : [{ type: "span", props: { children: label } }]
99
+ }
100
+ };
101
+ const iconWidth = showIcon ? 26 : 0;
102
+ const textWidth = label.length * 8;
103
+ const padding = 20;
104
+ const width = Math.max(Math.ceil(iconWidth + textWidth + padding), 140);
105
+ const height = 32;
106
+ const svg = await satori(element, {
107
+ width,
108
+ height,
109
+ fonts: [
110
+ {
111
+ name: "Inter",
112
+ data: await loadFont(),
113
+ weight: 500,
114
+ style: "normal"
115
+ }
116
+ ]
117
+ });
118
+ return svg;
119
+ }
120
+ async function loadFont() {
121
+ const response = await fetch(
122
+ "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuI6fAZ9hjp-Ek-_EeA.woff"
123
+ );
124
+ if (!response.ok) {
125
+ throw new Error(`Failed to load font: ${response.status} ${response.statusText}`);
126
+ }
127
+ return response.arrayBuffer();
128
+ }
129
+ export default defineEventHandler(async (event) => {
130
+ const query = getQuery(event);
131
+ const ide = query.ide || "cursor";
132
+ const ideConfig = IDE_CONFIG[ide] || IDE_CONFIG.cursor;
133
+ const options = {
134
+ ide,
135
+ label: query.label || ideConfig.defaultLabel,
136
+ color: query.color || "171717",
137
+ textColor: query.textColor || "ffffff",
138
+ borderColor: query.borderColor || "404040",
139
+ showIcon: query.icon !== "false"
140
+ };
141
+ try {
142
+ const svg = await generateBadgeSVG(options);
143
+ setHeader(event, "Content-Type", "image/svg+xml");
144
+ setHeader(event, "Cache-Control", "public, max-age=86400");
145
+ return svg;
146
+ } catch {
147
+ setHeader(event, "Content-Type", "image/svg+xml");
148
+ setHeader(event, "Cache-Control", "no-cache");
149
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="140" height="32">
150
+ <rect width="140" height="32" fill="#171717" stroke="#404040"/>
151
+ <text x="70" y="20" fill="#fff" font-size="12" text-anchor="middle">${options.label}</text>
152
+ </svg>`;
153
+ }
154
+ });
@@ -0,0 +1,3 @@
1
+ export type SupportedIDE = 'cursor' | 'vscode';
2
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, string | Response>;
3
+ export default _default;
@@ -0,0 +1,62 @@
1
+ import { defineEventHandler, getRequestURL, getQuery, setHeader } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ const IDE_CONFIGS = {
4
+ cursor: {
5
+ name: "Cursor",
6
+ generateDeeplink: (serverName, mcpUrl) => {
7
+ const config = { type: "http", url: mcpUrl };
8
+ const configBase64 = Buffer.from(JSON.stringify(config)).toString("base64");
9
+ return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(serverName)}&config=${encodeURIComponent(configBase64)}`;
10
+ }
11
+ },
12
+ vscode: {
13
+ name: "VS Code",
14
+ generateDeeplink: (serverName, mcpUrl) => {
15
+ const config = { name: serverName, type: "http", url: mcpUrl };
16
+ return `vscode:mcp/install?${encodeURIComponent(JSON.stringify(config))}`;
17
+ }
18
+ }
19
+ };
20
+ function escapeHtmlAttr(str) {
21
+ return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
22
+ }
23
+ function escapeJs(str) {
24
+ return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/'/g, "\\'").replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
25
+ }
26
+ export default defineEventHandler((event) => {
27
+ const runtimeConfig = useRuntimeConfig(event).mcp;
28
+ const requestUrl = getRequestURL(event);
29
+ const query = getQuery(event);
30
+ const ide = query.ide || "cursor";
31
+ const ideConfig = IDE_CONFIGS[ide];
32
+ if (!ideConfig) {
33
+ setHeader(event, "Location", "/");
34
+ return new Response(null, { status: 302 });
35
+ }
36
+ const serverName = runtimeConfig.name || "mcp-server";
37
+ const mcpUrl = `${requestUrl.origin}${runtimeConfig.route || "/mcp"}`;
38
+ const deeplink = ideConfig.generateDeeplink(serverName, mcpUrl);
39
+ const htmlDeeplink = escapeHtmlAttr(deeplink);
40
+ const jsDeeplink = escapeJs(deeplink);
41
+ setHeader(event, "Content-Type", "text/html; charset=utf-8");
42
+ return `<!DOCTYPE html>
43
+ <html lang="en">
44
+ <head>
45
+ <meta charset="utf-8">
46
+ <meta name="viewport" content="width=device-width, initial-scale=1">
47
+ <title>Opening ${ideConfig.name}...</title>
48
+ <style>
49
+ body { font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #0a0a0a; color: #fff; }
50
+ .container { text-align: center; padding: 2rem; }
51
+ a { color: #3b82f6; }
52
+ </style>
53
+ </head>
54
+ <body>
55
+ <div class="container">
56
+ <p>Opening ${ideConfig.name}...</p>
57
+ <p>If nothing happens, <a href="${htmlDeeplink}">click here to install</a>.</p>
58
+ </div>
59
+ <script>window.location.href = "${jsDeeplink}";<\/script>
60
+ </body>
61
+ </html>`;
62
+ });
@@ -7,7 +7,7 @@ export type MsCacheDuration = '1s' | '5s' | '10s' | '15s' | '30s' | '45s' | '1m'
7
7
  * @see https://nitro.build/guide/cache#options
8
8
  */
9
9
  export interface McpCacheOptions<Args = unknown> {
10
- /** Cache duration as string (e.g. '1h') or milliseconds (required) */
10
+ /** Cache duration as string (e.g. '1h') or seconds (required) */
11
11
  maxAge: MsCacheDuration | number;
12
12
  /** Duration for stale-while-revalidate */
13
13
  staleMaxAge?: number;
@@ -26,7 +26,7 @@ export interface McpCacheOptions<Args = unknown> {
26
26
  */
27
27
  export type McpCache<Args = unknown> = MsCacheDuration | number | McpCacheOptions<Args>;
28
28
  /**
29
- * Parse cache duration to milliseconds
29
+ * Parse cache duration to seconds
30
30
  */
31
31
  export declare function parseCacheDuration(duration: MsCacheDuration | number): number;
32
32
  /**
@@ -8,7 +8,7 @@ export function parseCacheDuration(duration) {
8
8
  if (parsed === void 0) {
9
9
  throw new Error(`Invalid cache duration: ${duration}`);
10
10
  }
11
- return parsed;
11
+ return Math.ceil(parsed / 1e3);
12
12
  }
13
13
  export function createCacheOptions(cache, name, defaultGetKey) {
14
14
  if (typeof cache === "object") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxtjs/mcp-toolkit",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Create MCP servers directly in your Nuxt application. Define tools, resources, and prompts with a simple and intuitive API.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,6 +40,7 @@
40
40
  "defu": "^6.1.4",
41
41
  "ms": "^2.1.3",
42
42
  "pathe": "^2.0.3",
43
+ "satori": "^0.18.3",
43
44
  "scule": "^1.3.0",
44
45
  "tinyglobby": "^0.2.15"
45
46
  },