webmcp-codegen 0.2.0 → 0.3.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.
- package/README.md +45 -36
- package/dist/{chunk-WYGVTIGI.js → chunk-3LTHWIAP.js} +37 -4
- package/dist/chunk-3LTHWIAP.js.map +1 -0
- package/dist/{chunk-BIKKPCRT.js → chunk-FWSATV7C.js} +26 -2
- package/dist/chunk-FWSATV7C.js.map +1 -0
- package/dist/chunk-JVBVTHZ7.js +235 -0
- package/dist/chunk-JVBVTHZ7.js.map +1 -0
- package/dist/{chunk-5L4KN6F4.js → chunk-KSQMJERY.js} +3 -3
- package/dist/chunk-KSQMJERY.js.map +1 -0
- package/dist/{chunk-R3DEBBQ3.js → chunk-MJQ5B6HB.js} +111 -21
- package/dist/chunk-MJQ5B6HB.js.map +1 -0
- package/dist/chunk-TGOJ3HUE.js +382 -0
- package/dist/chunk-TGOJ3HUE.js.map +1 -0
- package/dist/cli.js +263 -102
- package/dist/cli.js.map +1 -1
- package/dist/generators/index.d.ts +3 -3
- package/dist/generators/index.js +2 -2
- package/dist/index.d.ts +15 -5
- package/dist/index.js +3 -3
- package/dist/server-OR4IMRQ5.js +638 -0
- package/dist/server-OR4IMRQ5.js.map +1 -0
- package/dist/sources/index.d.ts +1 -1
- package/dist/sources/index.js +3 -3
- package/dist/{types-Bf5MxWeH.d.ts → types-DWUum51l.d.ts} +56 -3
- package/package.json +1 -1
- package/dist/chunk-5L4KN6F4.js.map +0 -1
- package/dist/chunk-BIKKPCRT.js.map +0 -1
- package/dist/chunk-GDJDVR4E.js +0 -251
- package/dist/chunk-GDJDVR4E.js.map +0 -1
- package/dist/chunk-R3DEBBQ3.js.map +0 -1
- package/dist/chunk-WYGVTIGI.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sources/openapi.ts"],"sourcesContent":["/**\n * The OpenAPI source.\n *\n * Reads an OpenAPI 3.x document (YAML or JSON) and turns every operation\n * into a CandidateTool. This is the highest-reach source: most backend\n * frameworks can already emit an OpenAPI spec, so teams get value without\n * changing any application code.\n *\n * What we read from each operation:\n * - name ← operationId, slugified (falls back to method + path)\n * - description ← summary, else the first line of description, else a template\n * - inputSchema ← path + query parameters merged with the JSON request body\n * - outputSchema ← the first 2xx response's JSON schema, when present\n *\n * Header and cookie parameters are skipped on purpose: agents should not be\n * setting those by hand, and auth headers are the app's job, not the tool's.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { nameFromRoute, toToolName } from \"../naming.js\";\nimport { deepDeref, deref, pascalCase } from \"../schema.js\";\nimport type { CandidateTool, JsonSchema, Source } from \"../types.js\";\n\nexport interface OpenApiSourceOptions {\n /** Path to the OpenAPI document, relative to the project root. */\n spec: string;\n}\n\nconst HTTP_METHODS = [\"get\", \"post\", \"put\", \"patch\", \"delete\", \"head\", \"options\"] as const;\n\n/** Create an OpenAPI source for the config's `sources` array. */\nexport function openapi(options: OpenApiSourceOptions): Source {\n return {\n kind: \"openapi\",\n async collect() {\n const specPath = resolve(process.cwd(), options.spec);\n const spec = await readSpec(specPath);\n return operationsFromSpec(spec);\n },\n };\n}\n\nasync function readSpec(specPath: string): Promise<unknown> {\n let text: string;\n try {\n text = await readFile(specPath, \"utf8\");\n } catch {\n throw new Error(\n `Could not read the OpenAPI spec at \"${specPath}\". Check the \"spec\" path in codegen.config.`,\n );\n }\n // YAML is a superset of JSON, so one parser handles both file types.\n return parseYaml(text);\n}\n\nfunction operationsFromSpec(spec: unknown): CandidateTool[] {\n const root = spec as Record<string, unknown>;\n const paths = (root.paths ?? {}) as Record<string, Record<string, unknown>>;\n const rootSecurity = Array.isArray(root.security) && root.security.length > 0;\n const candidates: CandidateTool[] = [];\n\n for (const [path, pathItem] of Object.entries(paths)) {\n // Parameters declared on the path item apply to every operation under it.\n const sharedParams = Array.isArray(pathItem.parameters) ? pathItem.parameters : [];\n\n for (const method of HTTP_METHODS) {\n const operation = pathItem[method] as Record<string, unknown> | undefined;\n if (!operation) continue;\n\n const upperMethod = method.toUpperCase() as CandidateTool[\"httpMethod\"];\n const ref = `${upperMethod} ${path}`;\n const name =\n typeof operation.operationId === \"string\" && operation.operationId.length > 0\n ? toToolName(operation.operationId)\n : nameFromRoute(method, path);\n\n const opSecurity = operation.security;\n const requiresAuth = Array.isArray(opSecurity) ? opSecurity.length > 0 : rootSecurity;\n\n candidates.push({\n id: ref,\n name,\n source: { kind: \"openapi\", ref },\n inputSchema: buildInputSchema(operation, sharedParams, spec),\n outputSchema: findOutputSchema(operation, spec),\n inputTypeName: `${pascalCase(name)}Input`,\n httpMethod: upperMethod,\n // The safety layer refines this — the source only reports the verb.\n sideEffect: \"unknown\",\n requiresAuth,\n description: pickDescription(operation, upperMethod ?? method.toUpperCase(), path),\n descriptionSource:\n typeof operation.summary === \"string\" || typeof operation.description === \"string\"\n ? \"openapi-summary\"\n : \"generated-template\",\n });\n }\n }\n\n if (candidates.length === 0) {\n throw new Error('The OpenAPI spec has no operations under \"paths\". Nothing to generate.');\n }\n return candidates;\n}\n\n/**\n * Merge path + query parameters and the JSON request body into one object\n * schema — that single object is what the agent fills in when calling the tool.\n */\nfunction buildInputSchema(\n operation: Record<string, unknown>,\n sharedParams: unknown[],\n spec: unknown,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {};\n const required = new Set<string>();\n\n const parameters = [\n ...sharedParams,\n ...(Array.isArray(operation.parameters) ? operation.parameters : []),\n ];\n\n for (const rawParam of parameters) {\n const param = deref(rawParam as JsonSchema, spec) as Record<string, unknown>;\n // Headers and cookies are transport concerns, not tool inputs.\n if (param.in !== \"path\" && param.in !== \"query\") continue;\n if (typeof param.name !== \"string\") continue;\n\n const fieldSchema = param.schema\n ? deepDeref(param.schema as JsonSchema, spec)\n : { type: \"string\" };\n properties[param.name] =\n typeof param.description === \"string\"\n ? { ...fieldSchema, description: param.description }\n : fieldSchema;\n // Path params are always required by definition; query params say so.\n if (param.in === \"path\" || param.required === true) required.add(param.name);\n }\n\n const body = extractJsonBody(operation.requestBody, spec);\n if (body) {\n if (body.schema.type === \"object\" || body.schema.properties) {\n // The common case: an object body flattens into the tool input.\n for (const [key, value] of Object.entries(body.schema.properties ?? {})) {\n properties[key] = value;\n }\n if (body.required) {\n for (const key of body.schema.required ?? []) required.add(key);\n }\n } else {\n // A non-object body (array, raw string, …) goes under a \"body\" field.\n properties.body = body.schema;\n if (body.required) required.add(\"body\");\n }\n }\n\n return { type: \"object\", properties, required: [...required] };\n}\n\n/** Find the operation's JSON request body schema, if it declares one. */\nfunction extractJsonBody(\n requestBody: unknown,\n spec: unknown,\n): { schema: JsonSchema; required: boolean } | undefined {\n if (!requestBody || typeof requestBody !== \"object\") return undefined;\n const body = deref(requestBody as JsonSchema, spec) as Record<string, unknown>;\n const content = body.content as Record<string, { schema?: JsonSchema }> | undefined;\n // Prefer application/json; accept any \"+json\" media type as a fallback.\n const jsonEntry =\n content?.[\"application/json\"] ??\n Object.entries(content ?? {}).find(([mediaType]) => mediaType.endsWith(\"+json\"))?.[1];\n if (!jsonEntry?.schema) return undefined;\n return {\n schema: deepDeref(jsonEntry.schema, spec),\n required: body.required === true,\n };\n}\n\n/** The response contract, used by the safety layer's PII scan (and later, docs). */\nfunction findOutputSchema(\n operation: Record<string, unknown>,\n spec: unknown,\n): JsonSchema | undefined {\n const responses = operation.responses as Record<string, unknown> | undefined;\n if (!responses) return undefined;\n // The first 2xx response with a JSON schema wins.\n for (const [status, rawResponse] of Object.entries(responses)) {\n if (!status.startsWith(\"2\")) continue;\n const response = deref(rawResponse as JsonSchema, spec) as Record<string, unknown>;\n const content = response.content as Record<string, { schema?: JsonSchema }> | undefined;\n const jsonEntry =\n content?.[\"application/json\"] ??\n Object.entries(content ?? {}).find(([mediaType]) => mediaType.endsWith(\"+json\"))?.[1];\n if (jsonEntry?.schema) return deepDeref(jsonEntry.schema, spec);\n }\n return undefined;\n}\n\n/**\n * The description is part of the agent's prompt, so we take the spec's own\n * words when they exist and only fall back to a plain template. Both paths\n * are marked so the audit report shows which descriptions need human love.\n */\nfunction pickDescription(operation: Record<string, unknown>, method: string, path: string): string {\n if (typeof operation.summary === \"string\" && operation.summary.trim().length > 0) {\n return operation.summary.trim();\n }\n if (typeof operation.description === \"string\" && operation.description.trim().length > 0) {\n // Use the first line only — long prose belongs in docs, not in a prompt.\n return operation.description.trim().split(\"\\n\")[0] as string;\n }\n return `${method} ${path}`;\n}\n"],"mappings":"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","names":[]}
|