Skip to content

Sanity MCP ByteBuddy Cookbook

This cookbook introduces how to use Sanity MCP to build intelligent content management systems for headless CMS, enabling ByteBuddy to automate content workflows.

Overview

Sanity MCP provides deep integration with Sanity CMS, allowing ByteBuddy to:

  • Automate content creation and management
  • Generate and optimize content intelligently
  • Manage multimedia assets
  • Schedule content publishing

Configuration

1. Install Sanity MCP

bash
npm install -g sanity-mcp-server

2. Configure ByteBuddy

json
{
  "mcpServers": {
    "sanity": {
      "command": "node",
      "args": ["sanity-mcp-server"],
      "env": {
        "SANITY_PROJECT_ID": "your-project-id",
        "SANITY_DATASET": "production",
        "SANITY_API_VERSION": "2023-01-01",
        "SANITY_TOKEN": "your-api-token"
      }
    }
  }
}

Use Cases

Scenario 1: Automatic Content Generation

typescript
// Intelligent content generation
class ContentGenerator {
  async generateArticle(topic: string, keywords: string[]) {
    // Generate article outline
    const outline = await this.generateOutline(topic, keywords);

    // Generate article content
    const content = await this.generateContent(outline);

    // Create Sanity document
    const document = await mcp.call("sanity.create", {
      _type: "article",
      title: topic,
      slug: {
        _type: "slug",
        current: this.generateSlug(topic),
      },
      publishedAt: new Date().toISOString(),
      author: {
        _type: "reference",
        _ref: "default-author-id",
      },
      categories: this.mapToCategories(keywords),
      body: this.convertToPortableText(content),
      seo: {
        title: topic,
        description: content.excerpt,
        keywords: keywords.join(", "),
      },
    });

    // Generate related images
    if (content.needsImage) {
      const image = await this.generateImage(topic);
      await this.attachImage(document._id, image);
    }

    return document;
  }

  private convertToPortableText(content: any) {
    return content.blocks.map((block) => ({
      _type: "block",
      _key: randomId(),
      style: block.type,
      markDefs: block.marks || [],
      children: block.text.map((text) => ({
        _type: "span",
        text: text.content,
        marks: text.marks || [],
      })),
    }));
  }
}

Scenario 2: Content Workflow Automation

typescript
// Content workflow management
class ContentWorkflow {
  async setupWorkflow() {
    // Set up content state change listeners
    mcp.on("document.created", async (event) => {
      if (event.document._type === "article") {
        await this.processNewArticle(event.document);
      }
    });

    mcp.on("document.updated", async (event) => {
      if (event.document._type === "article") {
        await this.processArticleUpdate(event.document);
      }
    });
  }

  private async processNewArticle(article: any) {
    // Content quality check
    const qualityCheck = await this.checkContentQuality(article);

    if (!qualityCheck.passed) {
      await this.updateDraftStatus(
        article._id,
        "needs-review",
        qualityCheck.issues,
      );
      return;
    }

    // SEO optimization
    const seoOptimization = await this.optimizeForSEO(article);
    await this.applySEOChanges(article._id, seoOptimization);

    // Automatically generate related content
    const relatedContent = await this.generateRelatedContent(article);
    await this.linkRelatedContent(article._id, relatedContent);

    // Notify review team
    await this.notifyReviewTeam(article._id);
  }

  private async checkContentQuality(article: any) {
    const checks = {
      wordCount: this.checkWordCount(article.body),
      readability: this.checkReadability(article.body),
      links: this.checkInternalLinks(article.body),
      images: this.checkImageOptimization(article.body),
    };

    const issues = [];

    if (checks.wordCount < 500) {
      issues.push(
        "Article word count is too low, recommend at least 500 words",
      );
    }

    if (checks.readability.score < 60) {
      issues.push(
        "Article readability is low, suggest simplifying sentence structure",
      );
    }

    if (checks.links.count < 2) {
      issues.push("Too few internal links, recommend adding related links");
    }

    return {
      passed: issues.length === 0,
      issues,
      score: this.calculateQualityScore(checks),
    };
  }
}

Media Management

1: Intelligent Image Processing

