skedyul 0.3.0 → 0.3.2
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/dist/.build-stamp +1 -1
- package/dist/config/app-config.d.ts +73 -0
- package/dist/config/app-config.js +12 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.js +33 -0
- package/dist/config/loader.d.ts +7 -0
- package/dist/config/loader.js +119 -0
- package/dist/config/types/agent.d.ts +29 -0
- package/dist/config/types/agent.js +5 -0
- package/dist/config/types/channel.d.ts +46 -0
- package/dist/config/types/channel.js +2 -0
- package/dist/config/types/compute.d.ts +1 -0
- package/dist/config/types/compute.js +5 -0
- package/dist/config/types/env.d.ts +16 -0
- package/dist/config/types/env.js +5 -0
- package/dist/config/types/index.d.ts +9 -0
- package/dist/config/types/index.js +26 -0
- package/dist/config/types/model.d.ts +62 -0
- package/dist/config/types/model.js +2 -0
- package/dist/config/types/page.d.ts +436 -0
- package/dist/config/types/page.js +5 -0
- package/dist/config/types/resource.d.ts +30 -0
- package/dist/config/types/resource.js +5 -0
- package/dist/config/types/webhook.d.ts +35 -0
- package/dist/config/types/webhook.js +5 -0
- package/dist/config/types/workflow.d.ts +24 -0
- package/dist/config/types/workflow.js +2 -0
- package/dist/config/utils.d.ts +16 -0
- package/dist/config/utils.js +37 -0
- package/dist/config.d.ts +5 -767
- package/dist/config.js +11 -151
- package/dist/schemas.d.ts +43 -43
- package/dist/server/core-api-handler.d.ts +8 -0
- package/dist/server/core-api-handler.js +148 -0
- package/dist/server/dedicated.d.ts +7 -0
- package/dist/server/dedicated.js +610 -0
- package/dist/server/handler-helpers.d.ts +24 -0
- package/dist/server/handler-helpers.js +75 -0
- package/dist/server/index.d.ts +19 -0
- package/dist/server/index.js +196 -0
- package/dist/server/serverless.d.ts +7 -0
- package/dist/server/serverless.js +629 -0
- package/dist/server/startup-logger.d.ts +9 -0
- package/dist/server/startup-logger.js +113 -0
- package/dist/server/tool-handler.d.ts +14 -0
- package/dist/server/tool-handler.js +189 -0
- package/dist/server/types.d.ts +22 -0
- package/dist/server/types.js +2 -0
- package/dist/server/utils/env.d.ts +12 -0
- package/dist/server/utils/env.js +38 -0
- package/dist/server/utils/http.d.ts +30 -0
- package/dist/server/utils/http.js +81 -0
- package/dist/server/utils/index.d.ts +3 -0
- package/dist/server/utils/index.js +24 -0
- package/dist/server/utils/schema.d.ts +22 -0
- package/dist/server/utils/schema.js +102 -0
- package/dist/server.d.ts +7 -11
- package/dist/server.js +39 -2026
- package/dist/types/aws.d.ts +15 -0
- package/dist/types/aws.js +5 -0
- package/dist/types/handlers.d.ts +122 -0
- package/dist/types/handlers.js +2 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.js +16 -0
- package/dist/types/server.d.ts +43 -0
- package/dist/types/server.js +2 -0
- package/dist/types/shared.d.ts +16 -0
- package/dist/types/shared.js +5 -0
- package/dist/types/tool-context.d.ts +64 -0
- package/dist/types/tool-context.js +12 -0
- package/dist/types/tool.d.ts +96 -0
- package/dist/types/tool.js +19 -0
- package/dist/types/webhook.d.ts +116 -0
- package/dist/types/webhook.js +7 -0
- package/dist/types.d.ts +4 -461
- package/dist/types.js +21 -31
- package/package.json +2 -2
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.padEnd = padEnd;
|
|
4
|
+
exports.printStartupLog = printStartupLog;
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
/**
|
|
7
|
+
* Pad a string to the right with spaces
|
|
8
|
+
*/
|
|
9
|
+
function padEnd(str, length) {
|
|
10
|
+
if (str.length >= length) {
|
|
11
|
+
return str.slice(0, length);
|
|
12
|
+
}
|
|
13
|
+
return str + ' '.repeat(length - str.length);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Prints a styled startup log showing server configuration
|
|
17
|
+
*/
|
|
18
|
+
function printStartupLog(config, tools, webhookRegistry, port) {
|
|
19
|
+
// Skip startup log during tests
|
|
20
|
+
if (process.env.NODE_ENV === 'test') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const webhookCount = webhookRegistry ? Object.keys(webhookRegistry).length : 0;
|
|
24
|
+
const webhookNames = webhookRegistry ? Object.keys(webhookRegistry) : [];
|
|
25
|
+
const maxRequests = config.maxRequests ??
|
|
26
|
+
(0, utils_1.parseNumberEnv)(process.env.MCP_MAX_REQUESTS) ??
|
|
27
|
+
null;
|
|
28
|
+
const ttlExtendSeconds = config.ttlExtendSeconds ??
|
|
29
|
+
(0, utils_1.parseNumberEnv)(process.env.MCP_TTL_EXTEND) ??
|
|
30
|
+
3600;
|
|
31
|
+
const executableId = process.env.SKEDYUL_EXECUTABLE_ID || 'local';
|
|
32
|
+
const divider = '═'.repeat(70);
|
|
33
|
+
const thinDivider = '─'.repeat(70);
|
|
34
|
+
// eslint-disable-next-line no-console
|
|
35
|
+
console.log('');
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.log(`╔${divider}╗`);
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
console.log(`║ 🚀 Skedyul MCP Server Starting ║`);
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.log(`╠${divider}╣`);
|
|
42
|
+
// eslint-disable-next-line no-console
|
|
43
|
+
console.log(`║ ║`);
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.log(`║ 📦 Server: ${padEnd(config.metadata.name, 49)}║`);
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
47
|
+
console.log(`║ 🏷️ Version: ${padEnd(config.metadata.version, 49)}║`);
|
|
48
|
+
// eslint-disable-next-line no-console
|
|
49
|
+
console.log(`║ ⚡ Compute: ${padEnd(config.computeLayer, 49)}║`);
|
|
50
|
+
if (port) {
|
|
51
|
+
// eslint-disable-next-line no-console
|
|
52
|
+
console.log(`║ 🌐 Port: ${padEnd(String(port), 49)}║`);
|
|
53
|
+
}
|
|
54
|
+
// eslint-disable-next-line no-console
|
|
55
|
+
console.log(`║ 🔑 Executable: ${padEnd(executableId, 49)}║`);
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.log(`║ ║`);
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.log(`╟${thinDivider}╢`);
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.log(`║ ║`);
|
|
62
|
+
// eslint-disable-next-line no-console
|
|
63
|
+
console.log(`║ 🔧 Tools (${tools.length}): ║`);
|
|
64
|
+
// List tools (max 10, then show "and X more...")
|
|
65
|
+
const maxToolsToShow = 10;
|
|
66
|
+
const toolsToShow = tools.slice(0, maxToolsToShow);
|
|
67
|
+
for (const tool of toolsToShow) {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.log(`║ • ${padEnd(tool.name, 61)}║`);
|
|
70
|
+
}
|
|
71
|
+
if (tools.length > maxToolsToShow) {
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
console.log(`║ ... and ${tools.length - maxToolsToShow} more ║`);
|
|
74
|
+
}
|
|
75
|
+
if (webhookCount > 0) {
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
console.log(`║ ║`);
|
|
78
|
+
// eslint-disable-next-line no-console
|
|
79
|
+
console.log(`║ 🪝 Webhooks (${webhookCount}): ║`);
|
|
80
|
+
const maxWebhooksToShow = 5;
|
|
81
|
+
const webhooksToShow = webhookNames.slice(0, maxWebhooksToShow);
|
|
82
|
+
for (const name of webhooksToShow) {
|
|
83
|
+
// eslint-disable-next-line no-console
|
|
84
|
+
console.log(`║ • /webhooks/${padEnd(name, 51)}║`);
|
|
85
|
+
}
|
|
86
|
+
if (webhookCount > maxWebhooksToShow) {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.log(`║ ... and ${webhookCount - maxWebhooksToShow} more ║`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// eslint-disable-next-line no-console
|
|
92
|
+
console.log(`║ ║`);
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.log(`╟${thinDivider}╢`);
|
|
95
|
+
// eslint-disable-next-line no-console
|
|
96
|
+
console.log(`║ ║`);
|
|
97
|
+
// eslint-disable-next-line no-console
|
|
98
|
+
console.log(`║ ⚙️ Configuration: ║`);
|
|
99
|
+
// eslint-disable-next-line no-console
|
|
100
|
+
console.log(`║ Max Requests: ${padEnd(maxRequests !== null ? String(maxRequests) : 'unlimited', 46)}║`);
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
102
|
+
console.log(`║ TTL Extend: ${padEnd(`${ttlExtendSeconds}s`, 46)}║`);
|
|
103
|
+
// eslint-disable-next-line no-console
|
|
104
|
+
console.log(`║ ║`);
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.log(`╟${thinDivider}╢`);
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
108
|
+
console.log(`║ ✅ Ready at ${padEnd(new Date().toISOString(), 55)}║`);
|
|
109
|
+
// eslint-disable-next-line no-console
|
|
110
|
+
console.log(`╚${divider}╝`);
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.log('');
|
|
113
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolCallResponse, ToolMetadata, ToolRegistry } from '../types';
|
|
2
|
+
import type { RequestState } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Builds tool metadata array from a tool registry
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildToolMetadata(registry: ToolRegistry): ToolMetadata[];
|
|
7
|
+
/**
|
|
8
|
+
* Creates a request state tracker for managing request counts and health status
|
|
9
|
+
*/
|
|
10
|
+
export declare function createRequestState(maxRequests: number | null, ttlExtendSeconds: number, runtimeLabel: string, toolNames: string[]): RequestState;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a tool call handler function for executing tools from the registry
|
|
13
|
+
*/
|
|
14
|
+
export declare function createCallToolHandler<T extends ToolRegistry>(registry: T, state: RequestState, onMaxRequests?: () => void): (nameRaw: unknown, argsRaw: unknown) => Promise<ToolCallResponse>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildToolMetadata = buildToolMetadata;
|
|
4
|
+
exports.createRequestState = createRequestState;
|
|
5
|
+
exports.createCallToolHandler = createCallToolHandler;
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const client_1 = require("../core/client");
|
|
8
|
+
const errors_1 = require("../errors");
|
|
9
|
+
/**
|
|
10
|
+
* Builds tool metadata array from a tool registry
|
|
11
|
+
*/
|
|
12
|
+
function buildToolMetadata(registry) {
|
|
13
|
+
return Object.values(registry).map((tool) => {
|
|
14
|
+
const timeout = typeof tool.timeout === 'number' && tool.timeout > 0 ? tool.timeout : 10000;
|
|
15
|
+
return {
|
|
16
|
+
name: tool.name,
|
|
17
|
+
displayName: tool.label || tool.name,
|
|
18
|
+
description: tool.description,
|
|
19
|
+
inputSchema: (0, utils_1.getJsonSchemaFromToolSchema)(tool.inputSchema),
|
|
20
|
+
outputSchema: (0, utils_1.getJsonSchemaFromToolSchema)(tool.outputSchema),
|
|
21
|
+
timeout, // Default to 10 seconds
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a request state tracker for managing request counts and health status
|
|
27
|
+
*/
|
|
28
|
+
function createRequestState(maxRequests, ttlExtendSeconds, runtimeLabel, toolNames) {
|
|
29
|
+
let requestCount = 0;
|
|
30
|
+
let lastRequestTime = Date.now();
|
|
31
|
+
return {
|
|
32
|
+
incrementRequestCount() {
|
|
33
|
+
requestCount += 1;
|
|
34
|
+
lastRequestTime = Date.now();
|
|
35
|
+
},
|
|
36
|
+
shouldShutdown() {
|
|
37
|
+
return maxRequests !== null && requestCount >= maxRequests;
|
|
38
|
+
},
|
|
39
|
+
getHealthStatus() {
|
|
40
|
+
return {
|
|
41
|
+
status: 'running',
|
|
42
|
+
requests: requestCount,
|
|
43
|
+
maxRequests,
|
|
44
|
+
requestsRemaining: maxRequests !== null ? Math.max(0, maxRequests - requestCount) : null,
|
|
45
|
+
lastRequestTime,
|
|
46
|
+
ttlExtendSeconds,
|
|
47
|
+
runtime: runtimeLabel,
|
|
48
|
+
tools: [...toolNames],
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a tool call handler function for executing tools from the registry
|
|
55
|
+
*/
|
|
56
|
+
function createCallToolHandler(registry, state, onMaxRequests) {
|
|
57
|
+
return async function callTool(nameRaw, argsRaw) {
|
|
58
|
+
const toolName = String(nameRaw);
|
|
59
|
+
const tool = registry[toolName];
|
|
60
|
+
if (!tool) {
|
|
61
|
+
throw new Error(`Tool "${toolName}" not found in registry`);
|
|
62
|
+
}
|
|
63
|
+
if (!tool.handler || typeof tool.handler !== 'function') {
|
|
64
|
+
throw new Error(`Tool "${toolName}" handler is not a function`);
|
|
65
|
+
}
|
|
66
|
+
const fn = tool.handler;
|
|
67
|
+
const args = (argsRaw ?? {});
|
|
68
|
+
const estimateMode = args.estimate === true;
|
|
69
|
+
if (!estimateMode) {
|
|
70
|
+
state.incrementRequestCount();
|
|
71
|
+
if (state.shouldShutdown()) {
|
|
72
|
+
onMaxRequests?.();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const requestEnv = args.env ?? {};
|
|
76
|
+
const originalEnv = { ...process.env };
|
|
77
|
+
Object.assign(process.env, requestEnv);
|
|
78
|
+
try {
|
|
79
|
+
// Get tool inputs (clean, no context)
|
|
80
|
+
const inputs = (args.inputs ?? {});
|
|
81
|
+
// Get context from args.context (separate from inputs)
|
|
82
|
+
const rawContext = (args.context ?? {});
|
|
83
|
+
// Extract app info (required for all contexts)
|
|
84
|
+
const app = rawContext.app;
|
|
85
|
+
// Determine trigger type from context
|
|
86
|
+
const trigger = rawContext.trigger || 'agent';
|
|
87
|
+
// Build execution context based on trigger type
|
|
88
|
+
let executionContext;
|
|
89
|
+
if (trigger === 'provision') {
|
|
90
|
+
// Provision context - no installation, no workplace
|
|
91
|
+
executionContext = {
|
|
92
|
+
trigger: 'provision',
|
|
93
|
+
app,
|
|
94
|
+
env: process.env,
|
|
95
|
+
mode: estimateMode ? 'estimate' : 'execute',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Runtime context - has installation, workplace, request
|
|
100
|
+
const workplace = rawContext.workplace;
|
|
101
|
+
const request = rawContext.request;
|
|
102
|
+
const appInstallationId = rawContext.appInstallationId;
|
|
103
|
+
const envVars = process.env;
|
|
104
|
+
const modeValue = estimateMode ? 'estimate' : 'execute';
|
|
105
|
+
if (trigger === 'field_change') {
|
|
106
|
+
const field = rawContext.field;
|
|
107
|
+
executionContext = { trigger: 'field_change', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, field };
|
|
108
|
+
}
|
|
109
|
+
else if (trigger === 'page_action') {
|
|
110
|
+
const page = rawContext.page;
|
|
111
|
+
executionContext = { trigger: 'page_action', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, page };
|
|
112
|
+
}
|
|
113
|
+
else if (trigger === 'form_submit') {
|
|
114
|
+
const form = rawContext.form;
|
|
115
|
+
executionContext = { trigger: 'form_submit', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, form };
|
|
116
|
+
}
|
|
117
|
+
else if (trigger === 'workflow') {
|
|
118
|
+
executionContext = { trigger: 'workflow', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
119
|
+
}
|
|
120
|
+
else if (trigger === 'page_context') {
|
|
121
|
+
// Page context trigger - similar to agent but for page context resolution
|
|
122
|
+
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Default to agent
|
|
126
|
+
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Build request-scoped config from env passed in MCP call
|
|
130
|
+
const requestConfig = {
|
|
131
|
+
baseUrl: requestEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? '',
|
|
132
|
+
apiToken: requestEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? '',
|
|
133
|
+
};
|
|
134
|
+
// Call handler with two arguments: (input, context)
|
|
135
|
+
// Wrap in runWithConfig for request-scoped SDK configuration
|
|
136
|
+
const functionResult = await (0, client_1.runWithConfig)(requestConfig, async () => {
|
|
137
|
+
return await fn(inputs, executionContext);
|
|
138
|
+
});
|
|
139
|
+
const billing = (0, utils_1.normalizeBilling)(functionResult.billing);
|
|
140
|
+
return {
|
|
141
|
+
output: functionResult.output,
|
|
142
|
+
billing,
|
|
143
|
+
meta: functionResult.meta ?? {
|
|
144
|
+
success: true,
|
|
145
|
+
message: 'OK',
|
|
146
|
+
toolName,
|
|
147
|
+
},
|
|
148
|
+
effect: functionResult.effect,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
// Check if it's an AppAuthInvalidError
|
|
153
|
+
if (error instanceof errors_1.AppAuthInvalidError) {
|
|
154
|
+
return {
|
|
155
|
+
output: null,
|
|
156
|
+
billing: { credits: 0 },
|
|
157
|
+
meta: {
|
|
158
|
+
success: false,
|
|
159
|
+
message: error.message,
|
|
160
|
+
toolName,
|
|
161
|
+
},
|
|
162
|
+
error: {
|
|
163
|
+
code: error.code,
|
|
164
|
+
message: error.message,
|
|
165
|
+
},
|
|
166
|
+
// Note: redirect URL will be added by workflow after detecting APP_AUTH_INVALID
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// Generic error handling for other errors
|
|
170
|
+
const errorMessage = error instanceof Error ? error.message : String(error ?? '');
|
|
171
|
+
return {
|
|
172
|
+
output: null,
|
|
173
|
+
billing: { credits: 0 },
|
|
174
|
+
meta: {
|
|
175
|
+
success: false,
|
|
176
|
+
message: errorMessage,
|
|
177
|
+
toolName,
|
|
178
|
+
},
|
|
179
|
+
error: {
|
|
180
|
+
code: 'TOOL_EXECUTION_ERROR',
|
|
181
|
+
message: errorMessage,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
process.env = originalEnv;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HealthStatus } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Arguments passed to tool call handlers
|
|
4
|
+
*/
|
|
5
|
+
export type ToolCallArgs = {
|
|
6
|
+
env?: Record<string, string | undefined>;
|
|
7
|
+
inputs?: Record<string, unknown>;
|
|
8
|
+
context?: Record<string, unknown>;
|
|
9
|
+
estimate?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Interface for tracking request state and health status
|
|
13
|
+
*/
|
|
14
|
+
export interface RequestState {
|
|
15
|
+
incrementRequestCount(): void;
|
|
16
|
+
shouldShutdown(): boolean;
|
|
17
|
+
getHealthStatus(): HealthStatus;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Supported core API methods
|
|
21
|
+
*/
|
|
22
|
+
export type CoreMethod = 'createCommunicationChannel' | 'updateCommunicationChannel' | 'deleteCommunicationChannel' | 'getCommunicationChannel' | 'getCommunicationChannels' | 'communicationChannel.list' | 'communicationChannel.get' | 'workplace.list' | 'workplace.get' | 'sendMessage';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a JSON string into a Record, returning empty object on failure
|
|
3
|
+
*/
|
|
4
|
+
export declare function parseJsonRecord(value?: string): Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Parses a string environment variable as a number
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseNumberEnv(value?: string): number | null;
|
|
9
|
+
/**
|
|
10
|
+
* Merges baked-in environment variables with runtime environment variables
|
|
11
|
+
*/
|
|
12
|
+
export declare function mergeRuntimeEnv(): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseJsonRecord = parseJsonRecord;
|
|
4
|
+
exports.parseNumberEnv = parseNumberEnv;
|
|
5
|
+
exports.mergeRuntimeEnv = mergeRuntimeEnv;
|
|
6
|
+
/**
|
|
7
|
+
* Parses a JSON string into a Record, returning empty object on failure
|
|
8
|
+
*/
|
|
9
|
+
function parseJsonRecord(value) {
|
|
10
|
+
if (!value) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(value);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parses a string environment variable as a number
|
|
22
|
+
*/
|
|
23
|
+
function parseNumberEnv(value) {
|
|
24
|
+
if (!value) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const parsed = Number.parseInt(value, 10);
|
|
28
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Merges baked-in environment variables with runtime environment variables
|
|
32
|
+
*/
|
|
33
|
+
function mergeRuntimeEnv() {
|
|
34
|
+
const bakedEnv = parseJsonRecord(process.env.MCP_ENV_JSON);
|
|
35
|
+
const runtimeEnv = parseJsonRecord(process.env.MCP_ENV);
|
|
36
|
+
const merged = { ...bakedEnv, ...runtimeEnv };
|
|
37
|
+
Object.assign(process.env, merged);
|
|
38
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import http, { IncomingMessage } from 'http';
|
|
2
|
+
import type { APIGatewayProxyResult, CorsOptions, SkedyulServerConfig } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Reads the raw request body from an IncomingMessage
|
|
5
|
+
*/
|
|
6
|
+
export declare function readRawRequestBody(req: IncomingMessage): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Parses JSON body from an IncomingMessage
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseJSONBody(req: IncomingMessage): Promise<unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Sends a JSON response
|
|
13
|
+
*/
|
|
14
|
+
export declare function sendJSON(res: http.ServerResponse, statusCode: number, data: unknown): void;
|
|
15
|
+
/**
|
|
16
|
+
* Sends an HTML response
|
|
17
|
+
*/
|
|
18
|
+
export declare function sendHTML(res: http.ServerResponse, statusCode: number, html: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Gets default CORS headers
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDefaultHeaders(options?: CorsOptions): Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Creates an API Gateway proxy response
|
|
25
|
+
*/
|
|
26
|
+
export declare function createResponse(statusCode: number, body: unknown, headers: Record<string, string>): APIGatewayProxyResult;
|
|
27
|
+
/**
|
|
28
|
+
* Gets the port to listen on from config or environment
|
|
29
|
+
*/
|
|
30
|
+
export declare function getListeningPort(config: SkedyulServerConfig): number;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readRawRequestBody = readRawRequestBody;
|
|
4
|
+
exports.parseJSONBody = parseJSONBody;
|
|
5
|
+
exports.sendJSON = sendJSON;
|
|
6
|
+
exports.sendHTML = sendHTML;
|
|
7
|
+
exports.getDefaultHeaders = getDefaultHeaders;
|
|
8
|
+
exports.createResponse = createResponse;
|
|
9
|
+
exports.getListeningPort = getListeningPort;
|
|
10
|
+
/**
|
|
11
|
+
* Reads the raw request body from an IncomingMessage
|
|
12
|
+
*/
|
|
13
|
+
function readRawRequestBody(req) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
let body = '';
|
|
16
|
+
req.on('data', (chunk) => {
|
|
17
|
+
body += chunk.toString();
|
|
18
|
+
});
|
|
19
|
+
req.on('end', () => {
|
|
20
|
+
resolve(body);
|
|
21
|
+
});
|
|
22
|
+
req.on('error', reject);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parses JSON body from an IncomingMessage
|
|
27
|
+
*/
|
|
28
|
+
async function parseJSONBody(req) {
|
|
29
|
+
const rawBody = await readRawRequestBody(req);
|
|
30
|
+
try {
|
|
31
|
+
return rawBody ? JSON.parse(rawBody) : {};
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sends a JSON response
|
|
39
|
+
*/
|
|
40
|
+
function sendJSON(res, statusCode, data) {
|
|
41
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
42
|
+
res.end(JSON.stringify(data));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sends an HTML response
|
|
46
|
+
*/
|
|
47
|
+
function sendHTML(res, statusCode, html) {
|
|
48
|
+
res.writeHead(statusCode, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
49
|
+
res.end(html);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gets default CORS headers
|
|
53
|
+
*/
|
|
54
|
+
function getDefaultHeaders(options) {
|
|
55
|
+
return {
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
'Access-Control-Allow-Origin': options?.allowOrigin ?? '*',
|
|
58
|
+
'Access-Control-Allow-Methods': options?.allowMethods ?? 'GET, POST, OPTIONS',
|
|
59
|
+
'Access-Control-Allow-Headers': options?.allowHeaders ?? 'Content-Type',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Creates an API Gateway proxy response
|
|
64
|
+
*/
|
|
65
|
+
function createResponse(statusCode, body, headers) {
|
|
66
|
+
return {
|
|
67
|
+
statusCode,
|
|
68
|
+
headers,
|
|
69
|
+
body: JSON.stringify(body),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Gets the port to listen on from config or environment
|
|
74
|
+
*/
|
|
75
|
+
function getListeningPort(config) {
|
|
76
|
+
const envPort = Number.parseInt(process.env.PORT ?? '', 10);
|
|
77
|
+
if (!Number.isNaN(envPort)) {
|
|
78
|
+
return envPort;
|
|
79
|
+
}
|
|
80
|
+
return config.defaultPort ?? 3000;
|
|
81
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { normalizeBilling, toJsonSchema, isToolSchemaWithJson, getZodSchema, getJsonSchemaFromToolSchema, } from './schema';
|
|
2
|
+
export { parseJsonRecord, parseNumberEnv, mergeRuntimeEnv, } from './env';
|
|
3
|
+
export { readRawRequestBody, parseJSONBody, sendJSON, sendHTML, getDefaultHeaders, createResponse, getListeningPort, } from './http';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getListeningPort = exports.createResponse = exports.getDefaultHeaders = exports.sendHTML = exports.sendJSON = exports.parseJSONBody = exports.readRawRequestBody = exports.mergeRuntimeEnv = exports.parseNumberEnv = exports.parseJsonRecord = exports.getJsonSchemaFromToolSchema = exports.getZodSchema = exports.isToolSchemaWithJson = exports.toJsonSchema = exports.normalizeBilling = void 0;
|
|
4
|
+
// Schema utilities
|
|
5
|
+
var schema_1 = require("./schema");
|
|
6
|
+
Object.defineProperty(exports, "normalizeBilling", { enumerable: true, get: function () { return schema_1.normalizeBilling; } });
|
|
7
|
+
Object.defineProperty(exports, "toJsonSchema", { enumerable: true, get: function () { return schema_1.toJsonSchema; } });
|
|
8
|
+
Object.defineProperty(exports, "isToolSchemaWithJson", { enumerable: true, get: function () { return schema_1.isToolSchemaWithJson; } });
|
|
9
|
+
Object.defineProperty(exports, "getZodSchema", { enumerable: true, get: function () { return schema_1.getZodSchema; } });
|
|
10
|
+
Object.defineProperty(exports, "getJsonSchemaFromToolSchema", { enumerable: true, get: function () { return schema_1.getJsonSchemaFromToolSchema; } });
|
|
11
|
+
// Environment utilities
|
|
12
|
+
var env_1 = require("./env");
|
|
13
|
+
Object.defineProperty(exports, "parseJsonRecord", { enumerable: true, get: function () { return env_1.parseJsonRecord; } });
|
|
14
|
+
Object.defineProperty(exports, "parseNumberEnv", { enumerable: true, get: function () { return env_1.parseNumberEnv; } });
|
|
15
|
+
Object.defineProperty(exports, "mergeRuntimeEnv", { enumerable: true, get: function () { return env_1.mergeRuntimeEnv; } });
|
|
16
|
+
// HTTP utilities
|
|
17
|
+
var http_1 = require("./http");
|
|
18
|
+
Object.defineProperty(exports, "readRawRequestBody", { enumerable: true, get: function () { return http_1.readRawRequestBody; } });
|
|
19
|
+
Object.defineProperty(exports, "parseJSONBody", { enumerable: true, get: function () { return http_1.parseJSONBody; } });
|
|
20
|
+
Object.defineProperty(exports, "sendJSON", { enumerable: true, get: function () { return http_1.sendJSON; } });
|
|
21
|
+
Object.defineProperty(exports, "sendHTML", { enumerable: true, get: function () { return http_1.sendHTML; } });
|
|
22
|
+
Object.defineProperty(exports, "getDefaultHeaders", { enumerable: true, get: function () { return http_1.getDefaultHeaders; } });
|
|
23
|
+
Object.defineProperty(exports, "createResponse", { enumerable: true, get: function () { return http_1.createResponse; } });
|
|
24
|
+
Object.defineProperty(exports, "getListeningPort", { enumerable: true, get: function () { return http_1.getListeningPort; } });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import type { BillingInfo, ToolSchema, ToolSchemaWithJson } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes billing info to ensure credits field exists
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeBilling(billing?: BillingInfo): BillingInfo;
|
|
7
|
+
/**
|
|
8
|
+
* Converts a Zod schema to JSON Schema format
|
|
9
|
+
*/
|
|
10
|
+
export declare function toJsonSchema(schema?: z.ZodTypeAny): Record<string, unknown> | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Type guard to check if a schema is a ToolSchemaWithJson
|
|
13
|
+
*/
|
|
14
|
+
export declare function isToolSchemaWithJson(schema: ToolSchema | undefined): schema is ToolSchemaWithJson;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts the Zod schema from a ToolSchema
|
|
17
|
+
*/
|
|
18
|
+
export declare function getZodSchema(schema?: ToolSchema): z.ZodTypeAny | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Gets JSON schema from a ToolSchema, either from explicit jsonSchema or by converting Zod
|
|
21
|
+
*/
|
|
22
|
+
export declare function getJsonSchemaFromToolSchema(schema?: ToolSchema): Record<string, unknown> | undefined;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeBilling = normalizeBilling;
|
|
37
|
+
exports.toJsonSchema = toJsonSchema;
|
|
38
|
+
exports.isToolSchemaWithJson = isToolSchemaWithJson;
|
|
39
|
+
exports.getZodSchema = getZodSchema;
|
|
40
|
+
exports.getJsonSchemaFromToolSchema = getJsonSchemaFromToolSchema;
|
|
41
|
+
const z = __importStar(require("zod"));
|
|
42
|
+
/**
|
|
43
|
+
* Normalizes billing info to ensure credits field exists
|
|
44
|
+
*/
|
|
45
|
+
function normalizeBilling(billing) {
|
|
46
|
+
if (!billing || typeof billing.credits !== 'number') {
|
|
47
|
+
return { credits: 0 };
|
|
48
|
+
}
|
|
49
|
+
return billing;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts a Zod schema to JSON Schema format
|
|
53
|
+
*/
|
|
54
|
+
function toJsonSchema(schema) {
|
|
55
|
+
if (!schema)
|
|
56
|
+
return undefined;
|
|
57
|
+
try {
|
|
58
|
+
// Zod v4 has native JSON Schema support via z.toJSONSchema()
|
|
59
|
+
return z.toJSONSchema(schema, {
|
|
60
|
+
unrepresentable: 'any', // Handle z.date(), z.bigint() etc gracefully
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error('[toJsonSchema] Failed to convert schema:', err);
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Type guard to check if a schema is a ToolSchemaWithJson
|
|
70
|
+
*/
|
|
71
|
+
function isToolSchemaWithJson(schema) {
|
|
72
|
+
return Boolean(schema &&
|
|
73
|
+
typeof schema === 'object' &&
|
|
74
|
+
'zod' in schema &&
|
|
75
|
+
schema.zod instanceof z.ZodType);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Extracts the Zod schema from a ToolSchema
|
|
79
|
+
*/
|
|
80
|
+
function getZodSchema(schema) {
|
|
81
|
+
if (!schema)
|
|
82
|
+
return undefined;
|
|
83
|
+
if (schema instanceof z.ZodType) {
|
|
84
|
+
return schema;
|
|
85
|
+
}
|
|
86
|
+
if (isToolSchemaWithJson(schema)) {
|
|
87
|
+
return schema.zod;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Gets JSON schema from a ToolSchema, either from explicit jsonSchema or by converting Zod
|
|
93
|
+
*/
|
|
94
|
+
function getJsonSchemaFromToolSchema(schema) {
|
|
95
|
+
if (!schema)
|
|
96
|
+
return undefined;
|
|
97
|
+
if (isToolSchemaWithJson(schema) && schema.jsonSchema) {
|
|
98
|
+
return schema.jsonSchema;
|
|
99
|
+
}
|
|
100
|
+
const zodSchema = getZodSchema(schema);
|
|
101
|
+
return toJsonSchema(zodSchema);
|
|
102
|
+
}
|