utils.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. package mcp
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/spf13/cast"
  6. )
  7. // ClientRequest types
  8. var _ ClientRequest = &PingRequest{}
  9. var _ ClientRequest = &InitializeRequest{}
  10. var _ ClientRequest = &CompleteRequest{}
  11. var _ ClientRequest = &SetLevelRequest{}
  12. var _ ClientRequest = &GetPromptRequest{}
  13. var _ ClientRequest = &ListPromptsRequest{}
  14. var _ ClientRequest = &ListResourcesRequest{}
  15. var _ ClientRequest = &ReadResourceRequest{}
  16. var _ ClientRequest = &SubscribeRequest{}
  17. var _ ClientRequest = &UnsubscribeRequest{}
  18. var _ ClientRequest = &CallToolRequest{}
  19. var _ ClientRequest = &ListToolsRequest{}
  20. // ClientNotification types
  21. var _ ClientNotification = &CancelledNotification{}
  22. var _ ClientNotification = &ProgressNotification{}
  23. var _ ClientNotification = &InitializedNotification{}
  24. var _ ClientNotification = &RootsListChangedNotification{}
  25. // ClientResult types
  26. var _ ClientResult = &EmptyResult{}
  27. var _ ClientResult = &CreateMessageResult{}
  28. var _ ClientResult = &ListRootsResult{}
  29. // ServerRequest types
  30. var _ ServerRequest = &PingRequest{}
  31. var _ ServerRequest = &CreateMessageRequest{}
  32. var _ ServerRequest = &ListRootsRequest{}
  33. // ServerNotification types
  34. var _ ServerNotification = &CancelledNotification{}
  35. var _ ServerNotification = &ProgressNotification{}
  36. var _ ServerNotification = &LoggingMessageNotification{}
  37. var _ ServerNotification = &ResourceUpdatedNotification{}
  38. var _ ServerNotification = &ResourceListChangedNotification{}
  39. var _ ServerNotification = &ToolListChangedNotification{}
  40. var _ ServerNotification = &PromptListChangedNotification{}
  41. // ServerResult types
  42. var _ ServerResult = &EmptyResult{}
  43. var _ ServerResult = &InitializeResult{}
  44. var _ ServerResult = &CompleteResult{}
  45. var _ ServerResult = &GetPromptResult{}
  46. var _ ServerResult = &ListPromptsResult{}
  47. var _ ServerResult = &ListResourcesResult{}
  48. var _ ServerResult = &ReadResourceResult{}
  49. var _ ServerResult = &CallToolResult{}
  50. var _ ServerResult = &ListToolsResult{}
  51. // Helper functions for type assertions
  52. // asType attempts to cast the given interface to the given type
  53. func asType[T any](content any) (*T, bool) {
  54. tc, ok := content.(T)
  55. if !ok {
  56. return nil, false
  57. }
  58. return &tc, true
  59. }
  60. // AsTextContent attempts to cast the given interface to TextContent
  61. func AsTextContent(content any) (*TextContent, bool) {
  62. return asType[TextContent](content)
  63. }
  64. // AsImageContent attempts to cast the given interface to ImageContent
  65. func AsImageContent(content any) (*ImageContent, bool) {
  66. return asType[ImageContent](content)
  67. }
  68. // AsAudioContent attempts to cast the given interface to AudioContent
  69. func AsAudioContent(content any) (*AudioContent, bool) {
  70. return asType[AudioContent](content)
  71. }
  72. // AsEmbeddedResource attempts to cast the given interface to EmbeddedResource
  73. func AsEmbeddedResource(content any) (*EmbeddedResource, bool) {
  74. return asType[EmbeddedResource](content)
  75. }
  76. // AsTextResourceContents attempts to cast the given interface to TextResourceContents
  77. func AsTextResourceContents(content any) (*TextResourceContents, bool) {
  78. return asType[TextResourceContents](content)
  79. }
  80. // AsBlobResourceContents attempts to cast the given interface to BlobResourceContents
  81. func AsBlobResourceContents(content any) (*BlobResourceContents, bool) {
  82. return asType[BlobResourceContents](content)
  83. }
  84. // Helper function for JSON-RPC
  85. // NewJSONRPCResponse creates a new JSONRPCResponse with the given id and result
  86. func NewJSONRPCResponse(id RequestId, result Result) JSONRPCResponse {
  87. return JSONRPCResponse{
  88. JSONRPC: JSONRPC_VERSION,
  89. ID: id,
  90. Result: result,
  91. }
  92. }
  93. // NewJSONRPCError creates a new JSONRPCResponse with the given id, code, and message
  94. func NewJSONRPCError(
  95. id RequestId,
  96. code int,
  97. message string,
  98. data any,
  99. ) JSONRPCError {
  100. return JSONRPCError{
  101. JSONRPC: JSONRPC_VERSION,
  102. ID: id,
  103. Error: struct {
  104. Code int `json:"code"`
  105. Message string `json:"message"`
  106. Data any `json:"data,omitempty"`
  107. }{
  108. Code: code,
  109. Message: message,
  110. Data: data,
  111. },
  112. }
  113. }
  114. // NewProgressNotification
  115. // Helper function for creating a progress notification
  116. func NewProgressNotification(
  117. token ProgressToken,
  118. progress float64,
  119. total *float64,
  120. message *string,
  121. ) ProgressNotification {
  122. notification := ProgressNotification{
  123. Notification: Notification{
  124. Method: "notifications/progress",
  125. },
  126. Params: struct {
  127. ProgressToken ProgressToken `json:"progressToken"`
  128. Progress float64 `json:"progress"`
  129. Total float64 `json:"total,omitempty"`
  130. Message string `json:"message,omitempty"`
  131. }{
  132. ProgressToken: token,
  133. Progress: progress,
  134. },
  135. }
  136. if total != nil {
  137. notification.Params.Total = *total
  138. }
  139. if message != nil {
  140. notification.Params.Message = *message
  141. }
  142. return notification
  143. }
  144. // NewLoggingMessageNotification
  145. // Helper function for creating a logging message notification
  146. func NewLoggingMessageNotification(
  147. level LoggingLevel,
  148. logger string,
  149. data any,
  150. ) LoggingMessageNotification {
  151. return LoggingMessageNotification{
  152. Notification: Notification{
  153. Method: "notifications/message",
  154. },
  155. Params: struct {
  156. Level LoggingLevel `json:"level"`
  157. Logger string `json:"logger,omitempty"`
  158. Data any `json:"data"`
  159. }{
  160. Level: level,
  161. Logger: logger,
  162. Data: data,
  163. },
  164. }
  165. }
  166. // NewPromptMessage
  167. // Helper function to create a new PromptMessage
  168. func NewPromptMessage(role Role, content Content) PromptMessage {
  169. return PromptMessage{
  170. Role: role,
  171. Content: content,
  172. }
  173. }
  174. // NewTextContent
  175. // Helper function to create a new TextContent
  176. func NewTextContent(text string) TextContent {
  177. return TextContent{
  178. Type: ContentTypeText,
  179. Text: text,
  180. }
  181. }
  182. // NewImageContent
  183. // Helper function to create a new ImageContent
  184. func NewImageContent(data, mimeType string) ImageContent {
  185. return ImageContent{
  186. Type: ContentTypeImage,
  187. Data: data,
  188. MIMEType: mimeType,
  189. }
  190. }
  191. // Helper function to create a new AudioContent
  192. func NewAudioContent(data, mimeType string) AudioContent {
  193. return AudioContent{
  194. Type: ContentTypeAudio,
  195. Data: data,
  196. MIMEType: mimeType,
  197. }
  198. }
  199. // Helper function to create a new ResourceLink
  200. func NewResourceLink(uri, name, description, mimeType string) ResourceLink {
  201. return ResourceLink{
  202. Type: ContentTypeLink,
  203. URI: uri,
  204. Name: name,
  205. Description: description,
  206. MIMEType: mimeType,
  207. }
  208. }
  209. // Helper function to create a new EmbeddedResource
  210. func NewEmbeddedResource(resource ResourceContents) EmbeddedResource {
  211. return EmbeddedResource{
  212. Type: ContentTypeResource,
  213. Resource: resource,
  214. }
  215. }
  216. // NewToolResultText creates a new CallToolResult with a text content
  217. func NewToolResultText(text string) *CallToolResult {
  218. return &CallToolResult{
  219. Content: []Content{
  220. TextContent{
  221. Type: ContentTypeText,
  222. Text: text,
  223. },
  224. },
  225. }
  226. }
  227. // NewToolResultStructured creates a new CallToolResult with structured content.
  228. // It includes both the structured content and a text representation for backward compatibility.
  229. func NewToolResultStructured(structured any, fallbackText string) *CallToolResult {
  230. return &CallToolResult{
  231. Content: []Content{
  232. TextContent{
  233. Type: "text",
  234. Text: fallbackText,
  235. },
  236. },
  237. StructuredContent: structured,
  238. }
  239. }
  240. // NewToolResultStructuredOnly creates a new CallToolResult with structured
  241. // content and creates a JSON string fallback for backwards compatibility.
  242. // This is useful when you want to provide structured data without any specific text fallback.
  243. func NewToolResultStructuredOnly(structured any) *CallToolResult {
  244. var fallbackText string
  245. // Convert to JSON string for backward compatibility
  246. jsonBytes, err := json.Marshal(structured)
  247. if err != nil {
  248. fallbackText = fmt.Sprintf("Error serializing structured content: %v", err)
  249. } else {
  250. fallbackText = string(jsonBytes)
  251. }
  252. return &CallToolResult{
  253. Content: []Content{
  254. TextContent{
  255. Type: "text",
  256. Text: fallbackText,
  257. },
  258. },
  259. StructuredContent: structured,
  260. }
  261. }
  262. // NewToolResultImage creates a new CallToolResult with both text and image content
  263. func NewToolResultImage(text, imageData, mimeType string) *CallToolResult {
  264. return &CallToolResult{
  265. Content: []Content{
  266. TextContent{
  267. Type: ContentTypeText,
  268. Text: text,
  269. },
  270. ImageContent{
  271. Type: ContentTypeImage,
  272. Data: imageData,
  273. MIMEType: mimeType,
  274. },
  275. },
  276. }
  277. }
  278. // NewToolResultAudio creates a new CallToolResult with both text and audio content
  279. func NewToolResultAudio(text, imageData, mimeType string) *CallToolResult {
  280. return &CallToolResult{
  281. Content: []Content{
  282. TextContent{
  283. Type: ContentTypeText,
  284. Text: text,
  285. },
  286. AudioContent{
  287. Type: ContentTypeAudio,
  288. Data: imageData,
  289. MIMEType: mimeType,
  290. },
  291. },
  292. }
  293. }
  294. // NewToolResultResource creates a new CallToolResult with an embedded resource
  295. func NewToolResultResource(
  296. text string,
  297. resource ResourceContents,
  298. ) *CallToolResult {
  299. return &CallToolResult{
  300. Content: []Content{
  301. TextContent{
  302. Type: ContentTypeText,
  303. Text: text,
  304. },
  305. EmbeddedResource{
  306. Type: ContentTypeResource,
  307. Resource: resource,
  308. },
  309. },
  310. }
  311. }
  312. // NewToolResultError creates a new CallToolResult with an error message.
  313. // Any errors that originate from the tool SHOULD be reported inside the result object.
  314. func NewToolResultError(text string) *CallToolResult {
  315. return &CallToolResult{
  316. Content: []Content{
  317. TextContent{
  318. Type: ContentTypeText,
  319. Text: text,
  320. },
  321. },
  322. IsError: true,
  323. }
  324. }
  325. // NewToolResultErrorFromErr creates a new CallToolResult with an error message.
  326. // If an error is provided, its details will be appended to the text message.
  327. // Any errors that originate from the tool SHOULD be reported inside the result object.
  328. func NewToolResultErrorFromErr(text string, err error) *CallToolResult {
  329. if err != nil {
  330. text = fmt.Sprintf("%s: %v", text, err)
  331. }
  332. return &CallToolResult{
  333. Content: []Content{
  334. TextContent{
  335. Type: ContentTypeText,
  336. Text: text,
  337. },
  338. },
  339. IsError: true,
  340. }
  341. }
  342. // NewToolResultErrorf creates a new CallToolResult with an error message.
  343. // The error message is formatted using the fmt package.
  344. // Any errors that originate from the tool SHOULD be reported inside the result object.
  345. func NewToolResultErrorf(format string, a ...any) *CallToolResult {
  346. return &CallToolResult{
  347. Content: []Content{
  348. TextContent{
  349. Type: ContentTypeText,
  350. Text: fmt.Sprintf(format, a...),
  351. },
  352. },
  353. IsError: true,
  354. }
  355. }
  356. // NewListResourcesResult creates a new ListResourcesResult
  357. func NewListResourcesResult(
  358. resources []Resource,
  359. nextCursor Cursor,
  360. ) *ListResourcesResult {
  361. return &ListResourcesResult{
  362. PaginatedResult: PaginatedResult{
  363. NextCursor: nextCursor,
  364. },
  365. Resources: resources,
  366. }
  367. }
  368. // NewListResourceTemplatesResult creates a new ListResourceTemplatesResult
  369. func NewListResourceTemplatesResult(
  370. templates []ResourceTemplate,
  371. nextCursor Cursor,
  372. ) *ListResourceTemplatesResult {
  373. return &ListResourceTemplatesResult{
  374. PaginatedResult: PaginatedResult{
  375. NextCursor: nextCursor,
  376. },
  377. ResourceTemplates: templates,
  378. }
  379. }
  380. // NewReadResourceResult creates a new ReadResourceResult with text content
  381. func NewReadResourceResult(text string) *ReadResourceResult {
  382. return &ReadResourceResult{
  383. Contents: []ResourceContents{
  384. TextResourceContents{
  385. Text: text,
  386. },
  387. },
  388. }
  389. }
  390. // NewListPromptsResult creates a new ListPromptsResult
  391. func NewListPromptsResult(
  392. prompts []Prompt,
  393. nextCursor Cursor,
  394. ) *ListPromptsResult {
  395. return &ListPromptsResult{
  396. PaginatedResult: PaginatedResult{
  397. NextCursor: nextCursor,
  398. },
  399. Prompts: prompts,
  400. }
  401. }
  402. // NewGetPromptResult creates a new GetPromptResult
  403. func NewGetPromptResult(
  404. description string,
  405. messages []PromptMessage,
  406. ) *GetPromptResult {
  407. return &GetPromptResult{
  408. Description: description,
  409. Messages: messages,
  410. }
  411. }
  412. // NewListToolsResult creates a new ListToolsResult
  413. func NewListToolsResult(tools []Tool, nextCursor Cursor) *ListToolsResult {
  414. return &ListToolsResult{
  415. PaginatedResult: PaginatedResult{
  416. NextCursor: nextCursor,
  417. },
  418. Tools: tools,
  419. }
  420. }
  421. // NewInitializeResult creates a new InitializeResult
  422. func NewInitializeResult(
  423. protocolVersion string,
  424. capabilities ServerCapabilities,
  425. serverInfo Implementation,
  426. instructions string,
  427. ) *InitializeResult {
  428. return &InitializeResult{
  429. ProtocolVersion: protocolVersion,
  430. Capabilities: capabilities,
  431. ServerInfo: serverInfo,
  432. Instructions: instructions,
  433. }
  434. }
  435. // FormatNumberResult
  436. // Helper for formatting numbers in tool results
  437. func FormatNumberResult(value float64) *CallToolResult {
  438. return NewToolResultText(fmt.Sprintf("%.2f", value))
  439. }
  440. func ExtractString(data map[string]any, key string) string {
  441. if value, ok := data[key]; ok {
  442. if str, ok := value.(string); ok {
  443. return str
  444. }
  445. }
  446. return ""
  447. }
  448. func ExtractMap(data map[string]any, key string) map[string]any {
  449. if value, ok := data[key]; ok {
  450. if m, ok := value.(map[string]any); ok {
  451. return m
  452. }
  453. }
  454. return nil
  455. }
  456. func ParseContent(contentMap map[string]any) (Content, error) {
  457. contentType := ExtractString(contentMap, "type")
  458. switch contentType {
  459. case ContentTypeText:
  460. text := ExtractString(contentMap, "text")
  461. return NewTextContent(text), nil
  462. case ContentTypeImage:
  463. data := ExtractString(contentMap, "data")
  464. mimeType := ExtractString(contentMap, "mimeType")
  465. if data == "" || mimeType == "" {
  466. return nil, fmt.Errorf("image data or mimeType is missing")
  467. }
  468. return NewImageContent(data, mimeType), nil
  469. case ContentTypeAudio:
  470. data := ExtractString(contentMap, "data")
  471. mimeType := ExtractString(contentMap, "mimeType")
  472. if data == "" || mimeType == "" {
  473. return nil, fmt.Errorf("audio data or mimeType is missing")
  474. }
  475. return NewAudioContent(data, mimeType), nil
  476. case ContentTypeLink:
  477. uri := ExtractString(contentMap, "uri")
  478. name := ExtractString(contentMap, "name")
  479. description := ExtractString(contentMap, "description")
  480. mimeType := ExtractString(contentMap, "mimeType")
  481. if uri == "" || name == "" {
  482. return nil, fmt.Errorf("resource_link uri or name is missing")
  483. }
  484. return NewResourceLink(uri, name, description, mimeType), nil
  485. case ContentTypeResource:
  486. resourceMap := ExtractMap(contentMap, "resource")
  487. if resourceMap == nil {
  488. return nil, fmt.Errorf("resource is missing")
  489. }
  490. resourceContents, err := ParseResourceContents(resourceMap)
  491. if err != nil {
  492. return nil, err
  493. }
  494. return NewEmbeddedResource(resourceContents), nil
  495. }
  496. return nil, fmt.Errorf("unsupported content type: %s", contentType)
  497. }
  498. func ParseGetPromptResult(rawMessage *json.RawMessage) (*GetPromptResult, error) {
  499. if rawMessage == nil {
  500. return nil, fmt.Errorf("response is nil")
  501. }
  502. var jsonContent map[string]any
  503. if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
  504. return nil, fmt.Errorf("failed to unmarshal response: %w", err)
  505. }
  506. result := GetPromptResult{}
  507. meta, ok := jsonContent["_meta"]
  508. if ok {
  509. if metaMap, ok := meta.(map[string]any); ok {
  510. result.Meta = NewMetaFromMap(metaMap)
  511. }
  512. }
  513. description, ok := jsonContent["description"]
  514. if ok {
  515. if descriptionStr, ok := description.(string); ok {
  516. result.Description = descriptionStr
  517. }
  518. }
  519. messages, ok := jsonContent["messages"]
  520. if ok {
  521. messagesArr, ok := messages.([]any)
  522. if !ok {
  523. return nil, fmt.Errorf("messages is not an array")
  524. }
  525. for _, message := range messagesArr {
  526. messageMap, ok := message.(map[string]any)
  527. if !ok {
  528. return nil, fmt.Errorf("message is not an object")
  529. }
  530. // Extract role
  531. roleStr := ExtractString(messageMap, "role")
  532. if roleStr == "" || (roleStr != string(RoleAssistant) && roleStr != string(RoleUser)) {
  533. return nil, fmt.Errorf("unsupported role: %s", roleStr)
  534. }
  535. // Extract content
  536. contentMap, ok := messageMap["content"].(map[string]any)
  537. if !ok {
  538. return nil, fmt.Errorf("content is not an object")
  539. }
  540. // Process content
  541. content, err := ParseContent(contentMap)
  542. if err != nil {
  543. return nil, err
  544. }
  545. // Append processed message
  546. result.Messages = append(result.Messages, NewPromptMessage(Role(roleStr), content))
  547. }
  548. }
  549. return &result, nil
  550. }
  551. func ParseCallToolResult(rawMessage *json.RawMessage) (*CallToolResult, error) {
  552. if rawMessage == nil {
  553. return nil, fmt.Errorf("response is nil")
  554. }
  555. var jsonContent map[string]any
  556. if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
  557. return nil, fmt.Errorf("failed to unmarshal response: %w", err)
  558. }
  559. var result CallToolResult
  560. meta, ok := jsonContent["_meta"]
  561. if ok {
  562. if metaMap, ok := meta.(map[string]any); ok {
  563. result.Meta = NewMetaFromMap(metaMap)
  564. }
  565. }
  566. isError, ok := jsonContent["isError"]
  567. if ok {
  568. if isErrorBool, ok := isError.(bool); ok {
  569. result.IsError = isErrorBool
  570. }
  571. }
  572. contents, ok := jsonContent["content"]
  573. if !ok {
  574. return nil, fmt.Errorf("content is missing")
  575. }
  576. contentArr, ok := contents.([]any)
  577. if !ok {
  578. return nil, fmt.Errorf("content is not an array")
  579. }
  580. for _, content := range contentArr {
  581. // Extract content
  582. contentMap, ok := content.(map[string]any)
  583. if !ok {
  584. return nil, fmt.Errorf("content is not an object")
  585. }
  586. // Process content
  587. content, err := ParseContent(contentMap)
  588. if err != nil {
  589. return nil, err
  590. }
  591. result.Content = append(result.Content, content)
  592. }
  593. // Handle structured content
  594. structuredContent, ok := jsonContent["structuredContent"]
  595. if ok {
  596. result.StructuredContent = structuredContent
  597. }
  598. return &result, nil
  599. }
  600. func ParseResourceContents(contentMap map[string]any) (ResourceContents, error) {
  601. uri := ExtractString(contentMap, "uri")
  602. if uri == "" {
  603. return nil, fmt.Errorf("resource uri is missing")
  604. }
  605. mimeType := ExtractString(contentMap, "mimeType")
  606. if text := ExtractString(contentMap, "text"); text != "" {
  607. return TextResourceContents{
  608. URI: uri,
  609. MIMEType: mimeType,
  610. Text: text,
  611. }, nil
  612. }
  613. if blob := ExtractString(contentMap, "blob"); blob != "" {
  614. return BlobResourceContents{
  615. URI: uri,
  616. MIMEType: mimeType,
  617. Blob: blob,
  618. }, nil
  619. }
  620. return nil, fmt.Errorf("unsupported resource type")
  621. }
  622. func ParseReadResourceResult(rawMessage *json.RawMessage) (*ReadResourceResult, error) {
  623. if rawMessage == nil {
  624. return nil, fmt.Errorf("response is nil")
  625. }
  626. var jsonContent map[string]any
  627. if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
  628. return nil, fmt.Errorf("failed to unmarshal response: %w", err)
  629. }
  630. var result ReadResourceResult
  631. meta, ok := jsonContent["_meta"]
  632. if ok {
  633. if metaMap, ok := meta.(map[string]any); ok {
  634. result.Meta = NewMetaFromMap(metaMap)
  635. }
  636. }
  637. contents, ok := jsonContent["contents"]
  638. if !ok {
  639. return nil, fmt.Errorf("contents is missing")
  640. }
  641. contentArr, ok := contents.([]any)
  642. if !ok {
  643. return nil, fmt.Errorf("contents is not an array")
  644. }
  645. for _, content := range contentArr {
  646. // Extract content
  647. contentMap, ok := content.(map[string]any)
  648. if !ok {
  649. return nil, fmt.Errorf("content is not an object")
  650. }
  651. // Process content
  652. content, err := ParseResourceContents(contentMap)
  653. if err != nil {
  654. return nil, err
  655. }
  656. result.Contents = append(result.Contents, content)
  657. }
  658. return &result, nil
  659. }
  660. func ParseArgument(request CallToolRequest, key string, defaultVal any) any {
  661. args := request.GetArguments()
  662. if _, ok := args[key]; !ok {
  663. return defaultVal
  664. } else {
  665. return args[key]
  666. }
  667. }
  668. // ParseBoolean extracts and converts a boolean parameter from a CallToolRequest.
  669. // If the key is not found in the Arguments map, the defaultValue is returned.
  670. // The function uses cast.ToBool for conversion which handles various string representations
  671. // such as "true", "yes", "1", etc.
  672. func ParseBoolean(request CallToolRequest, key string, defaultValue bool) bool {
  673. v := ParseArgument(request, key, defaultValue)
  674. return cast.ToBool(v)
  675. }
  676. // ParseInt64 extracts and converts an int64 parameter from a CallToolRequest.
  677. // If the key is not found in the Arguments map, the defaultValue is returned.
  678. func ParseInt64(request CallToolRequest, key string, defaultValue int64) int64 {
  679. v := ParseArgument(request, key, defaultValue)
  680. return cast.ToInt64(v)
  681. }
  682. // ParseInt32 extracts and converts an int32 parameter from a CallToolRequest.
  683. func ParseInt32(request CallToolRequest, key string, defaultValue int32) int32 {
  684. v := ParseArgument(request, key, defaultValue)
  685. return cast.ToInt32(v)
  686. }
  687. // ParseInt16 extracts and converts an int16 parameter from a CallToolRequest.
  688. func ParseInt16(request CallToolRequest, key string, defaultValue int16) int16 {
  689. v := ParseArgument(request, key, defaultValue)
  690. return cast.ToInt16(v)
  691. }
  692. // ParseInt8 extracts and converts an int8 parameter from a CallToolRequest.
  693. func ParseInt8(request CallToolRequest, key string, defaultValue int8) int8 {
  694. v := ParseArgument(request, key, defaultValue)
  695. return cast.ToInt8(v)
  696. }
  697. // ParseInt extracts and converts an int parameter from a CallToolRequest.
  698. func ParseInt(request CallToolRequest, key string, defaultValue int) int {
  699. v := ParseArgument(request, key, defaultValue)
  700. return cast.ToInt(v)
  701. }
  702. // ParseUInt extracts and converts an uint parameter from a CallToolRequest.
  703. func ParseUInt(request CallToolRequest, key string, defaultValue uint) uint {
  704. v := ParseArgument(request, key, defaultValue)
  705. return cast.ToUint(v)
  706. }
  707. // ParseUInt64 extracts and converts an uint64 parameter from a CallToolRequest.
  708. func ParseUInt64(request CallToolRequest, key string, defaultValue uint64) uint64 {
  709. v := ParseArgument(request, key, defaultValue)
  710. return cast.ToUint64(v)
  711. }
  712. // ParseUInt32 extracts and converts an uint32 parameter from a CallToolRequest.
  713. func ParseUInt32(request CallToolRequest, key string, defaultValue uint32) uint32 {
  714. v := ParseArgument(request, key, defaultValue)
  715. return cast.ToUint32(v)
  716. }
  717. // ParseUInt16 extracts and converts an uint16 parameter from a CallToolRequest.
  718. func ParseUInt16(request CallToolRequest, key string, defaultValue uint16) uint16 {
  719. v := ParseArgument(request, key, defaultValue)
  720. return cast.ToUint16(v)
  721. }
  722. // ParseUInt8 extracts and converts an uint8 parameter from a CallToolRequest.
  723. func ParseUInt8(request CallToolRequest, key string, defaultValue uint8) uint8 {
  724. v := ParseArgument(request, key, defaultValue)
  725. return cast.ToUint8(v)
  726. }
  727. // ParseFloat32 extracts and converts a float32 parameter from a CallToolRequest.
  728. func ParseFloat32(request CallToolRequest, key string, defaultValue float32) float32 {
  729. v := ParseArgument(request, key, defaultValue)
  730. return cast.ToFloat32(v)
  731. }
  732. // ParseFloat64 extracts and converts a float64 parameter from a CallToolRequest.
  733. func ParseFloat64(request CallToolRequest, key string, defaultValue float64) float64 {
  734. v := ParseArgument(request, key, defaultValue)
  735. return cast.ToFloat64(v)
  736. }
  737. // ParseString extracts and converts a string parameter from a CallToolRequest.
  738. func ParseString(request CallToolRequest, key string, defaultValue string) string {
  739. v := ParseArgument(request, key, defaultValue)
  740. return cast.ToString(v)
  741. }
  742. // ParseStringMap extracts and converts a string map parameter from a CallToolRequest.
  743. func ParseStringMap(request CallToolRequest, key string, defaultValue map[string]any) map[string]any {
  744. v := ParseArgument(request, key, defaultValue)
  745. return cast.ToStringMap(v)
  746. }
  747. // ToBoolPtr returns a pointer to the given boolean value
  748. func ToBoolPtr(b bool) *bool {
  749. return &b
  750. }