@toolfactory.dev/core 1.0.0-rc

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/out/codegen/access-stubs.d.ts +2 -0
  4. package/out/codegen/access-stubs.js +6 -0
  5. package/out/codegen/auth-module-names.d.ts +11 -0
  6. package/out/codegen/auth-module-names.js +34 -0
  7. package/out/codegen/auth-pipeline-render.d.ts +10 -0
  8. package/out/codegen/auth-pipeline-render.js +157 -0
  9. package/out/codegen/auth-stub-bootstrap.d.ts +42 -0
  10. package/out/codegen/auth-stub-bootstrap.js +252 -0
  11. package/out/codegen/document-validation.d.ts +22 -0
  12. package/out/codegen/document-validation.js +76 -0
  13. package/out/codegen/generated-layout.d.ts +15 -0
  14. package/out/codegen/generated-layout.js +53 -0
  15. package/out/codegen/index.d.ts +20 -0
  16. package/out/codegen/index.js +20 -0
  17. package/out/codegen/langium-cli-types.d.ts +45 -0
  18. package/out/codegen/langium-cli-types.js +1 -0
  19. package/out/codegen/logging-adapter-bootstrap.d.ts +6 -0
  20. package/out/codegen/logging-adapter-bootstrap.js +69 -0
  21. package/out/codegen/mcp-host-credential-validation.d.ts +5 -0
  22. package/out/codegen/mcp-host-credential-validation.js +15 -0
  23. package/out/codegen/mcp-host-product-runtime.d.ts +22 -0
  24. package/out/codegen/mcp-host-product-runtime.js +413 -0
  25. package/out/codegen/project-bootstrap.d.ts +29 -0
  26. package/out/codegen/project-bootstrap.js +153 -0
  27. package/out/codegen/render-http-mcp-server.d.ts +3 -0
  28. package/out/codegen/render-http-mcp-server.js +194 -0
  29. package/out/codegen/render-mcp-host-shared.d.ts +7 -0
  30. package/out/codegen/render-mcp-host-shared.js +671 -0
  31. package/out/codegen/render-oauth-http-mcp-server.d.ts +5 -0
  32. package/out/codegen/render-oauth-http-mcp-server.js +220 -0
  33. package/out/codegen/render-stdio-mcp-server.d.ts +5 -0
  34. package/out/codegen/render-stdio-mcp-server.js +58 -0
  35. package/out/codegen/write-demos-test-support.d.ts +2 -0
  36. package/out/codegen/write-demos-test-support.js +28 -0
  37. package/out/codegen/zod-codegen.d.ts +9 -0
  38. package/out/codegen/zod-codegen.js +149 -0
  39. package/out/scripts/generated-scripts-banner.d.ts +2 -0
  40. package/out/scripts/generated-scripts-banner.js +2 -0
  41. package/out/scripts/render-kill-listeners-on-port.mjs.d.ts +1 -0
  42. package/out/scripts/render-kill-listeners-on-port.mjs.js +81 -0
  43. package/out/scripts/render-load-env-local.mjs.d.ts +1 -0
  44. package/out/scripts/render-load-env-local.mjs.js +67 -0
  45. package/out/scripts/render-require-env.mjs.d.ts +1 -0
  46. package/out/scripts/render-require-env.mjs.js +36 -0
  47. package/out/scripts/write-generated-scripts.d.ts +4 -0
  48. package/out/scripts/write-generated-scripts.js +24 -0
  49. package/package.json +58 -0
