@_odbo_/calmag-mcp-server
Version:
Model Context Protocol server for Webklex CalMag nutrient calculator
144 lines (138 loc) ⢠6.03 kB
JavaScript
/**
* CalMag Get Fertilizers Tool
* Fetches available fertilizers from the CalMag API
*/
import { getCalmagAttribution } from '../utils/config.js';
import { fetchFertilizersFromApi } from '../utils/api.js';
export const calmagGetFertilizersTool = {
name: "calmag_get_fertilizers",
description: `Get all available fertilizers from the CalMag professional nutrient database.
š± **FERTILIZER DATABASE:**
- **15+ Professional Brands**: Canna, BioBizz, General Hydroponics, Advanced Nutrients, and more
- **Complete Product Lines**: Base nutrients, Cal-Mag products, specialized formulations
- **Detailed Compositions**: Exact nutrient profiles, densities, pH values for each product
š **WHEN TO USE:**
- **ALWAYS use this tool FIRST** before making any nutrient calculations
- To see all available fertilizer options for your plant nutrition system
- To compare different brands and products
- To get exact fertilizer names for use in calmag_calculate_nutrients
ā ļø **CRITICAL WORKFLOW REQUIREMENT:**
1. **MANDATORY FIRST STEP**: Call this tool to show fertilizer options
2. **PRESENT ALL OPTIONS**: Show the complete list to the user
3. **ASK USER TO CHOOSE**: Never automatically select fertilizers
4. **USE EXACT NAMES**: Copy the 'fullName' field exactly for calculations
š **STRICT USAGE POLICY:**
- NEVER automatically select 'popular' or 'optimal' fertilizers
- ALWAYS let the user choose their preferred product
- NEVER make assumptions about user preferences
- ALWAYS use exact fertilizer names from this database
š” **INTEGRATION:**
Use the exact 'fullName' from results (e.g., 'Canna - CalMag Agent') as the 'fertilizer' parameter in calmag_calculate_nutrients for plant nutrition calculations.`,
inputSchema: {
type: "object",
properties: {
brand: {
type: "string",
description: "Optional: Filter fertilizers by brand name (e.g., 'Canna', 'BioBizz')"
},
includeElements: {
type: "boolean",
description: "Include detailed element compositions in the response",
default: true
}
},
additionalProperties: false
}
};
export async function executeCalmagGetFertilizers(args) {
const { brand, includeElements = true } = args;
try {
// Fetch data from the new API endpoint
const apiResponse = await fetchFertilizersFromApi();
// Transform the API response to match our expected format
const transformedData = transformApiResponseToToolFormat(apiResponse, brand, includeElements);
return {
success: true,
data: {
...transformedData,
query: {
brand: brand || "all",
includeElements,
resultsCount: transformedData.totalCount
},
usage: {
description: "Use the fertilizer name (e.g., 'Canna - CalMag Agent') when making nutrient calculations",
example_usage: {
fertilizer_name: transformedData.fertilizers[0]?.fullName || "Canna - CalMag Agent",
curl_example: `curl -X POST -H "Content-Type: application/json" -d '{"fertilizer":"${transformedData.fertilizers[0]?.fullName || "Canna - CalMag Agent"}","elements":{"calcium":0,"magnesium":0},"ratio":3.5}' https://www.calmag.eu/`
}
},
attribution: getCalmagAttribution(),
data_sources: {
fertilizer_database: "CalMag API fertilizer database",
website: "https://www.calmag.eu/",
api_endpoint: "https://www.calmag.eu/?method=fertilizers",
total_brands: transformedData.brands.length,
total_products: transformedData.totalCount,
api_version: apiResponse.version
}
}
};
}
catch (error) {
console.error('Error fetching fertilizers:', error);
return {
success: false,
data: null,
error: `Failed to fetch fertilizers from API: ${error instanceof Error ? error.message : 'Unknown error'}`
};
}
}
/**
* Transforms the API response into the format expected by the tool
*/
function transformApiResponseToToolFormat(apiResponse, brandFilter, includeElements = true) {
// Extract unique brands from fertilizers
const brandMap = new Map();
const fertilizers = [];
// Process fertilizers from API response
Object.entries(apiResponse.fertilizers).forEach(([fullName, data]) => {
const brandName = data.brand;
const productName = data.name;
// Skip if brand filter is provided and doesn't match
if (brandFilter && !brandName.toLowerCase().includes(brandFilter.toLowerCase())) {
return;
}
// Add to fertilizers array
const fertilizerItem = {
key: productName.toLowerCase().replace(/\s+/g, '_'),
name: productName,
brandName,
fullName,
elements: includeElements ? data.elements : undefined,
density: data.density,
ph: data.ph
};
fertilizers.push(fertilizerItem);
// Process brand data
if (!brandMap.has(brandName)) {
brandMap.set(brandName, {
key: brandName.toLowerCase().replace(/\s+/g, '_'),
name: brandName,
website: data.link || { de: '', us: '' },
products: []
});
}
// Add product to brand
const brandData = brandMap.get(brandName);
brandData.products.push(fertilizerItem);
});
// Convert brands map to array
const brands = Array.from(brandMap.values());
return {
brands,
fertilizers,
totalCount: fertilizers.length,
version: apiResponse.version
};
}