#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// Environment configuration
const SAPTIVA_API_KEY = process.env.SAPTIVA_API_KEY;
const SAPTIVA_BASE_URL = process.env.SAPTIVA_BASE_URL || "https://api.saptiva.com";
// Available Saptiva models
const SAPTIVA_MODELS = {
"Saptiva Turbo": {
description: "Fast responses, high concurrency. Based on Qwen 3:30B",
supportsTools: true,
supportsVision: false,
pricing: { input: 0.2, output: 0.6 },
},
"Saptiva Cortex": {
description: "Reasoning tasks with chain-of-thought. Based on Qwen 3:30B Think",
supportsTools: true,
supportsVision: false,
pricing: { input: 0.3, output: 0.8 },
},
"Saptiva Ops": {
description: "Complex cases, RAG, web search. Based on GPT OSS 20B",
supportsTools: false,
supportsVision: false,
pricing: { input: 0.2, output: 0.6 },
},
"Saptiva Legacy": {
description: "Compatibility with legacy tools. Based on LLama 3.3 70B",
supportsTools: true,
supportsVision: false,
pricing: { input: 0.2, output: 0.6 },
},
"Saptiva OCR": {
description: "Intelligent text extraction and image interpretation",
supportsTools: false,
supportsVision: true,
pricing: { input: 0.15, output: 0.5 },
},
"Saptiva Embed": {
description: "Semantic vectorization. Based on Qwen3 Embedding 8B",
supportsTools: false,
supportsVision: false,
pricing: { input: 0.01, output: 0 },
},
"Saptiva KAL": {
description: "Mexico-specific context and compliance. Based on Mistral Small 3.2 24B",
supportsTools: true,
supportsVision: false,
pricing: { input: 0.2, output: 0.6 },
},
} as const;
type SaptivaModel = keyof typeof SAPTIVA_MODELS;
// Zod schemas for input validation
const ChatCompletionSchema = z.object({
model: z.string().default("Saptiva Turbo"),
messages: z.array(
z.object({
role: z.enum(["system", "user", "assistant"]),
content: z.string(),
})
),
max_tokens: z.number().optional().default(600),
temperature: z.number().min(0).max(1).optional().default(0.7),
top_p: z.number().min(0).max(1).optional().default(0.9),
stream: z.boolean().optional().default(false),
});
const ReasoningSchema = z.object({
question: z.string().describe("The question or problem that requires reasoning"),
context: z.string().optional().describe("Additional context to help with reasoning"),
max_tokens: z.number().optional().default(1000),
});
const OCRRequestSchema = z.object({
image_url: z.string().describe("URL of the image or base64 encoded image (data:image/png;base64,...)"),
prompt: z.string().optional().default("Extract and describe the text content in this image"),
});
const EmbeddingRequestSchema = z.object({
text: z.string().describe("Text to convert to embedding vector"),
});
const BatchEmbeddingSchema = z.object({
texts: z.array(z.string()).describe("Array of texts to convert to embeddings"),
});
const HelpSchema = z.object({
topic: z.enum([
"quick_start",
"chat_example",
"reasoning_example",
"ocr_example",
"embedding_example",
"all_tools",
"curl_examples",
"agents_sdk"
]).optional().default("quick_start").describe("Help topic to display"),
});
// API request helper
async function saptivaRequest(endpoint: string, body: object): Promise<any> {
if (!SAPTIVA_API_KEY) {
throw new Error("SAPTIVA_API_KEY environment variable is not set");
}
const response = await fetch(`${SAPTIVA_BASE_URL}${endpoint}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${SAPTIVA_API_KEY}`,
},
body: JSON.stringify(body),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Saptiva API error (${response.status}): ${errorText}`);
}
return response.json();
}
// Create the MCP server
const server = new Server(
{
name: "mcp-saptiva",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "saptiva_chat",
description:
"Send a chat completion request to Saptiva AI models. Supports multiple models including Saptiva Turbo (fast), Cortex (reasoning), Legacy (tool-compatible), and more.",
inputSchema: {
type: "object",
properties: {
model: {
type: "string",
description: "Model to use. Options: Saptiva Turbo, Saptiva Cortex, Saptiva Ops, Saptiva Legacy, Saptiva KAL",
default: "Saptiva Turbo",
},
messages: {
type: "array",
description: "Array of message objects with role and content",
items: {
type: "object",
properties: {
role: { type: "string", enum: ["system", "user", "assistant"] },
content: { type: "string" },
},
required: ["role", "content"],
},
},
max_tokens: { type: "number", description: "Maximum tokens to generate", default: 600 },
temperature: { type: "number", description: "Sampling temperature (0.0 to 1.0)", default: 0.7 },
top_p: { type: "number", description: "Top-p sampling parameter (0.0 to 1.0)", default: 0.9 },
},
required: ["messages"],
},
},
{
name: "saptiva_reason",
description:
"Use Saptiva Cortex for complex reasoning tasks. Shows the model's chain-of-thought reasoning process along with the final answer. Best for math, logic, analysis, and multi-step problems.",
inputSchema: {
type: "object",
properties: {
question: { type: "string", description: "The question or problem that requires reasoning" },
context: { type: "string", description: "Additional context to help with reasoning" },
max_tokens: { type: "number", description: "Maximum tokens for the response", default: 1000 },
},
required: ["question"],
},
},
{
name: "saptiva_ocr",
description:
"Extract text from images using Saptiva OCR model. Supports both URLs and base64 encoded images. Great for document processing, receipt scanning, and image text extraction.",
inputSchema: {
type: "object",
properties: {
image_url: { type: "string", description: "URL of the image or base64 encoded image (format: data:image/png;base64,...)" },
prompt: { type: "string", description: "Instructions for what to extract or describe from the image", default: "Extract and describe the text content in this image" },
},
required: ["image_url"],
},
},
{
name: "saptiva_embed",
description:
"Generate semantic embeddings for text using Saptiva Embed model. Useful for similarity search, clustering, and RAG applications.",
inputSchema: {
type: "object",
properties: {
text: { type: "string", description: "Text to convert to embedding vector" },
},
required: ["text"],
},
},
{
name: "saptiva_batch_embed",
description:
"Generate embeddings for multiple texts at once. More efficient than calling saptiva_embed multiple times.",
inputSchema: {
type: "object",
properties: {
texts: {
type: "array",
items: { type: "string" },
description: "Array of texts to convert to embeddings",
},
},
required: ["texts"],
},
},
{
name: "saptiva_list_models",
description: "List all available Saptiva AI models with their capabilities, descriptions, and pricing.",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "saptiva_help",
description: `🎓 GUÍA PARA PRINCIPIANTES - Muestra ejemplos de peticiones y respuestas de la API de Saptiva.
Temas disponibles:
- quick_start: Inicio rápido con ejemplo básico
- chat_example: Ejemplo completo de chat con request/response
- reasoning_example: Ejemplo de razonamiento con Cortex
- ocr_example: Ejemplo de extracción de texto de imágenes
- embedding_example: Ejemplo de generación de embeddings
- all_tools: Lista de todas las herramientas disponibles
- curl_examples: Ejemplos en cURL para usar directamente
- agents_sdk: Información sobre Saptiva Agents SDK para construir agentes`,
inputSchema: {
type: "object",
properties: {
topic: {
type: "string",
enum: ["quick_start", "chat_example", "reasoning_example", "ocr_example", "embedding_example", "all_tools", "curl_examples", "agents_sdk"],
description: "Tema de ayuda a mostrar",
default: "quick_start",
},
},
},
},
],
};
});
// List available prompts
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "code_review",
description: "Review code for bugs, improvements, and best practices",
arguments: [
{ name: "code", description: "The code to review", required: true },
{ name: "language", description: "Programming language", required: false },
],
},
{
name: "explain_concept",
description: "Explain a technical concept in simple terms",
arguments: [
{ name: "concept", description: "The concept to explain", required: true },
{ name: "audience", description: "Target audience level (beginner, intermediate, expert)", required: false },
],
},
{
name: "write_documentation",
description: "Generate documentation for code or APIs",
arguments: [
{ name: "code", description: "The code to document", required: true },
{ name: "style", description: "Documentation style (docstring, markdown, jsdoc)", required: false },
],
},
{
name: "debug_help",
description: "Help debug an error or issue",
arguments: [
{ name: "error", description: "The error message or description", required: true },
{ name: "context", description: "Additional context about the issue", required: false },
],
},
{
name: "mexican_legal",
description: "Get help with Mexican legal and regulatory context using Saptiva KAL",
arguments: [
{ name: "question", description: "Legal or regulatory question", required: true },
{ name: "area", description: "Area of law (fiscal, laboral, mercantil, etc.)", required: false },
],
},
],
};
});
// Get prompt content
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "code_review":
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Please review the following ${args?.language || ""} code for bugs, potential improvements, and best practices:\n\n\`\`\`${args?.language || ""}\n${args?.code}\n\`\`\`\n\nProvide specific feedback on:\n1. Potential bugs or errors\n2. Performance improvements\n3. Code style and readability\n4. Security considerations`,
},
},
],
};
case "explain_concept":
const audienceMap: Record<string, string> = {
beginner: "someone new to programming",
intermediate: "a developer with some experience",
expert: "an experienced software engineer",
};
const audience = audienceMap[args?.audience || "intermediate"] || audienceMap.intermediate;
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Explain the concept of "${args?.concept}" to ${audience}. Use simple language, provide examples, and explain why it's important.`,
},
},
],
};
case "write_documentation":
const styleMap: Record<string, string> = {
docstring: "Python docstring format",
markdown: "Markdown documentation",
jsdoc: "JSDoc format",
};
const style = styleMap[args?.style || "markdown"] || styleMap.markdown;
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Generate ${style} documentation for the following code:\n\n\`\`\`\n${args?.code}\n\`\`\`\n\nInclude:\n- Description of what the code does\n- Parameters/arguments\n- Return values\n- Usage examples`,
},
},
],
};
case "debug_help":
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `I'm encountering the following error:\n\n${args?.error}\n\n${args?.context ? `Additional context: ${args.context}\n\n` : ""}Please help me:\n1. Understand what's causing this error\n2. Suggest potential solutions\n3. Explain how to prevent this in the future`,
},
},
],
};
case "mexican_legal":
return {
messages: [
{
role: "system",
content: {
type: "text",
text: "Eres un experto en legislación y regulaciones mexicanas. Proporciona información precisa y actualizada sobre temas legales en México, citando las leyes y normativas relevantes cuando sea posible.",
},
},
{
role: "user",
content: {
type: "text",
text: `${args?.area ? `[Área: ${args.area}]\n\n` : ""}${args?.question}`,
},
},
],
};
default:
throw new Error(`Unknown prompt: ${name}`);
}
});
// List available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "saptiva://models",
name: "Saptiva Models",
description: "List of available Saptiva AI models and their capabilities",
mimeType: "application/json",
},
{
uri: "saptiva://pricing",
name: "Saptiva Pricing",
description: "Pricing information for Saptiva models (per million tokens)",
mimeType: "application/json",
},
],
};
});
// Read resources
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === "saptiva://models") {
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(SAPTIVA_MODELS, null, 2),
},
],
};
}
if (uri === "saptiva://pricing") {
const pricing = Object.entries(SAPTIVA_MODELS).map(([name, info]) => ({
model: name,
input_per_million: `$${info.pricing.input}`,
output_per_million: `$${info.pricing.output}`,
}));
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(pricing, null, 2),
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "saptiva_chat": {
const input = ChatCompletionSchema.parse(args);
const response = await saptivaRequest("/v1/chat/completions", {
model: input.model,
messages: input.messages,
max_tokens: input.max_tokens,
temperature: input.temperature,
top_p: input.top_p,
stream: false,
});
const choice = response.choices?.[0];
const content = choice?.message?.content || "No response generated";
const reasoning = choice?.message?.reasoning_content;
let resultText = content;
if (reasoning) {
resultText = `**Reasoning:**\n${reasoning}\n\n**Response:**\n${content}`;
}
return {
content: [{ type: "text", text: resultText }],
};
}
case "saptiva_reason": {
const input = ReasoningSchema.parse(args);
const messages = [
{ role: "user" as const, content: input.context ? `Context: ${input.context}\n\nQuestion: ${input.question}` : input.question },
];
// Try Saptiva Cortex first, fall back to Saptiva Ops if it fails
let response;
let modelUsed = "Saptiva Cortex";
try {
response = await saptivaRequest("/v1/chat/completions", {
model: "Saptiva Cortex",
messages,
max_tokens: input.max_tokens,
});
} catch (cortexError) {
// Fallback to Saptiva Ops which also supports reasoning
modelUsed = "Saptiva Ops";
response = await saptivaRequest("/v1/chat/completions", {
model: "Saptiva Ops",
messages,
max_tokens: input.max_tokens,
});
}
const choice = response.choices?.[0];
const content = choice?.message?.content || "No response generated";
const reasoning = choice?.message?.reasoning_content;
let resultText = "";
if (reasoning) {
resultText = `## Reasoning Process\n${reasoning}\n\n## Answer\n${content}`;
} else {
resultText = content;
}
// Add model info if fallback was used
if (modelUsed === "Saptiva Ops") {
resultText = `*Note: Used ${modelUsed} (Cortex unavailable)*\n\n${resultText}`;
}
return {
content: [{ type: "text", text: resultText }],
};
}
case "saptiva_ocr": {
const input = OCRRequestSchema.parse(args);
const response = await saptivaRequest("/v1/chat/completions", {
model: "Saptiva OCR",
messages: [
{
role: "user",
content: [
{ type: "image_url", image_url: { url: input.image_url } },
{ type: "text", text: input.prompt },
],
},
],
});
const content = response.choices?.[0]?.message?.content || "No text extracted";
return {
content: [{ type: "text", text: content }],
};
}
case "saptiva_embed": {
const input = EmbeddingRequestSchema.parse(args);
const response = await saptivaRequest("/api/embed", {
model: "Saptiva Embed",
prompt: input.text,
});
return {
content: [
{
type: "text",
text: JSON.stringify({
model: response.model,
dimensions: response.embeddings?.length || 0,
embeddings: response.embeddings,
usage: response.usage,
}),
},
],
};
}
case "saptiva_batch_embed": {
const input = BatchEmbeddingSchema.parse(args);
const results = await Promise.all(
input.texts.map(async (text, index) => {
const response = await saptivaRequest("/api/embed", {
model: "Saptiva Embed",
prompt: text,
});
return {
index,
text: text.substring(0, 50) + (text.length > 50 ? "..." : ""),
dimensions: response.embeddings?.length || 0,
embeddings: response.embeddings,
};
})
);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
case "saptiva_list_models": {
const modelList = Object.entries(SAPTIVA_MODELS).map(([name, info]) => ({
name,
...info,
}));
return {
content: [{ type: "text", text: JSON.stringify(modelList, null, 2) }],
};
}
case "saptiva_help": {
const input = HelpSchema.parse(args);
const helpTopics: Record<string, string> = {
quick_start: `# 🚀 Inicio Rápido con Saptiva API
## ¿Qué es Saptiva?
Saptiva es una plataforma de IA que te da acceso a modelos de lenguaje potentes para:
- Generar texto y respuestas
- Analizar documentos e imágenes (OCR)
- Crear embeddings para búsqueda semántica
- Razonamiento complejo
## Ejemplo más simple posible:
### REQUEST (lo que envías):
\`\`\`json
{
"model": "Saptiva Turbo",
"messages": [
{
"role": "user",
"content": "¿Cuál es la capital de México?"
}
]
}
\`\`\`
### RESPONSE (lo que recibes):
\`\`\`json
{
"choices": [
{
"message": {
"role": "assistant",
"content": "La capital de México es Ciudad de México."
}
}
]
}
\`\`\`
## Estructura de messages:
- \`role: "system"\` → Instrucciones para el modelo (opcional)
- \`role: "user"\` → Lo que pregunta el usuario
- \`role: "assistant"\` → Respuesta del modelo
💡 Usa \`saptiva_help\` con topic="chat_example" para ver más detalles.`,
chat_example: `# 💬 Ejemplo Completo de Chat
## Endpoint
\`POST https://api.saptiva.com/v1/chat/completions\`
## Headers requeridos:
\`\`\`
Content-Type: application/json
Authorization: Bearer TU_API_KEY
\`\`\`
## REQUEST completo:
\`\`\`json
{
"model": "Saptiva Turbo",
"messages": [
{
"role": "system",
"content": "Eres un asistente amigable que responde en español."
},
{
"role": "user",
"content": "Explícame qué es una API en términos simples"
}
],
"max_tokens": 500,
"temperature": 0.7,
"top_p": 0.9
}
\`\`\`
## Explicación de parámetros:
- **model**: Modelo a usar (Saptiva Turbo es el más rápido)
- **messages**: Array de mensajes de la conversación
- **max_tokens**: Máximo de tokens en la respuesta (1 token ≈ 4 caracteres)
- **temperature**: Creatividad (0=determinístico, 1=creativo)
- **top_p**: Diversidad de vocabulario
## RESPONSE completa:
\`\`\`json
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1234567890,
"model": "Saptiva Turbo",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Una API es como un mesero en un restaurante..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 45,
"completion_tokens": 120,
"total_tokens": 165
}
}
\`\`\`
## Campos importantes de la respuesta:
- **choices[0].message.content**: La respuesta del modelo
- **usage**: Tokens usados (para calcular costos)
- **finish_reason**: "stop" = terminó normalmente`,
reasoning_example: `# 🧠 Ejemplo de Razonamiento (Saptiva Cortex)
Cortex es un modelo que "piensa en voz alta" - muestra su proceso de razonamiento.
## REQUEST:
\`\`\`json
{
"model": "Saptiva Cortex",
"messages": [
{
"role": "user",
"content": "Si tengo 3 manzanas y le doy 1 a mi amigo, luego compro 5 más, ¿cuántas tengo?"
}
],
"max_tokens": 500
}
\`\`\`
## RESPONSE:
\`\`\`json
{
"choices": [
{
"message": {
"role": "assistant",
"content": "Tienes **7 manzanas**.",
"reasoning_content": "Veamos paso a paso:
1. Empiezo con 3 manzanas
2. Le doy 1 a mi amigo: 3 - 1 = 2 manzanas
3. Compro 5 más: 2 + 5 = 7 manzanas
Por lo tanto, tengo 7 manzanas al final."
}
}
]
}
\`\`\`
## Campos especiales:
- **content**: Respuesta final
- **reasoning_content**: El proceso de pensamiento del modelo
💡 Usa Cortex para: matemáticas, lógica, análisis, problemas paso a paso`,
ocr_example: `# 📷 Ejemplo de OCR (Extracción de texto de imágenes)
## REQUEST con URL de imagen:
\`\`\`json
{
"model": "Saptiva OCR",
"messages": [
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://ejemplo.com/mi-documento.png"
}
},
{
"type": "text",
"text": "Extrae todo el texto de esta imagen"
}
]
}
]
}
\`\`\`
## REQUEST con imagen en Base64:
\`\`\`json
{
"model": "Saptiva OCR",
"messages": [
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgo..."
}
},
{
"type": "text",
"text": "¿Qué dice este documento?"
}
]
}
]
}
\`\`\`
## Notas importantes:
- Resolución recomendada: 150-300 DPI
- Tamaño máximo: 50 MB
- Formatos: PNG, JPG, PDF
- La imagen debe ser accesible públicamente si usas URL`,
embedding_example: `# 🔢 Ejemplo de Embeddings
Los embeddings convierten texto en vectores numéricos que capturan el SIGNIFICADO.
## Endpoint diferente:
\`POST https://api.saptiva.com/api/embed\`
## REQUEST:
\`\`\`json
{
"model": "Saptiva Embed",
"prompt": "Inteligencia artificial y aprendizaje automático"
}
\`\`\`
## RESPONSE:
\`\`\`json
{
"model": "Saptiva Embed",
"embeddings": [
0.0156, -0.0126, 0.0260, -0.0208, 0.0247, ...
// 4096 números en total
],
"usage": {
"prompt_tokens": 8,
"total_tokens": 8
}
}
\`\`\`
## ¿Para qué sirven los embeddings?
1. **Búsqueda semántica**: Encontrar documentos similares por significado
2. **Clustering**: Agrupar textos por tema
3. **RAG**: Retrieval Augmented Generation
4. **Detección de duplicados**: Encontrar contenido similar
## Ejemplo práctico:
- "Me gusta el café" → [0.1, 0.2, -0.3, ...]
- "Disfruto el café" → [0.1, 0.19, -0.31, ...] ← Vectores muy similares
- "El cielo es azul" → [-0.5, 0.8, 0.1, ...] ← Vector muy diferente`,
all_tools: `# 🛠️ Todas las Herramientas Disponibles
## Chat y Generación:
| Herramienta | Descripción |
|-------------|-------------|
| \`saptiva_chat\` | Chat con cualquier modelo |
| \`saptiva_reason\` | Razonamiento con Cortex (muestra pensamiento) |
## Embeddings:
| Herramienta | Descripción |
|-------------|-------------|
| \`saptiva_embed\` | Generar embedding de un texto |
| \`saptiva_batch_embed\` | Embeddings de múltiples textos |
## Visión:
| Herramienta | Descripción |
|-------------|-------------|
| \`saptiva_ocr\` | Extraer texto de imágenes |
## Utilidades:
| Herramienta | Descripción |
|-------------|-------------|
| \`saptiva_list_models\` | Ver modelos disponibles y precios |
| \`saptiva_help\` | Esta guía de ayuda |
## Modelos disponibles:
- **Saptiva Turbo**: Rápido, económico ($0.20/$0.60 por M tokens)
- **Saptiva Cortex**: Razonamiento con chain-of-thought
- **Saptiva Ops**: Casos complejos, RAG
- **Saptiva Legacy**: Compatibilidad con tools
- **Saptiva OCR**: Visión y extracción de texto
- **Saptiva Embed**: Vectorización semántica
- **Saptiva KAL**: Contexto mexicano (legal, fiscal)`,
curl_examples: `# 🖥️ Ejemplos cURL para Terminal
## 1. Chat básico:
\`\`\`bash
curl -X POST https://api.saptiva.com/v1/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer TU_API_KEY" \\
-d '{
"model": "Saptiva Turbo",
"messages": [
{"role": "user", "content": "Hola, ¿cómo estás?"}
]
}'
\`\`\`
## 2. Chat con sistema:
\`\`\`bash
curl -X POST https://api.saptiva.com/v1/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer TU_API_KEY" \\
-d '{
"model": "Saptiva Turbo",
"messages": [
{"role": "system", "content": "Responde siempre en español formal"},
{"role": "user", "content": "Explica qué es machine learning"}
],
"max_tokens": 500,
"temperature": 0.7
}'
\`\`\`
## 3. Razonamiento con Cortex:
\`\`\`bash
curl -X POST https://api.saptiva.com/v1/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer TU_API_KEY" \\
-d '{
"model": "Saptiva Cortex",
"messages": [
{"role": "user", "content": "Si 2x + 5 = 15, ¿cuánto vale x?"}
]
}'
\`\`\`
## 4. Embedding:
\`\`\`bash
curl -X POST https://api.saptiva.com/api/embed \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer TU_API_KEY" \\
-d '{
"model": "Saptiva Embed",
"prompt": "Texto para convertir en vector"
}'
\`\`\`
## 5. OCR con URL:
\`\`\`bash
curl -X POST https://api.saptiva.com/v1/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer TU_API_KEY" \\
-d '{
"model": "Saptiva OCR",
"messages": [
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "https://ejemplo.com/imagen.png"}},
{"type": "text", "text": "Extrae el texto"}
]
}
]
}'
\`\`\`
💡 Reemplaza TU_API_KEY con tu clave de https://lab.saptiva.com/`,
agents_sdk: `# 🤖 Saptiva Agents SDK
## ¿Qué es?
Un framework en Python para construir agentes de IA que pueden:
- Usar herramientas personalizadas (Custom Tools)
- Orquestar múltiples agentes
- Mantener conversaciones con memoria
- Ejecutar flujos complejos
## Instalación
\`\`\`bash
pip install saptiva-agents
\`\`\`
## Documentación Completa
📚 **https://saptiva.gitbook.io/saptiva-agents**
## Secciones principales:
- **Introducción**: Conceptos básicos
- **Custom Tools**: Crear herramientas personalizadas
- **Instalación**: Setup del entorno
- **Quick Start**: Primer agente en minutos
- **Tutorial**: Guías paso a paso
- **Avanzado**: Configuraciones avanzadas
- **Conceptos del Núcleo**: Arquitectura interna
- **Guía de Framework**: Integración con frameworks
- **Guía de Componentes**: Componentes disponibles
- **Patrones Multi-Agente**: Orquestación de agentes
- **Ejemplos**: Casos de uso reales
## PyPi
📦 **https://pypi.org/project/saptiva-agents/**
## Ejemplo rápido:
\`\`\`python
from saptiva_agents import Agent, Tool
# Definir una herramienta
@Tool
def buscar_clima(ciudad: str) -> str:
return f"El clima en {ciudad} es soleado"
# Crear agente
agent = Agent(
name="Asistente",
model="Saptiva Turbo",
tools=[buscar_clima]
)
# Ejecutar
respuesta = agent.run("¿Cómo está el clima en CDMX?")
\`\`\`
## Recursos adicionales:
- API Key: https://lab.saptiva.com/
- Documentación API: https://saptiva.gitbook.io/saptiva-docs
- Soporte: contacto@saptiva.com`,
};
const helpContent = helpTopics[input.topic] || helpTopics.quick_start;
return {
content: [{ type: "text", text: helpContent }],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [{ type: "text", text: `Error: ${errorMessage}` }],
isError: true,
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Saptiva MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});