modelcontextprotocol / modelcontextprotocol/typescript-sdk
Use types for tool annotations to reduce confusion
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 15h
- Merged PRs (30d)
- 4
Description
Is your feature request related to a problem? Please describe.
The way that tool annotations work is confusing because some of the properties only matter if you have read-only set to false.
Describe the solution you'd like
I would like to have type warnings if I am setting destructiveHint or idempotentHint to anything when readOnly is set to false.
Something like this:
Implement a discriminated union type that:
- Enforces the read-only constraint: When
readOnlyHint: true,destructiveHintandidempotentHintcannot be specified - Prevents redundant defaults: Only allows specifying properties when they differ from their default values
- Uses defaults:
destructiveHint: true,idempotentHint: false,openWorldHint: true,readOnlyHint: false
Proposed Type Definition:
type ToolAnnotations =
| {
readOnlyHint: true;
openWorldHint?: boolean;
}
| {
destructiveHint?: false; // Only allow false (default is true)
idempotentHint?: true; // Only allow true (default is false)
openWorldHint?: false; // Only allow false (default is true)
};
Benefits:
- Cleaner configurations: No need to specify default values
- Type safety: Prevents invalid combinations at compile time
- Explicit intent: Only specify what differs from defaults
- Constraint enforcement: Cannot set destructive/idempotent on read-only tools
Examples:
type ToolAnnotations =
| {
readOnlyHint: true;
openWorldHint?: boolean;
}
| {
destructiveHint?: false; // Only allow false (default is true)
idempotentHint?: true; // Only allow true (default is false)
openWorldHint?: false; // Only allow false (default is true)
};
// ✅ Clean - all defaults
const defaultTool: ToolAnnotations = {};
// ✅ Only specify non-defaults
const nonDestructiveTool: ToolAnnotations = {
destructiveHint: false // Only specify when false (default is true)
};
// ✅ Read-only tool
const readOnlyTool: ToolAnnotations = {
readOnlyHint: true,
openWorldHint: false
};
// ❌ TypeScript error - cannot specify defaults
const invalidDefaults: ToolAnnotations = {
destructiveHint: true, // Error: Type 'true' is not assignable to type 'false'
idempotentHint: false, // Error: Type 'false' is not assignable to type 'true'
openWorldHint: true // Error: Type 'true' is not assignable to type 'false'
};
// ❌ TypeScript error - cannot set destructive/idempotent on read-only
const invalidReadOnly: ToolAnnotations = {
readOnlyHint: true,
destructiveHint: true // Error: Property 'destructiveHint' does not exist
};
Describe alternatives you've considered
The status quo is me being pretty confused 😅
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No file or test is named in the issue. Start by locating the existing ToolAnnotations type and the tool registration entry point, then compare their current defaults and read-only behavior with the proposed discriminated union. Done means the public types reject invalid combinations at compile time while accepting valid default and non-default annotations, with the relevant type checks passing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100