@karlangas12/openapi-to-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.es.md +130 -0
  3. package/README.md +222 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +169 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/telemetry/index.d.ts +78 -0
  8. package/dist/core/telemetry/index.js +152 -0
  9. package/dist/core/telemetry/index.js.map +1 -0
  10. package/dist/generator/codegen.d.ts +15 -0
  11. package/dist/generator/codegen.js +33 -0
  12. package/dist/generator/codegen.js.map +1 -0
  13. package/dist/generator/operations.d.ts +47 -0
  14. package/dist/generator/operations.js +143 -0
  15. package/dist/generator/operations.js.map +1 -0
  16. package/dist/http/client.d.ts +47 -0
  17. package/dist/http/client.js +92 -0
  18. package/dist/http/client.js.map +1 -0
  19. package/dist/http/format.d.ts +10 -0
  20. package/dist/http/format.js +22 -0
  21. package/dist/http/format.js.map +1 -0
  22. package/dist/index.d.ts +27 -0
  23. package/dist/index.js +18 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/mcp/jsonrpc.d.ts +43 -0
  26. package/dist/mcp/jsonrpc.js +27 -0
  27. package/dist/mcp/jsonrpc.js.map +1 -0
  28. package/dist/mcp/server.d.ts +32 -0
  29. package/dist/mcp/server.js +99 -0
  30. package/dist/mcp/server.js.map +1 -0
  31. package/dist/mcp/stdio.d.ts +10 -0
  32. package/dist/mcp/stdio.js +49 -0
  33. package/dist/mcp/stdio.js.map +1 -0
  34. package/dist/openapi/load.d.ts +15 -0
  35. package/dist/openapi/load.js +60 -0
  36. package/dist/openapi/load.js.map +1 -0
  37. package/dist/openapi/resolve.d.ts +20 -0
  38. package/dist/openapi/resolve.js +57 -0
  39. package/dist/openapi/resolve.js.map +1 -0
  40. package/dist/openapi/types.d.ts +94 -0
  41. package/dist/openapi/types.js +20 -0
  42. package/dist/openapi/types.js.map +1 -0
  43. package/dist/schema/to-json.d.ts +14 -0
  44. package/dist/schema/to-json.js +41 -0
  45. package/dist/schema/to-json.js.map +1 -0
  46. package/dist/schema/to-zod.d.ts +8 -0
  47. package/dist/schema/to-zod.js +131 -0
  48. package/dist/schema/to-zod.js.map +1 -0
  49. package/dist/utils/errors.d.ts +47 -0
  50. package/dist/utils/errors.js +81 -0
  51. package/dist/utils/errors.js.map +1 -0
  52. package/dist/utils/http.d.ts +46 -0
  53. package/dist/utils/http.js +70 -0
  54. package/dist/utils/http.js.map +1 -0
  55. package/dist/utils/index.d.ts +4 -0
  56. package/dist/utils/index.js +5 -0
  57. package/dist/utils/index.js.map +1 -0
  58. package/dist/utils/time.d.ts +27 -0
  59. package/dist/utils/time.js +32 -0
  60. package/dist/utils/time.js.map +1 -0
  61. package/package.json +74 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Telemetría unificada: logging estructurado y métricas.