typescript
// Image intelligent management
class ImageManager {
  async processImage(imageId: string) {
    // Get image information
    const image = await mcp.call("sanity.getDocument", {
      id: imageId,
    });

    // Automatically generate multiple sizes
    const variants = await this.generateVariants(image);

    // Optimize image
    const optimized = await this.optimizeImage(image);

    // Generate ALT text
    const altText = await this.generateAltText(optimized);

    // Update document
    await mcp.call("sanity.patch", {
      id: imageId,
      set: {
        altText: altText,
        variants: variants,
        metadata: optimized.metadata,
      },
    });

    return optimized;
  }

  private async generateVariants(image: any) {
    const sizes = [
      { name: "thumbnail", width: 150, height: 150 },
      { name: "small", width: 400, height: 300 },
      { name: "medium", width: 800, height: 600 },
      { name: "large", width: 1200, height: 900 },
    ];

    const variants = [];

    for (const size of sizes) {
      const variant = await this.resizeImage(image, size);
      variants.push({
        _key: size.name,
        _type: "imageVariant",
        url: variant.url,
        width: size.width,
        height: size.height,
        size: variant.fileSize,
      });
    }

    return variants;
  }

  private async generateAltText(image: any) {
    // Use AI to analyze image content
    const analysis = await mcp.call("ai.analyzeImage", {
      imageUrl: image.url,
      features: ["objects", "text", "scenes"],
    });

    return this.formatAltText(analysis);
  }
}

2: Video Content Management

typescript
// Video content management
class VideoManager {
  async processVideo(videoId: string) {
    const video = await mcp.call("sanity.getDocument", {
      id: videoId,
    });

    // Generate thumbnail
    const thumbnail = await this.generateThumbnail(video);

    // Extract subtitles
    const subtitles = await this.extractSubtitles(video);

    // Generate video summary
    const summary = await this.generateVideoSummary(video);

    // Create preview clip
    const preview = await this.generatePreview(video);

    await mcp.call("sanity.patch", {
      id: videoId,
      set: {
        thumbnail: { _type: "image", asset: { _ref: thumbnail.id } },
        subtitles: subtitles,
        summary: summary,
        preview: { _type: "file", asset: { _ref: preview.id } },
        processed: true,
        processedAt: new Date().toISOString(),
      },
    });

    return { thumbnail, subtitles, summary, preview };
  }
}

Content Publishing

1: Intelligent Publishing Scheduling

typescript
// Publishing scheduling system
class PublishScheduler {
  async schedulePublishing(documentId: string, scheduleOptions: any) {
    // Analyze optimal publishing time
    const optimalTime = await this.analyzeOptimalPublishTime(documentId);

    // Set publishing schedule
    const schedule = await mcp.call("sanity.create", {
      _type: "publishSchedule",
      document: { _type: "reference", _ref: documentId },
      scheduledTime: optimalTime,
      timezone: scheduleOptions.timezone,
      channels: scheduleOptions.channels,
      conditions: scheduleOptions.conditions,
    });

    // Set up automation tasks
    await this.setupAutomationTasks(schedule._id);

    return schedule;
  }

  private async analyzeOptimalPublishTime(documentId: string) {
    // Get historical publishing data
    const historicalData = await mcp.call("sanity.query", {
      query: `*[_type == "article" && publishedAt < now()]{
        publishedAt,
        views,
        engagement
      } | order(publishedAt desc) [0..100]`,
    });

    // Analyze user activity times
    const engagementAnalysis = this.analyzeEngagementByTime(historicalData);

    // Consider content type
    const document = await mcp.call("sanity.getDocument", { id: documentId });
    const typeMultiplier = this.getTypeMultiplier(document._type);

    // Calculate optimal time
    return this.calculateOptimalTime(engagementAnalysis, typeMultiplier);
  }

  async executePublishing(scheduleId: string) {
    const schedule = await mcp.call("sanity.getDocument", { id: scheduleId });

    // Check publishing conditions
    const conditionsMet = await this.checkPublishConditions(
      schedule.conditions,
    );

    if (!conditionsMet) {
      await this.reschedulePublishing(scheduleId, "conditions_not_met");
      return;
    }

    // Publish document
    await this.publishDocument(schedule.document._ref);

    // Distribute to channels
    for (const channel of schedule.channels) {
      await this.distributeToChannel(schedule.document._ref, channel);
    }

    // Update status
    await mcp.call("sanity.patch", {
      id: scheduleId,
      set: {
        status: "published",
        publishedAt: new Date().toISOString(),
      },
    });
  }
}

