skedyul 0.1.7 → 0.1.9
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/cli/commands/invoke.d.ts +1 -0
- package/dist/cli/commands/invoke.js +223 -0
- package/dist/cli/commands/serve.d.ts +1 -0
- package/dist/cli/commands/serve.js +123 -0
- package/dist/cli/commands/tools.d.ts +1 -0
- package/dist/cli/commands/tools.js +148 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +80 -0
- package/dist/cli/utils.d.ts +25 -0
- package/dist/cli/utils.js +186 -0
- package/dist/server.js +21 -3
- package/package.json +5 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function invokeCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,223 @@
|
|
|
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.invokeCommand = invokeCommand;
|
|
37
|
+
const z = __importStar(require("zod"));
|
|
38
|
+
const utils_1 = require("../utils");
|
|
39
|
+
function printHelp() {
|
|
40
|
+
console.log(`
|
|
41
|
+
skedyul dev invoke - Invoke a tool from the registry
|
|
42
|
+
|
|
43
|
+
Usage:
|
|
44
|
+
skedyul dev invoke <tool-name> [options]
|
|
45
|
+
|
|
46
|
+
Arguments:
|
|
47
|
+
<tool-name> Name of the tool to invoke (e.g., 'calendar_slots.list')
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
--registry, -r Path to the registry file (default: ./dist/registry.js)
|
|
51
|
+
--args, -a JSON string of arguments to pass to the tool
|
|
52
|
+
--env, -e Set environment variable (can be used multiple times)
|
|
53
|
+
Format: --env KEY=VALUE
|
|
54
|
+
--env-file Load environment variables from a file (e.g., .env.local)
|
|
55
|
+
--estimate Run in estimate mode (billing only, no execution)
|
|
56
|
+
--help, -h Show this help message
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
# Basic invocation
|
|
60
|
+
skedyul dev invoke my_tool --registry ./dist/registry.js --args '{"key": "value"}'
|
|
61
|
+
|
|
62
|
+
# With environment variables
|
|
63
|
+
skedyul dev invoke api_call \\
|
|
64
|
+
--registry ./dist/registry.js \\
|
|
65
|
+
--args '{"endpoint": "/users"}' \\
|
|
66
|
+
--env API_KEY=secret123 \\
|
|
67
|
+
--env BASE_URL=https://api.example.com
|
|
68
|
+
|
|
69
|
+
# Load env from file
|
|
70
|
+
skedyul dev invoke api_call \\
|
|
71
|
+
--registry ./dist/registry.js \\
|
|
72
|
+
--args '{"endpoint": "/users"}' \\
|
|
73
|
+
--env-file .env.local
|
|
74
|
+
|
|
75
|
+
# Estimate mode (billing only)
|
|
76
|
+
skedyul dev invoke expensive_tool \\
|
|
77
|
+
--registry ./dist/registry.js \\
|
|
78
|
+
--args '{"data": "test"}' \\
|
|
79
|
+
--estimate
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
function getZodSchema(schema) {
|
|
83
|
+
if (!schema)
|
|
84
|
+
return undefined;
|
|
85
|
+
if (schema instanceof z.ZodType) {
|
|
86
|
+
return schema;
|
|
87
|
+
}
|
|
88
|
+
if (typeof schema === 'object' && schema !== null && 'zod' in schema) {
|
|
89
|
+
const schemaWithZod = schema;
|
|
90
|
+
if (schemaWithZod.zod instanceof z.ZodType) {
|
|
91
|
+
return schemaWithZod.zod;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
async function invokeCommand(args) {
|
|
97
|
+
const { flags, positional } = (0, utils_1.parseArgs)(args);
|
|
98
|
+
if (flags.help || flags.h) {
|
|
99
|
+
printHelp();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const toolName = positional[0];
|
|
103
|
+
if (!toolName) {
|
|
104
|
+
console.error('Error: Tool name is required');
|
|
105
|
+
console.error("Run 'skedyul dev invoke --help' for usage information.");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
// Get registry path
|
|
109
|
+
const registryPath = (flags.registry || flags.r || './dist/registry.js');
|
|
110
|
+
// Parse tool arguments
|
|
111
|
+
let toolArgs = {};
|
|
112
|
+
const argsValue = flags.args || flags.a;
|
|
113
|
+
if (argsValue && typeof argsValue === 'string') {
|
|
114
|
+
try {
|
|
115
|
+
toolArgs = JSON.parse(argsValue);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
console.error('Error: Invalid JSON in --args');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Build environment
|
|
123
|
+
const env = { ...process.env };
|
|
124
|
+
// Load from env file if specified
|
|
125
|
+
const envFile = flags['env-file'];
|
|
126
|
+
if (envFile && typeof envFile === 'string') {
|
|
127
|
+
try {
|
|
128
|
+
const fileEnv = (0, utils_1.loadEnvFile)(envFile);
|
|
129
|
+
Object.assign(env, fileEnv);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error(`Error loading env file: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Parse --env flags from raw args
|
|
137
|
+
const cliEnv = (0, utils_1.parseEnvFlags)(args);
|
|
138
|
+
Object.assign(env, cliEnv);
|
|
139
|
+
// Check for estimate mode
|
|
140
|
+
const estimateMode = Boolean(flags.estimate);
|
|
141
|
+
// Load registry
|
|
142
|
+
let registry;
|
|
143
|
+
try {
|
|
144
|
+
registry = await (0, utils_1.loadRegistry)(registryPath);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
// Find tool
|
|
151
|
+
let tool;
|
|
152
|
+
// Try exact match first
|
|
153
|
+
if (registry[toolName]) {
|
|
154
|
+
tool = registry[toolName];
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Search by tool.name property
|
|
158
|
+
for (const [, entry] of Object.entries(registry)) {
|
|
159
|
+
if (entry.name === toolName) {
|
|
160
|
+
tool = entry;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (!tool) {
|
|
166
|
+
console.error(`Error: Tool "${toolName}" not found in registry`);
|
|
167
|
+
console.error('\nAvailable tools:');
|
|
168
|
+
for (const [key, entry] of Object.entries(registry)) {
|
|
169
|
+
console.error(` - ${entry.name || key}`);
|
|
170
|
+
}
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
// Validate inputs if schema exists
|
|
174
|
+
const inputSchema = getZodSchema(tool.inputs);
|
|
175
|
+
let validatedArgs = toolArgs;
|
|
176
|
+
if (inputSchema) {
|
|
177
|
+
try {
|
|
178
|
+
validatedArgs = inputSchema.parse(toolArgs);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
if (error instanceof z.ZodError) {
|
|
182
|
+
console.error('Error: Invalid tool arguments');
|
|
183
|
+
for (const issue of error.issues) {
|
|
184
|
+
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
|
|
185
|
+
}
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Create context
|
|
192
|
+
const context = {
|
|
193
|
+
env,
|
|
194
|
+
mode: estimateMode ? 'estimate' : 'execute',
|
|
195
|
+
};
|
|
196
|
+
// Execute tool
|
|
197
|
+
console.error(`Invoking tool: ${tool.name}`);
|
|
198
|
+
if (estimateMode) {
|
|
199
|
+
console.error('Mode: estimate (billing only)');
|
|
200
|
+
}
|
|
201
|
+
console.error('');
|
|
202
|
+
try {
|
|
203
|
+
const handler = tool.handler;
|
|
204
|
+
const result = await handler({
|
|
205
|
+
input: validatedArgs,
|
|
206
|
+
context,
|
|
207
|
+
});
|
|
208
|
+
// Output result
|
|
209
|
+
if (estimateMode) {
|
|
210
|
+
console.log((0, utils_1.formatJson)({ billing: result.billing }));
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
console.log((0, utils_1.formatJson)({
|
|
214
|
+
output: result.output,
|
|
215
|
+
billing: result.billing,
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
console.error('Error executing tool:', error instanceof Error ? error.message : String(error));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function serveCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serveCommand = serveCommand;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const server_1 = require("../../server");
|
|
6
|
+
function printHelp() {
|
|
7
|
+
console.log(`
|
|
8
|
+
skedyul dev serve - Start a local MCP server for testing
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
skedyul dev serve [options]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--registry, -r Path to the registry file (default: ./dist/registry.js)
|
|
15
|
+
--port, -p Port to listen on (default: 3000)
|
|
16
|
+
--name Server name for MCP metadata (default: 'Local Dev Server')
|
|
17
|
+
--version Server version for MCP metadata (default: '0.0.1')
|
|
18
|
+
--env, -e Set environment variable (can be used multiple times)
|
|
19
|
+
Format: --env KEY=VALUE
|
|
20
|
+
--env-file Load environment variables from a file
|
|
21
|
+
--help, -h Show this help message
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
# Start server on default port
|
|
25
|
+
skedyul dev serve --registry ./dist/registry.js
|
|
26
|
+
|
|
27
|
+
# Start on custom port
|
|
28
|
+
skedyul dev serve --registry ./dist/registry.js --port 3001
|
|
29
|
+
|
|
30
|
+
# With environment variables
|
|
31
|
+
skedyul dev serve \\
|
|
32
|
+
--registry ./dist/registry.js \\
|
|
33
|
+
--env API_KEY=secret123 \\
|
|
34
|
+
--env-file .env.local
|
|
35
|
+
|
|
36
|
+
Endpoints:
|
|
37
|
+
POST /mcp MCP JSON-RPC endpoint (tools/list, tools/call)
|
|
38
|
+
GET /health Health check endpoint
|
|
39
|
+
POST /estimate Estimate billing for a tool call
|
|
40
|
+
POST /core Core API methods (if configured)
|
|
41
|
+
|
|
42
|
+
Testing with curl:
|
|
43
|
+
# List tools
|
|
44
|
+
curl -X POST http://localhost:3000/mcp \\
|
|
45
|
+
-H 'Content-Type: application/json' \\
|
|
46
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
47
|
+
|
|
48
|
+
# Call a tool
|
|
49
|
+
curl -X POST http://localhost:3000/mcp \\
|
|
50
|
+
-H 'Content-Type: application/json' \\
|
|
51
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"my_tool","arguments":{"key":"value"}}}'
|
|
52
|
+
`);
|
|
53
|
+
}
|
|
54
|
+
async function serveCommand(args) {
|
|
55
|
+
const { flags } = (0, utils_1.parseArgs)(args);
|
|
56
|
+
if (flags.help || flags.h) {
|
|
57
|
+
printHelp();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Get registry path
|
|
61
|
+
const registryPath = (flags.registry || flags.r || './dist/registry.js');
|
|
62
|
+
// Get port
|
|
63
|
+
let port = 3000;
|
|
64
|
+
const portFlag = flags.port || flags.p;
|
|
65
|
+
if (portFlag && typeof portFlag === 'string') {
|
|
66
|
+
const parsed = parseInt(portFlag, 10);
|
|
67
|
+
if (!isNaN(parsed)) {
|
|
68
|
+
port = parsed;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Get server metadata
|
|
72
|
+
const serverName = (flags.name || 'Local Dev Server');
|
|
73
|
+
const serverVersion = (flags.version || '0.0.1');
|
|
74
|
+
// Build environment
|
|
75
|
+
const envFile = flags['env-file'];
|
|
76
|
+
if (envFile && typeof envFile === 'string') {
|
|
77
|
+
try {
|
|
78
|
+
const fileEnv = (0, utils_1.loadEnvFile)(envFile);
|
|
79
|
+
Object.assign(process.env, fileEnv);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error(`Error loading env file: ${error instanceof Error ? error.message : String(error)}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Parse --env flags from raw args
|
|
87
|
+
const cliEnv = (0, utils_1.parseEnvFlags)(args);
|
|
88
|
+
Object.assign(process.env, cliEnv);
|
|
89
|
+
// Load registry
|
|
90
|
+
let registry;
|
|
91
|
+
try {
|
|
92
|
+
registry = await (0, utils_1.loadRegistry)(registryPath);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const toolCount = Object.keys(registry).length;
|
|
99
|
+
console.log(`Loaded ${toolCount} tool(s) from registry`);
|
|
100
|
+
// Create server
|
|
101
|
+
const server = (0, server_1.createSkedyulServer)({
|
|
102
|
+
computeLayer: 'dedicated',
|
|
103
|
+
metadata: {
|
|
104
|
+
name: serverName,
|
|
105
|
+
version: serverVersion,
|
|
106
|
+
},
|
|
107
|
+
defaultPort: port,
|
|
108
|
+
}, registry);
|
|
109
|
+
// Start listening
|
|
110
|
+
const dedicatedServer = server;
|
|
111
|
+
try {
|
|
112
|
+
await dedicatedServer.listen(port);
|
|
113
|
+
console.log(`\nEndpoints:`);
|
|
114
|
+
console.log(` POST http://localhost:${port}/mcp - MCP JSON-RPC`);
|
|
115
|
+
console.log(` GET http://localhost:${port}/health - Health check`);
|
|
116
|
+
console.log(` POST http://localhost:${port}/estimate - Billing estimate`);
|
|
117
|
+
console.log(`\nPress Ctrl+C to stop`);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error('Failed to start server:', error instanceof Error ? error.message : String(error));
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toolsCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,148 @@
|
|
|
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.toolsCommand = toolsCommand;
|
|
37
|
+
const z = __importStar(require("zod"));
|
|
38
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
39
|
+
const utils_1 = require("../utils");
|
|
40
|
+
// Cast for Zod v4 compatibility
|
|
41
|
+
const zodToJsonSchemaLoose = zod_to_json_schema_1.zodToJsonSchema;
|
|
42
|
+
function printHelp() {
|
|
43
|
+
console.log(`
|
|
44
|
+
skedyul dev tools - List all tools in the registry
|
|
45
|
+
|
|
46
|
+
Usage:
|
|
47
|
+
skedyul dev tools [options]
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
--registry, -r Path to the registry file (default: ./dist/registry.js)
|
|
51
|
+
--json Output as JSON (for programmatic use)
|
|
52
|
+
--verbose, -v Show full input/output schemas
|
|
53
|
+
--help, -h Show this help message
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
# List all tools
|
|
57
|
+
skedyul dev tools --registry ./dist/registry.js
|
|
58
|
+
|
|
59
|
+
# Output as JSON
|
|
60
|
+
skedyul dev tools --registry ./dist/registry.js --json
|
|
61
|
+
|
|
62
|
+
# Show full schemas
|
|
63
|
+
skedyul dev tools --registry ./dist/registry.js --verbose
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
function getZodSchema(schema) {
|
|
67
|
+
if (!schema)
|
|
68
|
+
return undefined;
|
|
69
|
+
if (schema instanceof z.ZodType) {
|
|
70
|
+
return schema;
|
|
71
|
+
}
|
|
72
|
+
if (typeof schema === 'object' && schema !== null && 'zod' in schema) {
|
|
73
|
+
const schemaWithZod = schema;
|
|
74
|
+
if (schemaWithZod.zod instanceof z.ZodType) {
|
|
75
|
+
return schemaWithZod.zod;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
function toJsonSchema(schema) {
|
|
81
|
+
if (!schema)
|
|
82
|
+
return undefined;
|
|
83
|
+
try {
|
|
84
|
+
return zodToJsonSchemaLoose(schema, {
|
|
85
|
+
target: 'jsonSchema7',
|
|
86
|
+
$refStrategy: 'none',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function toolsCommand(args) {
|
|
94
|
+
const { flags } = (0, utils_1.parseArgs)(args);
|
|
95
|
+
if (flags.help || flags.h) {
|
|
96
|
+
printHelp();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Get registry path
|
|
100
|
+
const registryPath = (flags.registry || flags.r || './dist/registry.js');
|
|
101
|
+
const jsonOutput = Boolean(flags.json);
|
|
102
|
+
const verbose = Boolean(flags.verbose || flags.v);
|
|
103
|
+
// Load registry
|
|
104
|
+
let registry;
|
|
105
|
+
try {
|
|
106
|
+
registry = await (0, utils_1.loadRegistry)(registryPath);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const tools = [];
|
|
113
|
+
for (const [key, tool] of Object.entries(registry)) {
|
|
114
|
+
const inputZod = getZodSchema(tool.inputs);
|
|
115
|
+
const outputZod = getZodSchema(tool.outputSchema);
|
|
116
|
+
tools.push({
|
|
117
|
+
name: tool.name || key,
|
|
118
|
+
description: tool.description || '',
|
|
119
|
+
inputSchema: verbose ? toJsonSchema(inputZod) : undefined,
|
|
120
|
+
outputSchema: verbose ? toJsonSchema(outputZod) : undefined,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (jsonOutput) {
|
|
124
|
+
console.log((0, utils_1.formatJson)(tools));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Human-readable output
|
|
128
|
+
console.log(`\nFound ${tools.length} tool(s) in registry:\n`);
|
|
129
|
+
for (const tool of tools) {
|
|
130
|
+
console.log(` ${tool.name}`);
|
|
131
|
+
if (tool.description) {
|
|
132
|
+
console.log(` ${tool.description}`);
|
|
133
|
+
}
|
|
134
|
+
if (verbose && tool.inputSchema) {
|
|
135
|
+
console.log('\n Input Schema:');
|
|
136
|
+
const schemaStr = (0, utils_1.formatJson)(tool.inputSchema);
|
|
137
|
+
const indented = schemaStr.split('\n').map(line => ` ${line}`).join('\n');
|
|
138
|
+
console.log(indented);
|
|
139
|
+
}
|
|
140
|
+
if (verbose && tool.outputSchema) {
|
|
141
|
+
console.log('\n Output Schema:');
|
|
142
|
+
const schemaStr = (0, utils_1.formatJson)(tool.outputSchema);
|
|
143
|
+
const indented = schemaStr.split('\n').map(line => ` ${line}`).join('\n');
|
|
144
|
+
console.log(indented);
|
|
145
|
+
}
|
|
146
|
+
console.log('');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const invoke_1 = require("./commands/invoke");
|
|
5
|
+
const tools_1 = require("./commands/tools");
|
|
6
|
+
const serve_1 = require("./commands/serve");
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
function printUsage() {
|
|
9
|
+
console.log(`
|
|
10
|
+
skedyul - Skedyul SDK CLI
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
skedyul dev <command> [options]
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
dev invoke <tool> Invoke a tool from the registry
|
|
17
|
+
dev tools List all tools in the registry
|
|
18
|
+
dev serve Start a local MCP server
|
|
19
|
+
|
|
20
|
+
Run 'skedyul dev <command> --help' for more information on a command.
|
|
21
|
+
`);
|
|
22
|
+
}
|
|
23
|
+
function printDevUsage() {
|
|
24
|
+
console.log(`
|
|
25
|
+
skedyul dev - Development tools for testing MCP servers locally
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
skedyul dev <command> [options]
|
|
29
|
+
|
|
30
|
+
Commands:
|
|
31
|
+
invoke <tool> Invoke a tool from the registry
|
|
32
|
+
tools List all tools in the registry
|
|
33
|
+
serve Start a local MCP server
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
skedyul dev invoke my_tool --registry ./dist/registry.js --args '{"key": "value"}'
|
|
37
|
+
skedyul dev tools --registry ./dist/registry.js
|
|
38
|
+
skedyul dev serve --registry ./dist/registry.js --port 3001
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--help, -h Show help for a command
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
async function main() {
|
|
45
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
46
|
+
printUsage();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
const command = args[0];
|
|
50
|
+
if (command !== 'dev') {
|
|
51
|
+
console.error(`Unknown command: ${command}`);
|
|
52
|
+
console.error(`Run 'skedyul --help' for usage information.`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const subCommand = args[1];
|
|
56
|
+
if (!subCommand || subCommand === '--help' || subCommand === '-h') {
|
|
57
|
+
printDevUsage();
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
const subArgs = args.slice(2);
|
|
61
|
+
switch (subCommand) {
|
|
62
|
+
case 'invoke':
|
|
63
|
+
await (0, invoke_1.invokeCommand)(subArgs);
|
|
64
|
+
break;
|
|
65
|
+
case 'tools':
|
|
66
|
+
await (0, tools_1.toolsCommand)(subArgs);
|
|
67
|
+
break;
|
|
68
|
+
case 'serve':
|
|
69
|
+
await (0, serve_1.serveCommand)(subArgs);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
console.error(`Unknown dev command: ${subCommand}`);
|
|
73
|
+
console.error(`Run 'skedyul dev --help' for usage information.`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
main().catch((error) => {
|
|
78
|
+
console.error('Error:', error instanceof Error ? error.message : String(error));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ToolRegistry } from '../types';
|
|
2
|
+
export interface ParsedArgs {
|
|
3
|
+
flags: Record<string, string | boolean>;
|
|
4
|
+
positional: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse command line arguments into flags and positional args
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseArgs(args: string[]): ParsedArgs;
|
|
10
|
+
/**
|
|
11
|
+
* Parse multiple --env flags into a record
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnvFlags(args: string[]): Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Load environment variables from a .env file
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadEnvFile(filePath: string): Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Load a registry from a JS/TS file
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadRegistry(registryPath: string): Promise<ToolRegistry>;
|
|
22
|
+
/**
|
|
23
|
+
* Format JSON for console output with optional color
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatJson(data: unknown, pretty?: boolean): string;
|
|
@@ -0,0 +1,186 @@
|
|
|
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.parseArgs = parseArgs;
|
|
37
|
+
exports.parseEnvFlags = parseEnvFlags;
|
|
38
|
+
exports.loadEnvFile = loadEnvFile;
|
|
39
|
+
exports.loadRegistry = loadRegistry;
|
|
40
|
+
exports.formatJson = formatJson;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
/**
|
|
44
|
+
* Parse command line arguments into flags and positional args
|
|
45
|
+
*/
|
|
46
|
+
function parseArgs(args) {
|
|
47
|
+
const flags = {};
|
|
48
|
+
const positional = [];
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < args.length) {
|
|
51
|
+
const arg = args[i];
|
|
52
|
+
if (arg.startsWith('--')) {
|
|
53
|
+
const key = arg.slice(2);
|
|
54
|
+
// Check if it's a key=value format
|
|
55
|
+
if (key.includes('=')) {
|
|
56
|
+
const [k, ...vParts] = key.split('=');
|
|
57
|
+
flags[k] = vParts.join('=');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Check if next arg is the value (not another flag)
|
|
61
|
+
const nextArg = args[i + 1];
|
|
62
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
63
|
+
flags[key] = nextArg;
|
|
64
|
+
i++;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
flags[key] = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (arg.startsWith('-') && arg.length === 2) {
|
|
72
|
+
const key = arg.slice(1);
|
|
73
|
+
const nextArg = args[i + 1];
|
|
74
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
75
|
+
flags[key] = nextArg;
|
|
76
|
+
i++;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
flags[key] = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
positional.push(arg);
|
|
84
|
+
}
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
return { flags, positional };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse multiple --env flags into a record
|
|
91
|
+
*/
|
|
92
|
+
function parseEnvFlags(args) {
|
|
93
|
+
const env = {};
|
|
94
|
+
for (let i = 0; i < args.length; i++) {
|
|
95
|
+
const arg = args[i];
|
|
96
|
+
if (arg === '--env' || arg === '-e') {
|
|
97
|
+
const nextArg = args[i + 1];
|
|
98
|
+
if (nextArg && nextArg.includes('=')) {
|
|
99
|
+
const [key, ...valueParts] = nextArg.split('=');
|
|
100
|
+
env[key] = valueParts.join('=');
|
|
101
|
+
i++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (arg.startsWith('--env=')) {
|
|
105
|
+
const value = arg.slice(6);
|
|
106
|
+
if (value.includes('=')) {
|
|
107
|
+
const [key, ...valueParts] = value.split('=');
|
|
108
|
+
env[key] = valueParts.join('=');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return env;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Load environment variables from a .env file
|
|
116
|
+
*/
|
|
117
|
+
function loadEnvFile(filePath) {
|
|
118
|
+
const env = {};
|
|
119
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
120
|
+
if (!fs.existsSync(absolutePath)) {
|
|
121
|
+
throw new Error(`Environment file not found: ${absolutePath}`);
|
|
122
|
+
}
|
|
123
|
+
const content = fs.readFileSync(absolutePath, 'utf-8');
|
|
124
|
+
const lines = content.split('\n');
|
|
125
|
+
for (const line of lines) {
|
|
126
|
+
const trimmed = line.trim();
|
|
127
|
+
// Skip empty lines and comments
|
|
128
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const equalIndex = trimmed.indexOf('=');
|
|
132
|
+
if (equalIndex === -1) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const key = trimmed.slice(0, equalIndex).trim();
|
|
136
|
+
let value = trimmed.slice(equalIndex + 1).trim();
|
|
137
|
+
// Remove surrounding quotes
|
|
138
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
139
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
140
|
+
value = value.slice(1, -1);
|
|
141
|
+
}
|
|
142
|
+
env[key] = value;
|
|
143
|
+
}
|
|
144
|
+
return env;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Load a registry from a JS/TS file
|
|
148
|
+
*/
|
|
149
|
+
async function loadRegistry(registryPath) {
|
|
150
|
+
const absolutePath = path.resolve(process.cwd(), registryPath);
|
|
151
|
+
if (!fs.existsSync(absolutePath)) {
|
|
152
|
+
throw new Error(`Registry file not found: ${absolutePath}`);
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
// Use dynamic import for ES modules compatibility
|
|
156
|
+
const module = await Promise.resolve(`${absolutePath}`).then(s => __importStar(require(s)));
|
|
157
|
+
// Check for registry export (default or named)
|
|
158
|
+
const registry = module.registry || module.default?.registry || module.default;
|
|
159
|
+
if (!registry || typeof registry !== 'object') {
|
|
160
|
+
throw new Error(`Registry file must export a 'registry' object. Got: ${typeof registry}`);
|
|
161
|
+
}
|
|
162
|
+
// Validate it looks like a tool registry
|
|
163
|
+
const keys = Object.keys(registry);
|
|
164
|
+
if (keys.length === 0) {
|
|
165
|
+
throw new Error('Registry is empty');
|
|
166
|
+
}
|
|
167
|
+
// Check that at least one entry has expected tool shape
|
|
168
|
+
const firstTool = registry[keys[0]];
|
|
169
|
+
if (!firstTool || typeof firstTool.name !== 'string') {
|
|
170
|
+
throw new Error('Registry entries must have a "name" property. Is this a valid tool registry?');
|
|
171
|
+
}
|
|
172
|
+
return registry;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (error instanceof Error && error.message.includes('Registry')) {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
throw new Error(`Failed to load registry from ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Format JSON for console output with optional color
|
|
183
|
+
*/
|
|
184
|
+
function formatJson(data, pretty = true) {
|
|
185
|
+
return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
186
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -42,8 +42,20 @@ const http_1 = __importDefault(require("http"));
|
|
|
42
42
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
43
43
|
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
44
44
|
const z = __importStar(require("zod"));
|
|
45
|
-
const
|
|
45
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
46
46
|
const service_1 = require("./core/service");
|
|
47
|
+
const zodToJsonSchemaLoose = zod_to_json_schema_1.zodToJsonSchema;
|
|
48
|
+
let toJsonSchemaCompatFn = null;
|
|
49
|
+
try {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
51
|
+
const compat = require('@modelcontextprotocol/sdk/server/zod-json-schema-compat.js');
|
|
52
|
+
if (compat?.toJsonSchemaCompat) {
|
|
53
|
+
toJsonSchemaCompatFn = compat.toJsonSchemaCompat;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
toJsonSchemaCompatFn = null;
|
|
58
|
+
}
|
|
47
59
|
function normalizeBilling(billing) {
|
|
48
60
|
if (!billing || typeof billing.credits !== 'number') {
|
|
49
61
|
return { credits: 0 };
|
|
@@ -54,9 +66,15 @@ function toJsonSchema(schema) {
|
|
|
54
66
|
if (!schema)
|
|
55
67
|
return undefined;
|
|
56
68
|
try {
|
|
57
|
-
|
|
69
|
+
if (toJsonSchemaCompatFn) {
|
|
70
|
+
return toJsonSchemaCompatFn(schema, {
|
|
71
|
+
target: 'jsonSchema7',
|
|
72
|
+
pipeStrategy: 'input',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return zodToJsonSchemaLoose(schema, {
|
|
58
76
|
target: 'jsonSchema7',
|
|
59
|
-
|
|
77
|
+
$refStrategy: 'none',
|
|
60
78
|
});
|
|
61
79
|
}
|
|
62
80
|
catch {
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skedyul",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "The Skedyul SDK for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"skedyul": "./dist/cli/index.js"
|
|
9
|
+
},
|
|
7
10
|
"exports": {
|
|
8
11
|
".": {
|
|
9
12
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +26,7 @@
|
|
|
23
26
|
"author": "Skedyul <support@skedyul.com>",
|
|
24
27
|
"license": "MIT",
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
27
30
|
"zod": "^4.0.0",
|
|
28
31
|
"zod-to-json-schema": "^3.23.0"
|
|
29
32
|
},
|