From 16020bf615ae1ca5d932c80b113b22b4546e2bde Mon Sep 17 00:00:00 2001 From: Ratnakar Asara Date: Tue, 4 Nov 2025 10:54:08 -0500 Subject: [PATCH 1/3] add snippet for prescribed operations and variables descriptions Signed-off-by: Ratnakar Asara --- executable/persisted/tests/Test.js | 3 - executable/tools-with-descriptions/README.md | 121 ++++++++++++ .../tools-with-descriptions/index.graphql | 183 ++++++++++++++++++ .../operations.graphql | 34 ++++ .../stepzen.config.json | 3 + .../tools-with-descriptions/tests/Test.js | 90 +++++++++ 6 files changed, 431 insertions(+), 3 deletions(-) create mode 100644 executable/tools-with-descriptions/README.md create mode 100644 executable/tools-with-descriptions/index.graphql create mode 100644 executable/tools-with-descriptions/operations.graphql create mode 100644 executable/tools-with-descriptions/stepzen.config.json create mode 100644 executable/tools-with-descriptions/tests/Test.js diff --git a/executable/persisted/tests/Test.js b/executable/persisted/tests/Test.js index d86da41..a31259a 100644 --- a/executable/persisted/tests/Test.js +++ b/executable/persisted/tests/Test.js @@ -9,9 +9,6 @@ const { testDescription = getTestDescription("snippets", __dirname); -const requestsFile = path.join(path.dirname(__dirname), "operations.graphql"); -const requests = fs.readFileSync(requestsFile, "utf8").toString(); - describe(testDescription, function () { const tests = [ { diff --git a/executable/tools-with-descriptions/README.md b/executable/tools-with-descriptions/README.md new file mode 100644 index 0000000..ed0580c --- /dev/null +++ b/executable/tools-with-descriptions/README.md @@ -0,0 +1,121 @@ +# Prescribed Tools with Descriptions + +This sample demonstrates how to use the `@tool` directive with prescribed operations that contains descriptions that can be used through to create MCP (Model Context Protocol) tools. + +## Overview + +The sample implements a mock weather service API with a simple operations, Weather forecast for a city + +The key feature demonstrated is how to create a prescribed tool with rich descriptions that help AI models understand how to use the tool effectively. + +## Schema Structure + +The schema consists of: + +1. A main schema file (`index.graphql`) that defines: + - The GraphQL types for weather data + - The `@tool` directive that creates a prescribed tool + - The `@sdl` directive that includes persisted operations + +2. An operations file (`operations.graphql`) that contains: + - Documented GraphQL operations with descriptions + - Variable descriptions that are used by the tool + +## How Prescribed Tools Work + +A prescribed tool is defined using the `@tool` directive with the `prescribed` argument pointing to a specific operation in a persisted document: + +```graphql +@tool( + name: "weather-lookup" + prescribed: "WeatherForecast" +) +``` + +The operation itself can include descriptions: + +```graphql +""" +Get detailed weather forecast for a specific city +This operation provides a multi-day weather forecast including temperature, conditions, and other meteorological data +""" +query WeatherForecast( + """The name of the city to get weather forecast for""" + $city: String!, + """Number of days to forecast (1-7), defaults to 3 days""" + $days: Int = 3 +) { + // operation details +} +``` + +## MCP Tool Description + +When deployed, this schema will expose a tool through the MCP endpoint with the following description: + +```json +{ + "name": "weather-lookup", + "description": "Weather forecast lookup tool for cities and locations", + "inputSchema": { + "type": "object", + "properties": { + "variables": { + "properties": { + "city": { + "description": "The name of the city to get weather forecast for", + "type": "string" + }, + "days": { + "description": "Number of days to forecast (1-7), defaults to 3 days", + "type": "integer", + "default": 3 + } + }, + "required": ["city"], + "type": "object" + } + }, + "required": ["variables"] + } +} +``` + +## Using the Tool + +An AI model can use this tool by: + +1. Understanding the tool's purpose from its description +2. Providing the required variables (city name and optionally number of days) +3. Receiving structured weather forecast data in response + +## Benefits of Prescribed Tools with Descriptions + +1. **Improved AI Understanding**: Detailed descriptions help AI models understand the purpose and parameters of the tool. +2. **Structured Input Validation**: The GraphQL schema ensures that inputs are properly validated. +3. **Documentation**: The descriptions serve as both documentation for developers and instructions for AI models. + +## Testing + +You can test this tool by: + +1. Deploying the schema to StepZen using the command `stepzen deploy` +2. Making requests to the MCP endpoint with tool calls +3. Verifying that the tool returns properly structured weather data. + + + +Sydney, defaults to 3 days + +curl \ + --header "Authorization: Apikey $(stepzen whoami --apikey)" \ + --header "Content-Type: application/json" \ + 'https://changjaeto.us-east-a.ibm.stepzen.net/api/miscellaneous/graphql?documentId=sha256:1bc7a3eefaa1f9dc0a3bbe2eba6cdcbf393aac3b1273a036b885ac1407eac11a&operationName=WeatherForecast&variables=%7B%22city%22%3A%20%22Sydney%22%7D' + + +Sydney, 1 day + +curl \ + --header "Authorization: Apikey $(stepzen whoami --apikey)" \ + --header "Content-Type: application/json" \ + 'https://changjaeto.us-east-a.ibm.stepzen.net/api/miscellaneous/graphql?documentId=sha256:1bc7a3eefaa1f9dc0a3bbe2eba6cdcbf393aac3b1273a036b885ac1407eac11a&operationName=WeatherForecast&variables=%7B%22city%22%3A%20%22Sydney%22%2C%20%22days%22%3A%201%7D' \ No newline at end of file diff --git a/executable/tools-with-descriptions/index.graphql b/executable/tools-with-descriptions/index.graphql new file mode 100644 index 0000000..9f1d577 --- /dev/null +++ b/executable/tools-with-descriptions/index.graphql @@ -0,0 +1,183 @@ +schema + @sdl( + files: [] + executables: [{ document: "operations.graphql", persist: true }] + ) + @tool(name: "weather-lookup", prescribed: "WeatherForecast") { + query: Query +} + +type Query { + # Get weather forecast for a specific city + weatherForecast(city: String!, days: Int = 3): WeatherForecast + @value( + script: { + src: """ + function weatherForecast() { + const cities = { + "new york": { + name: "New York", + country: "United States", + latitude: 40.7128, + longitude: -74.0060, + timezone: "America/New_York", + population: 8804190 + }, + "london": { + name: "London", + country: "United Kingdom", + latitude: 51.5074, + longitude: -0.1278, + timezone: "Europe/London", + population: 8982000 + }, + "tokyo": { + name: "Tokyo", + country: "Japan", + latitude: 35.6762, + longitude: 139.6503, + timezone: "Asia/Tokyo", + population: 13960000 + }, + "sydney": { + name: "Sydney", + country: "Australia", + latitude: -33.8688, + longitude: 151.2093, + timezone: "Australia/Sydney", + population: 5312000 + } + }; + + // Default to 3 days if not specified or out of range + const daysToForecast = days < 1 || days > 7 ? 3 : days; + + const normalizedCity = city.toLowerCase(); + const cityData = cities[normalizedCity] || { + name: city, + country: "Unknown", + latitude: 0, + longitude: 0, + timezone: "UTC", + population: null + }; + + // Fixed forecast patterns for each city + const forecastPatterns = { + "new york": [ + { conditions: "Partly Cloudy", high: 22, low: 15, precipitation: 20, humidity: 65, windSpeed: 12, windDirection: "NW" }, + { conditions: "Sunny", high: 24, low: 16, precipitation: 5, humidity: 55, windSpeed: 8, windDirection: "W" }, + { conditions: "Cloudy", high: 20, low: 14, precipitation: 30, humidity: 70, windSpeed: 15, windDirection: "NE" }, + { conditions: "Rain", high: 18, low: 12, precipitation: 75, humidity: 85, windSpeed: 18, windDirection: "E" }, + { conditions: "Partly Cloudy", high: 23, low: 16, precipitation: 15, humidity: 60, windSpeed: 10, windDirection: "SW" }, + { conditions: "Sunny", high: 25, low: 17, precipitation: 0, humidity: 50, windSpeed: 7, windDirection: "W" }, + { conditions: "Thunderstorm", high: 21, low: 15, precipitation: 90, humidity: 90, windSpeed: 25, windDirection: "S" } + ], + "london": [ + { conditions: "Cloudy", high: 16, low: 10, precipitation: 40, humidity: 75, windSpeed: 14, windDirection: "SW" }, + { conditions: "Rain", high: 15, low: 9, precipitation: 65, humidity: 80, windSpeed: 16, windDirection: "W" }, + { conditions: "Partly Cloudy", high: 17, low: 11, precipitation: 25, humidity: 70, windSpeed: 12, windDirection: "NW" }, + { conditions: "Cloudy", high: 16, low: 10, precipitation: 35, humidity: 75, windSpeed: 13, windDirection: "SW" }, + { conditions: "Rain", high: 14, low: 8, precipitation: 70, humidity: 85, windSpeed: 18, windDirection: "W" }, + { conditions: "Partly Cloudy", high: 18, low: 12, precipitation: 20, humidity: 65, windSpeed: 11, windDirection: "NW" }, + { conditions: "Sunny", high: 19, low: 13, precipitation: 10, humidity: 60, windSpeed: 9, windDirection: "N" } + ], + "tokyo": [ + { conditions: "Sunny", high: 26, low: 19, precipitation: 5, humidity: 60, windSpeed: 10, windDirection: "E" }, + { conditions: "Partly Cloudy", high: 25, low: 18, precipitation: 15, humidity: 65, windSpeed: 12, windDirection: "SE" }, + { conditions: "Cloudy", high: 23, low: 17, precipitation: 30, humidity: 70, windSpeed: 14, windDirection: "S" }, + { conditions: "Rain", high: 22, low: 16, precipitation: 60, humidity: 80, windSpeed: 16, windDirection: "SW" }, + { conditions: "Partly Cloudy", high: 24, low: 18, precipitation: 20, humidity: 65, windSpeed: 11, windDirection: "E" }, + { conditions: "Sunny", high: 27, low: 20, precipitation: 5, humidity: 55, windSpeed: 9, windDirection: "NE" }, + { conditions: "Cloudy", high: 24, low: 18, precipitation: 25, humidity: 68, windSpeed: 13, windDirection: "SE" } + ], + "sydney": [ + { conditions: "Sunny", high: 28, low: 20, precipitation: 10, humidity: 60, windSpeed: 15, windDirection: "NE" }, + { conditions: "Partly Cloudy", high: 27, low: 19, precipitation: 15, humidity: 65, windSpeed: 14, windDirection: "E" }, + { conditions: "Sunny", high: 29, low: 21, precipitation: 5, humidity: 55, windSpeed: 13, windDirection: "NE" }, + { conditions: "Partly Cloudy", high: 26, low: 19, precipitation: 20, humidity: 70, windSpeed: 16, windDirection: "SE" }, + { conditions: "Cloudy", high: 24, low: 18, precipitation: 35, humidity: 75, windSpeed: 18, windDirection: "S" }, + { conditions: "Rain", high: 22, low: 17, precipitation: 70, humidity: 85, windSpeed: 20, windDirection: "SW" }, + { conditions: "Partly Cloudy", high: 25, low: 18, precipitation: 25, humidity: 70, windDirection: "W", windSpeed: 17 } + ] + }; + + // Get pattern for city or use default + const pattern = forecastPatterns[normalizedCity] || forecastPatterns["new york"]; + + // Generate forecast for the requested number of days + const forecast = []; + const today = new Date(); + + for (let i = 0; i < daysToForecast; i++) { + const forecastDate = new Date(); + forecastDate.setDate(today.getDate() + i); + + const dayPattern = pattern[i % pattern.length]; + + forecast.push({ + date: forecastDate.toISOString().split('T')[0], + sunrise: "06:25 AM", + sunset: "06:35 PM", + high: { + celsius: dayPattern.high, + fahrenheit: Math.round(dayPattern.high * 9 / 5 + 32) + }, + low: { + celsius: dayPattern.low, + fahrenheit: Math.round(dayPattern.low * 9 / 5 + 32) + }, + conditions: dayPattern.conditions, + precipitation: dayPattern.precipitation, + humidity: dayPattern.humidity, + windSpeed: dayPattern.windSpeed, + windDirection: dayPattern.windDirection + }); + } + + return { + city: cityData, + forecast: forecast, + }; + } + weatherForecast() + """ + } + ) +} + +type WeatherForecast { + city: City! + forecast: [DailyForecast!]! + lastUpdated: DateTime +} + +type City { + name: String! + country: String! + latitude: Float! + longitude: Float! + timezone: String! + population: Int +} + +type DailyForecast { + date: Date! + sunrise: String! + sunset: String! + high: Temperature! + low: Temperature! + conditions: String! + precipitation: Float! + humidity: Int! + windSpeed: Float! + windDirection: String! +} + +type Temperature { + celsius: Float! + fahrenheit: Float! +} + +scalar Date +scalar DateTime diff --git a/executable/tools-with-descriptions/operations.graphql b/executable/tools-with-descriptions/operations.graphql new file mode 100644 index 0000000..c100579 --- /dev/null +++ b/executable/tools-with-descriptions/operations.graphql @@ -0,0 +1,34 @@ +""" +Get detailed weather forecast for a specific city +This operation provides a multi-day weather forecast including temperature, conditions, and other meteorological data +""" +query WeatherForecast( + """The name of the city to get weather forecast for""" + $city: String!, + """Number of days to forecast (1-7), defaults to 3 days""" + $days: Int = 3 +) { + weatherForecast(city: $city, days: $days) { + city { + name + country + timezone + } + forecast { + date + high { + celsius + fahrenheit + } + low { + celsius + fahrenheit + } + conditions + precipitation + humidity + windSpeed + windDirection + } + } +} diff --git a/executable/tools-with-descriptions/stepzen.config.json b/executable/tools-with-descriptions/stepzen.config.json new file mode 100644 index 0000000..af1c0ea --- /dev/null +++ b/executable/tools-with-descriptions/stepzen.config.json @@ -0,0 +1,3 @@ +{ + "endpoint": "api/miscellaneous" +} diff --git a/executable/tools-with-descriptions/tests/Test.js b/executable/tools-with-descriptions/tests/Test.js new file mode 100644 index 0000000..d55e189 --- /dev/null +++ b/executable/tools-with-descriptions/tests/Test.js @@ -0,0 +1,90 @@ +const fs = require("fs"); +const path = require("node:path"); +const { + deployAndRun, + stepzen, + getTestDescription, +} = require("../../../tests/gqltest.js"); + +testDescription = getTestDescription("snippets", __dirname); + +describe(testDescription, function () { + const forecastDates = Array.from({ length: 3 }, (_, i) => { + const d = new Date(); + d.setDate(d.getDate() + i); + return d.toISOString().split('T')[0]; + }); + + + const tests = [ + { + label: "WeatherForecast", + documentId: + "sha256:68026b11d1c611f4285a1dd21837f8243e12e6f5e96719a361d6f864525a72da", + operationName: "WeatherForecast", + variables: { + city: "Sydney", + }, + expected: { + weatherForecast: { + city: { + name: "Sydney", + country: "Australia", + timezone: "Australia/Sydney" + }, + forecast: [ + { + date: forecastDates[0], + high: { + celsius: 28, + fahrenheit: 82 + }, + low: { + celsius: 20, + fahrenheit: 68 + }, + conditions: "Sunny", + precipitation: 10, + humidity: 60, + windSpeed: 15, + windDirection: "NE" + }, + { + date: forecastDates[1], + high: { + celsius: 27, + fahrenheit: 81 + }, + low: { + celsius: 19, + fahrenheit: 66 + }, + conditions: "Partly Cloudy", + precipitation: 15, + humidity: 65, + windSpeed: 14, + windDirection: "E" + }, + { + date: forecastDates[2], + high: { + celsius: 29, + fahrenheit: 84 + }, + low: { + celsius: 21, + fahrenheit: 70 + }, + conditions: "Sunny", + precipitation: 5, + humidity: 55, + windSpeed: 13, + windDirection: "NE" + } + ], + }, + }, + }, + ]; + return deployAndRun(__dirname, tests, stepzen.admin); +}); From c90654710d92ceca6718cf7ce61f78009935f7f4 Mon Sep 17 00:00:00 2001 From: Ratnakar Asara Date: Tue, 4 Nov 2025 14:23:03 -0500 Subject: [PATCH 2/3] replace graphql api testing with mcp tool testing Signed-off-by: Ratnakar Asara --- executable/tools-with-descriptions/README.md | 27 ++++++-------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/executable/tools-with-descriptions/README.md b/executable/tools-with-descriptions/README.md index ed0580c..a15a86e 100644 --- a/executable/tools-with-descriptions/README.md +++ b/executable/tools-with-descriptions/README.md @@ -95,27 +95,16 @@ An AI model can use this tool by: 2. **Structured Input Validation**: The GraphQL schema ensures that inputs are properly validated. 3. **Documentation**: The descriptions serve as both documentation for developers and instructions for AI models. -## Testing +### Testing as an MCP Tool -You can test this tool by: +To test this as an MCP tool with AI models: -1. Deploying the schema to StepZen using the command `stepzen deploy` -2. Making requests to the MCP endpoint with tool calls -3. Verifying that the tool returns properly structured weather data. +1. Deploy the schema to StepZen using the command `stepzen deploy` +2. [Connect Claude Desktop](https://modelcontextprotocol.io/docs/develop/connect-local-servers) to your StepZen MCP endpoint +3. The tool will appear as `weather-lookup` and can be called by the AI model +**Example**: Interaction between MCP and the Claude UI. +Image -Sydney, defaults to 3 days - -curl \ - --header "Authorization: Apikey $(stepzen whoami --apikey)" \ - --header "Content-Type: application/json" \ - 'https://changjaeto.us-east-a.ibm.stepzen.net/api/miscellaneous/graphql?documentId=sha256:1bc7a3eefaa1f9dc0a3bbe2eba6cdcbf393aac3b1273a036b885ac1407eac11a&operationName=WeatherForecast&variables=%7B%22city%22%3A%20%22Sydney%22%7D' - - -Sydney, 1 day - -curl \ - --header "Authorization: Apikey $(stepzen whoami --apikey)" \ - --header "Content-Type: application/json" \ - 'https://changjaeto.us-east-a.ibm.stepzen.net/api/miscellaneous/graphql?documentId=sha256:1bc7a3eefaa1f9dc0a3bbe2eba6cdcbf393aac3b1273a036b885ac1407eac11a&operationName=WeatherForecast&variables=%7B%22city%22%3A%20%22Sydney%22%2C%20%22days%22%3A%201%7D' \ No newline at end of file +Image \ No newline at end of file From 2245fd4ee0b03ea639594c55726925f4f023b49d Mon Sep 17 00:00:00 2001 From: Ratnakar Asara Date: Wed, 5 Nov 2025 15:13:02 -0500 Subject: [PATCH 3/3] updates as per suggested comments Signed-off-by: Ratnakar Asara --- executable/prescribed/README.md | 141 ++++++++++++++++++ .../index.graphql | 8 +- .../operations.graphql | 5 +- .../stepzen.config.json | 0 executable/prescribed/tests/Test.js | 48 ++++++ executable/tools-with-descriptions/README.md | 110 -------------- .../tools-with-descriptions/tests/Test.js | 90 ----------- 7 files changed, 196 insertions(+), 206 deletions(-) create mode 100644 executable/prescribed/README.md rename executable/{tools-with-descriptions => prescribed}/index.graphql (95%) rename executable/{tools-with-descriptions => prescribed}/operations.graphql (87%) rename executable/{tools-with-descriptions => prescribed}/stepzen.config.json (100%) create mode 100644 executable/prescribed/tests/Test.js delete mode 100644 executable/tools-with-descriptions/README.md delete mode 100644 executable/tools-with-descriptions/tests/Test.js diff --git a/executable/prescribed/README.md b/executable/prescribed/README.md new file mode 100644 index 0000000..040cfe1 --- /dev/null +++ b/executable/prescribed/README.md @@ -0,0 +1,141 @@ +# Prescribed Tools + +A **prescribed tool** is a tool that maps to a specific [GraphQL operation](https://spec.graphql.org/September2025/#sec-Language.Operations) in a [persisted document](https://spec.graphql.org/September2025/#sec-Persisted-Documents). The `@tool(prescribed:)` argument links the tool definition to an operation name in a persisted document. This approach provides a structured way to expose specific GraphQL operations as tools that can be called by AI models. + +This sample demonstrates how to use the `@tool` directive to create prescribed tools for MCP (Model Context Protocol). + +## Overview + +The sample implements a mock weather service API with a single operation: weather forecast for a city. + +The key feature demonstrated is how to create a prescribed tool that maps to a persisted GraphQL operation, allowing AI models to execute specific, well-defined queries. + +## Schema Structure + +The schema consists of: + +1. A main schema file (`index.graphql`) that defines: + - The GraphQL types for weather data + - The `@tool` directive that creates a prescribed tool + - The `@sdl` directive that includes the persisted operation + +2. An operations file (`operations.graphql`) that contains: + - A GraphQL operation that will be exposed as a tool + - Descriptions for the operation and its variables (recommended best practice) + +## How Prescribed Tools Work + +A prescribed tool is defined using the `@tool` directive with the `prescribed` argument pointing to a specific operation in a persisted document: + +```graphql +schema + # Load the persisted operations document that contains the WeatherForecast operation + @sdl( + files: [] + executables: [{ document: "operations.graphql", persist: true }] + ) + # Define a prescribed tool that maps to the WeatherForecast operation in the persisted document + @tool(name: "weather-lookup", prescribed: "WeatherForecast") { + query: Query +} +``` + +The operation in the persisted document should include descriptions ([new to GraphQL September 2025](https://spec.graphql.org/September2025/#Description)) to help AI models understand how to use the tool: + +```graphql +""" +Get detailed weather forecast for a specific city +This operation provides a multi-day weather forecast including temperature, conditions, and other meteorological data +""" +query WeatherForecast( + """The name of the city to get weather forecast for""" + $city: String!, + """Number of days to forecast (1-7), defaults to 3 days""" + $days: Int = 3 +) { + weatherForecast(city: $city, days: $days) { + city { + name + country + timezone + } + forecast { + date + conditions + high { + celsius + fahrenheit + } + low { + celsius + fahrenheit + } + precipitation + humidity + windSpeed + windDirection + } + } +} +``` + +## MCP Tool Description + +When deployed, this schema will expose a tool through the MCP endpoint. The tool's description and parameter information are derived from the GraphQL operation's descriptions: + +```json +{ + "name": "weather-lookup", + "description": "Get detailed weather forecast for a specific city. This operation provides a multi-day weather forecast including temperature, conditions, and other meteorological data", + "inputSchema": { + "type": "object", + "properties": { + "variables": { + "properties": { + "city": { + "description": "The name of the city to get weather forecast for", + "type": "string" + }, + "days": { + "description": "Number of days to forecast (1-7), defaults to 3 days", + "type": "integer", + "default": 3 + } + }, + "required": ["city"], + "type": "object" + } + }, + "required": ["variables"] + } +} +``` + +## Using the Tool + +An AI model can use this tool by: + +1. Understanding the tool's purpose from the operation's description +2. Providing the required variables (city name and optionally number of days) +3. Receiving structured weather forecast data in response + +## Benefits of Prescribed Tools + +1. **Controlled Access**: Only specific, predefined operations are exposed as tools, providing fine-grained control over what AI models can execute. +2. **Type Safety**: The GraphQL schema ensures that inputs are properly validated. +3. **Clear Documentation**: Operation descriptions serve as both documentation for developers and instructions for AI models. +4. **Versioning**: Operations can be versioned and updated independently of the tool definition. + +## Testing as an MCP Tool + +To test this as an MCP tool with AI models: + +1. Deploy the schema to StepZen using the command `stepzen deploy` +2. [Connect Claude Desktop](https://modelcontextprotocol.io/docs/develop/connect-local-servers) to your StepZen MCP endpoint +3. The tool will appear as `weather-lookup` and can be called by the AI model + +**Example**: Interaction between MCP and the Claude UI. + +Image + +Image \ No newline at end of file diff --git a/executable/tools-with-descriptions/index.graphql b/executable/prescribed/index.graphql similarity index 95% rename from executable/tools-with-descriptions/index.graphql rename to executable/prescribed/index.graphql index 9f1d577..726b8f1 100644 --- a/executable/tools-with-descriptions/index.graphql +++ b/executable/prescribed/index.graphql @@ -1,15 +1,17 @@ schema + # Load the persisted operations document that contains the WeatherForecast operation @sdl( files: [] executables: [{ document: "operations.graphql", persist: true }] ) + # Define a prescribed tool that maps to the WeatherForecast operation in the persisted document @tool(name: "weather-lookup", prescribed: "WeatherForecast") { query: Query } type Query { # Get weather forecast for a specific city - weatherForecast(city: String!, days: Int = 3): WeatherForecast + weatherForecast(city: String!, days: Int = 1): WeatherForecast @value( script: { src: """ @@ -49,8 +51,8 @@ type Query { } }; - // Default to 3 days if not specified or out of range - const daysToForecast = days < 1 || days > 7 ? 3 : days; + // Default to 1 day if not specified or out of range + const daysToForecast = days < 1 || days > 7 ? 1 : days; const normalizedCity = city.toLowerCase(); const cityData = cities[normalizedCity] || { diff --git a/executable/tools-with-descriptions/operations.graphql b/executable/prescribed/operations.graphql similarity index 87% rename from executable/tools-with-descriptions/operations.graphql rename to executable/prescribed/operations.graphql index c100579..a220226 100644 --- a/executable/tools-with-descriptions/operations.graphql +++ b/executable/prescribed/operations.graphql @@ -5,8 +5,8 @@ This operation provides a multi-day weather forecast including temperature, cond query WeatherForecast( """The name of the city to get weather forecast for""" $city: String!, - """Number of days to forecast (1-7), defaults to 3 days""" - $days: Int = 3 + """Number of days to forecast (1-7), defaults to current day""" + $days: Int = 1 ) { weatherForecast(city: $city, days: $days) { city { @@ -15,7 +15,6 @@ query WeatherForecast( timezone } forecast { - date high { celsius fahrenheit diff --git a/executable/tools-with-descriptions/stepzen.config.json b/executable/prescribed/stepzen.config.json similarity index 100% rename from executable/tools-with-descriptions/stepzen.config.json rename to executable/prescribed/stepzen.config.json diff --git a/executable/prescribed/tests/Test.js b/executable/prescribed/tests/Test.js new file mode 100644 index 0000000..2b8819a --- /dev/null +++ b/executable/prescribed/tests/Test.js @@ -0,0 +1,48 @@ +const { + deployAndRun, + stepzen, + getTestDescription, +} = require("../../../tests/gqltest.js"); + +testDescription = getTestDescription("snippets", __dirname); + +describe(testDescription, function () { + const tests = [ + { + label: "WeatherForecast", + documentId: + "sha256:eb01da571734ea3074e4aa494398f947ff76c3b339ad0c15d5c9127b5f53ac4d", + operationName: "WeatherForecast", + variables: { + city: "Sydney", + }, + expected: { + weatherForecast: { + city: { + name: "Sydney", + country: "Australia", + timezone: "Australia/Sydney" + }, + forecast: [ + { + high: { + celsius: 28, + fahrenheit: 82 + }, + low: { + celsius: 20, + fahrenheit: 68 + }, + conditions: "Sunny", + precipitation: 10, + humidity: 60, + windSpeed: 15, + windDirection: "NE" + }, + ], + }, + }, + }, + ]; + return deployAndRun(__dirname, tests, stepzen.admin); +}); diff --git a/executable/tools-with-descriptions/README.md b/executable/tools-with-descriptions/README.md deleted file mode 100644 index a15a86e..0000000 --- a/executable/tools-with-descriptions/README.md +++ /dev/null @@ -1,110 +0,0 @@ -# Prescribed Tools with Descriptions - -This sample demonstrates how to use the `@tool` directive with prescribed operations that contains descriptions that can be used through to create MCP (Model Context Protocol) tools. - -## Overview - -The sample implements a mock weather service API with a simple operations, Weather forecast for a city - -The key feature demonstrated is how to create a prescribed tool with rich descriptions that help AI models understand how to use the tool effectively. - -## Schema Structure - -The schema consists of: - -1. A main schema file (`index.graphql`) that defines: - - The GraphQL types for weather data - - The `@tool` directive that creates a prescribed tool - - The `@sdl` directive that includes persisted operations - -2. An operations file (`operations.graphql`) that contains: - - Documented GraphQL operations with descriptions - - Variable descriptions that are used by the tool - -## How Prescribed Tools Work - -A prescribed tool is defined using the `@tool` directive with the `prescribed` argument pointing to a specific operation in a persisted document: - -```graphql -@tool( - name: "weather-lookup" - prescribed: "WeatherForecast" -) -``` - -The operation itself can include descriptions: - -```graphql -""" -Get detailed weather forecast for a specific city -This operation provides a multi-day weather forecast including temperature, conditions, and other meteorological data -""" -query WeatherForecast( - """The name of the city to get weather forecast for""" - $city: String!, - """Number of days to forecast (1-7), defaults to 3 days""" - $days: Int = 3 -) { - // operation details -} -``` - -## MCP Tool Description - -When deployed, this schema will expose a tool through the MCP endpoint with the following description: - -```json -{ - "name": "weather-lookup", - "description": "Weather forecast lookup tool for cities and locations", - "inputSchema": { - "type": "object", - "properties": { - "variables": { - "properties": { - "city": { - "description": "The name of the city to get weather forecast for", - "type": "string" - }, - "days": { - "description": "Number of days to forecast (1-7), defaults to 3 days", - "type": "integer", - "default": 3 - } - }, - "required": ["city"], - "type": "object" - } - }, - "required": ["variables"] - } -} -``` - -## Using the Tool - -An AI model can use this tool by: - -1. Understanding the tool's purpose from its description -2. Providing the required variables (city name and optionally number of days) -3. Receiving structured weather forecast data in response - -## Benefits of Prescribed Tools with Descriptions - -1. **Improved AI Understanding**: Detailed descriptions help AI models understand the purpose and parameters of the tool. -2. **Structured Input Validation**: The GraphQL schema ensures that inputs are properly validated. -3. **Documentation**: The descriptions serve as both documentation for developers and instructions for AI models. - -### Testing as an MCP Tool - -To test this as an MCP tool with AI models: - -1. Deploy the schema to StepZen using the command `stepzen deploy` -2. [Connect Claude Desktop](https://modelcontextprotocol.io/docs/develop/connect-local-servers) to your StepZen MCP endpoint -3. The tool will appear as `weather-lookup` and can be called by the AI model - -**Example**: Interaction between MCP and the Claude UI. - -Image - -Image \ No newline at end of file diff --git a/executable/tools-with-descriptions/tests/Test.js b/executable/tools-with-descriptions/tests/Test.js deleted file mode 100644 index d55e189..0000000 --- a/executable/tools-with-descriptions/tests/Test.js +++ /dev/null @@ -1,90 +0,0 @@ -const fs = require("fs"); -const path = require("node:path"); -const { - deployAndRun, - stepzen, - getTestDescription, -} = require("../../../tests/gqltest.js"); - -testDescription = getTestDescription("snippets", __dirname); - -describe(testDescription, function () { - const forecastDates = Array.from({ length: 3 }, (_, i) => { - const d = new Date(); - d.setDate(d.getDate() + i); - return d.toISOString().split('T')[0]; - }); - - - const tests = [ - { - label: "WeatherForecast", - documentId: - "sha256:68026b11d1c611f4285a1dd21837f8243e12e6f5e96719a361d6f864525a72da", - operationName: "WeatherForecast", - variables: { - city: "Sydney", - }, - expected: { - weatherForecast: { - city: { - name: "Sydney", - country: "Australia", - timezone: "Australia/Sydney" - }, - forecast: [ - { - date: forecastDates[0], - high: { - celsius: 28, - fahrenheit: 82 - }, - low: { - celsius: 20, - fahrenheit: 68 - }, - conditions: "Sunny", - precipitation: 10, - humidity: 60, - windSpeed: 15, - windDirection: "NE" - }, - { - date: forecastDates[1], - high: { - celsius: 27, - fahrenheit: 81 - }, - low: { - celsius: 19, - fahrenheit: 66 - }, - conditions: "Partly Cloudy", - precipitation: 15, - humidity: 65, - windSpeed: 14, - windDirection: "E" - }, - { - date: forecastDates[2], - high: { - celsius: 29, - fahrenheit: 84 - }, - low: { - celsius: 21, - fahrenheit: 70 - }, - conditions: "Sunny", - precipitation: 5, - humidity: 55, - windSpeed: 13, - windDirection: "NE" - } - ], - }, - }, - }, - ]; - return deployAndRun(__dirname, tests, stepzen.admin); -});