SEO Optimization

1: Automatic SEO Optimization

typescript
// SEO optimizer
class SEOOptimizer {
  async optimizeDocument(documentId: string) {
    const document = await mcp.call("sanity.getDocument", {
      id: documentId,
    });

    const optimizations = {
      seo: await this.optimizeSEO(document),
      structure: await this.optimizeStructure(document),
      performance: await this.optimizePerformance(document),
      accessibility: await this.optimizeAccessibility(document),
    };

    // Apply optimizations
    await this.applyOptimizations(documentId, optimizations);

    return optimizations;
  }

  private async optimizeSEO(document: any) {
    const seoData = {
      title: this.optimizeTitle(document.title),
      description: this.generateMetaDescription(document.body),
      keywords: this.extractKeywords(document.body),
      openGraph: this.generateOpenGraphData(document),
      structuredData: this.generateStructuredData(document),
    };

    return seoData;
  }

  private generateStructuredData(document: any) {
    return {
      "@context": "https://schema.org",
      "@type": "Article",
      headline: document.title,
      description: document.seo?.description,
      author: {
        "@type": "Person",
        name: document.author?.name || "Anonymous",
      },
      datePublished: document.publishedAt,
      dateModified: document._updatedAt,
      mainEntityOfPage: {
        "@type": "WebPage",
        "@id": `https://yoursite.com/articles/${document.slug.current}`,
      },
    };
  }
}

Content Analysis

1: Content Performance Analysis

typescript
// Content performance analyzer
class ContentAnalyzer {
  async analyzeContentPerformance(timeRange: string = "30d") {
    // Get content data
    const content = await mcp.call("sanity.query", {
      query: `*[_type == "article" && publishedAt >= now() - $timeRange]{
        _id,
        title,
        publishedAt,
        views,
        engagement,
        conversionRate
      }`,
      variables: { timeRange },
    });

    // Calculate key metrics
    const metrics = {
      totalViews: this.sumField(content, "views"),
      avgEngagement: this.averageField(content, "engagement"),
      topPerforming: this.findTopPerforming(content),
      trends: this.analyzeTrends(content),
      recommendations: await this.generateRecommendations(content),
    };

    // Create analysis report
    const report = await this.createAnalyticsReport(metrics);

    return report;
  }

  private async generateRecommendations(content: any[]) {
    const recommendations = [];

    // Analyze characteristics of well-performing content
    const topPerformers = content
      .sort((a, b) => b.engagement - a.engagement)
      .slice(0, 5);

    const commonThemes = this.identifyCommonThemes(topPerformers);

    recommendations.push({
      type: "content_strategy",
      title: "Content Strategy Recommendations",
      description: `Top performing content focuses on: ${commonThemes.join(", ")}`,
      action: "Increase content creation on these topics",
    });

    // Identify improvement opportunities
    const lowPerforming = content.filter((c) => c.engagement < 0.1);
    if (lowPerforming.length > 0) {
      recommendations.push({
        type: "optimization",
        title: "Content Optimization Opportunities",
        description: `${lowPerforming.length} articles are underperforming`,
        action: "Re-optimize or update this content",
      });
    }

    return recommendations;
  }
}

Best Practices

1: Content Governance

typescript
// Content governance system
class ContentGovernance {
  async setupGovernanceRules() {
    const rules = {
      publishing: {
        requiredFields: ["title", "slug", "body", "author"],
        validationRules: [
          { field: "title", rule: "minLength(10)" },
          { field: "body", rule: "minLength(200)" },
          { field: "seo.description", rule: "maxLength(160)" },
        ],
      },
      quality: {
        minWordCount: 300,
        maxReadabilityScore: 12,
        requiredImages: 1,
        minInternalLinks: 2,
      },
      workflow: {
        reviewRequired: true,
        autoPublish: false,
        approvalLevels: 2,
      },
    };

    return await mcp.call("sanity.create", {
      _type: "governanceRules",
      rules: rules,
      version: "1.0.0",
      createdAt: new Date().toISOString(),
    });
  }
}

Through Sanity MCP, ByteBuddy can provide powerful content management capabilities, making content creation and management more intelligent and efficient.