({
annotations,
}: {
annotations: ToolAnnotations | undefined;
})
| 96 | // Helper to render annotation badges |
| 97 | // Shows all 4 annotation values with their state (true/false/implied default) |
| 98 | const AnnotationBadges = ({ |
| 99 | annotations, |
| 100 | }: { |
| 101 | annotations: ToolAnnotations | undefined; |
| 102 | }) => { |
| 103 | // Spec defaults: readOnlyHint=false, destructiveHint=true, idempotentHint=false, openWorldHint=true |
| 104 | const getValueAndImplied = ( |
| 105 | value: boolean | undefined, |
| 106 | defaultValue: boolean, |
| 107 | ): { value: boolean; implied: boolean } => ({ |
| 108 | value: value ?? defaultValue, |
| 109 | implied: value === undefined, |
| 110 | }); |
| 111 | |
| 112 | const readOnly = getValueAndImplied(annotations?.readOnlyHint, false); |
| 113 | const destructive = getValueAndImplied(annotations?.destructiveHint, true); |
| 114 | const idempotent = getValueAndImplied(annotations?.idempotentHint, false); |
| 115 | const openWorld = getValueAndImplied(annotations?.openWorldHint, true); |
| 116 | |
| 117 | // Descriptions from MCP spec |
| 118 | const badges = [ |
| 119 | { |
| 120 | label: "Read-only", |
| 121 | value: readOnly.value, |
| 122 | implied: readOnly.implied, |
| 123 | description: "Tool does not modify its environment", |
| 124 | }, |
| 125 | { |
| 126 | label: "Destructive", |
| 127 | value: destructive.value, |
| 128 | implied: destructive.implied, |
| 129 | description: |
| 130 | "Tool may perform destructive updates (delete/overwrite data)", |
| 131 | }, |
| 132 | { |
| 133 | label: "Idempotent", |
| 134 | value: idempotent.value, |
| 135 | implied: idempotent.implied, |
| 136 | description: "Calling repeatedly with same args has no additional effect", |
| 137 | }, |
| 138 | { |
| 139 | label: "Open-world", |
| 140 | value: openWorld.value, |
| 141 | implied: openWorld.implied, |
| 142 | description: |
| 143 | "Tool may interact with external entities beyond its local environment", |
| 144 | }, |
| 145 | ]; |
| 146 | |
| 147 | return ( |
| 148 | <div className="flex flex-wrap gap-1 mt-2"> |
| 149 | {badges.map(({ label, value, implied, description }) => ( |
| 150 | <span |
| 151 | key={label} |
| 152 | title={`${description}\n\nValue: ${value ? "Yes" : "No"} (${implied ? "implied default" : "explicitly set"})`} |
| 153 | className={cn( |
| 154 | "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium border", |
| 155 | "bg-slate-100 text-slate-700 border-slate-300 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-600", |
nothing calls this directly
no test coverage detected