#!/usr/bin/env python3
"""
Servidor MCP personalizado con múltiples herramientas
Autor: Tu Nombre
"""
import asyncio
import os
import sys
import platform
import subprocess
from pathlib import Path
from typing import Any
import json
# Importar el SDK de MCP
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
# Crear instancia del servidor
app = Server("mi-servidor-mcp-python")
# ============================================
# DEFINIR LAS HERRAMIENTAS DISPONIBLES
# ============================================
@app.list_tools()
async def list_tools() -> list[Tool]:
"""Lista todas las herramientas disponibles"""
return [
Tool(
name="crear_archivo_escritorio",
description="Crea un archivo de texto en el escritorio del usuario",
inputSchema={
"type": "object",
"properties": {
"nombre_archivo": {
"type": "string",
"description": "Nombre del archivo (ej: 'nota.txt')"
},
"contenido": {
"type": "string",
"description": "Contenido que se escribirá en el archivo"
}
},
"required": ["nombre_archivo", "contenido"]
}
),
Tool(
name="leer_archivo",
description="Lee el contenido de un archivo desde cualquier ubicación",
inputSchema={
"type": "object",
"properties": {
"ruta": {
"type": "string",
"description": "Ruta completa del archivo a leer"
}
},
"required": ["ruta"]
}
),
Tool(
name="listar_archivos",
description="Lista todos los archivos y carpetas en un directorio",
inputSchema={
"type": "object",
"properties": {
"directorio": {
"type": "string",
"description": "Ruta del directorio (por defecto: escritorio)"
}
}
}
),
Tool(
name="eliminar_archivo",
description="Elimina un archivo del sistema",
inputSchema={
"type": "object",
"properties": {
"ruta": {
"type": "string",
"description": "Ruta completa del archivo a eliminar"
}
},
"required": ["ruta"]
}
),
Tool(
name="crear_carpeta",
description="Crea una nueva carpeta en la ubicación especificada",
inputSchema={
"type": "object",
"properties": {
"ruta": {
"type": "string",
"description": "Ruta completa donde crear la carpeta"
}
},
"required": ["ruta"]
}
),
Tool(
name="info_sistema",
description="Obtiene información detallada del sistema operativo",
inputSchema={
"type": "object",
"properties": {}
}
),
Tool(
name="ejecutar_comando",
description="Ejecuta un comando de terminal (usar con precaución)",
inputSchema={
"type": "object",
"properties": {
"comando": {
"type": "string",
"description": "Comando a ejecutar en la terminal"
}
},
"required": ["comando"]
}
),
Tool(
name="buscar_archivos",
description="Busca archivos por nombre en un directorio",
inputSchema={
"type": "object",
"properties": {
"directorio": {
"type": "string",
"description": "Directorio donde buscar"
},
"patron": {
"type": "string",
"description": "Patrón de búsqueda (ej: '*.txt', '*.py')"
}
},
"required": ["patron"]
}
),
Tool(
name="obtener_tamano_archivo",
description="Obtiene el tamaño de un archivo en bytes",
inputSchema={
"type": "object",
"properties": {
"ruta": {
"type": "string",
"description": "Ruta del archivo"
}
},
"required": ["ruta"]
}
)
]
# ============================================
# IMPLEMENTAR LA LÓGICA DE CADA HERRAMIENTA
# ============================================
@app.call_tool()
async def call_tool(name: str, arguments: Any) -> list[TextContent]:
"""Ejecuta la herramienta solicitada"""
try:
if name == "crear_archivo_escritorio":
return await crear_archivo_escritorio(arguments)
elif name == "leer_archivo":
return await leer_archivo(arguments)
elif name == "listar_archivos":
return await listar_archivos(arguments)
elif name == "eliminar_archivo":
return await eliminar_archivo(arguments)
elif name == "crear_carpeta":
return await crear_carpeta(arguments)
elif name == "info_sistema":
return await info_sistema()
elif name == "ejecutar_comando":
return await ejecutar_comando(arguments)
elif name == "buscar_archivos":
return await buscar_archivos(arguments)
elif name == "obtener_tamano_archivo":
return await obtener_tamano_archivo(arguments)
else:
return [TextContent(
type="text",
text=f"❌ Herramienta desconocida: {name}"
)]
except Exception as e:
return [TextContent(
type="text",
text=f"❌ Error al ejecutar {name}: {str(e)}"
)]
# ============================================
# FUNCIONES DE IMPLEMENTACIÓN
# ============================================
async def crear_archivo_escritorio(args: dict) -> list[TextContent]:
"""Crea un archivo en el escritorio"""
nombre_archivo = args["nombre_archivo"]
contenido = args["contenido"]
# Obtener ruta del escritorio
escritorio = Path.home() / "Desktop"
ruta_completa = escritorio / nombre_archivo
# Escribir archivo
with open(ruta_completa, "w", encoding="utf-8") as f:
f.write(contenido)
return [TextContent(
type="text",
text=f"✅ Archivo creado exitosamente:\n📁 Ubicación: {ruta_completa}\n📄 Tamaño: {len(contenido)} caracteres"
)]
async def leer_archivo(args: dict) -> list[TextContent]:
"""Lee el contenido de un archivo"""
ruta = Path(args["ruta"])
if not ruta.exists():
return [TextContent(
type="text",
text=f"❌ El archivo no existe: {ruta}"
)]
with open(ruta, "r", encoding="utf-8") as f:
contenido = f.read()
stats = ruta.stat()
return [TextContent(
type="text",
text=f"📄 Contenido del archivo: {ruta}\n📊 Tamaño: {stats.st_size} bytes\n\n─────────────────────\n{contenido}"
)]
async def listar_archivos(args: dict) -> list[TextContent]:
"""Lista archivos en un directorio"""
directorio = args.get("directorio")
if not directorio:
directorio = Path.home() / "Desktop"
else:
directorio = Path(directorio)
if not directorio.exists():
return [TextContent(
type="text",
text=f"❌ El directorio no existe: {directorio}"
)]
archivos = []
for item in directorio.iterdir():
icono = "📁" if item.is_dir() else "📄"
archivos.append(f"{icono} {item.name}")
return [TextContent(
type="text",
text=f"📂 Contenido de: {directorio}\n📊 Total: {len(archivos)} elementos\n\n" + "\n".join(archivos)
)]
async def eliminar_archivo(args: dict) -> list[TextContent]:
"""Elimina un archivo"""
ruta = Path(args["ruta"])
if not ruta.exists():
return [TextContent(
type="text",
text=f"❌ El archivo no existe: {ruta}"
)]
ruta.unlink()
return [TextContent(
type="text",
text=f"🗑️ Archivo eliminado exitosamente: {ruta}"
)]
async def crear_carpeta(args: dict) -> list[TextContent]:
"""Crea una carpeta"""
ruta = Path(args["ruta"])
ruta.mkdir(parents=True, exist_ok=True)
return [TextContent(
type="text",
text=f"📁 Carpeta creada exitosamente: {ruta}"
)]
async def info_sistema() -> list[TextContent]:
"""Obtiene información del sistema"""
import psutil
info = {
"sistema": platform.system(),
"version": platform.version(),
"arquitectura": platform.machine(),
"procesador": platform.processor(),
"python_version": platform.python_version(),
"usuario": os.getlogin(),
"directorio_home": str(Path.home()),
"directorio_actual": os.getcwd(),
"memoria_total": f"{psutil.virtual_memory().total / (1024**3):.2f} GB",
"memoria_disponible": f"{psutil.virtual_memory().available / (1024**3):.2f} GB",
"cpu_cores": psutil.cpu_count(),
"uso_cpu": f"{psutil.cpu_percent()}%"
}
texto = "💻 Información del Sistema:\n\n"
for key, value in info.items():
texto += f"{key}: {value}\n"
return [TextContent(type="text", text=texto)]
async def ejecutar_comando(args: dict) -> list[TextContent]:
"""Ejecuta un comando del sistema"""
comando = args["comando"]
try:
resultado = subprocess.run(
comando,
shell=True,
capture_output=True,
text=True,
timeout=30
)
salida = resultado.stdout if resultado.stdout else resultado.stderr
return [TextContent(
type="text",
text=f"⚙️ Comando ejecutado: {comando}\n\n✅ Resultado:\n{salida}"
)]
except subprocess.TimeoutExpired:
return [TextContent(
type="text",
text=f"❌ El comando excedió el tiempo límite de 30 segundos"
)]
except Exception as e:
return [TextContent(
type="text",
text=f"❌ Error al ejecutar comando: {str(e)}"
)]
async def buscar_archivos(args: dict) -> list[TextContent]:
"""Busca archivos por patrón"""
directorio = args.get("directorio", str(Path.home() / "Desktop"))
patron = args["patron"]
directorio_path = Path(directorio)
archivos_encontrados = list(directorio_path.rglob(patron))
if not archivos_encontrados:
return [TextContent(
type="text",
text=f"🔍 No se encontraron archivos que coincidan con '{patron}' en {directorio}"
)]
lista = "\n".join([f"📄 {archivo}" for archivo in archivos_encontrados[:50]])
return [TextContent(
type="text",
text=f"🔍 Archivos encontrados ({len(archivos_encontrados)}):\n\n{lista}"
)]
async def obtener_tamano_archivo(args: dict) -> list[TextContent]:
"""Obtiene el tamaño de un archivo"""
ruta = Path(args["ruta"])
if not ruta.exists():
return [TextContent(
type="text",
text=f"❌ El archivo no existe: {ruta}"
)]
tamano_bytes = ruta.stat().st_size
tamano_kb = tamano_bytes / 1024
tamano_mb = tamano_kb / 1024
return [TextContent(
type="text",
text=f"📊 Tamaño del archivo {ruta.name}:\n"
f"• {tamano_bytes} bytes\n"
f"• {tamano_kb:.2f} KB\n"
f"• {tamano_mb:.2f} MB"
)]
# ============================================
# INICIAR EL SERVIDOR
# ============================================
async def main():
"""Función principal para iniciar el servidor"""
async with stdio_server() as (read_stream, write_stream):
print("🚀 Servidor MCP Python iniciado correctamente", file=sys.stderr)
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
if __name__ == "__main__":
# Ejecutar el servidor
asyncio.run(main())