The MCP content system provides polymorphic content types for representing text, images, audio, and resource references in messages, prompts, and tool results.
type Content interface {
MarshalJSON() ([]byte, error)
// Has unexported methods
}All content types implement this interface. Content can be:
type TextContent struct {
Text string
Meta Meta
Annotations *Annotations
}Represents textual content.
Fields:
Text: The text contentMeta: Additional metadataAnnotations: Display and usage hintsMethods:
func (c *TextContent) MarshalJSON() ([]byte, error)Example:
content := &mcp.TextContent{
Text: "Hello, world!",
Annotations: &mcp.Annotations{
Priority: 1.0,
Audience: []mcp.Role{"user"},
},
}JSON Format:
{
"type": "text",
"text": "Hello, world!",
"annotations": {
"priority": 1.0,
"audience": ["user"]
}
}type ImageContent struct {
Meta Meta
Annotations *Annotations
Data []byte
MIMEType string
}Contains base64-encoded image data.
Fields:
Data: Raw image bytes (will be base64-encoded in JSON)MIMEType: Image MIME type (e.g., "image/png", "image/jpeg")Meta: Additional metadataAnnotations: Display and usage hintsMethods:
func (c *ImageContent) MarshalJSON() ([]byte, error)Example:
imageData, err := os.ReadFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
content := &mcp.ImageContent{
Data: imageData,
MIMEType: "image/jpeg",
Annotations: &mcp.Annotations{
Priority: 0.8,
},
}JSON Format:
{
"type": "image",
"data": "base64-encoded-image-data...",
"mimeType": "image/jpeg",
"annotations": {
"priority": 0.8
}
}type AudioContent struct {
Data []byte
MIMEType string
Meta Meta
Annotations *Annotations
}Contains base64-encoded audio data.
Fields:
Data: Raw audio bytes (will be base64-encoded in JSON)MIMEType: Audio MIME type (e.g., "audio/wav", "audio/mpeg")Meta: Additional metadataAnnotations: Display and usage hintsMethods:
func (c *AudioContent) MarshalJSON() ([]byte, error)Example:
audioData, err := os.ReadFile("speech.mp3")
if err != nil {
log.Fatal(err)
}
content := &mcp.AudioContent{
Data: audioData,
MIMEType: "audio/mpeg",
Annotations: &mcp.Annotations{
Audience: []mcp.Role{"user"},
},
}JSON Format:
{
"type": "audio",
"data": "base64-encoded-audio-data...",
"mimeType": "audio/mpeg",
"annotations": {
"audience": ["user"]
}
}type ResourceLink struct {
URI string
Name string
Title string
Description string
MIMEType string
Size *int64
Meta Meta
Annotations *Annotations
}A link to a resource without embedding its contents.
Fields:
URI: Resource URIName: Human-readable nameTitle: Human-readable titleDescription: Resource descriptionMIMEType: Resource MIME typeSize: Optional resource size in bytesMeta: Additional metadataAnnotations: Display and usage hintsMethods:
func (r *ResourceLink) MarshalJSON() ([]byte, error)Example:
size := int64(1024)
content := &mcp.ResourceLink{
URI: "file:///home/user/doc.pdf",
Name: "Documentation",
Title: "API Documentation",
Description: "Complete API reference",
MIMEType: "application/pdf",
Size: &size,
}JSON Format:
{
"type": "resource",
"resource": {
"uri": "file:///home/user/doc.pdf",
"name": "Documentation",
"title": "API Documentation",
"description": "Complete API reference",
"mimeType": "application/pdf",
"size": 1024
}
}type EmbeddedResource struct {
Resource *ResourceContents
Meta Meta
Annotations *Annotations
}Contains embedded resource contents directly in the message.
Fields:
Resource: Resource contentsMeta: Additional metadataAnnotations: Display and usage hintsMethods:
func (r *EmbeddedResource) MarshalJSON() ([]byte, error)Example:
content := &mcp.EmbeddedResource{
Resource: &mcp.ResourceContents{
URI: "config://app.json",
MIMEType: "application/json",
Text: `{"version": "1.0", "enabled": true}`,
},
Annotations: &mcp.Annotations{
Priority: 1.0,
},
}JSON Format:
{
"type": "resource",
"resource": {
"uri": "config://app.json",
"mimeType": "application/json",
"text": "{\"version\": \"1.0\", \"enabled\": true}"
},
"annotations": {
"priority": 1.0
}
}type ResourceContents struct {
URI string `json:"uri"`
MIMEType string `json:"mimeType,omitempty"`
Text string `json:"text,omitempty"`
Blob []byte `json:"blob,omitempty"`
Meta Meta `json:"_meta,omitempty"`
}Contents of a resource or sub-resource. Either Text or Blob should be set, not both.
Fields:
URI: Resource URIMIMEType: Resource MIME typeText: Text content (for text-based resources)Blob: Binary content (will be base64-encoded in JSON)Meta: Additional metadataMethods:
func (r *ResourceContents) MarshalJSON() ([]byte, error)Example (Text):
contents := &mcp.ResourceContents{
URI: "file:///config.yaml",
MIMEType: "text/yaml",
Text: "server:\n port: 8080\n",
}Example (Binary):
imageData, _ := os.ReadFile("logo.png")
contents := &mcp.ResourceContents{
URI: "file:///logo.png",
MIMEType: "image/png",
Blob: imageData,
}func myTool(ctx context.Context, req *mcp.CallToolRequest, input MyInput) (
*mcp.CallToolResult,
MyOutput,
error,
) {
// Return result with multiple content types
result := &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{
Text: "Operation completed successfully",
},
&mcp.ImageContent{
Data: chartImage,
MIMEType: "image/png",
},
&mcp.ResourceLink{
URI: "file:///report.pdf",
Name: "Full Report",
},
},
}
return result, output, nil
}func myPrompt(ctx context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
return &mcp.GetPromptResult{
Messages: []*mcp.PromptMessage{
{
Role: "user",
Content: &mcp.TextContent{
Text: "Analyze this image:",
},
},
{
Role: "user",
Content: &mcp.ImageContent{
Data: imageData,
MIMEType: "image/jpeg",
},
},
},
}, nil
}params := &mcp.CreateMessageParams{
MaxTokens: 1000,
Messages: []*mcp.SamplingMessage{
{
Role: "user",
Content: &mcp.TextContent{
Text: "What's in this image?",
},
},
{
Role: "user",
Content: &mcp.ImageContent{
Data: imageBytes,
MIMEType: "image/png",
},
},
},
}
result, err := session.CreateMessage(ctx, params)// Handle different content types
for _, content := range result.Content {
switch c := content.(type) {
case *mcp.TextContent:
fmt.Printf("Text: %s\n", c.Text)
case *mcp.ImageContent:
fmt.Printf("Image: %d bytes, type: %s\n", len(c.Data), c.MIMEType)
// Save or display image
os.WriteFile("output.png", c.Data, 0644)
case *mcp.AudioContent:
fmt.Printf("Audio: %d bytes, type: %s\n", len(c.Data), c.MIMEType)
case *mcp.ResourceLink:
fmt.Printf("Resource link: %s (%s)\n", c.URI, c.Name)
case *mcp.EmbeddedResource:
fmt.Printf("Embedded resource: %s\n", c.Resource.URI)
if c.Resource.Text != "" {
fmt.Printf(" Text: %s\n", c.Resource.Text)
}
}
}type Annotations struct {
Audience []Role `json:"audience,omitempty"`
LastModified string `json:"lastModified,omitempty"`
Priority float64 `json:"priority,omitempty"`
}Optional annotations for content objects to inform how they are used or displayed.
Fields:
Audience: Intended viewers (e.g., ["user"], ["assistant"])LastModified: ISO 8601 formatted timestamp of last modificationPriority: Importance from 0.0 (optional) to 1.0 (required)Example:
content := &mcp.TextContent{
Text: "Critical system alert",
Annotations: &mcp.Annotations{
Priority: 1.0,
Audience: []mcp.Role{"user"},
LastModified: time.Now().Format(time.RFC3339),
},
}// Helper function to detect content type
func getContentType(content mcp.Content) string {
switch content.(type) {
case *mcp.TextContent:
return "text"
case *mcp.ImageContent:
return "image"
case *mcp.AudioContent:
return "audio"
case *mcp.ResourceLink:
return "resource_link"
case *mcp.EmbeddedResource:
return "embedded_resource"
default:
return "unknown"
}
}// Tool that returns multiple content types
func analyzeImage(ctx context.Context, req *mcp.CallToolRequest, input AnalyzeInput) (
*mcp.CallToolResult,
AnalyzeOutput,
error,
) {
// Process image
analysis := performAnalysis(input.ImageData)
// Create annotated chart
chart := generateChart(analysis)
// Return multiple content pieces
result := &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{
Text: fmt.Sprintf("Analysis complete: %s", analysis.Summary),
Annotations: &mcp.Annotations{
Priority: 1.0,
Audience: []mcp.Role{"user"},
},
},
&mcp.ImageContent{
Data: chart,
MIMEType: "image/png",
Annotations: &mcp.Annotations{
Priority: 0.8,
},
},
&mcp.ResourceLink{
URI: "analysis://results/" + analysis.ID,
Name: "Detailed Results",
Description: "Full analysis with metrics",
MIMEType: "application/json",
},
},
}
return result, AnalyzeOutput{ID: analysis.ID}, nil
}When receiving Content from the protocol, use type assertions to access specific fields:
// Unmarshal from JSON
var msg mcp.PromptMessage
err := json.Unmarshal(data, &msg)
if err != nil {
log.Fatal(err)
}
// Access content
if text, ok := msg.Content.(*mcp.TextContent); ok {
fmt.Println(text.Text)
}The SDK automatically handles unmarshaling the correct Content implementation based on the "type" field in JSON.