Tools

Groups, files & dynamic registration

group and tags, directory layout, type safety, and enabled guards for tools.

Advanced Examples

Tool with API Integration

Here's an example showing a typical API-backed tool:

server/mcp/tools/get-weather.ts
import { z } from 'zod'
import { createError } from 'h3'
import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpTool({
  name: 'get-weather',
  description: 'Get current weather for a city',
  inputSchema: {
    city: z.string().describe('City name'),
  },
  handler: async ({ city }) => {
    const data = await $fetch(`/api/weather/${city}`)
    if (!data) throw createError({ statusCode: 404, message: `City "${city}" not found` })
    return data
  },
})

Groups and Tags

Organize your tools with group and tags for filtering and progressive discovery. Groups and tags are exposed in _meta and will map to SEP-1300 when adopted.

Explicit Group and Tags

Set group and tags directly on the definition:

server/mcp/tools/delete-user.ts
import { z } from 'zod'
import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpTool({
  group: 'admin',
  tags: ['destructive', 'user-management'],
  description: 'Delete a user account',
  inputSchema: {
    userId: z.string(),
  },
  handler: async ({ userId }) => {
    // ...
  },
})

Auto-Inferred Group from Directory

Place tools in subdirectories and the group is inferred automatically:

server/mcp/tools/
├── admin/
│   ├── delete-user.ts    → group: 'admin'
│   └── stats.ts          → group: 'admin'
├── content/
│   └── list-pages.ts     → group: 'content'
└── search.ts             → no group

An explicit group on the definition always takes precedence over the directory-inferred value.

How Clients See Groups and Tags

Groups and tags are included in the _meta field of tools/list responses:

{
  "name": "delete-user",
  "_meta": {
    "group": "admin",
    "tags": ["destructive", "user-management"]
  }
}

MCP clients can use these values to filter, sort, or group tools in their UI.

For resources and prompts, group and tags are stored on the definition objects but are not yet exposed in protocol responses (resources/list, prompts/list). This will be supported when SEP-1300 is adopted by the MCP SDK.

File Organization

Organize your tools in the server/mcp/tools/ directory. Both flat and nested layouts are supported:

server/
└── mcp/
    └── tools/
        ├── echo.ts
        ├── calculator.ts
        ├── admin/
        │   ├── delete-user.ts
        │   └── stats.ts
        └── content/
            └── list-pages.ts

Each file should export a default tool definition. Subdirectories automatically set the group for all tools within them.

Type Safety

The module provides full TypeScript type inference:

// Input types are inferred from inputSchema
handler: async ({ message }) => {
  // message is typed as string
}

// Output types are inferred from outputSchema
const result = {
  structuredContent: {
    bmi: 25.5,      // number
    category: '...', // string
  },
}

Conditional Registration

You can control whether a tool is visible to clients using the enabled guard:

server/mcp/tools/admin-tool.ts
import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpTool({
  name: 'admin-tool',
  description: 'Admin-only tool',
  enabled: event => event.context.user?.role === 'admin',
  handler: async () => {
    // ...
  },
})

When enabled returns false, the tool is hidden from tools/list and cannot be called.

See the Dynamic Definitions guide for detailed documentation on auth-based filtering.

Next Steps

Copyright © 2026