or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

auth.mdindex.mdjsonrpc.mdmcp-capabilities.mdmcp-client.mdmcp-content.mdmcp-protocol.mdmcp-server.mdmcp-transports.mdoauthex.md
tile.json

mcp-content.mddocs/

MCP Content

The MCP content system provides polymorphic content types for representing text, images, audio, and resource references in messages, prompts, and tool results.

Content Interface

type Content interface {
	MarshalJSON() ([]byte, error)
	// Has unexported methods
}

All content types implement this interface. Content can be:

  • TextContent: Plain text
  • ImageContent: Base64-encoded images
  • AudioContent: Base64-encoded audio
  • ResourceLink: Reference to a resource
  • EmbeddedResource: Embedded resource contents

Text Content

type TextContent struct {
	Text        string
	Meta        Meta
	Annotations *Annotations
}

Represents textual content.

Fields:

  • Text: The text content
  • Meta: Additional metadata
  • Annotations: Display and usage hints

Methods:

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"]
  }
}

Image Content

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 metadata
  • Annotations: Display and usage hints

Methods:

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
  }
}

Audio Content

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 metadata
  • Annotations: Display and usage hints

Methods:

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"]
  }
}

Resource Link

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 URI
  • Name: Human-readable name
  • Title: Human-readable title
  • Description: Resource description
  • MIMEType: Resource MIME type
  • Size: Optional resource size in bytes
  • Meta: Additional metadata
  • Annotations: Display and usage hints

Methods:

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
  }
}

Embedded Resource

type EmbeddedResource struct {
	Resource    *ResourceContents
	Meta        Meta
	Annotations *Annotations
}

Contains embedded resource contents directly in the message.

Fields:

  • Resource: Resource contents
  • Meta: Additional metadata
  • Annotations: Display and usage hints

Methods:

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
  }
}

Resource Contents

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 URI
  • MIMEType: Resource MIME type
  • Text: Text content (for text-based resources)
  • Blob: Binary content (will be base64-encoded in JSON)
  • Meta: Additional metadata

Methods:

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,
}

Content Usage Patterns

In Tool Results

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
}

In Prompts

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
}

In Sampling Messages

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)

Reading Mixed Content

// 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)
		}
	}
}

Annotations

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 modification
  • Priority: 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),
	},
}

Best Practices

Text Content

  • Use for human-readable messages
  • Prefer TextContent over structured data for explanations
  • Use Annotations to indicate importance

Image Content

  • Always specify correct MIMEType
  • Consider size limits for embedded images
  • Use ResourceLink for large images

Audio Content

  • Support common formats (WAV, MP3, OGG)
  • Include duration information in Annotations if available
  • Consider streaming for long audio

Resource Links

  • Use when resources are large or external
  • Provide meaningful Name and Description
  • Include Size when known

Embedded Resources

  • Use for small, frequently accessed resources
  • Prefer Text for text-based formats (JSON, YAML, etc.)
  • Use Blob for binary formats

Content Type Detection

// 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"
	}
}

Creating Multi-Content Responses

// 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
}

JSON Unmarshaling

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.