Módulo 3: Tres Primitivas — Resources, Tools, Prompts
Mini-Proyecto: MCP Server con 1 Resource, 1 Tool, 1 Prompt
Mini-Proyecto: MCP Server con 1 Resource, 1 Tool, 1 Prompt
Descripción de la cápsula
Este es el momento. Has aprendido qué son Resources, Tools y Prompts. Has visto cómo se combinan. Ahora vas a construir tu primer MCP server funcional con las 3 primitivas trabajando juntas.
El server que vas a construir es deliberadamente mínimo: 1 resource, 1 tool, y 1 prompt. No es un server de producción — es tu primer prototipo, la semilla que escalarás en los módulos 4-8. El objetivo es que experimentes el ciclo completo: crear un server, registrar primitivas, conectarlo a Claude Code, y verificar que funciona.
Cuando termines esta cápsula, habrás pasado de "entiendo las primitivas de MCP" a "construí un MCP server que funciona." Ese es un milestone importante.
¿Qué vamos a construir?
El server: DevFiles
Un MCP server llamado devfiles-server que ayuda a gestionar archivos de desarrollo:
devfiles-server
├── Resource: project-structure
│ → Lista los archivos y carpetas de un directorio de proyecto
│ → URI: files://project/structure
│
├── Tool: create_file
│ → Crea un nuevo archivo con contenido especificado
│ → Incluye validación y manejo de errores
│
└── Prompt: refactoring-plan
→ Template para pedir un plan de refactoring de un archivo
→ Incluye criterios y formato estandarizado
Por qué estas 3 primitivas
- Resource (project-structure): Es lo más básico que un developer necesita — ver qué archivos tiene. El modelo necesita este contexto para ayudar.
- Tool (create_file): Crea archivos nuevos — la acción más simple con side effects reales. Puedes verificar que funcionó mirando tu filesystem.
- Prompt (refactoring-plan): Estandariza cómo pedir un refactoring — algo que developers hacen frecuentemente y donde la calidad del prompt importa.
Prerequisitos
Antes de empezar, verifica:
# Node.js v18+
node --version
# npm
npm --version
# npx
npx --version
# Claude Code
claude --version
Si algo falta, instálalo antes de continuar. No dejes el setup para después.
Paso 1: Crear el proyecto
Estructura de archivos
# Crear el directorio del proyecto
mkdir devfiles-server
cd devfiles-server
# Inicializar el proyecto
npm init -y
Instalar dependencias
# SDK de MCP para TypeScript
npm install @modelcontextprotocol/sdk
# Zod para validación de schemas
npm install zod
# TypeScript y types de Node
npm install -D typescript @types/node
Configurar TypeScript
Crea el archivo tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true
},
"include": ["src/**/*"]
}
Configurar package.json
Actualiza tu package.json:
{
"name": "devfiles-server",
"version": "1.0.0",
"description": "MCP server mínimo con 1 resource, 1 tool, 1 prompt",
"type": "module",
"main": "build/index.js",
"scripts": {
"build": "tsc",
"start": "node build/index.js",
"dev": "tsc && node build/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.22.0"
},
"devDependencies": {
"typescript": "^5.3.0",
"@types/node": "^20.0.0"
}
}
Crear la estructura de código
mkdir src
Tu proyecto debería verse así:
devfiles-server/
├── package.json
├── tsconfig.json
├── node_modules/
└── src/
└── index.ts ← aquí irá todo el código
Paso 2: Implementar el server
Crea el archivo src/index.ts con el código completo del server. Vamos sección por sección.
2.1: Imports y setup del server
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import * as fs from "fs/promises";
import * as path from "path";
const server = new McpServer({
name: "devfiles-server",
version: "1.0.0",
});
Qué hace cada import:
McpServer— La clase principal del SDK para crear un MCP serverStdioServerTransport— Transport que usa stdin/stdout para comunicación localz— Zod para definir y validar schemas de inputsfs/promises— API de filesystem asíncrono de Node.jspath— Utilidades para manejar rutas de archivos
2.2: Resource — Estructura del proyecto
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
server.resource(
"project-structure",
"files://project/structure",
{
description: "Estructura de archivos y carpetas del proyecto actual",
mimeType: "application/json",
},
async (uri) => {
async function getStructure(dir: string, prefix: string = ""): Promise<string[]> {
const entries = await fs.readdir(dir, { withFileTypes: true });
const result: string[] = [];
const filtered = entries.filter(
(e) => !e.name.startsWith(".") && e.name !== "node_modules"
);
for (const entry of filtered) {
const fullPath = path.join(dir, entry.name);
const relativePath = path.relative(PROJECT_DIR, fullPath);
if (entry.isDirectory()) {
result.push(`📁 ${prefix}${entry.name}/`);
const children = await getStructure(fullPath, prefix + " ");
result.push(...children);
} else {
const stats = await fs.stat(fullPath);
const sizeKB = (stats.size / 1024).toFixed(1);
result.push(`📄 ${prefix}${entry.name} (${sizeKB} KB)`);
}
}
return result;
}
try {
const structure = await getStructure(PROJECT_DIR);
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(
{
projectDir: PROJECT_DIR,
totalItems: structure.length,
structure: structure,
},
null,
2
),
},
],
};
} catch (error) {
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(
{
error: `No se pudo leer ${PROJECT_DIR}: ${error instanceof Error ? error.message : "error desconocido"}`,
},
null,
2
),
},
],
};
}
}
);
Puntos clave:
- El resource lee la estructura del directorio recursivamente
- Filtra archivos ocultos (
.git,.env) ynode_modules - Muestra el tamaño de cada archivo
- Maneja errores graciosamente (no crash si el directorio no existe)
2.3: Tool — Crear archivo
server.tool(
"create_file",
"Crea un nuevo archivo en el proyecto con el contenido especificado. Crea directorios intermedios si no existen.",
{
filePath: z
.string()
.describe(
"Ruta relativa del archivo a crear (e.g., 'src/utils/helpers.ts')"
),
content: z.string().describe("Contenido completo del archivo"),
overwrite: z
.boolean()
.default(false)
.describe(
"Si true, sobreescribe el archivo si ya existe. Default: false"
),
},
async ({ filePath, content, overwrite }) => {
// Validación de seguridad
if (filePath.includes("..")) {
return {
content: [
{
type: "text" as const,
text: "❌ Error de seguridad: la ruta no puede contener '..' (path traversal)",
},
],
isError: true,
};
}
const absolutePath = path.resolve(PROJECT_DIR, filePath);
// Verificar que la ruta está dentro del proyecto
if (!absolutePath.startsWith(PROJECT_DIR)) {
return {
content: [
{
type: "text" as const,
text: "❌ Error de seguridad: la ruta debe estar dentro del directorio del proyecto",
},
],
isError: true,
};
}
// Verificar si el archivo ya existe
if (!overwrite) {
try {
await fs.access(absolutePath);
return {
content: [
{
type: "text" as const,
text: `❌ El archivo '${filePath}' ya existe. Usa overwrite: true para sobreescribirlo.`,
},
],
isError: true,
};
} catch {
// El archivo no existe — podemos continuar
}
}
try {
// Crear directorios intermedios
const dir = path.dirname(absolutePath);
await fs.mkdir(dir, { recursive: true });
// Escribir el archivo
await fs.writeFile(absolutePath, content, "utf-8");
// Verificar que se creó correctamente
const stats = await fs.stat(absolutePath);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
message: `✅ Archivo creado: ${filePath}`,
details: {
path: filePath,
absolutePath,
size: `${(stats.size / 1024).toFixed(1)} KB`,
characters: content.length,
lines: content.split("\n").length,
},
},
null,
2
),
},
],
};
} catch (error) {
return {
content: [
{
type: "text" as const,
text: `❌ Error al crear archivo: ${error instanceof Error ? error.message : "error desconocido"}`,
},
],
isError: true,
};
}
}
);
Puntos clave:
- Validación de seguridad: previene path traversal con
.. - Verifica que la ruta está dentro del directorio del proyecto
- Crea directorios intermedios automáticamente
- Comportamiento explícito con
overwrite(no sobreescribe por default) - Retorna detalles del archivo creado: tamaño, líneas, characters
2.4: Prompt — Plan de refactoring
server.prompt(
"refactoring-plan",
"Genera un plan de refactoring detallado para un archivo del proyecto",
{
filePath: z
.string()
.describe(
"Ruta del archivo a refactorizar (e.g., 'src/index.ts')"
),
goal: z
.string()
.default("mejorar legibilidad y mantenibilidad")
.describe(
"Objetivo del refactoring (e.g., 'separar responsabilidades', 'mejorar performance')"
),
level: z
.enum(["conservative", "moderate", "aggressive"])
.default("moderate")
.describe(
"Nivel de refactoring: conservative (mínimos cambios), moderate (balance), aggressive (reestructuración completa)"
),
},
async ({ filePath, goal, level }) => {
const absolutePath = path.resolve(PROJECT_DIR, filePath);
let fileContent: string;
try {
fileContent = await fs.readFile(absolutePath, "utf-8");
} catch {
fileContent = `[No se pudo leer el archivo: ${filePath}. Verifica que existe.]`;
}
const levelDescription = {
conservative:
"Aplica cambios mínimos: renaming, extracción de constantes, limpieza de código muerto. No cambia la estructura general.",
moderate:
"Balance entre mejora y estabilidad: extrae funciones, separa responsabilidades, mejora tipos. Cambia estructura interna pero mantiene la API.",
aggressive:
"Reestructuración completa si es necesario: cambia patrones de diseño, separa en módulos, reescribe secciones. Puede cambiar la API.",
};
const lineCount = fileContent.split("\n").length;
return {
messages: [
{
role: "user" as const,
content: {
type: "resource" as const,
resource: {
uri: `file:///${absolutePath}`,
text: fileContent,
mimeType: "text/plain",
},
},
},
{
role: "user" as const,
content: {
type: "text" as const,
text: `Genera un plan de refactoring para este archivo.
**Archivo:** ${filePath} (${lineCount} líneas)
**Objetivo:** ${goal}
**Nivel:** ${level} — ${levelDescription[level]}
**El plan debe incluir:**
### 1. Análisis del estado actual
- Qué hace el archivo (propósito principal)
- Problemas identificados (code smells, complejidad, duplicación)
- Métricas: funciones/clases, líneas por función, nivel de anidación
### 2. Cambios propuestos
Para cada cambio:
- **Qué:** descripción del cambio
- **Por qué:** qué problema resuelve
- **Impacto:** alto/medio/bajo
- **Riesgo:** qué podría romperse
### 3. Orden de ejecución
- Lista ordenada de pasos (hacer primero lo de menor riesgo)
- Dependencias entre pasos
### 4. Código sugerido
- Snippets de cómo quedaría después del refactoring
- Antes/después para los cambios principales
### 5. Tests necesarios
- Qué tests agregar ANTES de refactorizar (safety net)
- Qué tests agregar DESPUÉS (verificar nuevo comportamiento)
### 6. Estimación
- Tiempo estimado para cada paso
- Tiempo total
Usa el tool create_file si necesitas crear archivos nuevos como parte del plan.`,
},
},
],
};
}
);
Puntos clave:
- Lee el contenido del archivo automáticamente
- Lo incluye como resource embebido en el prompt
- Tres niveles de refactoring para diferentes necesidades
- Formato de output detallado y consistente
- Conecta con el tool
create_filepara materializar el plan
2.5: Conectar el transport e iniciar el server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("DevFiles MCP Server running on stdio");
console.error(`Project directory: ${PROJECT_DIR}`);
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
Nota: Usamos console.error (no console.log) porque stdout está reservado para la comunicación MCP vía stdio. Los logs van a stderr.
Paso 3: Compilar y verificar
Compilar el proyecto
npm run build
Deberías ver la carpeta build/ con el archivo index.js compilado.
Verificar que compila sin errores
# Si hay errores de TypeScript, corrígelos antes de continuar
# Los errores más comunes:
# - Import paths sin extensión .js
# - Tipos faltantes
# - strict mode violations
Verificar que el server arranca
# Ejecutar directamente (debería imprimir a stderr y esperar input en stdin)
node build/index.js
# Si ves "DevFiles MCP Server running on stdio", funciona
# Presiona Ctrl+C para salir
Paso 4: Probar con MCP Inspector
Antes de conectar a Claude Code, prueba con MCP Inspector — una herramienta visual para interactuar con MCP servers:
# Ejecutar MCP Inspector apuntando a tu server
npx @modelcontextprotocol/inspector node build/index.js
En el Inspector:
-
Resources tab — Deberías ver
project-structure. Haz click para leerlo y verificar que retorna la estructura de archivos. -
Tools tab — Deberías ver
create_file. Prueba con:{ "filePath": "test-file.txt", "content": "Hola desde MCP Inspector!" }Verifica que el archivo se creó en tu filesystem.
-
Prompts tab — Deberías ver
refactoring-plan. Prueba con:{ "filePath": "src/index.ts", "goal": "mejorar legibilidad", "level": "conservative" }Verifica que genera el template completo con el contenido del archivo.
Troubleshooting del Inspector
"No se puede conectar al server":
# Verifica que el build existe
ls build/index.js
# Verifica que el server arranca manualmente
node build/index.js
# Debería imprimir a stderr y esperar
"Resource retorna error":
# Verifica que el directorio de proyecto existe
echo $PROJECT_DIR
ls $(pwd)
# Asegúrate de ejecutar desde el directorio correcto
cd /tu/directorio/de/proyecto
npx @modelcontextprotocol/inspector node /ruta/a/devfiles-server/build/index.js
"Tool create_file falla":
# Verifica permisos de escritura
touch test-perms.txt && rm test-perms.txt
# Si falla, hay un problema de permisos en el directorio
Paso 5: Conectar a Claude Code
Agregar el server a Claude Code
# Desde el directorio de tu server:
claude mcp add devfiles -s user -- node /ruta/absoluta/a/devfiles-server/build/index.js
Importante: Usa la ruta absoluta al archivo index.js. Para obtenerla:
# Desde el directorio del server
echo "$(pwd)/build/index.js"
Verificar la conexión
# Abrir Claude Code
claude
# Verificar que el server está conectado
/mcp
Deberías ver:
MCP Servers:
devfiles: connected
Tools:
- create_file
Resources:
- project-structure (files://project/structure)
Prompts:
- refactoring-plan
Probar cada primitiva en Claude Code
Probar el Resource:
Tú: "¿Qué archivos hay en mi proyecto?"
Claude Code debería usar el resource project-structure y mostrarte la estructura.
Probar el Tool:
Tú: "Crea un archivo llamado src/utils/constants.ts con constantes básicas del proyecto"
Claude Code debería usar create_file y crear el archivo. Verifica que existe:
cat src/utils/constants.ts
Probar el Prompt:
Tú: Usa el prompt refactoring-plan para analizar src/index.ts con nivel moderate
Claude Code debería generar un plan de refactoring detallado usando el template.
Paso 6: Experimentar
Ahora que tu server funciona, experimenta:
Experiment 1: Flujo combinado
Pide a Claude Code que use las 3 primitivas en secuencia:
"Primero muéstrame la estructura del proyecto.
Luego crea un archivo src/README.md con documentación básica.
Finalmente, usa el prompt de refactoring para analizar el index.ts."
Observa cómo Claude Code orquesta las 3 primitivas automáticamente.
Experiment 2: Configurar PROJECT_DIR
Puedes apuntar tu server a cualquier directorio:
# Remover la configuración actual
claude mcp remove devfiles
# Re-agregar apuntando a otro directorio
PROJECT_DIR=/ruta/a/otro/proyecto claude mcp add devfiles -s user -- node /ruta/a/devfiles-server/build/index.js
Experiment 3: Agregar un segundo resource
Agrega un resource que lea el package.json del proyecto. Verás esto como ejercicio más abajo — inténtalo por tu cuenta antes de ver la solución. Recompila (npm run build) y reinicia Claude Code para que detecte el cambio.
Implementación alternativa en Python
Si prefieres Python, el setup es más simple. El SDK de Python usa decoradores en lugar de métodos:
mkdir devfiles-server-py && cd devfiles-server-py
python -m venv venv && source venv/bin/activate
pip install mcp
La estructura del código sigue el mismo patrón — @server.resource() para resources, @server.tool() para tools, @server.prompt() para prompts. Puedes ver ejemplos completos en las cápsulas 02-04 de este módulo, donde cada primitiva incluye implementaciones en ambos lenguajes.
# Conectar a Claude Code
claude mcp add devfiles -s user -- python /ruta/absoluta/a/server.py
Verificación final
Checklist de éxito
Antes de dar por terminado el mini-proyecto, verifica:
- El server compila sin errores (
npm run buildsin warnings) - El server arranca (imprime a stderr y espera input)
- MCP Inspector muestra las 3 primitivas (Resources, Tools, Prompts tabs)
- El Resource retorna datos (estructura de archivos en JSON)
- El Tool crea archivos (verifica en tu filesystem)
- El Tool maneja errores (prueba con archivo existente y
overwrite: false) - El Prompt genera el template (con el contenido del archivo incluido)
- Claude Code conecta (
/mcpmuestradevfiles: connected) - Las 3 primitivas funcionan en Claude Code (prueba cada una)
Si algo del checklist falla, revisa la sección de Troubleshooting a continuación.
Troubleshooting
"Error: Cannot find module @modelcontextprotocol/sdk"
Causa: Las dependencias no se instalaron correctamente.
Solución:
rm -rf node_modules package-lock.json
npm install
npm run build
"Server arranca pero Claude Code muestra 0 tools"
Causa: El server se registra pero las primitivas no se declaran antes del connect().
Solución: Verifica que todas las llamadas a server.resource(), server.tool(), y server.prompt() están antes de server.connect(transport) en el código.
"Error: EPERM operation not permitted"
Causa: El proceso no tiene permisos para escribir en el directorio.
Solución:
# macOS: verificar permisos de la terminal
# System Preferences → Privacy & Security → Files and Folders
# Linux: verificar permisos del directorio
chmod 755 /tu/directorio
"El prompt no incluye el contenido del archivo"
Causa: El path del archivo es relativo y no se resuelve correctamente.
Solución: Verifica que PROJECT_DIR está configurado correctamente y que el archivo existe en esa ruta:
ls -la $(pwd)/src/index.ts
"Inspector funciona pero Claude Code no"
Causa: Diferencia en cómo se invoca el server.
Solución:
# Prueba exactamente el mismo comando que Claude Code ejecutará:
node /ruta/absoluta/build/index.js
# Si falla, el problema es la ruta o permisos
# Si funciona, re-agrega a Claude Code con la misma ruta exacta
Ejercicios de extensión
Ejercicio 1: Agregar un resource de package.json (Fácil)
Agrega un segundo resource que retorne el contenido del package.json del proyecto. Verifica que aparece en MCP Inspector y Claude Code.
Ver solución
server.resource(
"package-info",
"files://project/package",
{
description: "Contenido del package.json del proyecto",
mimeType: "application/json",
},
async (uri) => {
try {
const content = await fs.readFile(
path.join(PROJECT_DIR, "package.json"),
"utf-8"
);
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: content,
}],
};
} catch {
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify({ error: "package.json no encontrado" }),
}],
};
}
}
);
Agrega este código después del resource existente, recompila con npm run build, y reinicia Claude Code.
Ejercicio 2: Agregar un tool de búsqueda (Medio)
Agrega un tool search_in_files que busque un texto en todos los archivos del proyecto y retorne las coincidencias con número de línea.
Ver solución
server.tool(
"search_in_files",
"Busca un texto en todos los archivos del proyecto y retorna las coincidencias",
{
query: z.string().describe("Texto a buscar"),
extension: z.string().optional().describe("Filtrar por extensión (e.g., '.ts', '.py')"),
},
async ({ query, extension }) => {
const results: Array<{ file: string; line: number; text: string }> = [];
async function searchDir(dir: string): Promise<void> {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
await searchDir(fullPath);
} else {
if (extension && !entry.name.endsWith(extension)) continue;
try {
const content = await fs.readFile(fullPath, "utf-8");
const lines = content.split("\n");
lines.forEach((line, idx) => {
if (line.includes(query)) {
results.push({
file: path.relative(PROJECT_DIR, fullPath),
line: idx + 1,
text: line.trim(),
});
}
});
} catch {
// Saltar archivos binarios o sin permisos
}
}
}
}
await searchDir(PROJECT_DIR);
return {
content: [{
type: "text" as const,
text: JSON.stringify({
query,
totalMatches: results.length,
results: results.slice(0, 50),
truncated: results.length > 50,
}, null, 2),
}],
};
}
);
Ejercicio 3: Conectar con otro directorio (Medio)
Configura tu server para que funcione con 2 proyectos diferentes simultáneamente en Claude Code. Pista: puedes agregar el mismo server con diferentes nombres y diferentes PROJECT_DIR.
Ver solución
# Server para proyecto 1
claude mcp add devfiles-frontend -s user -- \
sh -c "PROJECT_DIR=/ruta/a/frontend node /ruta/a/devfiles-server/build/index.js"
# Server para proyecto 2
claude mcp add devfiles-backend -s user -- \
sh -c "PROJECT_DIR=/ruta/a/backend node /ruta/a/devfiles-server/build/index.js"
# Verificar
claude
/mcp
# Deberías ver:
# devfiles-frontend: connected
# devfiles-backend: connected
# Ahora puedes pedir:
# "Muéstrame la estructura del frontend" → usa devfiles-frontend
# "Crea un archivo en el backend" → usa devfiles-backend
El truco es usar sh -c para pasar la variable de entorno PROJECT_DIR al server. Cada instancia del server opera sobre su propio directorio.
Ejercicio 5: Implementar en Python (Difícil)
Replica el server devfiles-server completo en Python usando FastMCP. Usa @server.resource() para la estructura del proyecto, @server.tool() para create_file con las mismas validaciones de seguridad, y @server.prompt() para el plan de refactoring. Conéctalo a Claude Code y verifica que funciona.
Ver solución
Usa los ejemplos de Python de las cápsulas 02-04 como base. La estructura general:
from mcp.server.fastmcp import FastMCP
import os, json
from pathlib import Path
PROJECT_DIR = os.environ.get("PROJECT_DIR", os.getcwd())
server = FastMCP("devfiles-server")
@server.resource("files://project/structure")
async def project_structure() -> str:
# Escanear directorio recursivamente, filtrar .git y node_modules
...
@server.tool()
async def create_file(file_path: str, content: str, overwrite: bool = False) -> str:
# Validar path traversal, verificar existencia, crear dirs, escribir
...
@server.prompt()
async def refactoring_plan(file_path: str, goal: str = "mejorar legibilidad") -> str:
# Leer archivo, generar template con instrucciones detalladas
...
if __name__ == "__main__":
server.run()
Conéctalo: claude mcp add devfiles-py -s user -- python /ruta/a/server.py
Qué sigue
Resumen de lo que lograste
En este mini-proyecto:
- ✅ Creaste un proyecto MCP desde cero con TypeScript y el SDK oficial
- ✅ Implementaste las 3 primitivas: Resource, Tool, y Prompt
- ✅ Compilaste y verificaste que el server funciona
- ✅ Probaste con MCP Inspector (testing visual)
- ✅ Conectaste a Claude Code y verificaste las 3 primitivas
- ✅ Experimentaste con flujos combinados
Esto es un milestone. Construiste tu primer MCP server funcional. Ya no eres solo un usuario de MCP — eres un creador.
Conexión con los módulos siguientes
Lo que hiciste (Módulo 3):
→ Server mínimo: 1 resource, 1 tool, 1 prompt
→ Validación básica
→ Transport stdio
→ In-memory data
Lo que viene en Módulo 4 (MCP Server en TypeScript):
→ Server completo: múltiples resources, tools, prompts
→ Zod schemas avanzados con validación completa
→ Error handling robusto
→ Transports: stdio + HTTP/SSE
→ Conexión con APIs y databases reales
Lo que viene en Módulo 8 (Proyecto Final):
→ Server production-ready
→ Testing completo
→ Documentación profesional
→ Deploy y distribución
El server mínimo de este módulo es la semilla. En el módulo 4, lo expandirás con TypeScript avanzado. En el módulo 8, lo convertirás en un server que podrías publicar.
Resumen
En esta cápsula:
- Construiste tu primer MCP server (
devfiles-server) con las 3 primitivas - Resource (
project-structure): expone la estructura de archivos del proyecto - Tool (
create_file): crea archivos con validación de seguridad - Prompt (
refactoring-plan): genera planes de refactoring con contexto del archivo - Probaste con MCP Inspector y Claude Code
- Verificaste que las primitivas funcionan juntas en un flujo real
Próximo módulo: MCP Server en TypeScript — escala tu server mínimo a un server completo con múltiples tools tipados, Zod schemas avanzados, y transports reales.
Recursos adicionales
- MCP TypeScript SDK — Getting Started - Guía oficial de inicio rápido
- MCP Python SDK — Getting Started - Alternativa en Python
- MCP Inspector - Herramienta de testing visual
- Claude Code MCP Configuration - Cómo configurar servers en Claude Code
- Zod Documentation - Validación de schemas usada en el SDK
- MCP Servers Examples - Servers oficiales como referencia
- Awesome MCP Servers - Directorio de servers de la comunidad
- MCP Specification - Referencia técnica completa del protocolo