@@ -872,6 +872,53 @@ class WeatherTool < MCP::Tool
872872end
873873```
874874
875+ ### Tool Responses with Image, Audio, and Embedded Resources
876+
877+ Tool responses are not limited to text. The ` MCP::Content ` module provides ` Image ` , ` Audio ` , and ` EmbeddedResource ` content types,
878+ which serialize to the ` image ` , ` audio ` , and ` resource ` content blocks defined by the MCP spec. Image and audio data is passed as
879+ a base64-encoded string together with its MIME type:
880+
881+ ``` ruby
882+ class ChartTool < MCP ::Tool
883+ description " Render a chart as a PNG image"
884+
885+ def self .call (server_context: )
886+ MCP ::Tool ::Response .new ([
887+ MCP ::Content ::Text .new (" Here is the rendered chart:" ).to_h,
888+ MCP ::Content ::Image .new (Base64 .strict_encode64(render_chart_png), " image/png" ).to_h,
889+ ])
890+ end
891+ end
892+
893+ class SpeechTool < MCP ::Tool
894+ description " Synthesize speech audio"
895+
896+ def self .call (server_context: )
897+ MCP ::Tool ::Response .new ([
898+ MCP ::Content ::Audio .new (Base64 .strict_encode64(synthesize_wav), " audio/wav" ).to_h,
899+ ])
900+ end
901+ end
902+ ```
903+
904+ An embedded resource wraps ` MCP::Resource::TextContents ` or ` MCP::Resource::BlobContents ` , allowing a tool to return resource contents inline:
905+
906+ ``` ruby
907+ class ReportTool < MCP ::Tool
908+ description " Return a report as an embedded resource"
909+
910+ def self .call (server_context: )
911+ contents = MCP ::Resource ::TextContents .new (
912+ uri: " report://monthly" ,
913+ mime_type: " application/json" ,
914+ text: { total: 42 }.to_json,
915+ )
916+
917+ MCP ::Tool ::Response .new ([MCP ::Content ::EmbeddedResource .new (contents).to_h])
918+ end
919+ end
920+ ```
921+
875922### Prompts
876923
877924MCP spec includes [ Prompts] ( https://modelcontextprotocol.io/specification/latest/server/prompts ) , which enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs.
@@ -1010,6 +1057,49 @@ The server will handle prompt listing and execution through the MCP protocol met
10101057- ` prompts/list ` - Lists all registered prompts and their schemas
10111058- ` prompts/get ` - Retrieves and executes a specific prompt with arguments
10121059
1060+ ### Prompts with Image and Embedded Resource Content
1061+
1062+ Prompt messages are not limited to text. The same ` MCP::Content ` types used in tool responses can be used as message content,
1063+ letting a prompt template include images or inline resource contents. Unlike tool responses, the content object is passed directly rather than as a hash;
1064+ ` MCP::Prompt::Message ` serializes it when the prompt result is returned:
1065+
1066+ ``` ruby
1067+ class CodeReviewPrompt < MCP ::Prompt
1068+ prompt_name " code_review"
1069+ description " Review a source file with an accompanying diagram"
1070+ arguments [
1071+ MCP ::Prompt ::Argument .new (name: " file_uri" , description: " URI of the file to review" , required: true ),
1072+ ]
1073+
1074+ class << self
1075+ def template (args , server_context: )
1076+ MCP ::Prompt ::Result .new (
1077+ messages: [
1078+ MCP ::Prompt ::Message .new (
1079+ role: " user" ,
1080+ content: MCP ::Content ::EmbeddedResource .new (
1081+ MCP ::Resource ::TextContents .new (
1082+ uri: args[" file_uri" ],
1083+ mime_type: " text/x-ruby" ,
1084+ text: read_source(args[" file_uri" ]),
1085+ ),
1086+ ),
1087+ ),
1088+ MCP ::Prompt ::Message .new (
1089+ role: " user" ,
1090+ content: MCP ::Content ::Image .new (architecture_diagram_base64, " image/png" ),
1091+ ),
1092+ MCP ::Prompt ::Message .new (
1093+ role: " user" ,
1094+ content: MCP ::Content ::Text .new (" Please review the code above, using the diagram for context." ),
1095+ ),
1096+ ],
1097+ )
1098+ end
1099+ end
1100+ end
1101+ ```
1102+
10131103### Resources
10141104
10151105MCP spec includes [ Resources] ( https://modelcontextprotocol.io/specification/latest/server/resources ) .
@@ -1126,6 +1216,34 @@ server.resources_read_handler do |params|
11261216end
11271217```
11281218
1219+ ### Reading Binary Resources
1220+
1221+ For binary resources, respond with a base64-encoded ` blob ` field instead of ` text ` .
1222+ The ` MCP::Resource::TextContents ` and ` MCP::Resource::BlobContents ` classes build the two contents shapes defined by the spec:
1223+
1224+ ``` ruby
1225+ server.resources_read_handler do |params |
1226+ case params[:uri ]
1227+ when " file:///logo.png"
1228+ [
1229+ MCP ::Resource ::BlobContents .new (
1230+ uri: params[:uri ],
1231+ mime_type: " image/png" ,
1232+ data: Base64 .strict_encode64(File .binread(" logo.png" )),
1233+ ).to_h,
1234+ ]
1235+ else
1236+ [
1237+ MCP ::Resource ::TextContents .new (
1238+ uri: params[:uri ],
1239+ mime_type: " text/plain" ,
1240+ text: " Hello from example resource!" ,
1241+ ).to_h,
1242+ ]
1243+ end
1244+ end
1245+ ```
1246+
11291247### Resource Templates
11301248
11311249Resource templates follow the same pattern. Class-based templates declare a ` uri_template ` and
@@ -1201,6 +1319,31 @@ server = MCP::Server.new(
12011319)
12021320```
12031321
1322+ Registered templates are listed through the ` resources/templates/list ` protocol method.
1323+ To serve reads for URIs that match a template, extract the variable parts of the URI in your ` resources_read_handler ` :
1324+
1325+ ``` ruby
1326+ resource_template = MCP ::ResourceTemplate .new (
1327+ uri_template: " file:///items/{item_id}" ,
1328+ name: " item" ,
1329+ mime_type: " application/json" ,
1330+ )
1331+
1332+ server = MCP ::Server .new (name: " my_server" , resource_templates: [resource_template])
1333+
1334+ server.resources_read_handler do |params |
1335+ if (match = params[:uri ].match(%r{\A file:///items/(?<item_id>[^/] +) \z } ))
1336+ [{
1337+ uri: params[:uri ],
1338+ mimeType: " application/json" ,
1339+ text: { id: match[:item_id ] }.to_json,
1340+ }]
1341+ else
1342+ raise MCP ::Server ::ResourceNotFoundError .new (params[:uri ], params)
1343+ end
1344+ end
1345+ ```
1346+
12041347### Roots
12051348
12061349The Model Context Protocol allows servers to request filesystem roots from clients through the ` roots/list ` method.
@@ -1793,6 +1936,40 @@ server.define_tool(name: "collect_contact", description: "Collect contact info")
17931936end
17941937```
17951938
1939+ The ` requested_schema ` must be a flat object schema: a top-level ` type: "object" ` whose ` properties ` are limited to
1940+ primitive types (` string ` , ` number ` , ` integer ` , ` boolean ` ). Nested objects and arrays are not allowed, which keeps
1941+ the schema simple enough for clients to render as a form. Per the MCP specification, the client validates
1942+ the user's input against this schema before returning it, so the ` content ` of an ` accept ` response matches the requested shape.
1943+
1944+ #### Default Values and Enums
1945+
1946+ Properties may declare a ` default ` value (SEP-1034), which clients use to pre-fill the form.
1947+ String properties may declare ` enum ` values, optionally with human-readable ` enumNames ` (SEP-1330), which clients render as a choice list:
1948+
1949+ ``` ruby
1950+ server.define_tool(name: " configure_deploy" , description: " Configure a deployment" ) do |server_context: |
1951+ result = server_context.create_form_elicitation(
1952+ message: " Configure the deployment" ,
1953+ requested_schema: {
1954+ type: " object" ,
1955+ properties: {
1956+ replicas: { type: " integer" , default: 3 },
1957+ verbose: { type: " boolean" , default: false },
1958+ environment: {
1959+ type: " string" ,
1960+ enum: [" dev" , " staging" , " prod" ],
1961+ enumNames: [" Development" , " Staging" , " Production" ],
1962+ default: " dev" ,
1963+ },
1964+ },
1965+ required: [" environment" ],
1966+ },
1967+ )
1968+
1969+ MCP ::Tool ::Response .new ([{ type: " text" , text: " Deploying to #{ result[:content ][:environment ] } " }])
1970+ end
1971+ ```
1972+
17961973#### URL Mode
17971974
17981975URL mode directs the user to an external URL for out-of-band interactions such as OAuth flows:
0 commit comments