opentool 0.4.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/dist/cli/build.d.ts +15 -0
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/build.js +127 -412
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +31 -76
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/generate-metadata.d.ts +7 -7
- package/dist/cli/generate-metadata.d.ts.map +1 -1
- package/dist/cli/generate-metadata.js +37 -238
- package/dist/cli/generate-metadata.js.map +1 -1
- package/dist/cli/shared/metadata.d.ts +19 -0
- package/dist/cli/shared/metadata.d.ts.map +1 -0
- package/dist/cli/shared/metadata.js +283 -0
- package/dist/cli/shared/metadata.js.map +1 -0
- package/dist/cli/validate.d.ts +5 -1
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +146 -237
- package/dist/cli/validate.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +118 -69
- package/dist/runtime/index.js.map +1 -1
- package/dist/types/index.d.ts +5 -22
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/metadata.d.ts +975 -59
- package/dist/types/metadata.d.ts.map +1 -1
- package/dist/types/metadata.js +105 -0
- package/dist/types/metadata.js.map +1 -1
- package/dist/utils/esbuild.d.ts +13 -0
- package/dist/utils/esbuild.d.ts.map +1 -0
- package/dist/utils/esbuild.js +95 -0
- package/dist/utils/esbuild.js.map +1 -0
- package/dist/utils/module-loader.d.ts +3 -0
- package/dist/utils/module-loader.d.ts.map +1 -0
- package/dist/utils/module-loader.js +49 -0
- package/dist/utils/module-loader.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -188,10 +188,9 @@ When you push a project with `opentool` dependency to GitHub and connect it to O
|
|
|
188
188
|
|
|
189
189
|
## Examples
|
|
190
190
|
|
|
191
|
-
See the `examples/` directory for
|
|
191
|
+
See the `examples/` directory for a comprehensive example:
|
|
192
192
|
|
|
193
|
-
- **`examples/full-metadata/`** -
|
|
194
|
-
- **`examples/minimal/`** - Minimal setup demonstrating smart defaults
|
|
193
|
+
- **`examples/full-metadata/`** - Metadata configuration with payment and discovery features
|
|
195
194
|
|
|
196
195
|
### Testing Examples Locally
|
|
197
196
|
|
|
@@ -207,16 +206,16 @@ cd examples/full-metadata
|
|
|
207
206
|
npm link opentool
|
|
208
207
|
npm run build
|
|
209
208
|
|
|
210
|
-
# Test the minimal example
|
|
211
|
-
cd ../minimal
|
|
212
|
-
npm link opentool
|
|
213
|
-
npm run build
|
|
214
|
-
|
|
215
209
|
# Examine generated output
|
|
216
210
|
cat dist/metadata.json
|
|
217
211
|
|
|
218
212
|
# Test the MCP server
|
|
219
213
|
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node dist/mcp-server.js
|
|
214
|
+
|
|
215
|
+
# Quick regression helpers from the repo root
|
|
216
|
+
npm run examples:build # Build full metadata example (CJS+ESM)
|
|
217
|
+
npm run examples:validate # Validate example metadata and tools
|
|
218
|
+
npm run examples:metadata # Regenerate metadata.json without rebuilding tools
|
|
220
219
|
```
|
|
221
220
|
|
|
222
221
|
## Metadata System
|
|
@@ -229,6 +228,10 @@ OpenTool features a sophisticated **three-tier metadata system**:
|
|
|
229
228
|
|
|
230
229
|
See [`METADATA.md`](./METADATA.md) for the complete guide to configuring metadata for on-chain registration and payments.
|
|
231
230
|
|
|
231
|
+
## Future Work
|
|
232
|
+
|
|
233
|
+
- Explore an esbuild-powered watch mode that keeps metadata and tool artifacts up to date for the dev server. This remains on the follow-up list once the new pipeline settles.
|
|
234
|
+
|
|
232
235
|
## Contributing
|
|
233
236
|
|
|
234
237
|
We welcome contributions! Please see our [Contributing Guide](https://github.com/openpond/opentool/blob/master/CONTRIBUTING.md) for details.
|
package/dist/cli/build.d.ts
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { InternalToolDefinition } from "../types";
|
|
2
|
+
import { Metadata } from "../types/metadata";
|
|
1
3
|
export interface BuildOptions {
|
|
2
4
|
input: string;
|
|
3
5
|
output: string;
|
|
4
6
|
name?: string;
|
|
5
7
|
version?: string;
|
|
6
8
|
}
|
|
9
|
+
interface BuildArtifacts {
|
|
10
|
+
metadata: Metadata;
|
|
11
|
+
defaultsApplied: string[];
|
|
12
|
+
tools: InternalToolDefinition[];
|
|
13
|
+
compiledTools: CompiledToolArtifact[];
|
|
14
|
+
}
|
|
15
|
+
interface CompiledToolArtifact {
|
|
16
|
+
name: string;
|
|
17
|
+
filename: string;
|
|
18
|
+
modulePath: string;
|
|
19
|
+
}
|
|
7
20
|
export declare function buildCommand(options: BuildOptions): Promise<void>;
|
|
21
|
+
export declare function buildProject(options: BuildOptions): Promise<BuildArtifacts>;
|
|
22
|
+
export {};
|
|
8
23
|
//# sourceMappingURL=build.d.ts.map
|
package/dist/cli/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,cAAc;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC,aAAa,EAAE,oBAAoB,EAAE,CAAC;CACvC;AAED,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAYvE;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CA6CjF"}
|
package/dist/cli/build.js
CHANGED
|
@@ -34,101 +34,121 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.buildCommand = buildCommand;
|
|
37
|
+
exports.buildProject = buildProject;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
|
-
const
|
|
40
|
-
const
|
|
40
|
+
const esbuild_1 = require("../utils/esbuild");
|
|
41
|
+
const metadata_1 = require("./shared/metadata");
|
|
41
42
|
const validate_1 = require("./validate");
|
|
42
|
-
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
43
|
-
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
44
43
|
async function buildCommand(options) {
|
|
45
|
-
const
|
|
46
|
-
console.log(`[${
|
|
47
|
-
const config = {
|
|
48
|
-
toolsDir: path.resolve(options.input),
|
|
49
|
-
outputDir: path.resolve(options.output),
|
|
50
|
-
serverName: options.name || "opentool-server",
|
|
51
|
-
serverVersion: options.version || "1.0.0",
|
|
52
|
-
};
|
|
44
|
+
const start = timestamp();
|
|
45
|
+
console.log(`[${start}] Building OpenTool project...`);
|
|
53
46
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
throw new Error(`Tools directory not found: ${config.toolsDir}`);
|
|
57
|
-
}
|
|
58
|
-
// Load and validate tools (validation integrated into build)
|
|
59
|
-
console.log(`[${new Date()
|
|
60
|
-
.toISOString()
|
|
61
|
-
.replace("T", " ")
|
|
62
|
-
.slice(0, 19)}] 🔍 Validating tools...`);
|
|
63
|
-
const tools = await (0, validate_1.loadAndValidateTools)(config.toolsDir);
|
|
64
|
-
if (tools.length === 0) {
|
|
65
|
-
throw new Error("No valid tools found - build aborted");
|
|
66
|
-
}
|
|
67
|
-
console.log(`[${new Date().toISOString().replace("T", " ").slice(0, 19)}] ✅ Found ${tools.length} valid tools`);
|
|
68
|
-
// Create output directory
|
|
69
|
-
if (!fs.existsSync(config.outputDir)) {
|
|
70
|
-
fs.mkdirSync(config.outputDir, { recursive: true });
|
|
71
|
-
}
|
|
72
|
-
// Generate JavaScript MCP server
|
|
73
|
-
await generateJavaScriptMcpServer(tools, config);
|
|
74
|
-
// Copy and compile tools to output directory
|
|
75
|
-
await copyAndCompileTools(config.toolsDir, config.outputDir, tools);
|
|
76
|
-
// Generate metadata JSON
|
|
77
|
-
await generateMetadataJson(tools, config);
|
|
78
|
-
const endTimestamp = new Date()
|
|
79
|
-
.toISOString()
|
|
80
|
-
.replace("T", " ")
|
|
81
|
-
.slice(0, 19);
|
|
82
|
-
console.log(`[${endTimestamp}] Build completed successfully!`);
|
|
83
|
-
console.log(`Output directory: ${config.outputDir}`);
|
|
84
|
-
console.log("Generated files:");
|
|
85
|
-
console.log(" mcp-server.js - JavaScript MCP server");
|
|
86
|
-
console.log(` tools/ - ${tools.length} compiled JavaScript tool files`);
|
|
87
|
-
console.log(" metadata.json - Metadata for on-chain registration");
|
|
88
|
-
console.log("\\nTest your MCP server:");
|
|
89
|
-
console.log(` echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node ${config.outputDir}/mcp-server.js`);
|
|
47
|
+
const artifacts = await buildProject(options);
|
|
48
|
+
logBuildSummary(artifacts, options);
|
|
90
49
|
}
|
|
91
50
|
catch (error) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.replace("T", " ")
|
|
95
|
-
.slice(0, 19)}] Build failed:`, error);
|
|
51
|
+
const end = timestamp();
|
|
52
|
+
console.error(`[${end}] Build failed:`, error);
|
|
96
53
|
process.exit(1);
|
|
97
54
|
}
|
|
98
55
|
}
|
|
99
|
-
async function
|
|
100
|
-
|
|
101
|
-
|
|
56
|
+
async function buildProject(options) {
|
|
57
|
+
const toolsDir = path.resolve(options.input);
|
|
58
|
+
if (!fs.existsSync(toolsDir)) {
|
|
59
|
+
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
60
|
+
}
|
|
61
|
+
const projectRoot = path.dirname(toolsDir);
|
|
62
|
+
const outputDir = path.resolve(options.output);
|
|
63
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
64
|
+
const serverName = options.name ?? "opentool-server";
|
|
65
|
+
const serverVersion = options.version ?? "1.0.0";
|
|
66
|
+
const tools = await (0, validate_1.loadAndValidateTools)(toolsDir, { projectRoot });
|
|
67
|
+
if (tools.length === 0) {
|
|
68
|
+
throw new Error("No valid tools found - build aborted");
|
|
69
|
+
}
|
|
70
|
+
const { metadata, defaultsApplied } = await (0, metadata_1.buildMetadataArtifact)({
|
|
71
|
+
projectRoot,
|
|
72
|
+
tools,
|
|
73
|
+
});
|
|
74
|
+
const metadataPath = path.join(outputDir, "metadata.json");
|
|
75
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
76
|
+
const compiledTools = await emitTools(tools, {
|
|
77
|
+
projectRoot,
|
|
78
|
+
outputDir,
|
|
79
|
+
});
|
|
80
|
+
await writeServer({
|
|
81
|
+
outputDir,
|
|
82
|
+
serverName,
|
|
83
|
+
serverVersion,
|
|
84
|
+
metadata,
|
|
85
|
+
compiledTools,
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
metadata,
|
|
89
|
+
defaultsApplied,
|
|
90
|
+
tools,
|
|
91
|
+
compiledTools,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async function emitTools(tools, config) {
|
|
95
|
+
const toolsOutDir = path.join(config.outputDir, "tools");
|
|
96
|
+
if (fs.existsSync(toolsOutDir)) {
|
|
97
|
+
fs.rmSync(toolsOutDir, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
fs.mkdirSync(toolsOutDir, { recursive: true });
|
|
100
|
+
const entryPoints = tools.map((tool) => {
|
|
101
|
+
if (!tool.sourcePath) {
|
|
102
|
+
throw new Error(`Missing sourcePath for tool ${tool.filename}`);
|
|
103
|
+
}
|
|
104
|
+
return tool.sourcePath;
|
|
105
|
+
});
|
|
106
|
+
await (0, esbuild_1.transpileWithEsbuild)({
|
|
107
|
+
entryPoints,
|
|
108
|
+
projectRoot: config.projectRoot,
|
|
109
|
+
format: "cjs",
|
|
110
|
+
outDir: toolsOutDir,
|
|
111
|
+
});
|
|
112
|
+
const compiled = tools.map((tool) => {
|
|
113
|
+
if (!tool.sourcePath) {
|
|
114
|
+
throw new Error(`Missing sourcePath for tool ${tool.filename}`);
|
|
115
|
+
}
|
|
116
|
+
const base = path.basename(tool.sourcePath).replace(/\.[^.]+$/, "");
|
|
117
|
+
const modulePath = path.join("tools", `${base}.js`);
|
|
118
|
+
if (!fs.existsSync(path.join(config.outputDir, modulePath))) {
|
|
119
|
+
throw new Error(`Expected compiled output missing: ${modulePath}`);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
name: tool.metadata?.name ?? tool.filename,
|
|
123
|
+
filename: base,
|
|
124
|
+
modulePath,
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
return compiled;
|
|
102
128
|
}
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
129
|
+
function renderServer(options) {
|
|
130
|
+
const toolImports = options.compiledTools
|
|
131
|
+
.map((tool, index) => `const tool${index} = require('./${tool.modulePath}');`)
|
|
132
|
+
.join("\n");
|
|
133
|
+
const registry = options.compiledTools
|
|
134
|
+
.map((_, index) => ` { meta: metadata.tools[${index}], module: tool${index} },`)
|
|
135
|
+
.join("\n");
|
|
136
|
+
return `#!/usr/bin/env node
|
|
106
137
|
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
107
138
|
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
108
139
|
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
109
|
-
const
|
|
140
|
+
const metadata = require('./metadata.json');
|
|
110
141
|
|
|
111
|
-
|
|
112
|
-
${tools
|
|
113
|
-
.map((tool, index) => `const tool${index} = require('./tools/${tool.filename}.js');`)
|
|
114
|
-
.join("\n")}
|
|
142
|
+
${toolImports}
|
|
115
143
|
|
|
116
|
-
const
|
|
117
|
-
${
|
|
118
|
-
.map((tool, index) => ` {
|
|
119
|
-
schema: tool${index}.schema,
|
|
120
|
-
metadata: tool${index}.metadata,
|
|
121
|
-
handler: tool${index}.TOOL,
|
|
122
|
-
filename: '${tool.filename}'
|
|
123
|
-
},`)
|
|
124
|
-
.join("\n")}
|
|
144
|
+
const toolRegistry = [
|
|
145
|
+
${registry}
|
|
125
146
|
];
|
|
126
147
|
|
|
127
|
-
// Create MCP server
|
|
128
148
|
const server = new Server(
|
|
129
149
|
{
|
|
130
|
-
name: '${
|
|
131
|
-
version: '${
|
|
150
|
+
name: '${escapeForJs(options.serverName)}',
|
|
151
|
+
version: '${escapeForJs(options.serverVersion)}',
|
|
132
152
|
},
|
|
133
153
|
{
|
|
134
154
|
capabilities: {
|
|
@@ -137,79 +157,32 @@ const server = new Server(
|
|
|
137
157
|
}
|
|
138
158
|
);
|
|
139
159
|
|
|
140
|
-
// Register list tools handler
|
|
141
160
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
142
|
-
tools:
|
|
143
|
-
// Convert Zod schema to JSON Schema format
|
|
144
|
-
let inputSchema = { type: 'object' };
|
|
145
|
-
const toolName = tool.metadata?.name || tool.filename;
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
inputSchema = zodToJsonSchema(tool.schema, {
|
|
149
|
-
name: \`\${toolName}Schema\`,
|
|
150
|
-
target: 'jsonSchema7',
|
|
151
|
-
$refStrategy: 'none'
|
|
152
|
-
});
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.warn(\`Failed to convert schema for tool \${toolName}:\`, error);
|
|
155
|
-
inputSchema = { type: 'object' };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const toolDef = {
|
|
159
|
-
name: toolName,
|
|
160
|
-
description: tool.metadata?.description || \`Tool \${index}\`,
|
|
161
|
-
inputSchema
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// Add annotations if they exist
|
|
165
|
-
if (tool.metadata?.annotations) {
|
|
166
|
-
toolDef.annotations = tool.metadata.annotations;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return toolDef;
|
|
170
|
-
}),
|
|
161
|
+
tools: toolRegistry.map(({ meta }) => meta),
|
|
171
162
|
}));
|
|
172
163
|
|
|
173
|
-
// Register call tool handler
|
|
174
164
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
});
|
|
179
|
-
if (!tool) {
|
|
180
|
-
throw new Error(\`Tool \${request.params.name} not found\`);
|
|
165
|
+
const entry = toolRegistry.find(({ meta }) => meta.name === request.params.name);
|
|
166
|
+
if (!entry) {
|
|
167
|
+
throw new Error('Tool ' + request.params.name + ' not found');
|
|
181
168
|
}
|
|
182
169
|
|
|
183
170
|
try {
|
|
184
|
-
const
|
|
185
|
-
const result = await
|
|
186
|
-
|
|
187
|
-
// Handle both string and object responses
|
|
171
|
+
const validated = entry.module.schema.parse(request.params.arguments);
|
|
172
|
+
const result = await entry.module.TOOL(validated);
|
|
188
173
|
if (typeof result === 'string') {
|
|
189
|
-
return {
|
|
190
|
-
content: [{ type: 'text', text: result }],
|
|
191
|
-
isError: false,
|
|
192
|
-
};
|
|
193
|
-
} else if (result && typeof result === 'object' && result.content) {
|
|
194
|
-
return {
|
|
195
|
-
content: result.content,
|
|
196
|
-
isError: result.isError || false,
|
|
197
|
-
};
|
|
198
|
-
} else {
|
|
199
|
-
return {
|
|
200
|
-
content: [{ type: 'text', text: String(result) }],
|
|
201
|
-
isError: false,
|
|
202
|
-
};
|
|
174
|
+
return { content: [{ type: 'text', text: result }], isError: false };
|
|
203
175
|
}
|
|
176
|
+
return { content: result.content, isError: result.isError || false };
|
|
204
177
|
} catch (error) {
|
|
178
|
+
const message = (error && error.message) || String(error);
|
|
205
179
|
return {
|
|
206
|
-
content: [{ type: 'text', text:
|
|
180
|
+
content: [{ type: 'text', text: 'Error: ' + message }],
|
|
207
181
|
isError: true,
|
|
208
182
|
};
|
|
209
183
|
}
|
|
210
184
|
});
|
|
211
185
|
|
|
212
|
-
// Start server with stdio transport
|
|
213
186
|
async function main() {
|
|
214
187
|
const transport = new StdioServerTransport();
|
|
215
188
|
await server.connect(transport);
|
|
@@ -219,290 +192,32 @@ if (require.main === module) {
|
|
|
219
192
|
main().catch(console.error);
|
|
220
193
|
}
|
|
221
194
|
|
|
222
|
-
module.exports = { server
|
|
195
|
+
module.exports = { server };
|
|
223
196
|
`;
|
|
224
|
-
const mcpServerPath = path.join(config.outputDir, "mcp-server.js");
|
|
225
|
-
fs.writeFileSync(mcpServerPath, mcpServerCode);
|
|
226
|
-
// Make executable
|
|
227
|
-
fs.chmodSync(mcpServerPath, 0o755);
|
|
228
197
|
}
|
|
229
|
-
async function
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
// Use the same temp compilation approach as in loadTools
|
|
235
|
-
const tempDir = path.join(sourceDir, ".opentool-temp");
|
|
236
|
-
if (fs.existsSync(tempDir)) {
|
|
237
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
238
|
-
}
|
|
239
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
240
|
-
try {
|
|
241
|
-
const files = fs.readdirSync(sourceDir);
|
|
242
|
-
const tsFiles = files.filter((file) => file.endsWith(".ts"));
|
|
243
|
-
if (tsFiles.length > 0) {
|
|
244
|
-
console.log(` Compiling ${tsFiles.length} TypeScript files to JavaScript...`);
|
|
245
|
-
// Copy all files to temp directory
|
|
246
|
-
for (const file of files) {
|
|
247
|
-
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
248
|
-
fs.copyFileSync(path.join(sourceDir, file), path.join(tempDir, file));
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// Compile TypeScript files
|
|
252
|
-
try {
|
|
253
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --outDir ${tempDir} ${tsFiles
|
|
254
|
-
.map((f) => path.join(tempDir, f))
|
|
255
|
-
.join(" ")}`);
|
|
256
|
-
}
|
|
257
|
-
catch (tscError) {
|
|
258
|
-
console.warn("TypeScript compilation failed, trying with relaxed settings...");
|
|
259
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --noImplicitAny false --strict false --outDir ${tempDir} ${tsFiles
|
|
260
|
-
.map((f) => path.join(tempDir, f))
|
|
261
|
-
.join(" ")}`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
// Copy compiled JavaScript files to output
|
|
265
|
-
for (const file of files) {
|
|
266
|
-
if (file.endsWith(".ts")) {
|
|
267
|
-
const jsFile = file.replace(".ts", ".js");
|
|
268
|
-
const sourcePath = path.join(tempDir, jsFile);
|
|
269
|
-
const outputPath = path.join(toolsOutputDir, jsFile);
|
|
270
|
-
if (fs.existsSync(sourcePath)) {
|
|
271
|
-
fs.copyFileSync(sourcePath, outputPath);
|
|
272
|
-
console.log(` Compiled and copied ${jsFile}`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
else if (file.endsWith(".js")) {
|
|
276
|
-
const sourcePath = path.join(sourceDir, file);
|
|
277
|
-
const outputPath = path.join(toolsOutputDir, file);
|
|
278
|
-
fs.copyFileSync(sourcePath, outputPath);
|
|
279
|
-
console.log(` Copied ${file}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
finally {
|
|
284
|
-
// Clean up temp directory
|
|
285
|
-
if (fs.existsSync(tempDir)) {
|
|
286
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
198
|
+
async function writeServer(options) {
|
|
199
|
+
const serverCode = renderServer(options);
|
|
200
|
+
const serverPath = path.join(options.outputDir, "mcp-server.js");
|
|
201
|
+
fs.writeFileSync(serverPath, serverCode);
|
|
202
|
+
fs.chmodSync(serverPath, 0o755);
|
|
289
203
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
204
|
+
function logBuildSummary(artifacts, options) {
|
|
205
|
+
const end = timestamp();
|
|
206
|
+
console.log(`[${end}] Build completed successfully!`);
|
|
207
|
+
console.log(`Output directory: ${path.resolve(options.output)}`);
|
|
208
|
+
console.log("Generated files:");
|
|
209
|
+
console.log(" • mcp-server.js (stdio server)");
|
|
210
|
+
console.log(` • tools/ (${artifacts.compiledTools.length} compiled tools)`);
|
|
211
|
+
console.log(" • metadata.json (registry artifact)");
|
|
212
|
+
if (artifacts.defaultsApplied.length > 0) {
|
|
213
|
+
console.log("\nDefaults applied during metadata synthesis:");
|
|
214
|
+
artifacts.defaultsApplied.forEach((entry) => console.log(` • ${entry}`));
|
|
298
215
|
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.warn(" Failed to read package.json:", error);
|
|
301
|
-
}
|
|
302
|
-
return {};
|
|
303
216
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const projectRoot = path.dirname(config.toolsDir);
|
|
310
|
-
// Try to load metadata from metadata.ts (or fall back to discovery.ts for backwards compatibility)
|
|
311
|
-
let rootMetadata = {};
|
|
312
|
-
const metadataTsPath = path.join(projectRoot, "metadata.ts");
|
|
313
|
-
const metadataJsPath = path.join(projectRoot, "metadata.js");
|
|
314
|
-
const discoveryPath = path.join(projectRoot, "discovery.ts"); // backwards compatibility
|
|
315
|
-
const discoveryJsPath = path.join(projectRoot, "discovery.js");
|
|
316
|
-
// Check for metadata.ts first, then discovery.ts for backwards compatibility
|
|
317
|
-
const metadataFilePath = fs.existsSync(metadataTsPath)
|
|
318
|
-
? metadataTsPath
|
|
319
|
-
: fs.existsSync(discoveryPath)
|
|
320
|
-
? discoveryPath
|
|
321
|
-
: null;
|
|
322
|
-
const metadataJsFilePath = fs.existsSync(metadataJsPath)
|
|
323
|
-
? metadataJsPath
|
|
324
|
-
: fs.existsSync(discoveryJsPath)
|
|
325
|
-
? discoveryJsPath
|
|
326
|
-
: null;
|
|
327
|
-
if (metadataFilePath) {
|
|
328
|
-
try {
|
|
329
|
-
// Use the same temp compilation approach as tools
|
|
330
|
-
const tempDir = path.join(projectRoot, ".opentool-temp");
|
|
331
|
-
if (!fs.existsSync(tempDir)) {
|
|
332
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
333
|
-
}
|
|
334
|
-
// Copy metadata file to temp directory
|
|
335
|
-
const tempFileName = path.basename(metadataFilePath);
|
|
336
|
-
const tempFilePath = path.join(tempDir, tempFileName);
|
|
337
|
-
fs.copyFileSync(metadataFilePath, tempFilePath);
|
|
338
|
-
// Compile TypeScript file
|
|
339
|
-
try {
|
|
340
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --outDir ${tempDir} ${tempFilePath}`);
|
|
341
|
-
}
|
|
342
|
-
catch (tscError) {
|
|
343
|
-
console.warn(`TypeScript compilation failed for ${tempFileName}, trying with relaxed settings...`);
|
|
344
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --noImplicitAny false --strict false --outDir ${tempDir} ${tempFilePath}`);
|
|
345
|
-
}
|
|
346
|
-
// Load the compiled JS file
|
|
347
|
-
const compiledFileName = tempFileName.replace(".ts", ".js");
|
|
348
|
-
const compiledPath = path.join(tempDir, compiledFileName);
|
|
349
|
-
if (fs.existsSync(compiledPath)) {
|
|
350
|
-
delete require.cache[require.resolve(compiledPath)];
|
|
351
|
-
const metadataModule = require(compiledPath);
|
|
352
|
-
// Support both 'metadata' and 'discovery' exports for backwards compatibility
|
|
353
|
-
rootMetadata =
|
|
354
|
-
metadataModule.metadata || metadataModule.discovery || {};
|
|
355
|
-
console.log(` Loaded metadata from ${tempFileName}`);
|
|
356
|
-
}
|
|
357
|
-
// Clean up temp directory
|
|
358
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
359
|
-
}
|
|
360
|
-
catch (error) {
|
|
361
|
-
console.warn(` Failed to load ${path.basename(metadataFilePath)}:`, error);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else if (metadataJsFilePath) {
|
|
365
|
-
try {
|
|
366
|
-
// For JavaScript files, use require directly
|
|
367
|
-
delete require.cache[require.resolve(metadataJsFilePath)];
|
|
368
|
-
const metadataModule = require(metadataJsFilePath);
|
|
369
|
-
// Support both 'metadata' and 'discovery' exports for backwards compatibility
|
|
370
|
-
rootMetadata = metadataModule.metadata || metadataModule.discovery || {};
|
|
371
|
-
console.log(` Loaded metadata from ${path.basename(metadataJsFilePath)}`);
|
|
372
|
-
}
|
|
373
|
-
catch (error) {
|
|
374
|
-
console.warn(` Failed to load ${path.basename(metadataJsFilePath)}:`, error);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
console.log(" No metadata.ts found, using smart defaults");
|
|
379
|
-
}
|
|
380
|
-
// Read package.json for fallback values
|
|
381
|
-
const packageInfo = readPackageJson(projectRoot);
|
|
382
|
-
// Generate smart defaults from folder name and package.json
|
|
383
|
-
const folderName = path.basename(projectRoot);
|
|
384
|
-
const smartDefaults = {
|
|
385
|
-
name: rootMetadata.name || packageInfo.name || folderName,
|
|
386
|
-
displayName: rootMetadata.displayName ||
|
|
387
|
-
(packageInfo.name
|
|
388
|
-
? packageInfo.name
|
|
389
|
-
.split("-")
|
|
390
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
391
|
-
.join(" ")
|
|
392
|
-
: folderName
|
|
393
|
-
.split("-")
|
|
394
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
395
|
-
.join(" ")),
|
|
396
|
-
version: rootMetadata.version || parseFloat(packageInfo.version || "1.0"),
|
|
397
|
-
description: rootMetadata.description ||
|
|
398
|
-
packageInfo.description ||
|
|
399
|
-
`OpenTool agent built from ${folderName}`,
|
|
400
|
-
author: rootMetadata.author || packageInfo.author || "Unknown",
|
|
401
|
-
repository: rootMetadata.repository ||
|
|
402
|
-
packageInfo.repository?.url ||
|
|
403
|
-
packageInfo.repository ||
|
|
404
|
-
"",
|
|
405
|
-
website: rootMetadata.website || packageInfo.homepage || "",
|
|
406
|
-
category: rootMetadata.category || rootMetadata.categories?.[0] || "utility",
|
|
407
|
-
termsOfService: rootMetadata.termsOfService || "Please review terms before use.",
|
|
408
|
-
};
|
|
409
|
-
// Convert tools to metadata format
|
|
410
|
-
const metadataTools = tools.map((tool) => {
|
|
411
|
-
// Use tool metadata name, fallback to filename without extension
|
|
412
|
-
const toolName = tool.metadata?.name || tool.filename.replace(/\.(ts|js)$/, "");
|
|
413
|
-
const toolDescription = tool.metadata?.description || `${toolName} tool`;
|
|
414
|
-
// Generate clean schema for metadata (same as MCP server)
|
|
415
|
-
let metadataInputSchema = { type: 'object' };
|
|
416
|
-
try {
|
|
417
|
-
metadataInputSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(tool.schema, {
|
|
418
|
-
name: `${toolName}Schema`,
|
|
419
|
-
target: 'jsonSchema7',
|
|
420
|
-
$refStrategy: 'none'
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
catch (error) {
|
|
424
|
-
console.warn(`Failed to convert schema for metadata tool ${toolName}:`, error);
|
|
425
|
-
metadataInputSchema = { type: 'object' };
|
|
426
|
-
}
|
|
427
|
-
// Build metadata tool object
|
|
428
|
-
const metadataTool = {
|
|
429
|
-
name: toolName,
|
|
430
|
-
description: toolDescription,
|
|
431
|
-
inputSchema: metadataInputSchema,
|
|
432
|
-
};
|
|
433
|
-
// Add annotations if they exist
|
|
434
|
-
if (tool.metadata?.annotations) {
|
|
435
|
-
metadataTool.annotations = tool.metadata.annotations;
|
|
436
|
-
}
|
|
437
|
-
// Add payment config (tool-level overrides agent-level)
|
|
438
|
-
if (tool.metadata?.payment) {
|
|
439
|
-
metadataTool.payment = tool.metadata.payment;
|
|
440
|
-
}
|
|
441
|
-
else if (rootMetadata.payment) {
|
|
442
|
-
// Use agent-level payment as default
|
|
443
|
-
metadataTool.payment = rootMetadata.payment;
|
|
444
|
-
}
|
|
445
|
-
// Add discovery metadata if it exists
|
|
446
|
-
if (tool.metadata?.discovery) {
|
|
447
|
-
metadataTool.discovery = tool.metadata.discovery;
|
|
448
|
-
}
|
|
449
|
-
return metadataTool;
|
|
450
|
-
});
|
|
451
|
-
// Build complete metadata JSON with new structure
|
|
452
|
-
const metadataJson = {
|
|
453
|
-
// Core fields using smart defaults
|
|
454
|
-
name: smartDefaults.name,
|
|
455
|
-
displayName: smartDefaults.displayName,
|
|
456
|
-
version: smartDefaults.version,
|
|
457
|
-
description: smartDefaults.description,
|
|
458
|
-
author: smartDefaults.author,
|
|
459
|
-
repository: smartDefaults.repository,
|
|
460
|
-
website: smartDefaults.website,
|
|
461
|
-
category: smartDefaults.category,
|
|
462
|
-
termsOfService: smartDefaults.termsOfService,
|
|
463
|
-
// Tools array (always populated by build process)
|
|
464
|
-
tools: metadataTools,
|
|
465
|
-
// UI Enhancement fields
|
|
466
|
-
...(rootMetadata.promptExamples && {
|
|
467
|
-
promptExamples: rootMetadata.promptExamples,
|
|
468
|
-
}),
|
|
469
|
-
...(rootMetadata.iconPath && { iconPath: rootMetadata.iconPath }),
|
|
470
|
-
...(rootMetadata.videoPath && { videoPath: rootMetadata.videoPath }),
|
|
471
|
-
// Agent-level payment defaults (create from pricing if exists)
|
|
472
|
-
...(rootMetadata.pricing && {
|
|
473
|
-
payment: {
|
|
474
|
-
amountUSDC: rootMetadata.pricing.defaultAmount || 0.01,
|
|
475
|
-
description: rootMetadata.pricing.description || "",
|
|
476
|
-
x402: true,
|
|
477
|
-
openpondDirect: true,
|
|
478
|
-
acceptedMethods: ["ETH", "USDC"],
|
|
479
|
-
chainIds: [8453], // Base
|
|
480
|
-
},
|
|
481
|
-
}),
|
|
482
|
-
// Discovery section (only include if metadata has discovery fields)
|
|
483
|
-
...((rootMetadata.keywords ||
|
|
484
|
-
rootMetadata.categories ||
|
|
485
|
-
rootMetadata.useCases ||
|
|
486
|
-
rootMetadata.capabilities ||
|
|
487
|
-
rootMetadata.requirements ||
|
|
488
|
-
rootMetadata.pricing ||
|
|
489
|
-
rootMetadata.compatibility ||
|
|
490
|
-
rootMetadata.discovery) && {
|
|
491
|
-
discovery: {
|
|
492
|
-
keywords: rootMetadata.keywords || [],
|
|
493
|
-
category: rootMetadata.categories?.[0] || smartDefaults.category,
|
|
494
|
-
useCases: rootMetadata.useCases || [],
|
|
495
|
-
capabilities: rootMetadata.capabilities || [],
|
|
496
|
-
requirements: rootMetadata.requirements || {},
|
|
497
|
-
pricing: rootMetadata.pricing || {},
|
|
498
|
-
compatibility: rootMetadata.compatibility || {},
|
|
499
|
-
...(rootMetadata.discovery || {}), // Include any nested discovery fields too
|
|
500
|
-
},
|
|
501
|
-
}),
|
|
502
|
-
};
|
|
503
|
-
// Write metadata JSON to output directory
|
|
504
|
-
const outputMetadataPath = path.join(config.outputDir, "metadata.json");
|
|
505
|
-
fs.writeFileSync(outputMetadataPath, JSON.stringify(metadataJson, null, 2));
|
|
506
|
-
console.log(` Generated metadata.json with ${metadataTools.length} tools`);
|
|
217
|
+
function timestamp() {
|
|
218
|
+
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
219
|
+
}
|
|
220
|
+
function escapeForJs(value) {
|
|
221
|
+
return value.replace(/'/g, "\\'");
|
|
507
222
|
}
|
|
508
223
|
//# sourceMappingURL=build.js.map
|