/**
* LiteFarm MCP Server - Crop Management Tools
*/
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import type { LiteFarmClient } from "../litefarm-client.js";
import { ResponseFormat, type LiteFarmCrop } from "../types.js";
import { createToolResponse, createErrorResponse, formatListResponse } from "../tool-utils.js";
export function registerCropTools(server: McpServer, client: LiteFarmClient): void {
// List crops
server.registerTool(
"litefarm_list_crops",
{
title: "List All Crops",
description: `List all available crops in the system or for a specific farm.
Args:
- farm_id (string): Optional farm ID to filter crops
- response_format ('markdown' | 'json'): Output format (default: 'markdown')
Returns: Array of crop objects with botanical and nutritional information`,
inputSchema: z.object({
farm_id: z.string().optional().describe("Optional farm ID filter"),
response_format: z.nativeEnum(ResponseFormat).default(ResponseFormat.MARKDOWN)
}).strict(),
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
},
async (params) => {
try {
const crops = await client.getCrops(params.farm_id ? { farm_id: params.farm_id } : undefined);
if (!crops || crops.length === 0) {
return createToolResponse("No crops found.");
}
const formatter = (crop: LiteFarmCrop) =>
`**${crop.crop_common_name}** (${crop.crop_genus} ${crop.crop_specie})\n- ID: ${crop.crop_id}\n- Group: ${crop.crop_group || "N/A"}`;
const response = formatListResponse(crops, formatter, params.response_format);
return createToolResponse(response.text, response.structuredContent);
} catch (error) {
return createErrorResponse(error);
}
}
);
// Get crop details
server.registerTool(
"litefarm_get_crop",
{
title: "Get Crop Details",
description: `Get detailed information about a specific crop including nutritional data.
Args:
- crop_id (string): Crop ID
- response_format ('markdown' | 'json'): Output format (default: 'markdown')
Returns: Crop object with full botanical and nutritional information`,
inputSchema: z.object({
crop_id: z.string().describe("Crop ID"),
response_format: z.nativeEnum(ResponseFormat).default(ResponseFormat.MARKDOWN)
}).strict(),
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
},
async (params) => {
try {
const crop = await client.getCrop(params.crop_id);
if (params.response_format === ResponseFormat.JSON) {
return createToolResponse(JSON.stringify(crop, null, 2), crop);
}
const markdown = `# ${crop.crop_common_name}
**Scientific Name:** ${crop.crop_genus} ${crop.crop_specie}
**Group:** ${crop.crop_group || "N/A"}
**Subgroup:** ${crop.crop_subgroup || "N/A"}
## Growing Information
- Max Rooting Depth: ${crop.max_rooting_depth || "N/A"} cm
- Max Height: ${crop.max_height || "N/A"} cm
## Nutritional Information (per 100g)
- Protein: ${crop.protein || "N/A"}g
- Energy: ${crop.energy || "N/A"} kcal
- Vitamin C: ${crop.vitc || "N/A"}mg`;
return createToolResponse(markdown, crop);
} catch (error) {
return createErrorResponse(error);
}
}
);
}