Agent recipes

Content pipeline

An agent that ingests raw material, finds related context in your Brain, drafts a post, and schedules it.

This recipe chains both products together: take a raw input (a Loom transcript, a sales call note, a customer email), search your Brain for related context, draft a polished blog post that builds on your existing content, and schedule it.

The flow

Raw input (transcript, email, note)

brain.query — what have we already written on this topic?

LLM drafts new post, weaving in references to existing posts

blog.search_posts — verify no duplicate title

blog.list_categories + blog.list_tags — pick the right ones

blog.create_draft — store it as draft for human review

(human reviews, fixes typos)

blog.publish_post with scheduledFor = tomorrow 9am UTC

This is the highest-value MCP recipe because it stitches your knowledge base to your blog — every new post builds on what's already there instead of repeating it.

The full agent

import Anthropic from "@anthropic-ai/sdk";
 
const VLOZI = "https://mcp.vlozi.app";
const KEY = process.env.VLOZI_API_KEY!;
const anthropic = new Anthropic();
 
async function call(name: string, body: object) {
  const r = await fetch(`${VLOZI}/tools/${name}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${KEY}`,
      "content-type": "application/json",
      "x-agent-id": "content-pipeline",
    },
    body: JSON.stringify(body),
  });
  return r.json();
}
 
const SYSTEM = `You are the content pipeline agent.
 
Process:
1. Use brain.query to find existing posts/notes related to the input topic.
   Limit 5 chunks.
2. Use blog.search_posts to confirm no duplicate title already exists.
3. Use blog.list_categories and blog.list_tags to discover existing
   categories/tags. Prefer reuse over invention.
4. Draft a post that:
   - Builds on prior context (cite by paraphrasing, not copy-paste)
   - Has a 60-char SEO title
   - Has a 150-char excerpt
   - Is 600-1200 words
   - Uses headings (## level 2 max)
5. Use blog.create_draft to store the post.
6. Use blog.publish_post with scheduledFor exactly 24 hours from now —
   gives a human review window.
7. Report: post ID, slug, scheduled time, and a 2-sentence summary.
 
Voice: warm, concrete, no jargon. Always speak to ONE reader in 2nd person.`;
 
const tools = [
  // 5 tools — the agent picks among them
  { name: "brain_query", description: "Semantic search KB", input_schema: { type: "object", required: ["query"], properties: { query: { type: "string" }, limit: { type: "number" } } } },
  { name: "blog_search_posts", description: "Search posts by title/excerpt", input_schema: { type: "object", required: ["query"], properties: { query: { type: "string" } } } },
  { name: "blog_list_categories", description: "List categories", input_schema: { type: "object", properties: {} } },
  { name: "blog_list_tags", description: "List tags", input_schema: { type: "object", properties: {} } },
  { name: "blog_create_draft", description: "Create a new draft", input_schema: { type: "object", required: ["title"], properties: { title: { type: "string" }, content: { type: "string" }, excerpt: { type: "string" }, seoTitle: { type: "string" }, seoDescription: { type: "string" }, categoryId: { type: "string" }, tags: { type: "array", items: { type: "string" } } } } },
  { name: "blog_publish_post", description: "Publish or schedule", input_schema: { type: "object", required: ["id"], properties: { id: { type: "string" }, scheduledFor: { type: "string" } } } },
];
 
export async function runPipeline(rawInput: string) {
  const messages: any[] = [{ role: "user", content: `New raw input:\n\n${rawInput}` }];
 
  while (true) {
    const res = await anthropic.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 8192,
      system: SYSTEM,
      tools,
      messages,
    });
 
    if (res.stop_reason !== "tool_use") return res.content;
 
    const out: any[] = [];
    for (const b of res.content) {
      if (b.type === "tool_use") {
        const name = b.name.replace("_", ".");
        const result = await call(name, b.input);
        out.push({ type: "tool_result", tool_use_id: b.id, content: JSON.stringify(result) });
      }
    }
    messages.push({ role: "assistant", content: res.content });
    messages.push({ role: "user", content: out });
  }
}
 
// Use:
await runPipeline(`
[Loom transcript — sales call with Acme]
We talked about why their team picked Vlozi over Contentful. The big reasons:
- The headless Editor wasn't going to satisfy their content team — they want WYSIWYG
- They didn't want to run their own CDN
- Tag and category management was clunky in Contentful
- Vlozi's pricing was 40% lower at their volume
`);

Sample transcript

What you'll see in the response:

[tool_use brain.query]   { query: "headless CMS comparison Contentful" }
[tool_result]            3 chunks found, top similarity 0.81 (old post:
                          "Why we built Vlozi headless")
 
[tool_use blog.search_posts]  { query: "contentful comparison" }
[tool_result]                 No existing post with that title
 
[tool_use blog.list_categories]
[tool_result]            { categories: [{ id: "cat_competitive", name: "Competitive" }, ...] }
 
[tool_use blog.list_tags]
[tool_result]            { tags: [{ name: "comparison", postCount: 4 }, ...] }
 
[tool_use blog.create_draft]  {
                          title: "Acme switched from Contentful to Vlozi — here's why",
                          content: "...",
                          excerpt: "...",
                          categoryId: "cat_competitive",
                          tags: ["comparison", "customer-story"]
                        }
[tool_result]            { post: { id: "post_xxx", slug: "acme-switched-..." } }
 
[tool_use blog.publish_post]  {
                          id: "post_xxx",
                          scheduledFor: "2026-05-15T13:24:00.000Z"
                        }
[tool_result]            { post: { status: "scheduled" } }
 
[final]   Drafted "Acme switched from Contentful to Vlozi — here's why"
          (post_xxx). Scheduled for tomorrow 13:24 UTC. Built on prior post
          "Why we built Vlozi headless" — see paragraph 3.

The agent did 6 tool calls + 1 LLM draft, took ~15 seconds, used ~$0.04 of tokens.

Why this works

The agent is doing what a human content strategist does:

  1. Research (brain.query) — what do we already say about this?
  2. Dedupe (blog.search_posts) — have we already shipped this exact post?
  3. Categorize (list_categories + list_tags) — where does it belong?
  4. Draft (create_draft) — write it
  5. Stage (publish_post with scheduledFor) — set up review

Each step is a tool call. The LLM glues the steps together, makes editorial decisions, and writes prose. You get the leverage of a real CMS workflow with the speed of an agent.

MCP · Agent recipesEdit on GitHub