tools.md•7.69 kB
# Tools
Tools are functions that AI agents can execute to perform actions or computations. In mcp-nest, tools are defined using the `@Tool()` decorator on service methods.
## Basic Tool
```typescript
import type { Request } from 'express';
import { Injectable } from '@nestjs/common';
import { Tool, Context } from '@rekog/mcp-nest';
import { z } from 'zod';
@Injectable()
export class GreetingTool {
  @Tool({
    name: 'greet-user',
    description: "Returns a personalized greeting in the user's preferred language",
    parameters: z.object({
      name: z.string().describe('The name of the person to greet'),
      language: z.string().describe('Language code (e.g., "en", "es", "fr")'),
    }),
  })
  async sayHello({ name, language }, context: Context, request: Request) {
    const greetings = {
      en: 'Hey',
      es: 'Qué tal',
      fr: 'Salut',
    };
    const greeting = greetings[language] || greetings.en;
    return `${greeting}, ${name}!`;
  }
}
```
### Understanding Tool Method Parameters
Every tool method receives exactly **three parameters** in this order:
1. **`args`** (first parameter): The validated input parameters as defined by the `parameters` Zod schema in the `@Tool` decorator.
2. **`context: Context`** (second parameter): The MCP execution context providing access to:
   - `reportProgress()` - Method to report progress updates to the client
   - `mcpServer` - Access to the underlying MCP server instance for advanced operations like elicitation
   - `mcpRequest` - The MCP request object
   - Logging capabilities and other contextual information
3. **`request: Request`** (third parameter): The original HTTP request object (Express/Fastify), providing access to headers, query parameters, authentication data, and other HTTP-specific information. This parameter is `undefined` when using STDIO transport.
### Tool Decorator Properties
The `@Tool()` decorator accepts a configuration object with the following properties:
- **`name`** (required): Unique identifier for the tool within your MCP server
- **`description`** (required): Human-readable description explaining what the tool does
- **`parameters`** (required): Zod schema defining the expected input parameters and their validation rules
- **`outputSchema`** (optional): Zod schema for validating and structuring the tool's return value
- **`annotations`** (optional): Metadata hints for AI agents, including:
  - `readOnlyHint`: Indicates if the tool only reads data without side effects
  - `destructiveHint`: Warns if the tool modifies or deletes data
  - `idempotentHint`: Indicates if repeated calls with same input produce same output
  - `openWorldHint`: Suggests if the tool's behavior is predictable or may vary
For detailed type definitions, refer to the `Context` interface and `ToolOptions` type in the `@rekog/mcp-nest` package.
## Tool with Progress Reporting
```typescript
@Tool({
  name: 'process-data',
  description: 'Processes data with progress updates',
  parameters: z.object({
    data: z.string(),
  }),
})
async processData({ data }, context: Context) {
  const totalSteps = 5;
  for (let i = 0; i < totalSteps; i++) {
    await new Promise(resolve => setTimeout(resolve, 100));
    // Report progress to the client
    await context.reportProgress({
      progress: (i + 1) * 20,
      total: 100,
    });
  }
  return `Processed: ${data}`;
}
```
## Tool with Output Schema
Tools can define structured output schemas for type safety:
```typescript
@Tool({
  name: 'greet-user-structured',
  description: 'Returns a structured greeting with metadata',
  parameters: z.object({
    name: z.string(),
    language: z.string(),
  }),
  outputSchema: z.object({
    greeting: z.string(),
    language: z.string(),
    languageName: z.string(),
  }),
})
async sayHelloStructured({ name, language }) {
  return {
    greeting: `Hey, ${name}!`,
    language,
    languageName: 'English',
  };
}
```
## Interactive Tool with Elicitation
Tools can request additional input from users:
```typescript
@Tool({
  name: 'greet-user-interactive',
  description: 'Interactive greeting with language selection',
  parameters: z.object({
    name: z.string(),
  }),
})
async sayHelloInteractive({ name }, context: Context) {
  const response = await context.mcpServer.server.elicitInput({
    message: 'Please select your preferred language',
    requestedSchema: {
      type: 'object',
      properties: {
        language: {
          type: 'string',
          enum: ['en', 'es', 'fr', 'de'],
          description: 'Your preferred language',
        },
      },
    },
  });
  const selectedLanguage = response.action === 'accept'
    ? response.content.language
    : 'en';
  return `Hello, ${name}! (in ${selectedLanguage})`;
}
```
## Testing Your Tools
### 1. Start the Server
Run the playground server:
```bash
npx ts-node-dev --respawn playground/servers/server-stateful.ts
```
### 2. List Available Tools
```bash
npx @modelcontextprotocol/inspector@0.16.2 --cli http://localhost:3030/mcp --transport http --method tools/list
```
Expected output:
```json
{
  "tools": [
    {
      "name": "greet-user",
      "description": "Returns a personalized greeting in the user's preferred language",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the person to greet"
          },
          "language": {
            "type": "string",
            "description": "Language code (e.g., \"en\", \"es\", \"fr\", \"de\")"
          }
        },
        "required": ["name", "language"]
      }
    }
  ]
}
```
### 3. Call a Tool
**Basic tool call:**
```bash
npx @modelcontextprotocol/inspector@0.16.2 --cli http://localhost:3030/mcp --transport http --method tools/call --tool-name greet-user --tool-arg name=Alice --tool-arg language=es
```
Expected output:
```json
{
  "content": [
    {
      "type": "text",
      "text": "\"Qué tal, Alice!\""
    }
  ]
}
```
**Interactive tool call:**
Interactive tool calls, use elicitation to get additional input from users. The **MCP Inspector CLI currently doesn't support elicitation**, but as soon as this [GitHub issue](https://github.com/modelcontextprotocol/inspector/issues/524) is resolved, you can test it with the command below. **In the meantime, you can test it using the MCP Inspector UI.**
```bash
npx @modelcontextprotocol/inspector@0.16.2 --cli http://localhost:3030/mcp --transport http --method tools/call --tool-name greet-user-interactive --tool-arg name=Bob
```
Elicited input:
```text
language: en
```
Expected output:
```json
{
  "content": [
    {
      "type": "text",
      "text": "Hey, Bob!"
    }
  ]
}
```
**Structured tool call (with output schema):**
```bash
npx @modelcontextprotocol/inspector@0.16.2 --cli http://localhost:3030/mcp --transport http --method tools/call --tool-name greet-user-structured --tool-arg name=Charlie --tool-arg language=fr
```
Expected output:
```json
{
  "content": [
    {
      "type": "text",
      "text": "{\n  \"greeting\": \"Salut, Charlie!\",\n  \"language\": \"fr\",\n  \"languageName\": \"French\"\n}"
    }
  ],
  "structuredContent": {
    "greeting": "Salut, Charlie!",
    "language": "fr",
    "languageName": "French"
  }
}
```
### 4. Interactive Testing
For interactive testing with progress updates, use the MCP Inspector UI:
```bash
npx @modelcontextprotocol/inspector@0.16.2
```
Connect to `http://localhost:3030/mcp` to test your tools interactively and see progress reporting in real-time.
## Example Location
See the complete example at: `playground/resources/greeting.tool.ts`