mcp-searcher
by ljutreras
README.md
# MCP Server Template
Template hexagonal para crear MCP servers en Node.js/TypeScript.
**Objetivo: agregar un nuevo tool = crear 1 archivo + 1 línea.**
## Estructura
```
src/
├── index.ts ← entrypoint (3 líneas)
│
├── core/
│ ├── registry.ts ← ToolRegistry: registro + dispatcher automático
│ ├── server.ts ← factory de instancias McpServer
│ └── run.ts ← transporte dual stdio/HTTP
│
├── tools/
│ ├── index.ts ← ← ← ÚNICO ARCHIVO QUE EDITAS AL AGREGAR TOOLS
│ └── examples/
│ └── es-search.tool.ts ← ejemplo completo (patrón a seguir)
│
├── infra/
│ ├── clients/
│ │ └── elasticsearch.client.ts ← singleton de ES
│ └── formatters/
│ └── result.formatter.ts ← limpieza de resultados para el LLM
│
├── config/
│ ├── env.ts ← variables de entorno validadas con Zod
│ └── logger.ts ← pino → stderr (MCP-safe)
│
└── shared/
├── types/
│ └── tool.types.ts ← ToolDefinition interface
└── errors/
└── mcp.error.ts ← toMcpError / toMcpSuccess helpers
```
## Agregar un nuevo tool (3 pasos)
### Paso 1 — Crea `src/tools/mi-feature.tool.ts`
```typescript
import { z } from "zod";
import { ToolDefinition } from "../shared/types/tool.types.js";
import { toMcpSuccess } from "../shared/errors/mcp.error.js";
const MiInput = z.object({
param: z.string().describe("Descripción para el LLM"),
});
async function miHandler(input: z.infer<typeof MiInput>) {
// tu lógica aquí
return toMcpSuccess({ resultado: input.param });
}
export const miTool: ToolDefinition<z.infer<typeof MiInput>> = {
name: "mi_tool",
description: "Descripción para el LLM",
inputSchema: MiInput,
handler: miHandler,
};
```
### Paso 2 — Regístralo en `src/tools/index.ts`
```typescript
import { miTool } from "./mi-feature.tool.js";
export function registerAllTools(registry: ToolRegistry): void {
registry
.register(esSearchKeywordTool)
.register(miTool); // ← esta línea
}
```
### Paso 3 — Listo. El dispatcher, JSON Schema y listado MCP se actualizan solos.
## Variables de entorno
```env
SERVER_NAME=mi-mcp-server
SERVER_VERSION=1.0.0
MCP_TRANSPORT=stdio # stdio | http
PORT=3001
ELASTICSEARCH_URL=http://localhost:9200
LOG_LEVEL=info
```
## Comandos
```bash
npm install
npm run dev # dev stdio
npm run dev:http # dev MCP over HTTP
npm run prod # prod MCP over HTTP
```
## Regla de oro del MCP logging
**Nunca uses `console.log` en un MCP server en modo stdio.**
`stdout` es el canal del protocolo. Un `console.log` rompe el handshake.
Usa siempre `logger.info(...)` de `config/logger.ts` — escribe a stderr.