@@ -0,0 +1,413 @@
1
+ /** Parameter name when GeneratedHostModule is required only for db2ai branches (api2ai → eslint _ prefix). */
2
+ export function generatedModuleParam(product) {
3
+ return product === 'api2ai' ? '_generated' : 'generated';
4
+ }
5
+ export function hostCoreTypes(product) {
6
+ if (product === 'db2ai') {
7
+ return `
8
+ type DatabaseDialect = 'postgres' | 'mysql' | 'mariadb' | 'sqlserver' | 'oracle';
9
+
10
+ /** Host context inside MCP server templates. Tool modules use DbHostContext; this wider shape is shared across stdio/HTTP hosts. */
11
+ type ApiLikeHostContext = {
12
+ baseUrl?: string;
13
+ connectionString?: string;
14
+ databaseDialect?: DatabaseDialect;
15
+ credential?: string;
16
+ upstreamCredential?: string;
17
+ credentials?: unknown;
18
+ };
19
+
20
+ type VerifyCredentialInput = {
21
+ inboundCredential: string;
22
+ };
23
+
24
+ type VerifyCredentialResult = {
25
+ upstreamCredential: string;
26
+ credentials: unknown;
27
+ };
28
+
29
+ type VerifyCredentialFn = (input: VerifyCredentialInput) => Promise<VerifyCredentialResult>;
30
+
31
+ type GeneratedHostModule = {
32
+ generatedTools: Array<{ toolName: string; title?: string; description: string; access?: string }>;
33
+ invokeTool: (
34
+ toolName: string,
35
+ args?: Record<string, unknown>,
36
+ hostContext?: unknown
37
+ ) => Promise<unknown>;
38
+ inputZodByTool?: Record<string, unknown>;
39
+ mcpServerName?: string;
40
+ mcpServerVersion?: string;
41
+ requiresAuth: boolean;
42
+ connectionEnv?: string;
43
+ databaseDialect?: DatabaseDialect;
44
+ verifyCredential?: VerifyCredentialFn;
45
+ };`.trim();
46
+ }
47
+ return `
48
+ /** Host context inside MCP server templates. Tool modules use ApiHostContext; this wider shape is shared across stdio/HTTP hosts. */
49
+ type ApiLikeHostContext = {
50
+ baseUrl?: string;
51
+ credential?: string;
52
+ upstreamCredential?: string;
53
+ credentials?: unknown;
54
+ };
55
+
56
+ type VerifyCredentialInput = {
57
+ inboundCredential: string;
58
+ };
59
+
60
+ type VerifyCredentialResult = {
61
+ upstreamCredential: string;
62
+ credentials: unknown;
63
+ };
64
+
65
+ type VerifyCredentialFn = (input: VerifyCredentialInput) => Promise<VerifyCredentialResult>;
66
+
67
+ type GeneratedHostModule = {
68
+ generatedTools: Array<{ toolName: string; title?: string; description: string; access?: string }>;
69
+ invokeTool: (
70
+ toolName: string,
71
+ args?: Record<string, unknown>,
72
+ hostContext?: unknown
73
+ ) => Promise<unknown>;
74
+ inputZodByTool?: Record<string, unknown>;
75
+ mcpServerName?: string;
76
+ mcpServerVersion?: string;
77
+ requiresAuth: boolean;
78
+ verifyCredential?: VerifyCredentialFn;
79
+ };`.trim();
80
+ }
81
+ export function dbOnlyHelperFunctions(product) {
82
+ if (product === 'api2ai') {
83
+ return '';
84
+ }
85
+ return `
86
+ function parseDatabaseDialect(value: unknown): DatabaseDialect | undefined {
87
+ return value === 'postgres' || value === 'mysql' || value === 'mariadb' || value === 'sqlserver' || value === 'oracle'
88
+ ? value
89
+ : undefined;
90
+ }
91
+
92
+ function isExpectedDatabaseUrl(connectionString: string, dialect: DatabaseDialect): boolean {
93
+ if (dialect === 'mysql') {
94
+ return connectionString.startsWith('mysql://');
95
+ }
96
+ if (dialect === 'mariadb') {
97
+ return connectionString.startsWith('mariadb://');
98
+ }
99
+ if (dialect === 'sqlserver') {
100
+ return (
101
+ connectionString.startsWith('sqlserver://') ||
102
+ connectionString.startsWith('mssql://') ||
103
+ /^Server=/i.test(connectionString)
104
+ );
105
+ }
106
+ if (dialect === 'oracle') {
107
+ return connectionString.startsWith('oracle://');
108
+ }
109
+ return connectionString.startsWith('postgresql://') || connectionString.startsWith('postgres://');
110
+ }`.trim();
111
+ }
112
+ function readVerifyCredentialExports() {
113
+ return `
114
+ const verifyCredential = imported.verifyCredential;
115
+ const verifyCredentialFn =
116
+ typeof verifyCredential === 'function' ? (verifyCredential as VerifyCredentialFn) : undefined;`.trim();
117
+ }
118
+ export function readGeneratedModuleTail(product) {
119
+ if (product === 'db2ai') {
120
+ return `
121
+ const connectionEnv = imported.connectionEnv;
122
+ ${readVerifyCredentialExports()}
123
+ return {
124
+ generatedTools: generatedTools as Array<{ toolName: string; title?: string; description: string }>,
125
+ invokeTool: invokeTool as (
126
+ toolName: string,
127
+ args?: Record<string, unknown>,
128
+ hostContext?: unknown
129
+ ) => Promise<unknown>,
130
+ inputZodByTool:
131
+ inputZodByTool && typeof inputZodByTool === 'object' && !Array.isArray(inputZodByTool)
132
+ ? (inputZodByTool as Record<string, unknown>)
133
+ : undefined,
134
+ mcpServerName: typeof mcpServerName === 'string' ? mcpServerName : undefined,
135
+ mcpServerVersion: typeof mcpServerVersion === 'string' ? mcpServerVersion : undefined,
136
+ requiresAuth: imported.requiresAuth === true,
137
+ connectionEnv: typeof connectionEnv === 'string' ? connectionEnv : undefined,
138
+ databaseDialect: parseDatabaseDialect(imported.databaseDialect),
139
+ verifyCredential: verifyCredentialFn
140
+ };`.trim();
141
+ }
142
+ return `
143
+ ${readVerifyCredentialExports()}
144
+ return {
145
+ generatedTools: generatedTools as Array<{ toolName: string; title?: string; description: string }>,
146
+ invokeTool: invokeTool as (
147
+ toolName: string,
148
+ args?: Record<string, unknown>,
149
+ hostContext?: unknown
150
+ ) => Promise<unknown>,
151
+ inputZodByTool:
152
+ inputZodByTool && typeof inputZodByTool === 'object' && !Array.isArray(inputZodByTool)
153
+ ? (inputZodByTool as Record<string, unknown>)
154
+ : undefined,
155
+ mcpServerName: typeof mcpServerName === 'string' ? mcpServerName : undefined,
156
+ mcpServerVersion: typeof mcpServerVersion === 'string' ? mcpServerVersion : undefined,
157
+ requiresAuth: imported.requiresAuth === true,
158
+ verifyCredential: verifyCredentialFn
159
+ };`.trim();
160
+ }
161
+ function dbConnectionStartupCheck() {
162
+ return `
163
+ const connectionString = process.env[generated.connectionEnv]?.trim();
164
+ if (!connectionString) {
165
+ throw new Error(
166
+ 'Environment variable "' + generated.connectionEnv + '" is missing or empty (database env from .db2ai).'
167
+ );
168
+ }
169
+ const dialect: DatabaseDialect = generated.databaseDialect ?? 'postgres';
170
+ if (!isExpectedDatabaseUrl(connectionString, dialect)) {
171
+ throw new Error(
172
+ 'Environment variable "' +
173
+ generated.connectionEnv +
174
+ '" does not match generated database dialect "' +
175
+ dialect +
176
+ '".'
177
+ );
178
+ }`;
179
+ }
180
+ function dbConnectionEnvValidationBlock() {
181
+ return `
182
+ const connectionString = process.env[generated.connectionEnv]?.trim();
183
+ if (!connectionString) {
184
+ throw new Error(
185
+ 'Missing database URL. Set environment variable "' + generated.connectionEnv + '" (from .db2ai).'
186
+ );
187
+ }
188
+ const dialect: DatabaseDialect = generated.databaseDialect ?? 'postgres';
189
+ if (!isExpectedDatabaseUrl(connectionString, dialect)) {
190
+ throw new Error(
191
+ 'Database URL from "' + generated.connectionEnv + '" does not match dialect "' + dialect + '".'
192
+ );
193
+ }`;
194
+ }
195
+ function dbConnectionResolveReturn() {
196
+ return `${dbConnectionEnvValidationBlock()}
197
+ return { connectionString, databaseDialect: dialect, credential: c };`;
198
+ }
199
+ function dbConnectionResolveReturnForOAuth() {
200
+ return `${dbConnectionEnvValidationBlock()}
201
+ return { connectionString, databaseDialect: dialect, credential: upstreamCredential, upstreamCredential, credentials };`;
202
+ }
203
+ export function withDbConnectionHostContextFn(product) {
204
+ if (product !== 'db2ai') {
205
+ return `
206
+ function withDbConnectionHostContext(
207
+ _generated: GeneratedHostModule,
208
+ context: ApiLikeHostContext
209
+ ): ApiLikeHostContext {
210
+ return context;
211
+ }`.trim();
212
+ }
213
+ return `
214
+ function withDbConnectionHostContext(
215
+ generated: GeneratedHostModule,
216
+ context: ApiLikeHostContext
217
+ ): ApiLikeHostContext {
218
+ if (!generated.connectionEnv) {
219
+ return context;
220
+ }${dbConnectionEnvValidationBlock()}
221
+ return { ...context, connectionString, databaseDialect: dialect };
222
+ }`.trim();
223
+ }
224
+ export function validateHostAtStartupFn(product) {
225
+ const dbBranch = product === 'db2ai'
226
+ ? `if (generated.connectionEnv) {${dbConnectionStartupCheck()}
227
+ } else {`
228
+ : '';
229
+ const closeDbBranch = product === 'db2ai' ? `}` : '';
230
+ return `
231
+ function validateHostAtStartup(hostConfig: HostRuntimeConfig, generated: GeneratedHostModule): void {
232
+ ${dbBranch}
233
+ const baseUrlKey = hostConfig.baseUrlEnvKey?.trim();
234
+ if (!baseUrlKey) {
235
+ throw new Error('Required: --base-url-env <ENV_VAR_NAME>');
236
+ }
237
+ const baseUrl = process.env[baseUrlKey]?.trim();
238
+ if (!baseUrl) {
239
+ throw new Error(
240
+ 'Environment variable "' + baseUrlKey + '" is missing or empty (required by --base-url-env).'
241
+ );
242
+ }
243
+ ${closeDbBranch}
244
+ if (generated.requiresAuth && !hostConfig.authEnvKey?.trim()) {
245
+ throw new Error('Generated tools require auth; pass --auth-env <ENV_VAR_NAME> on the MCP host.');
246
+ }
247
+ if (generated.requiresAuth && typeof generated.verifyCredential !== 'function') {
248
+ throw new Error(
249
+ 'Generated tools require auth; implement verify*Credentials in src/hooks/${product}/<module>/ and re-export from generated tools.'
250
+ );
251
+ }
252
+ }`.trim();
253
+ }
254
+ export function resolveHostContextForCallFn(product) {
255
+ const dbBranch = product === 'db2ai'
256
+ ? `if (generated.connectionEnv) {
257
+ ${dbConnectionResolveReturn()}
258
+ }`
259
+ : '';
260
+ return `
261
+ async function resolveHostContextForCall(
262
+ hostConfig: HostRuntimeConfig,
263
+ ${generatedModuleParam(product)}: GeneratedHostModule
264
+ ): Promise<ApiLikeHostContext> {
265
+ const credential = readCredentialFromEnv(hostConfig.authEnvKey);
266
+ const { credential: c } = resolveRelayHostCredential(credential);
267
+ ${dbBranch}
268
+ const baseUrlKey = hostConfig.baseUrlEnvKey?.trim();
269
+ const baseUrl = baseUrlKey ? process.env[baseUrlKey]?.trim() : undefined;
270
+ if (!baseUrl) {
271
+ throw new Error('Missing host base URL. Pass --base-url-env on stdio-mcp-server.js and set the variable.');
272
+ }
273
+ return { baseUrl, credential: c };
274
+ }`.trim();
275
+ }
276
+ export function validateHttpMcpHostAtStartupFn(product) {
277
+ const dbBranch = product === 'db2ai'
278
+ ? `if (generated.connectionEnv) {${dbConnectionStartupCheck()}
279
+ } else {`
280
+ : '';
281
+ const closeDbBranch = product === 'db2ai' ? `}` : '';
282
+ return `
283
+ function validateHttpMcpHostAtStartup(
284
+ httpHostConfig: HttpMcpHostRuntimeConfig,
285
+ ${generatedModuleParam(product)}: GeneratedHostModule
286
+ ): void {
287
+ ${dbBranch}
288
+ const baseUrlKey = httpHostConfig.baseUrlEnvKey?.trim();
289
+ if (!baseUrlKey) {
290
+ throw new Error('Required: --base-url-env <ENV_VAR_NAME>');
291
+ }
292
+ const baseUrl = process.env[baseUrlKey]?.trim();
293
+ if (!baseUrl) {
294
+ throw new Error(
295
+ 'Environment variable "' + baseUrlKey + '" is missing or empty (required by --base-url-env).'
296
+ );
297
+ }
298
+ ${closeDbBranch}
299
+ if (${generatedModuleParam(product)}.requiresAuth && typeof ${generatedModuleParam(product)}.verifyCredential !== 'function') {
300
+ throw new Error(
301
+ 'Generated tools require auth; implement verify*Credentials in src/hooks/${product}/<module>/ and re-export from generated tools.'
302
+ );
303
+ }
304
+ }`.trim();
305
+ }
306
+ export function resolveHostContextForHttpCallFn(product, httpMcpProfile) {
307
+ const readCredential = httpMcpProfile === 'public'
308
+ ? `const credential = undefined;`
309
+ : `const headerName = readAuthHeaderNameFromEnv();
310
+ let credential = readCredentialFromHttpHeaders(incomingHeaders, headerName);
311
+ if (!credential?.trim()) {
312
+ credential = readCredentialFromEnv(httpHostConfig.authEnvKey);
313
+ }`;
314
+ const dbBranch = product === 'db2ai'
315
+ ? `if (generated.connectionEnv) {
316
+ ${dbConnectionResolveReturn()}
317
+ }`
318
+ : '';
319
+ return `
320
+ async function resolveHostContextForHttpCall(
321
+ httpHostConfig: HttpMcpHostRuntimeConfig,
322
+ ${generatedModuleParam(product)}: GeneratedHostModule,
323
+ ${httpMcpProfile === 'public' ? '_incomingHeaders' : 'incomingHeaders'}: Record<string, string | string[] | undefined>
324
+ ): Promise<ApiLikeHostContext> {
325
+ ${readCredential}
326
+ const { credential: c } = resolveRelayHostCredential(credential);
327
+ ${dbBranch}
328
+ const baseUrlKey = httpHostConfig.baseUrlEnvKey?.trim();
329
+ const baseUrl = baseUrlKey ? process.env[baseUrlKey]?.trim() : undefined;
330
+ if (!baseUrl) {
331
+ throw new Error(
332
+ 'Missing host base URL. Pass --base-url-env on HTTP MCP host and set the variable.'
333
+ );
334
+ }
335
+ return { baseUrl, credential: c };
336
+ }`.trim();
337
+ }
338
+ export function validateOAuthHttpHostAtStartupFn(product) {
339
+ const dbBranch = product === 'db2ai'
340
+ ? `if (generated.connectionEnv) {${dbConnectionStartupCheck()}
341
+ } else {`
342
+ : '';
343
+ const closeDbBranch = product === 'db2ai' ? `}` : '';
344
+ return `
345
+ async function validateOAuthHttpHostAtStartup(
346
+ httpHostConfig: OAuthHttpHostRuntimeConfig,
347
+ ${generatedModuleParam(product)}: GeneratedHostModule
348
+ ): Promise<void> {
349
+ if (${generatedModuleParam(product)}.requiresAuth && typeof ${generatedModuleParam(product)}.verifyCredential !== 'function') {
350
+ throw new Error(
351
+ 'Generated tools require auth; implement verify*Credentials in src/hooks/${product}/<module>/ and re-export from generated tools.'
352
+ );
353
+ }
354
+ ${dbBranch}
355
+ const baseUrlKey = httpHostConfig.baseUrlEnvKey?.trim();
356
+ if (!baseUrlKey) {
357
+ throw new Error('Required: --base-url-env <ENV_VAR_NAME>');
358
+ }
359
+ const baseUrl = process.env[baseUrlKey]?.trim();
360
+ if (!baseUrl) {
361
+ throw new Error(
362
+ 'Environment variable "' + baseUrlKey + '" is missing or empty (required by --base-url-env).'
363
+ );
364
+ }
365
+ ${closeDbBranch}
366
+ }`.trim();
367
+ }
368
+ export function resolveHostContextForOAuthSessionDbBranch(product) {
369
+ if (product === 'api2ai') {
370
+ return '';
371
+ }
372
+ return `if (generated.connectionEnv) {${dbConnectionResolveReturnForOAuth()}
373
+ }`;
374
+ }
375
+ /** Skip baseUrl for db2ai modules that export connectionEnv (.db2ai SQL tools). */
376
+ export function oauthHostContextBaseUrlFieldsFn(product) {
377
+ const generatedParam = generatedModuleParam(product);
378
+ if (product === 'db2ai') {
379
+ return `
380
+ function oauthHostContextBaseUrlFields(
381
+ httpHostConfig: OAuthHttpHostRuntimeConfig,
382
+ ${generatedParam}: GeneratedHostModule
383
+ ): Pick<ApiLikeHostContext, 'baseUrl'> {
384
+ if (${generatedParam}.connectionEnv) {
385
+ return {};
386
+ }
387
+ return { baseUrl: resolveOAuthHostBaseUrl(httpHostConfig) };
388
+ }`.trim();
389
+ }
390
+ return `
391
+ function oauthHostContextBaseUrlFields(
392
+ httpHostConfig: OAuthHttpHostRuntimeConfig,
393
+ _generated: GeneratedHostModule
394
+ ): Pick<ApiLikeHostContext, 'baseUrl'> {
395
+ return { baseUrl: resolveOAuthHostBaseUrl(httpHostConfig) };
396
+ }`.trim();
397
+ }
398
+ export function requireBaseUrlEnvArgvCheck(product, hostConfigExpr) {
399
+ if (product === 'db2ai') {
400
+ return `if (!generated.connectionEnv && !${hostConfigExpr}) {
401
+ throw new Error(
402
+ 'Required: --base-url-env <ENV_VAR_NAME> for HTTP/OpenAPI tools, or export connectionEnv from a .db2ai module.'
403
+ );
404
+ }`;
405
+ }
406
+ return `if (!${hostConfigExpr}) {
407
+ throw new Error('Required: --base-url-env <ENV_VAR_NAME>');
408
+ }`;
409
+ }
410
+ /** @deprecated use validateHttpMcpHostAtStartupFn */
411
+ export function validateStatelessHttpHostAtStartupFn(product) {
412
+ return validateHttpMcpHostAtStartupFn(product);
413
+ }
@@ -0,0 +1,29 @@
1
+ import type { McpHostProduct } from './mcp-host-product-runtime.js';
2
+ export { resolveGeneratedCliDir, resolveGeneratedToolsPath, resolveHostProductFromGeneratedToolsPath } from './generated-layout.js';
3
+ export type ProjectBootstrapConfig = {
4
+ generatorImplementationDir: string;
5
+ /** api2ai: HTTP/OpenAPI hosts only. db2ai: adds connectionEnv / database URL validation. Default api2ai. */
6
+ hostProduct?: McpHostProduct;
7
+ embedHomeEnv?: string;
8
+ fallbackProjectName: string;
9
+ requiredRuntimeDeps: readonly string[];
10
+ dependencyVersionFallbacks?: Record<string, string>;
11
+ resolvePackageRoot?: (generatorImplementationDir: string) => string;
12
+ missingDepsMessage?: (packageJsonPath: string, missing: readonly string[]) => string;
13
+ };
14
+ export declare function resolveBootstrapProjectRootFromSource(sourcePath: string): string;
15
+ export declare function writeGeneratedStdioMcpHost(cliDir: string, config?: ProjectBootstrapConfig, projectRoot?: string): string;
16
+ export declare function writeGeneratedPublicHttpMcpHost(cliDir: string, config?: ProjectBootstrapConfig, projectRoot?: string): string;
17
+ export declare function writeGeneratedPassthroughHttpMcpHost(cliDir: string, config?: ProjectBootstrapConfig, projectRoot?: string): string;
18
+ /** Writes public and passthrough HTTP MCP hosts. */
19
+ export declare function writeGeneratedHttpMcpHosts(cliDir: string, config?: ProjectBootstrapConfig, projectRoot?: string): {
20
+ publicHttpMcpHostPath: string;
21
+ passthroughHttpMcpHostPath: string;
22
+ };
23
+ export declare function writeGeneratedOAuthHttpMcpHost(cliDir: string, config?: ProjectBootstrapConfig, projectRoot?: string): string;
24
+ export declare function resolveMcpServerIdentityFromDestination(destinationTsPath: string, config: ProjectBootstrapConfig): {
25
+ name: string;
26
+ version: string;
27
+ };
28
+ export declare function writeMinimalPackageJsonIfAbsent(projectRoot: string, config: ProjectBootstrapConfig): void;
29
+ export declare function ensureParentDir(destination: string): void;
@@ -0,0 +1,153 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { renderStdioMcpServerSource } from './render-stdio-mcp-server.js';
4
+ import { renderOAuthHttpMcpServerSource } from './render-oauth-http-mcp-server.js';
5
+ import { renderPassthroughHttpMcpServerSource, renderPublicHttpMcpServerSource } from './render-http-mcp-server.js';
6
+ import { loggingAdapterImportForCliFile, resolveProjectRootFromGeneratedCliDir } from './generated-layout.js';
7
+ export { resolveGeneratedCliDir, resolveGeneratedToolsPath, resolveHostProductFromGeneratedToolsPath } from './generated-layout.js';
8
+ function resolveEmbedHomeDirectory(config) {
9
+ const raw = config.embedHomeEnv ? process.env[config.embedHomeEnv]?.trim() : undefined;
10
+ return raw ? path.resolve(raw) : undefined;
11
+ }
12
+ export function resolveBootstrapProjectRootFromSource(sourcePath) {
13
+ return path.dirname(path.resolve(sourcePath));
14
+ }
15
+ function resolveCliPackageRoot(config) {
16
+ const embed = resolveEmbedHomeDirectory(config);
17
+ if (embed) {
18
+ return embed;
19
+ }
20
+ return (config.resolvePackageRoot?.(config.generatorImplementationDir) ??
21
+ path.resolve(config.generatorImplementationDir, '..'));
22
+ }
23
+ function resolveCliPackageJsonPathForVersions(config) {
24
+ return path.join(resolveCliPackageRoot(config), 'package.json');
25
+ }
26
+ function resolveHostWriteContext(cliDir, config, projectRoot) {
27
+ const product = config?.hostProduct ?? 'api2ai';
28
+ const root = projectRoot ?? resolveProjectRootFromGeneratedCliDir(cliDir);
29
+ return { product, root };
30
+ }
31
+ export function writeGeneratedStdioMcpHost(cliDir, config, projectRoot) {
32
+ if (!fs.existsSync(cliDir)) {
33
+ fs.mkdirSync(cliDir, { recursive: true });
34
+ }
35
+ const dest = path.join(cliDir, 'stdio-mcp-server.ts');
36
+ const { product, root } = resolveHostWriteContext(cliDir, config, projectRoot);
37
+ const loggingImport = loggingAdapterImportForCliFile(dest, root);
38
+ fs.writeFileSync(dest, renderStdioMcpServerSource(product, loggingImport), 'utf-8');
39
+ return dest;
40
+ }
41
+ export function writeGeneratedPublicHttpMcpHost(cliDir, config, projectRoot) {
42
+ if (!fs.existsSync(cliDir)) {
43
+ fs.mkdirSync(cliDir, { recursive: true });
44
+ }
45
+ const dest = path.join(cliDir, 'public-http-mcp-server.ts');
46
+ const { product, root } = resolveHostWriteContext(cliDir, config, projectRoot);
47
+ const loggingImport = loggingAdapterImportForCliFile(dest, root);
48
+ fs.writeFileSync(dest, renderPublicHttpMcpServerSource(product, loggingImport), 'utf-8');
49
+ return dest;
50
+ }
51
+ export function writeGeneratedPassthroughHttpMcpHost(cliDir, config, projectRoot) {
52
+ if (!fs.existsSync(cliDir)) {
53
+ fs.mkdirSync(cliDir, { recursive: true });
54
+ }
55
+ const dest = path.join(cliDir, 'passthrough-http-mcp-server.ts');
56
+ const { product, root } = resolveHostWriteContext(cliDir, config, projectRoot);
57
+ const loggingImport = loggingAdapterImportForCliFile(dest, root);
58
+ fs.writeFileSync(dest, renderPassthroughHttpMcpServerSource(product, loggingImport), 'utf-8');
59
+ return dest;
60
+ }
61
+ /** Writes public and passthrough HTTP MCP hosts. */
62
+ export function writeGeneratedHttpMcpHosts(cliDir, config, projectRoot) {
63
+ return {
64
+ publicHttpMcpHostPath: writeGeneratedPublicHttpMcpHost(cliDir, config, projectRoot),
65
+ passthroughHttpMcpHostPath: writeGeneratedPassthroughHttpMcpHost(cliDir, config, projectRoot)
66
+ };
67
+ }
68
+ export function writeGeneratedOAuthHttpMcpHost(cliDir, config, projectRoot) {
69
+ if (!fs.existsSync(cliDir)) {
70
+ fs.mkdirSync(cliDir, { recursive: true });
71
+ }
72
+ const dest = path.join(cliDir, 'oauth-http-mcp-server.ts');
73
+ const { product, root } = resolveHostWriteContext(cliDir, config, projectRoot);
74
+ const loggingImport = loggingAdapterImportForCliFile(dest, root);
75
+ fs.writeFileSync(dest, renderOAuthHttpMcpServerSource(product, loggingImport), 'utf-8');
76
+ return dest;
77
+ }
78
+ function readCliPackageJson(config) {
79
+ const p = resolveCliPackageJsonPathForVersions(config);
80
+ const raw = fs.readFileSync(p, 'utf-8');
81
+ const pkg = JSON.parse(raw);
82
+ return {
83
+ version: typeof pkg.version === 'string' ? pkg.version : '0.0.1',
84
+ dependencies: pkg.dependencies
85
+ };
86
+ }
87
+ function readCliVersionsForBootstrap(config) {
88
+ const pkg = readCliPackageJson(config);
89
+ const out = {};
90
+ for (const dep of config.requiredRuntimeDeps) {
91
+ out[dep] = pkg.dependencies?.[dep] ?? config.dependencyVersionFallbacks?.[dep] ?? '*';
92
+ }
93
+ return out;
94
+ }
95
+ export function resolveMcpServerIdentityFromDestination(destinationTsPath, config) {
96
+ const pkg = readCliPackageJson(config);
97
+ return {
98
+ name: path.parse(destinationTsPath).name,
99
+ version: pkg.version
100
+ };
101
+ }
102
+ function warnIfPackageJsonMissingMcpDeps(packageJsonDir, config) {
103
+ const pjsonPath = path.join(packageJsonDir, 'package.json');
104
+ if (!fs.existsSync(pjsonPath)) {
105
+ return;
106
+ }
107
+ let pkg;
108
+ try {
109
+ pkg = JSON.parse(fs.readFileSync(pjsonPath, 'utf-8'));
110
+ }
111
+ catch {
112
+ return;
113
+ }
114
+ if (!pkg || typeof pkg !== 'object') {
115
+ return;
116
+ }
117
+ const rec = pkg;
118
+ const merged = {
119
+ ...(rec.optionalDependencies ?? {}),
120
+ ...(rec.dependencies ?? {})
121
+ };
122
+ const missing = config.requiredRuntimeDeps.filter((key) => merged[key] === undefined);
123
+ if (missing.length > 0) {
124
+ console.warn(config.missingDepsMessage?.(pjsonPath, missing) ??
125
+ `[generate] "${pjsonPath}": install runtime dependencies: ${missing.join(', ')} (npm install), then generated/<product>/cli/stdio-mcp-server.js can run.`);
126
+ }
127
+ }
128
+ export function writeMinimalPackageJsonIfAbsent(projectRoot, config) {
129
+ const dest = path.join(projectRoot, 'package.json');
130
+ if (fs.existsSync(dest)) {
131
+ warnIfPackageJsonMissingMcpDeps(projectRoot, config);
132
+ return;
133
+ }
134
+ const versionsByDep = readCliVersionsForBootstrap(config);
135
+ const slug = path
136
+ .basename(projectRoot)
137
+ .replace(/[^a-zA-Z0-9-]/g, '-')
138
+ .replace(/^-+|-+$/g, '')
139
+ .slice(0, 80) || config.fallbackProjectName;
140
+ const body = {
141
+ name: slug,
142
+ private: true,
143
+ type: 'module',
144
+ dependencies: versionsByDep
145
+ };
146
+ fs.writeFileSync(dest, `${JSON.stringify(body, null, 4)}\n`, 'utf-8');
147
+ }
148
+ export function ensureParentDir(destination) {
149
+ const destinationDir = path.dirname(destination);
150
+ if (!fs.existsSync(destinationDir)) {
151
+ fs.mkdirSync(destinationDir, { recursive: true });
152
+ }
153
+ }
@@ -0,0 +1,3 @@
1
+ import { type McpHostProduct } from './mcp-host-product-runtime.js';
2
+ export declare function renderPublicHttpMcpServerSource(product: McpHostProduct | undefined, loggingImport: string): string;
3
+ export declare function renderPassthroughHttpMcpServerSource(product: McpHostProduct | undefined, loggingImport: string): string;