Skip to content

Commit 5d74ca9

Browse files
yasmewadadwsingh
authored andcommitted
Add @prompts trait to provide contextual guidance for LLMs when using Smithy services. Includes prompt templates, parameter descriptions, and usage conditions for services, resources, and operations.
1 parent a10e895 commit 5d74ca9

File tree

12 files changed

+409
-0
lines changed

12 files changed

+409
-0
lines changed

examples/mcp-traits-example/README.md

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# MCP Traits Example
2+
3+
This example demonstrates how to use the `@prompts` trait from the `mcp-traits` module to provide LLM guidance for Smithy services. The `@prompts` trait allows you to annotate services, resources, and operations with prompt templates that help LLMs understand when and how to use your API.
4+
5+
## Overview
6+
7+
The `@prompts` trait enables you to:
8+
9+
- **Provide contextual guidance**: Help LLMs understand when to use specific operations
10+
- **Include parameter descriptions**: Guide LLMs on how to populate operation inputs
11+
- **Define usage conditions**: Specify when certain operations should be preferred
12+
- **Create comprehensive templates**: Provide detailed instructions and examples
13+
14+
## Example Implementation
15+
16+
This example implements a simple `UserService` that demonstrates the key features of the `@prompts` trait:
17+
18+
### Service-Level Prompts
19+
20+
```smithy
21+
@prompts({
22+
search_users: {
23+
description: "Search for users in the system by various criteria",
24+
template: "Search for users where {{searchCriteria}}. Use pagination with limit={{limit}} if many results expected.",
25+
arguments: SearchUsersInput,
26+
preferWhen: "User wants to find specific users or browse user lists"
27+
}
28+
})
29+
service UserService {
30+
operations: [
31+
SearchUsers
32+
]
33+
}
34+
```
35+
36+
### Key Features
37+
38+
1. **Service-Level Guidance**: The service includes a prompt that explains how to search for users
39+
2. **Parameter Templates**: Uses `{{searchCriteria}}` and `{{limit}}` placeholders that reference the input structure
40+
3. **ArgumentShape Integration**: References `SearchUsersInput` to provide parameter context
41+
4. **Conditional Usage**: Uses `preferWhen` to specify when this operation should be preferred
42+
43+
### Complete Model Structure
44+
45+
```smithy
46+
namespace com.example
47+
48+
use amazon.smithy.llm#prompts
49+
50+
@prompts({
51+
search_users: {
52+
description: "Search for users in the system by various criteria",
53+
template: "Search for users where {{searchCriteria}}. Use pagination with limit={{limit}} if many results expected.",
54+
arguments: SearchUsersInput,
55+
preferWhen: "User wants to find specific users or browse user lists"
56+
}
57+
})
58+
service UserService {
59+
operations: [
60+
SearchUsers
61+
]
62+
}
63+
64+
operation SearchUsers {
65+
input: SearchUsersInput
66+
output: SearchUsersOutput
67+
}
68+
69+
structure SearchUsersInput {
70+
searchCriteria: String
71+
limit: Integer
72+
}
73+
74+
structure SearchUsersOutput {
75+
id: String
76+
}
77+
```
78+
79+
## Prompt Template Structure
80+
81+
Each prompt template in the `@prompts` trait map has the following structure:
82+
83+
```smithy
84+
"prompt_name": {
85+
description: String // Required: Brief description of the prompt's purpose
86+
template: String // Required: The actual prompt template with placeholders
87+
arguments: ArgumentShape // Optional: Reference to structure defining parameters
88+
preferWhen: String // Optional: Condition describing when to use this prompt
89+
}
90+
```
91+
92+
### Template Placeholders
93+
94+
Use `{{parameterName}}` syntax in templates to reference parameters defined in the `arguments` structure:
95+
96+
```smithy
97+
template: "Search for users where {{searchCriteria}}. Use pagination with limit={{limit}} if many results expected."
98+
arguments: SearchUsersInput
99+
```
100+
101+
The placeholders `{{searchCriteria}}` and `{{limit}}` correspond to the fields in the `SearchUsersInput` structure.
102+
103+
### Conditional Usage
104+
105+
The `preferWhen` field helps LLMs decide when to use specific operations:
106+
107+
```smithy
108+
preferWhen: "User wants to find specific users or browse user lists"
109+
```
110+
111+
## Building and Running
112+
113+
### Prerequisites
114+
115+
- Java 17 or later
116+
- Gradle 7.0 or later
117+
118+
### Build the Example
119+
120+
```bash
121+
# From the example directory
122+
gradle build
123+
```
124+
125+
### Validate the Model
126+
127+
```bash
128+
# Run Smithy build to validate the model and traits
129+
gradle smithyBuild
130+
```
131+
132+
### Expected Output
133+
134+
When you run `gradle smithyBuild`, you should see:
135+
136+
1. **Successful build** - indicating all traits are applied correctly
137+
2. **No validation errors** - confirming the model structure is valid
138+
3. **Generated build artifacts** - in the `build/smithyprojections/` directory
139+
140+
## Usage Patterns
141+
142+
### 1. Service-Level Guidance
143+
144+
Provide high-level guidance about the entire service:
145+
146+
```smithy
147+
@prompts({
148+
service_overview: {
149+
description: "Overview of the user management service"
150+
template: "This service manages user accounts and provides search capabilities."
151+
preferWhen: "User needs general information about user management"
152+
}
153+
})
154+
service UserService {
155+
// ...
156+
}
157+
```
158+
159+
### 2. Parameter-Rich Templates
160+
161+
Create detailed templates that guide parameter usage:
162+
163+
```smithy
164+
template: "Search for users where {{searchCriteria}}. Use pagination with limit={{limit}} if many results expected."
165+
```
166+
167+
### 3. Contextual Guidance
168+
169+
Use `preferWhen` to provide context about when operations should be used:
170+
171+
```smithy
172+
preferWhen: "User wants to find specific users or browse user lists"
173+
```
174+
175+
## Best Practices
176+
177+
### 1. Clear Descriptions
178+
179+
- Use concise but descriptive prompt names
180+
- Write clear `description` fields that explain the prompt's purpose
181+
- Make templates self-contained and easy to understand
182+
183+
### 2. Comprehensive Templates
184+
185+
- Include all relevant parameters in templates using `{{parameterName}}` syntax
186+
- Provide examples and usage patterns within templates
187+
- Explain constraints and expected input formats
188+
189+
### 3. Meaningful Parameter References
190+
191+
- Use the `arguments` field to reference input structures
192+
- Ensure parameter names in templates match structure field names
193+
- Keep parameter names descriptive and intuitive
194+
195+
### 4. Conditional Logic
196+
197+
- Use `preferWhen` to guide operation selection
198+
- Be specific about when operations should be used
199+
- Consider user intent and context in conditions
200+
201+
## Integration with MCP
202+
203+
This example is designed to work with Model Context Protocol (MCP) servers. The `@prompts` trait provides the metadata needed for MCP servers to:
204+
205+
1. **Understand API capabilities** - through service-level prompts
206+
2. **Generate appropriate calls** - using operation-specific guidance
207+
3. **Populate parameters correctly** - through ArgumentShape references
208+
4. **Provide context-aware suggestions** - using `preferWhen` conditions
209+
210+
## Extending the Example
211+
212+
To extend this example, you could:
213+
214+
1. **Add more operations** with their own prompt templates
215+
2. **Include resource-level prompts** for hierarchical guidance
216+
3. **Add error handling prompts** for common failure scenarios
217+
4. **Create workflow prompts** that guide multi-step processes
218+
219+
## Further Reading
220+
221+
- [Smithy Trait Documentation](https://smithy.io/2.0/spec/traits.html)
222+
- [Model Context Protocol](https://modelcontextprotocol.io/)
223+
- [Smithy Java Documentation](https://smithy.io/2.0/languages/java/)
224+
225+
## License
226+
227+
This example is provided under the same license as the Smithy Java project.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
plugins {
2+
`java-library`
3+
id("software.amazon.smithy.gradle.smithy-base")
4+
}
5+
6+
dependencies {
7+
val smithyJavaVersion: String by project
8+
val smithyVersion: String by project
9+
10+
// Include the mcp-traits module for the @prompts trait
11+
smithyBuild(project(":mcp:mcp-traits"))
12+
implementation(project(":mcp:mcp-traits"))
13+
14+
// Standard Smithy dependencies
15+
smithyBuild("software.amazon.smithy.java:plugins:$smithyJavaVersion")
16+
implementation("software.amazon.smithy:smithy-model:$smithyVersion")
17+
}
18+
19+
// Helps IDE's discover smithy models
20+
sourceSets {
21+
main {
22+
java {
23+
srcDir("model")
24+
}
25+
}
26+
}
27+
28+
repositories {
29+
mavenLocal()
30+
mavenCentral()
31+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
smithyJavaVersion=[0,1]
2+
smithyGradleVersion=1.3.0
3+
smithyVersion=[1,2]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace com.example
2+
3+
use amazon.smithy.llm#prompts
4+
5+
@prompts({
6+
search_users: { description: "Search for users in the system by various criteria", template: "Search for users where {{searchCriteria}}. Use pagination with limit={{limit}} if many results expected.", arguments: SearchUsersInput, preferWhen: "User wants to find specific users or browse user lists" }
7+
})
8+
service UserService {
9+
operations: [
10+
SearchUsers
11+
]
12+
}
13+
14+
operation SearchUsers {
15+
input: SearchUsersInput
16+
output: SearchUsersOutput
17+
}
18+
19+
structure SearchUsersOutput {
20+
id: String
21+
}
22+
23+
structure SearchUsersInput {
24+
searchCriteria: String
25+
limit: Integer
26+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* MCP Traits usage example.
3+
*/
4+
5+
pluginManagement {
6+
val smithyGradleVersion: String by settings
7+
8+
plugins {
9+
id("software.amazon.smithy.gradle.smithy-base").version(smithyGradleVersion)
10+
}
11+
12+
repositories {
13+
mavenLocal()
14+
mavenCentral()
15+
gradlePluginPortal()
16+
}
17+
}
18+
19+
rootProject.name = "mcp-traits-example"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"version": "1.0",
3+
"sources": ["model"],
4+
"plugins": {}
5+
}

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ smithy-validation-model = { module = "software.amazon.smithy:smithy-validation-m
3131
smithy-jmespath = { module = "software.amazon.smithy:smithy-jmespath", version.ref = "smithy" }
3232
smithy-waiters = { module = "software.amazon.smithy:smithy-waiters", version.ref = "smithy" }
3333
smithy-utils = { module = "software.amazon.smithy:smithy-utils", version.ref = "smithy" }
34+
smithy-traitcodegen = { module = "software.amazon.smithy:smithy-trait-codegen", version.ref = "smithy" }
3435

3536
# AWS SDK for Java V2 adapters.
3637
aws-sdk-retries-spi = {module = "software.amazon.awssdk:retries-spi", version.ref = "aws-sdk"}

mcp/mcp-server/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies {
1616
implementation(project(":codecs:json-codec", configuration = "shadow"))
1717
implementation(project(":mcp:mcp-schemas"))
1818
implementation(project(":mcp:mcp-bundle-api"))
19+
implementation(project(":mcp:mcp-traits"))
1920
testRuntimeOnly(libs.smithy.aws.traits)
2021
testRuntimeOnly(project(":aws:client:aws-client-awsjson"))
2122
}

mcp/mcp-traits/build.gradle.kts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
plugins {
2+
id("smithy-java.module-conventions")
3+
alias(libs.plugins.smithy.gradle.jar)
4+
}
5+
6+
description = "MCP Traits"
7+
8+
extra["displayName"] = "Smithy :: Java :: MCP Traits"
9+
extra["moduleName"] = "software.amazon.smithy.java.mcp.traits"
10+
11+
dependencies {
12+
api(libs.smithy.model)
13+
api(libs.smithy.traitcodegen)
14+
implementation(libs.smithy.traitcodegen)
15+
testImplementation(libs.junit.jupiter.api)
16+
testImplementation(libs.assertj.core)
17+
}
18+
19+
sourceSets {
20+
val traitsPath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "trait-codegen")
21+
sourceSets {
22+
main {
23+
java {
24+
srcDir(traitsPath)
25+
include("software/**")
26+
}
27+
28+
smithy {
29+
srcDir("$traitsPath/model")
30+
}
31+
32+
resources {
33+
srcDir(traitsPath)
34+
exclude("**/*.java")
35+
}
36+
}
37+
}
38+
}
39+
40+
tasks.sourcesJar {
41+
dependsOn("smithyJarStaging")
42+
}
43+
44+
spotbugs {
45+
ignoreFailures = true
46+
}
47+
48+
java.sourceSets["main"].java {
49+
srcDirs("model", "src/main/smithy")
50+
}

0 commit comments

Comments
 (0)