diff --git a/.changeset/apps-routing.md b/.changeset/apps-routing.md deleted file mode 100644 index b090acfe..00000000 --- a/.changeset/apps-routing.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -"@nuxtjs/mcp-toolkit": minor ---- - -Route MCP Apps to any named handler — no manual filtering required. Until now every `defineMcpApp` SFC was hard-attributed to the implicit `apps` handler, so multiple `app/mcp/*.vue` files could only be exposed together on `/mcp/apps`. Two new mechanisms (consistent with the rest of the module) let you split apps across handlers. - -### Sub-folder convention - -The first sub-directory under `app/mcp/` becomes the named-handler attribution — same idea as `server/mcp/handlers//` for tools, resources, and prompts: - -```bash -app/mcp/ -├── color-picker.vue # → /mcp/apps (default) -├── finder/ -│ └── stay-finder.vue # → /mcp/finder -└── checkout/ - └── stay-checkout.vue # → /mcp/checkout -``` - -Pair each sub-folder with its handler index file (one-liner is fine): - -```ts [server/mcp/handlers/finder/index.ts] -import { defineMcpHandler } from '@nuxtjs/mcp-toolkit/server' - -export default defineMcpHandler({}) -``` - -With `defaultHandlerStrategy: 'orphans'` (the default), each app surfaces on exactly one route. - -### Explicit `attachTo` / `group` / `tags` overrides - -Three new fields on `defineMcpApp` let an SFC opt out of the folder convention or add filterable metadata. They override any sub-folder default: - -```vue [app/mcp/stay-finder.vue] - -``` - -The generated tool and resource carry `_meta.handler = 'finder'`, top-level `group` and `tags`, so `getMcpTools({ handler: 'finder' })` / `getMcpTools({ tags: ['searchable'] })` filters work the same way they do for ordinary tools. - -### Build-time validation - -`attachTo`, `group`, and `tags` must be **string literals** (e.g. `'finder'`, `['a', 'b']`). The toolkit reads them statically from the `defineMcpApp` macro at build time so routing decisions are deterministic across dev, build, and deploy. A dynamic expression (`attachTo: someVar`) fails the build with a clear message. - -### Back-compat - -100% additive — apps without sub-folders or explicit overrides keep their previous behaviour (attached to `apps`, surfaced on `/mcp/apps`). The previous "manual filter inside `defineMcpHandler`" workaround documented in [MCP Apps internals](https://mcp-toolkit.nuxt.dev/advanced/mcp-apps-internals#multiple-handlers) is no longer required. - -See [Apps · Authoring → Routing apps to a specific handler](https://mcp-toolkit.nuxt.dev/apps/authoring#routing-apps-to-a-specific-handler). diff --git a/.changeset/nitro-runtime-hooks.md b/.changeset/nitro-runtime-hooks.md deleted file mode 100644 index 33252c4c..00000000 --- a/.changeset/nitro-runtime-hooks.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -"@nuxtjs/mcp-toolkit": minor ---- - -Expose two Nitro runtime hooks for the MCP request lifecycle. Subscribe from a `server/plugins/*.ts` plugin to inject custom logic without owning a `defineMcpHandler` — listeners that throw are logged via consola and the request continues. - -``` -defineMcpHandler middleware → mcp:config:resolved → createMcpServer → mcp:server:created → transport -``` - -### `mcp:config:resolved` - -Fires per request after dynamic `tools` / `resources` / `prompts` resolvers and `enabled(event)` guards have run, **before** the per-request `McpServer` is built. Mutate `ctx.config` in place to add, remove or transform definitions for this request only. - -```ts [server/plugins/mcp-filter.ts] -export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hook('mcp:config:resolved', ({ config, event }) => { - if (!event.context.user) { - config.tools = config.tools.filter(t => !t.tags?.includes('admin')) - } - }) -}) -``` - -### `mcp:server:created` - -Fires per request after every tool / resource / prompt has been registered, **before** the server is connected to the transport. Receives the SDK `McpServer` instance — call `server.registerTool(...)` to add definitions late, or use `getSdkServer(server)` to reach the low-level `Server` and `setRequestHandler(...)` for custom JSON-RPC methods. - -```ts [server/plugins/mcp-whoami.ts] -export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hook('mcp:server:created', ({ server, event }) => { - server.registerTool( - 'whoami', - { description: 'Return the current user id' }, - async () => ({ - content: [{ type: 'text', text: String(event.context.userId ?? 'anonymous') }], - }), - ) - }) -}) -``` - -### Public API additions - -- `McpResolvedConfig` — type of the resolved per-request server config. -- `getSdkServer(server)` — reach the underlying SDK `Server` instance from an `McpServer`. - -Both are exported from `@nuxtjs/mcp-toolkit/server`. See [Hooks · Runtime hooks](https://mcp-toolkit.nuxt.dev/advanced/hooks#runtime-hooks). diff --git a/apps/mcp-starter/package.json b/apps/mcp-starter/package.json index 465a8c41..8e59f6bf 100644 --- a/apps/mcp-starter/package.json +++ b/apps/mcp-starter/package.json @@ -17,7 +17,7 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@nuxtjs/mcp-toolkit": "^0.16.1", + "@nuxtjs/mcp-toolkit": "^0.17.0", "nuxt": "^4.4.5", "zod": "^4.1.13" }, diff --git a/packages/nuxt-mcp-toolkit/CHANGELOG.md b/packages/nuxt-mcp-toolkit/CHANGELOG.md index 5a2b0d5b..08dba19e 100644 --- a/packages/nuxt-mcp-toolkit/CHANGELOG.md +++ b/packages/nuxt-mcp-toolkit/CHANGELOG.md @@ -1,5 +1,108 @@ # @nuxtjs/mcp-toolkit +## 0.17.0 + +### Minor Changes + +- [#248](https://github.com/nuxt-modules/mcp-toolkit/pull/248) [`067ab3e`](https://github.com/nuxt-modules/mcp-toolkit/commit/067ab3e3e0164b0b69da16f5394dd1f870bf68ff) Thanks [@HugoRCD](https://github.com/HugoRCD)! - Route MCP Apps to any named handler — no manual filtering required. Until now every `defineMcpApp` SFC was hard-attributed to the implicit `apps` handler, so multiple `app/mcp/*.vue` files could only be exposed together on `/mcp/apps`. Two new mechanisms (consistent with the rest of the module) let you split apps across handlers. + + ### Sub-folder convention + + The first sub-directory under `app/mcp/` becomes the named-handler attribution — same idea as `server/mcp/handlers//` for tools, resources, and prompts: + + ```bash + app/mcp/ + ├── color-picker.vue # → /mcp/apps (default) + ├── finder/ + │ └── stay-finder.vue # → /mcp/finder + └── checkout/ + └── stay-checkout.vue # → /mcp/checkout + ``` + + Pair each sub-folder with its handler index file (one-liner is fine): + + ```ts [server/mcp/handlers/finder/index.ts] + import { defineMcpHandler } from "@nuxtjs/mcp-toolkit/server"; + + export default defineMcpHandler({}); + ``` + + With `defaultHandlerStrategy: 'orphans'` (the default), each app surfaces on exactly one route. + + ### Explicit `attachTo` / `group` / `tags` overrides + + Three new fields on `defineMcpApp` let an SFC opt out of the folder convention or add filterable metadata. They override any sub-folder default: + + ```vue [app/mcp/stay-finder.vue] + + ``` + + The generated tool and resource carry `_meta.handler = 'finder'`, top-level `group` and `tags`, so `getMcpTools({ handler: 'finder' })` / `getMcpTools({ tags: ['searchable'] })` filters work the same way they do for ordinary tools. + + ### Build-time validation + + `attachTo`, `group`, and `tags` must be **string literals** (e.g. `'finder'`, `['a', 'b']`). The toolkit reads them statically from the `defineMcpApp` macro at build time so routing decisions are deterministic across dev, build, and deploy. A dynamic expression (`attachTo: someVar`) fails the build with a clear message. + + ### Back-compat + + 100% additive — apps without sub-folders or explicit overrides keep their previous behaviour (attached to `apps`, surfaced on `/mcp/apps`). The previous "manual filter inside `defineMcpHandler`" workaround documented in [MCP Apps internals](https://mcp-toolkit.nuxt.dev/advanced/mcp-apps-internals#multiple-handlers) is no longer required. + + See [Apps · Authoring → Routing apps to a specific handler](https://mcp-toolkit.nuxt.dev/apps/authoring#routing-apps-to-a-specific-handler). + +- [#250](https://github.com/nuxt-modules/mcp-toolkit/pull/250) [`1ad6f3d`](https://github.com/nuxt-modules/mcp-toolkit/commit/1ad6f3d8eebd3e74e688e688a49f12734130158b) Thanks [@HugoRCD](https://github.com/HugoRCD)! - Expose two Nitro runtime hooks for the MCP request lifecycle. Subscribe from a `server/plugins/*.ts` plugin to inject custom logic without owning a `defineMcpHandler` — listeners that throw are logged via consola and the request continues. + + ``` + defineMcpHandler middleware → mcp:config:resolved → createMcpServer → mcp:server:created → transport + ``` + + ### `mcp:config:resolved` + + Fires per request after dynamic `tools` / `resources` / `prompts` resolvers and `enabled(event)` guards have run, **before** the per-request `McpServer` is built. Mutate `ctx.config` in place to add, remove or transform definitions for this request only. + + ```ts [server/plugins/mcp-filter.ts] + export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook("mcp:config:resolved", ({ config, event }) => { + if (!event.context.user) { + config.tools = config.tools.filter((t) => !t.tags?.includes("admin")); + } + }); + }); + ``` + + ### `mcp:server:created` + + Fires per request after every tool / resource / prompt has been registered, **before** the server is connected to the transport. Receives the SDK `McpServer` instance — call `server.registerTool(...)` to add definitions late, or use `getSdkServer(server)` to reach the low-level `Server` and `setRequestHandler(...)` for custom JSON-RPC methods. + + ```ts [server/plugins/mcp-whoami.ts] + export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook("mcp:server:created", ({ server, event }) => { + server.registerTool( + "whoami", + { description: "Return the current user id" }, + async () => ({ + content: [ + { type: "text", text: String(event.context.userId ?? "anonymous") }, + ], + }) + ); + }); + }); + ``` + + ### Public API additions + + - `McpResolvedConfig` — type of the resolved per-request server config. + - `getSdkServer(server)` — reach the underlying SDK `Server` instance from an `McpServer`. + + Both are exported from `@nuxtjs/mcp-toolkit/server`. See [Hooks · Runtime hooks](https://mcp-toolkit.nuxt.dev/advanced/hooks#runtime-hooks). + ## 0.16.1 ### Patch Changes diff --git a/packages/nuxt-mcp-toolkit/package.json b/packages/nuxt-mcp-toolkit/package.json index 7d190e6f..778c24dd 100644 --- a/packages/nuxt-mcp-toolkit/package.json +++ b/packages/nuxt-mcp-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@nuxtjs/mcp-toolkit", - "version": "0.16.1", + "version": "0.17.0", "description": "Create MCP servers directly in your Nuxt application. Define tools, resources, and prompts with a simple and intuitive API.", "repository": { "type": "git",