ai - AI Operations
Complete guide to AI operations in MCP.do - text generation, structured output, embeddings, and batch processing with support for multiple models including GPT-5, Claude Sonnet 4.5, Llama 4, Grok 4, and Gemini 2.5 Pro
ai - AI Operations
The ai primitive provides AI generation, embeddings, and batch processing capabilities through a unified interface. It supports multiple state-of-the-art models and enables both free-form text generation and structured output via JSON schemas.
Overview
The AI primitive is designed for:
- Text Generation: Generate natural language content with precise control
- Structured Output: Extract or generate data conforming to specific schemas
- Embeddings: Create vector representations for semantic search
- Batch Processing: Process multiple AI requests efficiently
- Dynamic Methods: Type-safe generation using
ai.generate${Noun}()pattern - Semantic Integration: Native support for Schema.org types via
$
Architecture
Type Signatures
interface AI {
// Generate text
generate(options: GenerateOptions): Promise<GenerateResult>
// Generate structured output
generate<T>(options: GenerateOptions & { schema: Record<string, unknown> }): Promise<GenerateResult & { data: T }>
// Chat completion
chat(options: ChatOptions): Promise<ChatResult>
// Generate embeddings
embed(text: string | string[], options?: EmbedOptions): Promise<number[][]>
// Batch processing
batch(requests: AIRequest[]): Promise<BatchResult>
}
// Enhanced AI with dynamic methods
type AIWithDynamicMethods = AI & {
[key: `generate${string}`]: <T = unknown>(options: Omit<GenerateOptions, 'schema'>) => Promise<T>
}
interface GenerateOptions {
prompt: string
model?: string
maxTokens?: number
temperature?: number
topP?: number
frequencyPenalty?: number
presencePenalty?: number
stop?: string[]
schema?: Record<string, unknown>
}
interface GenerateResult {
text: string
data?: unknown
model: string
usage: {
promptTokens: number
completionTokens: number
totalTokens: number
}
finishReason: 'stop' | 'length' | 'content_filter' | 'tool_calls'
}
interface ChatOptions {
messages: ChatMessage[]
model?: string
maxTokens?: number
temperature?: number
stream?: boolean
}
interface ChatMessage {
role: 'system' | 'user' | 'assistant'
content: string
}
interface EmbedOptions {
model?: string
dimensions?: number
}
interface AIRequest {
type: 'generate' | 'chat' | 'embed'
payload: GenerateOptions | ChatOptions | { text: string | string[]; options?: EmbedOptions }
id?: string
}
interface BatchResult {
results: Array<GenerateResult | ChatResult | { embeddings: number[][] }>
errors: Array<{ id?: string; error: string }>
}Supported Models
The AI worker provides access to the latest generation of AI models:
| Model | ID | Best For | Context | Notes |
|---|---|---|---|---|
| GPT-5 | gpt-5 | General purpose, reasoning | 128K | Default model, best overall |
| Claude Sonnet 4.5 | claude-sonnet-4.5 | Writing, analysis, code | 200K | Excellent for technical content |
| Llama 4 | llama-4 | Open source, privacy | 32K | Self-hosted option |
| Grok 4 | grok-4 | Real-time data, reasoning | 128K | Twitter/X integration |
| Gemini 2.5 Pro | gemini-2.5-pro | Multimodal, long context | 1M | Best for large documents |
Deprecated Models
The following models are deprecated and will be removed in a future release:
gpt-4*(usegpt-5)claude-3.5*(useclaude-sonnet-4.5)
Basic Text Generation
Simple Text Generation
Generate free-form text content:
const result = await ai.generate({
prompt: 'Write a product description for a smart coffee maker',
model: 'gpt-5',
})
console.log(result.text)
// "Introducing the SmartBrew 3000, a revolutionary coffee maker that..."
console.log(result.usage)
// { promptTokens: 12, completionTokens: 150, totalTokens: 162 }With Generation Parameters
Control output characteristics:
const result = await ai.generate({
prompt: 'Write a creative story about a time-traveling scientist',
model: 'claude-sonnet-4.5',
maxTokens: 1000,
temperature: 0.9, // Higher = more creative
topP: 0.95, // Nucleus sampling
frequencyPenalty: 0.5, // Reduce repetition
presencePenalty: 0.3, // Encourage topic diversity
stop: ['THE END', '\n\n\n'], // Stop sequences
})
console.log(result.text)
console.log(`Finish reason: ${result.finishReason}`)Model Selection Strategy
// For factual content - use GPT-5
const factual = await ai.generate({
prompt: 'Explain quantum computing in simple terms',
model: 'gpt-5',
temperature: 0.3, // Lower temperature for accuracy
})
// For creative writing - use Claude
const creative = await ai.generate({
prompt: 'Write a poem about artificial intelligence',
model: 'claude-sonnet-4.5',
temperature: 0.8, // Higher temperature for creativity
})
// For long documents - use Gemini
const longContext = await ai.generate({
prompt: `Summarize this document: ${largeDocument}`,
model: 'gemini-2.5-pro',
maxTokens: 2000,
})Structured Output
Basic Structured Generation
Generate data conforming to a schema:
import { z } from 'zod'
// Define schema
const ProductSchema = z.object({
name: z.string(),
price: z.number(),
description: z.string(),
features: z.array(z.string()),
category: z.enum(['electronics', 'clothing', 'food', 'other']),
})
// Generate with schema
const result = await ai.generate({
prompt: 'Generate a product for a wireless keyboard',
schema: ProductSchema,
model: 'gpt-5',
})
// Type-safe access to structured data
console.log(result.data.name) // Type: string
console.log(result.data.price) // Type: number
console.log(result.data.features) // Type: string[]Complex Nested Schemas
Generate complex structured data:
import { z } from 'zod'
const CompanySchema = z.object({
name: z.string(),
industry: z.string(),
employees: z.number(),
founded: z.number(),
headquarters: z.object({
city: z.string(),
country: z.string(),
address: z.string(),
}),
products: z.array(
z.object({
name: z.string(),
description: z.string(),
price: z.number(),
launched: z.number(),
})
),
leadership: z.array(
z.object({
name: z.string(),
title: z.string(),
bio: z.string(),
})
),
})
const company = await ai.generate({
prompt: 'Generate a fictional tech startup in the AI space',
schema: CompanySchema,
model: 'gpt-5',
})
console.log(company.data.name)
console.log(company.data.products[0].name)
console.log(company.data.leadership[0].title)Data Extraction
Extract structured data from unstructured text:
const EmailSchema = z.object({
from: z.string().email(),
to: z.array(z.string().email()),
subject: z.string(),
date: z.string(),
summary: z.string(),
actionItems: z.array(
z.object({
task: z.string(),
assignee: z.string().optional(),
dueDate: z.string().optional(),
})
),
sentiment: z.enum(['positive', 'neutral', 'negative']),
})
const emailText = `
From: [email protected]
To: [email protected], [email protected]
Subject: Q4 Planning Meeting
Hi team,
Let's schedule our Q4 planning meeting for next Tuesday at 2pm.
Bob - can you prepare the budget analysis?
Carol - please review the market research data.
Looking forward to a productive session!
Alice
`
const extracted = await ai.generate({
prompt: `Extract structured data from this email:\n\n${emailText}`,
schema: EmailSchema,
model: 'gpt-5',
})
console.log(extracted.data.actionItems)
// [
// { task: 'Prepare budget analysis', assignee: 'Bob', dueDate: 'Next Tuesday' },
// { task: 'Review market research data', assignee: 'Carol', dueDate: undefined }
// ]Dynamic Generate Methods
Using Registered Schemas
The AI primitive supports dynamic generate${Noun}() methods for registered schemas:
import { registerSchema, ai } from 'sdk.do'
import { z } from 'zod'
// Register a schema
registerSchema(
'Recipe',
z.object({
name: z.string(),
ingredients: z.array(
z.object({
item: z.string(),
amount: z.string(),
})
),
instructions: z.array(z.string()),
cookTime: z.string(),
servings: z.number(),
})
)
// Now use the dynamic method
const recipe = await ai.generateRecipe({
prompt: 'Generate a recipe for chocolate chip cookies',
})
// Returns just the data (no wrapper)
console.log(recipe.name) // Type: string
console.log(recipe.ingredients) // Type: Array<{item: string, amount: string}>
console.log(recipe.instructions) // Type: string[]Built-in Schema.org Types
Several Schema.org types are pre-registered:
// Person
const person = await ai.generatePerson({
prompt: 'Generate a fictional software engineer profile',
})
console.log(person.name)
console.log(person.email)
console.log(person.jobTitle)
// Organization
const org = await ai.generateOrganization({
prompt: 'Generate a tech startup profile',
})
console.log(org.name)
console.log(org.description)
console.log(org.address)
// Product
const product = await ai.generateProduct({
prompt: 'Generate a SaaS product',
})
console.log(product.name)
console.log(product.offers.price)
// Article
const article = await ai.generateArticle({
prompt: 'Write an article about remote work',
})
console.log(article.headline)
console.log(article.author)
console.log(article.datePublished)
// Event
const event = await ai.generateEvent({
prompt: 'Create a tech conference event',
})
console.log(event.name)
console.log(event.startDate)
console.log(event.location)Custom Namespace Registration
Register multiple schemas at once:
import { registerNamespace } from 'sdk.do'
import { z } from 'zod'
registerNamespace('ecommerce', {
Cart: z.object({
items: z.array(
z.object({
productId: z.string(),
quantity: z.number(),
price: z.number(),
})
),
total: z.number(),
customerId: z.string(),
}),
Order: z.object({
orderId: z.string(),
customerId: z.string(),
items: z.array(z.any()),
total: z.number(),
status: z.enum(['pending', 'processing', 'shipped', 'delivered']),
shippingAddress: z.object({
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.string(),
}),
}),
})
// Use with both plain and namespaced names
const cart = await ai.generateCart({ prompt: '...' })
const cart2 = await ai.generateEcommerceCart({ prompt: '...' })
const order = await ai.generateOrder({ prompt: '...' })
const order2 = await ai.generateEcommerceOrder({ prompt: '...' })Integration with $ (Semantic Types)
Using Semantic Schemas
Combine AI generation with semantic types:
import { $, ai, db } from 'sdk.do'
// Generate semantic entity
const business = await ai.generate({
prompt: 'Generate a coffee shop business',
schema: $.Business, // Use semantic schema
})
// Store in database
const saved = await db.create('Business', business.data)
// Create relationships
await db.relate({ type: 'Business', id: saved.id }, 'offers', { type: 'Product', id: product.id })Event-Driven AI Generation
import { $, ai, on, send } from 'sdk.do'
// Generate content when orders are created
on($.Order.created, async (order) => {
// Generate personalized thank you email
const email = await ai.generate({
prompt: `Write a thank you email for customer who ordered: ${order.items.map((i) => i.name).join(', ')}`,
schema: $.Email,
})
// Send email
await send($.Email.send, {
to: order.customer.email,
subject: email.data.subject,
body: email.data.body,
})
})Embeddings
Basic Embeddings
Generate vector embeddings for semantic search:
// Single text
const embedding = await ai.embed('Hello world')
console.log(embedding)
// [[0.123, -0.456, 0.789, ...]] // 1536 dimensions
// Multiple texts
const embeddings = await ai.embed(['First document', 'Second document', 'Third document'])
console.log(embeddings.length) // 3
console.log(embeddings[0].length) // 1536Semantic Search Implementation
import { ai, db } from 'sdk.do'
// Index documents
async function indexDocuments(documents: Array<{ id: string; text: string }>) {
// Generate embeddings
const texts = documents.map((d) => d.text)
const embeddings = await ai.embed(texts)
// Store with embeddings
for (let i = 0; i < documents.length; i++) {
await db.create('Document', {
id: documents[i].id,
text: documents[i].text,
embedding: embeddings[i],
})
}
}
// Search documents
async function searchDocuments(query: string, limit: number = 10) {
// Generate query embedding
const [queryEmbedding] = await ai.embed(query)
// Find similar documents (using cosine similarity)
const documents = await db.list('Document', { limit: 100 })
const results = documents.map((doc) => ({
...doc,
similarity: cosineSimilarity(queryEmbedding, doc.embedding),
}))
return results.sort((a, b) => b.similarity - a.similarity).slice(0, limit)
}
function cosineSimilarity(a: number[], b: number[]): number {
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0)
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0))
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0))
return dotProduct / (magnitudeA * magnitudeB)
}Custom Embedding Dimensions
// Smaller embeddings for performance
const smallEmbedding = await ai.embed('Hello world', {
dimensions: 256, // vs default 1536
})
// Use smaller model
const embedding = await ai.embed('Hello world', {
model: 'text-embedding-3-small',
})Chat Completions
Multi-Turn Conversations
const result = await ai.chat({
messages: [
{ role: 'system', content: 'You are a helpful coding assistant' },
{ role: 'user', content: 'How do I sort an array in JavaScript?' },
{ role: 'assistant', content: 'You can use the .sort() method...' },
{ role: 'user', content: 'What about sorting objects by a property?' },
],
model: 'gpt-5',
})
console.log(result.message.content)
console.log(result.usage)Building Conversational Agents
class ChatAgent {
private history: ChatMessage[] = []
constructor(systemPrompt: string) {
this.history.push({
role: 'system',
content: systemPrompt,
})
}
async chat(userMessage: string): Promise<string> {
// Add user message
this.history.push({
role: 'user',
content: userMessage,
})
// Get response
const result = await ai.chat({
messages: this.history,
model: 'claude-sonnet-4.5',
maxTokens: 500,
})
// Add assistant response to history
this.history.push(result.message)
return result.message.content
}
reset() {
this.history = this.history.slice(0, 1) // Keep system prompt
}
}
// Usage
const agent = new ChatAgent('You are a helpful business advisor')
const response1 = await agent.chat('How do I start a business?')
const response2 = await agent.chat('What about funding?')Batch Processing
Parallel AI Requests
Process multiple AI requests efficiently:
const results = await ai.batch([
{
type: 'generate',
payload: {
prompt: 'Write a product slogan',
maxTokens: 50,
},
id: 'slogan',
},
{
type: 'generate',
payload: {
prompt: 'Write a product tagline',
maxTokens: 30,
},
id: 'tagline',
},
{
type: 'embed',
payload: {
text: 'Product description text',
},
id: 'embedding',
},
])
console.log(results.results[0]) // Slogan result
console.log(results.results[1]) // Tagline result
console.log(results.results[2]) // Embedding result
// Check for errors
if (results.errors.length > 0) {
console.error('Failed requests:', results.errors)
}Bulk Content Generation
import { ai } from 'sdk.do'
async function generateProductDescriptions(products: Array<{ name: string; features: string[] }>) {
const requests = products.map((product, index) => ({
type: 'generate' as const,
payload: {
prompt: `Write a compelling product description for ${product.name} with features: ${product.features.join(', ')}`,
maxTokens: 200,
},
id: `product-${index}`,
}))
const results = await ai.batch(requests)
return results.results.map((result, index) => ({
productName: products[index].name,
description: (result as GenerateResult).text,
}))
}
const descriptions = await generateProductDescriptions([
{ name: 'Smart Watch', features: ['Heart rate monitor', 'GPS', 'Waterproof'] },
{ name: 'Wireless Earbuds', features: ['Noise canceling', '20hr battery', 'Touch controls'] },
{ name: 'Fitness Tracker', features: ['Sleep tracking', 'Step counter', '7-day battery'] },
])Mixed Request Types
// Generate and embed in one batch
const batch = await ai.batch([
{
type: 'generate',
payload: {
prompt: 'Summarize quarterly earnings',
maxTokens: 200,
schema: { summary: 'string', keyPoints: 'array' },
},
},
{
type: 'embed',
payload: {
text: ['Document 1 text', 'Document 2 text', 'Document 3 text'],
},
},
{
type: 'chat',
payload: {
messages: [{ role: 'user', content: 'What is the capital of France?' }],
},
},
])Readonly vs Authenticated Mode
Readonly Mode (Anonymous)
AI generation requires authentication due to computational costs:
// ❌ Will fail - requires authentication
const result = await ai.generate({
prompt: 'Hello world',
})
// Error: AuthenticationError - AI generation requires authenticationEmbeddings Are Readonly
Embeddings are available to anonymous users:
// ✅ Works without authentication
const embedding = await ai.embed('Search query text')Authenticated Mode
import { configure, ai } from 'sdk.do'
// Configure with API key
configure({
apiKey: process.env.API_KEY,
})
// ✅ Now works
const result = await ai.generate({
prompt: 'Write a story',
})Cost Optimization Strategies
Choose Appropriate Models
// Expensive: GPT-5 for simple task
const expensive = await ai.generate({
prompt: 'Capitalize this: hello world',
model: 'gpt-5', // Overkill
})
// Optimized: Smaller model
const optimized = await ai.generate({
prompt: 'Capitalize this: hello world',
model: 'gpt-3.5-turbo', // Sufficient
})Limit Token Usage
// Set appropriate maxTokens
const result = await ai.generate({
prompt: 'Write a one-sentence summary of quantum computing',
maxTokens: 50, // Prevent over-generation
temperature: 0.3, // More focused output
})Batch Related Requests
// Inefficient: Multiple separate calls
const slogan = await ai.generate({ prompt: 'Write a slogan' })
const tagline = await ai.generate({ prompt: 'Write a tagline' })
const description = await ai.generate({ prompt: 'Write a description' })
// Efficient: Single batch call
const results = await ai.batch([
{ type: 'generate', payload: { prompt: 'Write a slogan' } },
{ type: 'generate', payload: { prompt: 'Write a tagline' } },
{ type: 'generate', payload: { prompt: 'Write a description' } },
])Cache Embeddings
import { ai, db } from 'sdk.do'
async function getOrCreateEmbedding(text: string): Promise<number[]> {
// Check cache
const cached = await db.get('Embedding', text)
if (cached) {
return cached.vector
}
// Generate and cache
const [vector] = await ai.embed(text)
await db.create('Embedding', {
id: text,
vector,
createdAt: new Date(),
})
return vector
}Performance Considerations
Parallel Generation
// Sequential: Slow
const result1 = await ai.generate({ prompt: 'Task 1' })
const result2 = await ai.generate({ prompt: 'Task 2' })
const result3 = await ai.generate({ prompt: 'Task 3' })
// Parallel: Fast (use batch or Promise.all)
const [result1, result2, result3] = await Promise.all([ai.generate({ prompt: 'Task 1' }), ai.generate({ prompt: 'Task 2' }), ai.generate({ prompt: 'Task 3' })])
// Batch: Even better
const results = await ai.batch([
{ type: 'generate', payload: { prompt: 'Task 1' } },
{ type: 'generate', payload: { prompt: 'Task 2' } },
{ type: 'generate', payload: { prompt: 'Task 3' } },
])Streaming for UX
// Non-streaming: Wait for complete response
const result = await ai.generate({
prompt: 'Write a long article',
maxTokens: 2000,
})
// User waits 20-30 seconds
// Streaming: Progressive updates
const result = await ai.chat({
messages: [{ role: 'user', content: 'Write a long article' }],
stream: true,
})
// User sees text appear progressivelyTimeout Handling
import { ai, isSDKError } from 'sdk.do'
try {
const result = await ai.generate({
prompt: 'Write a very long document',
maxTokens: 4000,
model: 'gpt-5',
})
} catch (error) {
if (isSDKError(error) && error.code === 'NetworkError') {
console.error('Request timeout - try smaller maxTokens or different model')
}
throw error
}Common Pitfalls
Schema Mismatch
// ❌ Wrong: Schema doesn't match expected output
const result = await ai.generate({
prompt: 'Generate a person',
schema: z.object({
name: z.number(), // Wrong type!
age: z.string(), // Wrong type!
}),
})
// May fail or return unexpected results
// ✅ Correct: Schema matches semantic meaning
const result = await ai.generate({
prompt: 'Generate a person',
schema: z.object({
name: z.string(),
age: z.number(),
}),
})Overly Restrictive Schemas
// ❌ Too restrictive: Enum limits creativity
const result = await ai.generate({
prompt: 'Generate creative business ideas',
schema: z.object({
category: z.enum(['tech', 'retail']), // Only 2 options!
}),
})
// ✅ Better: Open string with validation
const result = await ai.generate({
prompt: 'Generate creative business ideas',
schema: z.object({
category: z.string().min(1),
}),
})Prompt Engineering Issues
// ❌ Vague prompt
const result = await ai.generate({
prompt: 'Write something',
})
// ✅ Specific prompt
const result = await ai.generate({
prompt: 'Write a 100-word product description for a wireless keyboard targeting software developers, emphasizing productivity features',
})Token Limit Errors
// ❌ Prompt + response exceeds model context
const result = await ai.generate({
prompt: veryLongDocument, // 100K tokens
maxTokens: 4000, // Total: 104K tokens
model: 'gpt-5', // Context: 128K tokens - OK
})
// But with smaller model:
const result = await ai.generate({
prompt: veryLongDocument, // 100K tokens
maxTokens: 4000,
model: 'llama-4', // Context: 32K tokens - FAILS!
})
// ✅ Use model with sufficient contextNot Handling Errors
// ❌ No error handling
const result = await ai.generate({ prompt: 'Hello' })
// ✅ Proper error handling
try {
const result = await ai.generate({ prompt: 'Hello' })
} catch (error) {
if (isSDKError(error)) {
if (error.code === 'RateLimitError') {
// Wait and retry
} else if (error.code === 'AuthenticationError') {
// Check API key
}
}
throw error
}Advanced Examples
Multi-Step AI Workflow
import { ai, db } from 'sdk.do'
async function analyzeCompetitor(url: string) {
// Step 1: Fetch website content
const content = await fetch(url).then((r) => r.text())
// Step 2: Extract company info
const company = await ai.generate({
prompt: `Extract company information from this website:\n${content}`,
schema: z.object({
name: z.string(),
description: z.string(),
products: z.array(z.string()),
targetMarket: z.string(),
}),
})
// Step 3: Generate competitive analysis
const analysis = await ai.generate({
prompt: `Analyze this competitor:\n${JSON.stringify(company.data, null, 2)}`,
schema: z.object({
strengths: z.array(z.string()),
weaknesses: z.array(z.string()),
opportunities: z.array(z.string()),
threats: z.array(z.string()),
}),
})
// Step 4: Generate strategic recommendations
const strategy = await ai.generate({
prompt: `Based on this competitive analysis, suggest strategies:\n${JSON.stringify(analysis.data, null, 2)}`,
schema: z.object({
recommendations: z.array(
z.object({
title: z.string(),
description: z.string(),
priority: z.enum(['high', 'medium', 'low']),
timeframe: z.string(),
})
),
}),
})
// Step 5: Store results
return await db.create('CompetitiveAnalysis', {
url,
company: company.data,
analysis: analysis.data,
strategy: strategy.data,
analyzedAt: new Date(),
})
}Content Moderation Pipeline
async function moderateContent(text: string) {
const moderation = await ai.generate({
prompt: `Analyze this content for safety:\n\n${text}`,
schema: z.object({
safe: z.boolean(),
categories: z.object({
hate: z.number().min(0).max(1),
violence: z.number().min(0).max(1),
sexual: z.number().min(0).max(1),
harassment: z.number().min(0).max(1),
}),
reasoning: z.string(),
}),
temperature: 0.1, // Low temperature for consistency
})
return moderation.data
}RAG (Retrieval Augmented Generation)
import { ai, db } from 'sdk.do'
async function answerQuestion(question: string) {
// Generate question embedding
const [questionEmbedding] = await ai.embed(question)
// Find relevant documents
const documents = await db.list('Document', { limit: 100 })
const relevant = documents
.map((doc) => ({
...doc,
similarity: cosineSimilarity(questionEmbedding, doc.embedding),
}))
.sort((a, b) => b.similarity - a.similarity)
.slice(0, 5)
// Generate answer with context
const context = relevant.map((d) => d.text).join('\n\n')
const answer = await ai.generate({
prompt: `Answer this question based on the context:
Context:
${context}
Question: ${question}
Answer:`,
model: 'gpt-5',
temperature: 0.3,
})
return {
answer: answer.text,
sources: relevant.map((d) => ({ id: d.id, title: d.title })),
}
}Cross-References
- $ - Semantic Types - Semantic schema integration
- db - Database Operations - Storing AI-generated content
- api - HTTP Client - External AI API integration
- on - Event Handlers - Event-driven AI workflows
- send - Event Publishing - Async AI processing
- Configuration - API key setup
- Authentication - Security model
See Also
- Model Context Protocol - MCP specification
- OpenAI API Reference - GPT models
- Anthropic API Reference - Claude models
- Zod Documentation - Schema validation
db - Database Operations
Complete guide to database CRUD operations, queries, relationships, and semantic data management on the .do platform
api - HTTP Client
Complete guide to HTTP operations and service proxy in MCP.do - external API calls, webhook handling, integration with Stripe, GitHub, Email, Composio, and Zapier