Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions executable/persisted/tests/Test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand Down
110 changes: 110 additions & 0 deletions executable/tools-with-descriptions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"prescribed tools"
"persisted operations"

are the terms

Not "prescribed operations"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to qualify "operation" as "GraphQL operation" (with a link to the spec) as the first mention.


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an overview of what a "prescribed tool" is would be essential at this point.

## Overview

The sample implements a mock weather service API with a simple operations, Weather forecast for a city
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"simple operations"

Remove "simple", and there's only a single operation right?


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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Documented ... with descriptions" is redundant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a single operation though?

- 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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "(new to GraphQL September 2025)"


```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.

<img width="563" height="360" alt="Image" src="https://github.com/user-attachments/assets/7da0cd20-2469-45cd-8a17-0891a1a03dec" />

<img width="502" height="588" alt="Image" src="https://github.com/user-attachments/assets/cf499b7e-a3fe-433c-b837-bdde25441739" />
183 changes: 183 additions & 0 deletions executable/tools-with-descriptions/index.graphql
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions executable/tools-with-descriptions/operations.graphql
Original file line number Diff line number Diff line change
@@ -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
}
}
}
3 changes: 3 additions & 0 deletions executable/tools-with-descriptions/stepzen.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"endpoint": "api/miscellaneous"
}
Loading