3
+ *
4
+ * Diseño pensado para el edge:
5
+ * - Sin dependencias externas: el transporte por defecto es la consola.
6
+ * - Estructurado en JSON, para que Better Stack / Axiom lo indexen tal cual.
7
+ * - Redacción automática de secretos: nunca queremos una API key en los logs.
8
+ *
9
+ * Uso típico en un Worker:
10
+ *
11
+ * const log = createLogger({ level: config.LOG_LEVEL, service: 'mi-activo' });
12
+ * log.info('petición recibida', { path: '/v1/generar' });
13
+ */
14
+ /** Prioridad numérica de cada nivel, para filtrar por umbral. */
15
+ const LEVEL_PRIORITY = {
16
+ debug: 10,
17
+ info: 20,
18
+ warn: 30,
19
+ error: 40,
20
+ };
21
+ /**
22
+ * Claves cuyo valor se sustituye por `[REDACTADO]`.
23
+ *
24
+ * La comparación es por subcadena y sin distinguir mayúsculas, de modo que
25
+ * `x-api-key`, `API_KEY` o `stripeSecret` quedan cubiertos por igual.
26
+ */
27
+ const REDACTED_KEY_PATTERNS = [
28
+ 'key',
29
+ 'token',
30
+ 'secret',
31
+ 'password',
32
+ 'authorization',
33
+ 'cookie',
34
+ 'signature',
35
+ ];
36
+ const REDACTED_PLACEHOLDER = '[REDACTADO]';
37
+ /** Indica si el nombre de un campo debe redactarse. */
38
+ function shouldRedact(key) {
39
+ const normalized = key.toLowerCase();
40
+ return REDACTED_KEY_PATTERNS.some((pattern) => normalized.includes(pattern));
41
+ }
42
+ /**
43
+ * Recorre un valor y redacta los campos sensibles.
44
+ *
45
+ * Limita la profundidad para no atascarse con estructuras enormes o cíclicas
46
+ * (un log nunca debe ser el cuello de botella de una petición).
47
+ */
48
+ export function redact(value, depth = 0) {
49
+ if (depth > 6)
50
+ return '[PROFUNDIDAD_MÁXIMA]';
51
+ if (value === null || typeof value !== 'object')
52
+ return value;
53
+ if (value instanceof Error) {
54
+ return { name: value.name, message: value.message, stack: value.stack };
55
+ }
56
+ if (Array.isArray(value)) {
57
+ return value.map((item) => redact(item, depth + 1));
58
+ }
59
+ const result = {};
60
+ for (const [key, item] of Object.entries(value)) {
61
+ result[key] = shouldRedact(key) ? REDACTED_PLACEHOLDER : redact(item, depth + 1);
62
+ }
63
+ return result;
64
+ }
65
+ /** Transporte por defecto: una línea JSON por registro en la consola. */
66
+ export const consoleTransport = {
67
+ emit(record) {
68
+ const line = JSON.stringify(record);
69
+ if (record.level === 'error')
70
+ console.error(line);
71
+ else if (record.level === 'warn')
72
+ console.warn(line);
73
+ else
74
+ console.log(line);
75
+ },
76
+ };
77
+ /**
78
+ * Transporte HTTP genérico para Better Stack, Axiom o cualquier colector que
79
+ * acepte JSON por POST.
80
+ *
81
+ * Los envíos son "fire and forget": si el colector falla no queremos tumbar la
82
+ * petición del usuario. Pasa el `Promise` a `ctx.waitUntil()` en un Worker si
83
+ * necesitas garantizar la entrega antes de que muera el aislado.
84
+ */
85
+ export function createHttpTransport(options) {
86
+ return {
87
+ emit(record) {
88
+ const promise = fetch(options.url, {
89
+ method: 'POST',
90
+ headers: { 'Content-Type': 'application/json', ...options.headers },
91
+ body: JSON.stringify(record),
92
+ }).catch((error) => {
93
+ // Fallo del colector: lo dejamos en consola y seguimos.
94
+ console.error(JSON.stringify({
95
+ level: 'error',
96
+ message: 'No se pudo enviar la telemetría al colector remoto.',
97
+ error: String(error),
98
+ }));
99
+ });
100
+ options.onFlush?.(promise);
101
+ },
102
+ };
103
+ }
104
+ /** Emite cada registro a varios destinos a la vez. */
105
+ export function combineTransports(...transports) {
106
+ return {
107
+ emit(record) {
108
+ for (const transport of transports)
109
+ transport.emit(record);
110
+ },
111
+ };
112
+ }
113
+ /** Crea un logger estructurado. */
114
+ export function createLogger(options = {}) {
115
+ const level = options.level ?? 'info';
116
+ const service = options.service ?? 'motor3';
117
+ const transport = options.transport ?? consoleTransport;
118
+ const baseContext = options.context ?? {};
119
+ const now = options.now ?? (() => Date.now());
120
+ const threshold = LEVEL_PRIORITY[level];
121
+ const write = (recordLevel, message, context) => {
122
+ if (LEVEL_PRIORITY[recordLevel] < threshold)
123
+ return;
124
+ const merged = { ...baseContext, ...context };
125
+ transport.emit({
126
+ timestamp: new Date(now()).toISOString(),
127
+ level: recordLevel,
128
+ message,
129
+ service,
130
+ context: redact(merged),
131
+ });
132
+ };
133
+ return {
134
+ debug: (message, context) => write('debug', message, context),
135
+ info: (message, context) => write('info', message, context),
136
+ warn: (message, context) => write('warn', message, context),
137
+ error: (message, context) => write('error', message, context),
138
+ metric: (name, value, context) => write('info', `métrica: ${name}`, { ...context, metric: name, value }),
139
+ child: (context) => createLogger({
140
+ level,
141
+ service,
142
+ transport,
143
+ context: { ...baseContext, ...context },
144
+ now,
145
+ }),
146
+ };
147
+ }
148
+ /** Logger silencioso, útil en tests que no deben ensuciar la salida. */
149
+ export const silentLogger = createLogger({
150
+ transport: { emit: () => undefined },
151
+ });
152
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/telemetry/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { OpenApiDocument } from '../openapi/types.js';
2
+ export interface CodegenOptions {
3
+ /** Nombre del paquete del que importar el runtime. */
4
+ readonly packageName?: string;
5
+ /** URL base a incrustar (si la especificación no declara servers). */
6
+ readonly baseUrl?: string;
7
+ /** Nombre del servidor anunciado en `initialize`. */
8
+ readonly serverName?: string;
9
+ }
10
+ /**
11
+ * Genera el código de un servidor MCP autocontenido en TypeScript que sirve una
12
+ * especificación concreta. El resultado incrusta la especificación y arranca el
13
+ * runtime de este paquete: un único fichero listo para ejecutar con `tsx`/`node`.
14
+ */
15
+ export declare function generateServerCode(doc: OpenApiDocument, options?: CodegenOptions): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Genera el código de un servidor MCP autocontenido en TypeScript que sirve una
3
+ * especificación concreta. El resultado incrusta la especificación y arranca el
4
+ * runtime de este paquete: un único fichero listo para ejecutar con `tsx`/`node`.
5
+ */
6
+ export function generateServerCode(doc, options = {}) {
7
+ const packageName = options.packageName ?? '@karlangas12/openapi-to-mcp';
8
+ const serverName = options.serverName ?? doc.info?.title ?? 'openapi-mcp-server';
9
+ const baseUrlLiteral = JSON.stringify(options.baseUrl ?? doc.servers?.[0]?.url ?? '');
10
+ const specLiteral = JSON.stringify(doc, null, 2);
11
+ return `#!/usr/bin/env node
12
+ // Servidor MCP generado por openapi-to-mcp. No editar a mano: regenéralo.
13
+ import { buildTools, createMcpServer, startStdioServer } from '${packageName}';
14
+
15
+ const spec = ${specLiteral} as const;
16
+
17
+ const { tools, baseUrl } = buildTools(spec);
18
+ const resolvedBaseUrl = baseUrl ?? ${baseUrlLiteral};
19
+ if (resolvedBaseUrl === '') {
20
+ throw new Error('No hay URL base: define servers[] en la especificación o pásala al generar.');
21
+ }
22
+
23
+ const server = createMcpServer({
24
+ tools,
25
+ baseUrl: resolvedBaseUrl,
26
+ serverInfo: { name: ${JSON.stringify(serverName)}, version: '0.1.0' },
27
+ fetchFn: (url, init) => fetch(url, init as RequestInit | undefined) as never,
28
+ });
29
+
30
+ startStdioServer(server);
31
+ `;
32
+ }
33
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/generator/codegen.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAoB,EAAE,UAA0B,EAAE;IACnF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,6BAA6B,CAAC;IACzE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,oBAAoB,CAAC;IACjF,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjD,OAAO;;iEAEwD,WAAW;;eAE7D,WAAW;;;qCAGW,cAAc;;;;;;;;wBAQ3B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;;;;;CAKjD,CAAC;AACF,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ import type { HttpMethod, OpenApiDocument } from '../openapi/types.js';
3
+ import type { JsonValue } from '../schema/to-json.js';
4
+ export interface ParamBinding {
5
+ readonly name: string;
6
+ readonly in: 'path' | 'query' | 'header' | 'cookie';
7
+ readonly required: boolean;
8
+ }
9
+ export interface ToolBinding {
10
+ readonly method: HttpMethod;
11
+ readonly pathTemplate: string;
12
+ readonly params: readonly ParamBinding[];
13
+ readonly requestBody?: {
14
+ readonly required: boolean;
15
+ readonly contentType: string;
16
+ };
17
+ }
18
+ export interface JsonSchemaObject {
19
+ readonly type: 'object';
20
+ readonly properties: Readonly<Record<string, JsonValue>>;
21
+ readonly required: readonly string[];
22
+ readonly additionalProperties: boolean;
23
+ }
24
+ export interface ToolDefinition {
25
+ /** Nombre de la herramienta MCP, único y válido (`[a-z0-9_]`). */
26
+ readonly name: string;
27
+ readonly description: string;
28
+ /** JSON Schema que se expone en `tools/list`. */
29
+ readonly inputSchema: JsonSchemaObject;
30
+ /** Validador Zod de los argumentos entrantes. */
31
+ readonly input: z.ZodTypeAny;
32
+ readonly binding: ToolBinding;
33
+ }
34
+ export interface BuildToolsResult {
35
+ readonly tools: readonly ToolDefinition[];
36
+ /** URL base resuelta (opción explícita o primer `servers[].url`). */
37
+ readonly baseUrl: string | undefined;
38
+ }
39
+ export interface BuildToolsOptions {
40
+ /** Fuerza la URL base, ignorando la declarada en la especificación. */
41
+ readonly baseUrl?: string;
42
+ }
43
+ /**
44
+ * Construye la lista de herramientas MCP a partir de un documento OpenAPI: cada
45
+ * par método + ruta se convierte en una herramienta con su schema y su binding.
46
+ */
47
+ export declare function buildTools(doc: OpenApiDocument, options?: BuildToolsOptions): BuildToolsResult;
@@ -0,0 +1,143 @@
1
+ import { z } from 'zod';
2
+ import { RefResolver } from '../openapi/resolve.js';
3
+ import { HTTP_METHODS } from '../openapi/types.js';
4
+ import { schemaToZod } from '../schema/to-zod.js';
5
+ import { toJsonSchema } from '../schema/to-json.js';
6
+ /** Tipo de contenido preferido para los cuerpos de petición. */
7
+ const PREFERRED_CONTENT = 'application/json';
8
+ /**
9
+ * Construye la lista de herramientas MCP a partir de un documento OpenAPI: cada
10
+ * par método + ruta se convierte en una herramienta con su schema y su binding.
11
+ */
12
+ export function buildTools(doc, options = {}) {
13
+ const resolver = new RefResolver(doc);
14
+ const baseUrl = options.baseUrl ?? firstServerUrl(doc);
15
+ const tools = [];
16
+ const usedNames = new Set();
17
+ for (const [path, pathItem] of Object.entries(doc.paths ?? {})) {
18
+ const pathParams = pathItem.parameters ?? [];
19
+ for (const method of HTTP_METHODS) {
20
+ const operation = pathItem[method];
21
+ if (operation === undefined)
22
+ continue;
23
+ const params = mergeParameters(pathParams, operation.parameters ?? [], resolver);
24
+ const name = uniqueName(toolName(operation.operationId, method, path), usedNames);
25
+ const properties = {};
26
+ const shape = {};
27
+ const required = [];
28
+ const paramBindings = [];
29
+ for (const param of params) {
30
+ if (param.name === undefined || param.in === undefined)
31
+ continue;
32
+ const isRequired = param.required === true || param.in === 'path';
33
+ const schema = param.schema ?? { type: 'string' };
34
+ if (param.in !== 'cookie') {
35
+ properties[param.name] = toJsonSchema(schema, resolver);
36
+ const zod = schemaToZod(schema, resolver);
37
+ shape[param.name] = isRequired ? zod : zod.optional();
38
+ if (isRequired)
39
+ required.push(param.name);
40
+ }
41
+ paramBindings.push({ name: param.name, in: param.in, required: isRequired });
42
+ }
43
+ let requestBody;
44
+ const bodySchema = jsonBodySchema(operation.requestBody?.content);
45
+ if (bodySchema !== undefined) {
46
+ const bodyRequired = operation.requestBody?.required === true;
47
+ properties['body'] = toJsonSchema(bodySchema, resolver);
48
+ const zod = schemaToZod(bodySchema, resolver);
49
+ shape['body'] = bodyRequired ? zod : zod.optional();
50
+ if (bodyRequired)
51
+ required.push('body');
52
+ requestBody = { required: bodyRequired, contentType: PREFERRED_CONTENT };
53
+ }
54
+ const inputSchema = {
55
+ type: 'object',
56
+ properties,
57
+ required,
58
+ additionalProperties: false,
59
+ };
60
+ tools.push({
61
+ name,
62
+ description: describe(operation.summary, operation.description, method, path),
63
+ inputSchema,
64
+ input: z.object(shape).passthrough(),
65
+ binding: {
66
+ method,
67
+ pathTemplate: path,
68
+ params: paramBindings,
69
+ ...(requestBody === undefined ? {} : { requestBody }),
70
+ },
71
+ });
72
+ }
73
+ }
74
+ return { tools, baseUrl };
75
+ }
76
+ function firstServerUrl(doc) {
77
+ const url = doc.servers?.[0]?.url;
78
+ return typeof url === 'string' && url.length > 0 ? url : undefined;
79
+ }
80
+ /** Fusiona parámetros de nivel de ruta y de operación; la operación gana. */
81
+ function mergeParameters(pathParams, operationParams, resolver) {
82
+ const byKey = new Map();
83
+ for (const raw of [...pathParams, ...operationParams]) {
84
+ const param = raw.$ref !== undefined ? resolver.resolve(raw.$ref) : raw;
85
+ if (param.name === undefined || param.in === undefined)
86
+ continue;
87
+ byKey.set(`${param.in}:${param.name}`, param);
88
+ }
89
+ return [...byKey.values()];
90
+ }
91
+ /** Extrae el schema del cuerpo JSON, si la operación declara uno. */
92
+ function jsonBodySchema(content) {
93
+ if (content === undefined)
94
+ return undefined;
95
+ const direct = content[PREFERRED_CONTENT]?.schema;
96
+ if (direct !== undefined)
97
+ return direct;
98
+ // Cualquier tipo `*/*+json` o similar también vale.
99
+ for (const [type, media] of Object.entries(content)) {
100
+ if (/json/i.test(type) && media.schema !== undefined)
101
+ return media.schema;
102
+ }
103
+ return undefined;
104
+ }
105
+ /** Deriva el nombre de la herramienta: `operationId` o `metodo_ruta`. */
106
+ function toolName(operationId, method, path) {
107
+ if (operationId !== undefined && operationId.trim() !== '') {
108
+ return sanitizeName(operationId);
109
+ }
110
+ const segments = path
111
+ .split('/')
112
+ .filter((segment) => segment.length > 0)
113
+ .map((segment) => segment.replace(/^\{(.+)\}$/, 'by_$1'));
114
+ return sanitizeName([method, ...segments].join('_'));
115
+ }
116
+ /** Normaliza a `snake_case` válido para un nombre de herramienta MCP. */
117
+ function sanitizeName(raw) {
118
+ const snake = raw
119
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
120
+ .toLowerCase()
121
+ .replace(/[^a-z0-9]+/g, '_')
122
+ .replace(/^_+|_+$/g, '');
123
+ return snake.length > 0 ? snake : 'tool';
124
+ }
125
+ /** Garantiza que el nombre no colisione con otro ya generado. */
126
+ function uniqueName(base, used) {
127
+ if (!used.has(base)) {
128
+ used.add(base);
129
+ return base;
130
+ }
131
+ let index = 2;
132
+ while (used.has(`${base}_${index}`))
133
+ index += 1;
134
+ const name = `${base}_${index}`;
135
+ used.add(name);
136
+ return name;
137
+ }
138
+ function describe(summary, description, method, path) {
139
+ const text = summary ?? description;
140
+ const suffix = `(${method.toUpperCase()} ${path})`;
141
+ return text !== undefined && text.trim() !== '' ? `${text} ${suffix}` : `${method.toUpperCase()} ${path}`;
142
+ }
143
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/generator/operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOnD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AA6CpD,gEAAgE;AAChE,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAoB,EAAE,UAA6B,EAAE;IAC9E,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACvD,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/D,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;QAE7C,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,SAAS,KAAK,SAAS;gBAAE,SAAS;YAEtC,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;YACjF,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;YAElF,MAAM,UAAU,GAA8B,EAAE,CAAC;YACjD,MAAM,KAAK,GAAiC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,aAAa,GAAmB,EAAE,CAAC;YAEzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS;oBAAE,SAAS;gBACjE,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC;gBAClE,MAAM,MAAM,GAAiB,KAAK,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;gBAEhE,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;oBAC1B,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;oBACxD,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAC1C,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBACtD,IAAI,UAAU;wBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5C,CAAC;gBACD,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;YAC/E,CAAC;YAED,IAAI,WAAuC,CAAC;YAC5C,MAAM,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAClE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,YAAY,GAAG,SAAS,CAAC,WAAW,EAAE,QAAQ,KAAK,IAAI,CAAC;gBAC9D,UAAU,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACxD,MAAM,GAAG,GAAG,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBAC9C,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACpD,IAAI,YAAY;oBAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxC,WAAW,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC;YAC3E,CAAC;YAED,MAAM,WAAW,GAAqB;gBACpC,IAAI,EAAE,QAAQ;gBACd,UAAU;gBACV,QAAQ;gBACR,oBAAoB,EAAE,KAAK;aAC5B,CAAC;YAEF,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI;gBACJ,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC;gBAC7E,WAAW;gBACX,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;gBACpC,OAAO,EAAE;oBACP,MAAM;oBACN,YAAY,EAAE,IAAI;oBAClB,MAAM,EAAE,aAAa;oBACrB,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;iBACtD;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,cAAc,CAAC,GAAoB;IAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;IAClC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAED,6EAA6E;AAC7E,SAAS,eAAe,CACtB,UAAsC,EACtC,eAA2C,EAC3C,QAAqB;IAErB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjD,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,UAAU,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAgC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxG,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS;YAAE,SAAS;QACjE,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,qEAAqE;AACrE,SAAS,cAAc,CACrB,OAAwE;IAExE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAClD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,oDAAoD;IACpD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC5E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,SAAS,QAAQ,CAAC,WAA+B,EAAE,MAAkB,EAAE,IAAY;IACjF,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI;SAClB,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;SACvC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,OAAO,YAAY,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,yEAAyE;AACzE,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,KAAK,GAAG,GAAG;SACd,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3C,CAAC;AAED,iEAAiE;AACjE,SAAS,UAAU,CAAC,IAAY,EAAE,IAAiB;IACjD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACf,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CACf,OAA2B,EAC3B,WAA+B,EAC/B,MAAkB,EAClB,IAAY;IAEZ,MAAM,IAAI,GAAG,OAAO,IAAI,WAAW,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,GAAG,CAAC;IACnD,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC;AAC5G,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { ToolDefinition } from '../generator/operations.js';
2
+ /**
3
+ * Forma mínima del cliente HTTP que necesita el activo, desacoplada del `fetch`
4
+ * global. Cualquier `fetch` de Node lo satisface de forma estructural, y un test
5
+ * puede inyectar un doble sin depender de la red.
6
+ */
7
+ export type FetchLike = (input: string, init?: FetchInit) => Promise<FetchResponse>;
8
+ export interface FetchInit {
9
+ method?: string;
10
+ headers?: Record<string, string>;
11
+ body?: string;
12
+ }
13
+ export interface FetchResponse {
14
+ status: number;
15
+ ok: boolean;
16
+ headers: {
17
+ get(name: string): string | null;
18
+ };
19
+ text(): Promise<string>;
20
+ }
21
+ export interface ExecuteOptions {
22
+ /** URL base de la API subyacente (sin barra final relevante). */
23
+ readonly baseUrl: string;
24
+ /** Cabeceras estáticas (autenticación, contenido) que se envían siempre. */
25
+ readonly headers?: Readonly<Record<string, string>>;
26
+ /** Cliente HTTP. Inyectable para los tests. */
27
+ readonly fetchFn: FetchLike;
28
+ }
29
+ export interface ToolCallResult {
30
+ readonly status: number;
31
+ readonly ok: boolean;
32
+ readonly contentType: string | null;
33
+ /** Cuerpo ya interpretado si era JSON; si no, el texto crudo. */
34
+ readonly body: unknown;
35
+ /** Texto crudo de la respuesta, por si el llamante lo necesita. */
36
+ readonly raw: string;
37
+ /** Método y URL finales, útiles para depurar y auditar. */
38
+ readonly request: {
39
+ method: string;
40
+ url: string;
41
+ };
42
+ }
43
+ /**
44
+ * Ejecuta la llamada HTTP que representa una herramienta, mapeando los
45
+ * argumentos validados a parámetros de ruta, query, cabecera y cuerpo.
46
+ */
47
+ export declare function executeTool(tool: ToolDefinition, args: Readonly<Record<string, unknown>>, options: ExecuteOptions): Promise<ToolCallResult>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Ejecuta la llamada HTTP que representa una herramienta, mapeando los
3
+ * argumentos validados a parámetros de ruta, query, cabecera y cuerpo.
4
+ */
5
+ export async function executeTool(tool, args, options) {
6
+ const { binding } = tool;
7
+ // 1. Ruta: sustituye los marcadores {name} por los parámetros de ruta.
8
+ let path = binding.pathTemplate;
9
+ for (const param of binding.params) {
10
+ if (param.in !== 'path')
11
+ continue;
12
+ const value = args[param.name];
13
+ path = path.replace(`{${param.name}}`, encodeURIComponent(stringifyValue(value)));
14
+ }
15
+ // 2. Query: añade los parámetros presentes en los argumentos.
16
+ const query = new URLSearchParams();
17
+ for (const param of binding.params) {
18
+ if (param.in !== 'query')
19
+ continue;
20
+ const value = args[param.name];
21
+ if (value === undefined || value === null)
22
+ continue;
23
+ if (Array.isArray(value)) {
24
+ for (const item of value)
25
+ query.append(param.name, stringifyValue(item));
26
+ }
27
+ else {
28
+ query.append(param.name, stringifyValue(value));
29
+ }
30
+ }
31
+ // 3. Cabeceras: estáticas + parámetros de cabecera de la operación.
32
+ const headers = { ...(options.headers ?? {}) };
33
+ for (const param of binding.params) {
34
+ if (param.in !== 'header')
35
+ continue;
36
+ const value = args[param.name];
37
+ if (value === undefined || value === null)
38
+ continue;
39
+ headers[param.name] = stringifyValue(value);
40
+ }
41
+ // 4. Cuerpo: sólo si la operación lo declara y viene en los argumentos.
42
+ let body;
43
+ if (binding.requestBody && args['body'] !== undefined) {
44
+ body = JSON.stringify(args['body']);
45
+ if (headers['content-type'] === undefined && headers['Content-Type'] === undefined) {
46
+ headers['content-type'] = binding.requestBody.contentType;
47
+ }
48
+ }
49
+ const queryString = query.toString();
50
+ const url = `${trimTrailingSlash(options.baseUrl)}${path}${queryString ? `?${queryString}` : ''}`;
51
+ const method = binding.method.toUpperCase();
52
+ const response = await options.fetchFn(url, {
53
+ method,
54
+ headers,
55
+ ...(body === undefined ? {} : { body }),
56
+ });
57
+ const raw = await response.text();
58
+ const contentType = response.headers.get('content-type');
59
+ const parsed = isJsonContent(contentType) ? tryParseJson(raw) : raw;
60
+ return {
61
+ status: response.status,
62
+ ok: response.ok,
63
+ contentType,
64
+ body: parsed,
65
+ raw,
66
+ request: { method, url },
67
+ };
68
+ }
69
+ function stringifyValue(value) {
70
+ if (value === null || value === undefined)
71
+ return '';
72
+ if (typeof value === 'object')
73
+ return JSON.stringify(value);
74
+ return String(value);
75
+ }
76
+ function trimTrailingSlash(url) {
77
+ return url.endsWith('/') ? url.slice(0, -1) : url;
78
+ }
79
+ function isJsonContent(contentType) {
80
+ return contentType !== null && /\bjson\b/i.test(contentType);
81
+ }
82
+ function tryParseJson(raw) {
83
+ if (raw.trim() === '')
84
+ return null;
85
+ try {
86
+ return JSON.parse(raw);
87
+ }
88
+ catch {
89
+ return raw;
90
+ }
91
+ }
92
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ToolCallResult } from './client.js';
2
+ export type FormatMode = 'markdown' | 'json';
3
+ /**
4
+ * Da forma a la respuesta HTTP para que ocupe poco y sea legible dentro de la
5
+ * ventana de contexto de un LLM.
6
+ *
7
+ * - `json`: un objeto compacto con estado y cuerpo, en JSON indentado.
8
+ * - `markdown`: una línea de estado y el cuerpo en un bloque de código.
9
+ */
10
+ export declare function formatResult(result: ToolCallResult, mode?: FormatMode): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Da forma a la respuesta HTTP para que ocupe poco y sea legible dentro de la
3
+ * ventana de contexto de un LLM.
4
+ *
5
+ * - `json`: un objeto compacto con estado y cuerpo, en JSON indentado.
6
+ * - `markdown`: una línea de estado y el cuerpo en un bloque de código.
7
+ */
8
+ export function formatResult(result, mode = 'markdown') {
9
+ if (mode === 'json') {
10
+ return JSON.stringify({ status: result.status, ok: result.ok, body: result.body }, null, 2);
11
+ }
12
+ const bodyText = typeof result.body === 'string' ? result.body : JSON.stringify(result.body, null, 2);
13
+ const lang = typeof result.body === 'string' ? '' : 'json';
14
+ return [
15
+ `HTTP ${result.status} ${result.ok ? '(OK)' : '(error)'} — ${result.request.method} ${result.request.url}`,
16
+ '',
17
+ '```' + lang,
18
+ bodyText,
19
+ '```',
20
+ ].join('\n');
21
+ }
22
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/http/format.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,MAAsB,EAAE,OAAmB,UAAU;IAChF,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAE3D,OAAO;QACL,QAAQ,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAC1G,EAAE;QACF,KAAK,GAAG,IAAI;QACZ,QAAQ;QACR,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * openapi-to-mcp — convierte una especificación OpenAPI 3.x en un servidor
3
+ * Model Context Protocol (MCP). Este barrel expone la API pública para usarlo
4
+ * como biblioteca; la CLI vive en `cli.ts`.
5
+ */
6
+ export { loadSpec, parseSpecContent } from './openapi/load.js';
7
+ export type { LoadOptions } from './openapi/load.js';
8
+ export { RefResolver } from './openapi/resolve.js';
9
+ export type { OpenApiDocument, OperationObject, ParameterObject, PathItemObject, RequestBodyObject, SchemaObject, ServerObject, HttpMethod, } from './openapi/types.js';
10
+ export { HTTP_METHODS } from './openapi/types.js';
11
+ export { schemaToZod } from './schema/to-zod.js';
12
+ export { toJsonSchema } from './schema/to-json.js';
13
+ export type { JsonValue } from './schema/to-json.js';
14
+ export { buildTools } from './generator/operations.js';
15
+ export type { BuildToolsOptions, BuildToolsResult, JsonSchemaObject, ParamBinding, ToolBinding, ToolDefinition, } from './generator/operations.js';
16
+ export { generateServerCode } from './generator/codegen.js';
17
+ export type { CodegenOptions } from './generator/codegen.js';
18
+ export { executeTool } from './http/client.js';
19
+ export type { ExecuteOptions, FetchInit, FetchLike, FetchResponse, ToolCallResult, } from './http/client.js';
20
+ export { formatResult } from './http/format.js';
21
+ export type { FormatMode } from './http/format.js';
22
+ export { createMcpServer, PROTOCOL_VERSION, defaultServerLogger } from './mcp/server.js';
23
+ export type { McpServer, McpServerOptions } from './mcp/server.js';
24
+ export { startStdioServer } from './mcp/stdio.js';
25
+ export type { StdioOptions } from './mcp/stdio.js';
26
+ export { failure, isRequest, success, JSON_RPC_ERROR, } from './mcp/jsonrpc.js';
27
+ export type { JsonRpcErrorResponse, JsonRpcIncoming, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, JsonRpcSuccess, } from './mcp/jsonrpc.js';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * openapi-to-mcp — convierte una especificación OpenAPI 3.x en un servidor
3
+ * Model Context Protocol (MCP). Este barrel expone la API pública para usarlo
4
+ * como biblioteca; la CLI vive en `cli.ts`.
5
+ */
6
+ export { loadSpec, parseSpecContent } from './openapi/load.js';
7
+ export { RefResolver } from './openapi/resolve.js';
8
+ export { HTTP_METHODS } from './openapi/types.js';
9
+ export { schemaToZod } from './schema/to-zod.js';
10
+ export { toJsonSchema } from './schema/to-json.js';
11
+ export { buildTools } from './generator/operations.js';
12
+ export { generateServerCode } from './generator/codegen.js';
13
+ export { executeTool } from './http/client.js';
14
+ export { formatResult } from './http/format.js';
15
+ export { createMcpServer, PROTOCOL_VERSION, defaultServerLogger } from './mcp/server.js';
16
+ export { startStdioServer } from './mcp/stdio.js';
17
+ export { failure, isRequest, success, JSON_RPC_ERROR, } from './mcp/jsonrpc.js';
18
+ //# sourceMappingURL=index.js.map