opentool 0.4.5 → 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 -398
- 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,100 +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 execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
43
43
|
async function buildCommand(options) {
|
|
44
|
-
const
|
|
45
|
-
console.log(`[${
|
|
46
|
-
const config = {
|
|
47
|
-
toolsDir: path.resolve(options.input),
|
|
48
|
-
outputDir: path.resolve(options.output),
|
|
49
|
-
serverName: options.name || "opentool-server",
|
|
50
|
-
serverVersion: options.version || "1.0.0",
|
|
51
|
-
};
|
|
44
|
+
const start = timestamp();
|
|
45
|
+
console.log(`[${start}] Building OpenTool project...`);
|
|
52
46
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
throw new Error(`Tools directory not found: ${config.toolsDir}`);
|
|
56
|
-
}
|
|
57
|
-
// Load and validate tools (validation integrated into build)
|
|
58
|
-
console.log(`[${new Date()
|
|
59
|
-
.toISOString()
|
|
60
|
-
.replace("T", " ")
|
|
61
|
-
.slice(0, 19)}] 🔍 Validating tools...`);
|
|
62
|
-
const tools = await (0, validate_1.loadAndValidateTools)(config.toolsDir);
|
|
63
|
-
if (tools.length === 0) {
|
|
64
|
-
throw new Error("No valid tools found - build aborted");
|
|
65
|
-
}
|
|
66
|
-
console.log(`[${new Date().toISOString().replace("T", " ").slice(0, 19)}] ✅ Found ${tools.length} valid tools`);
|
|
67
|
-
// Create output directory
|
|
68
|
-
if (!fs.existsSync(config.outputDir)) {
|
|
69
|
-
fs.mkdirSync(config.outputDir, { recursive: true });
|
|
70
|
-
}
|
|
71
|
-
// Generate JavaScript MCP server
|
|
72
|
-
await generateJavaScriptMcpServer(tools, config);
|
|
73
|
-
// Copy and compile tools to output directory
|
|
74
|
-
await copyAndCompileTools(config.toolsDir, config.outputDir, tools);
|
|
75
|
-
// Generate metadata JSON
|
|
76
|
-
await generateMetadataJson(tools, config);
|
|
77
|
-
const endTimestamp = new Date()
|
|
78
|
-
.toISOString()
|
|
79
|
-
.replace("T", " ")
|
|
80
|
-
.slice(0, 19);
|
|
81
|
-
console.log(`[${endTimestamp}] Build completed successfully!`);
|
|
82
|
-
console.log(`Output directory: ${config.outputDir}`);
|
|
83
|
-
console.log("Generated files:");
|
|
84
|
-
console.log(" mcp-server.js - JavaScript MCP server");
|
|
85
|
-
console.log(` tools/ - ${tools.length} compiled JavaScript tool files`);
|
|
86
|
-
console.log(" metadata.json - Metadata for on-chain registration");
|
|
87
|
-
console.log("\\nTest your MCP server:");
|
|
88
|
-
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);
|
|
89
49
|
}
|
|
90
50
|
catch (error) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.replace("T", " ")
|
|
94
|
-
.slice(0, 19)}] Build failed:`, error);
|
|
51
|
+
const end = timestamp();
|
|
52
|
+
console.error(`[${end}] Build failed:`, error);
|
|
95
53
|
process.exit(1);
|
|
96
54
|
}
|
|
97
55
|
}
|
|
98
|
-
async function
|
|
99
|
-
|
|
100
|
-
|
|
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;
|
|
101
128
|
}
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
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
|
|
105
137
|
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
106
138
|
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
107
139
|
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
108
|
-
const
|
|
140
|
+
const metadata = require('./metadata.json');
|
|
109
141
|
|
|
110
|
-
|
|
111
|
-
${tools
|
|
112
|
-
.map((tool, index) => `const tool${index} = require('./tools/${tool.filename}.js');`)
|
|
113
|
-
.join("\n")}
|
|
142
|
+
${toolImports}
|
|
114
143
|
|
|
115
|
-
const
|
|
116
|
-
${
|
|
117
|
-
.map((tool, index) => ` {
|
|
118
|
-
schema: tool${index}.schema,
|
|
119
|
-
metadata: tool${index}.metadata,
|
|
120
|
-
handler: tool${index}.TOOL,
|
|
121
|
-
filename: '${tool.filename}'
|
|
122
|
-
},`)
|
|
123
|
-
.join("\n")}
|
|
144
|
+
const toolRegistry = [
|
|
145
|
+
${registry}
|
|
124
146
|
];
|
|
125
147
|
|
|
126
|
-
// Create MCP server
|
|
127
148
|
const server = new Server(
|
|
128
149
|
{
|
|
129
|
-
name: '${
|
|
130
|
-
version: '${
|
|
150
|
+
name: '${escapeForJs(options.serverName)}',
|
|
151
|
+
version: '${escapeForJs(options.serverVersion)}',
|
|
131
152
|
},
|
|
132
153
|
{
|
|
133
154
|
capabilities: {
|
|
@@ -136,79 +157,32 @@ const server = new Server(
|
|
|
136
157
|
}
|
|
137
158
|
);
|
|
138
159
|
|
|
139
|
-
// Register list tools handler
|
|
140
160
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
141
|
-
tools:
|
|
142
|
-
// Convert Zod schema to JSON Schema format
|
|
143
|
-
let inputSchema = { type: 'object' };
|
|
144
|
-
const toolName = tool.metadata?.name || tool.filename;
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
inputSchema = zodToJsonSchema(tool.schema, {
|
|
148
|
-
name: \`\${toolName}Schema\`,
|
|
149
|
-
target: 'jsonSchema7',
|
|
150
|
-
$refStrategy: 'none'
|
|
151
|
-
});
|
|
152
|
-
} catch (error) {
|
|
153
|
-
console.warn(\`Failed to convert schema for tool \${toolName}:\`, error);
|
|
154
|
-
inputSchema = { type: 'object' };
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const toolDef = {
|
|
158
|
-
name: toolName,
|
|
159
|
-
description: tool.metadata?.description || \`Tool \${index}\`,
|
|
160
|
-
inputSchema
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// Add annotations if they exist
|
|
164
|
-
if (tool.metadata?.annotations) {
|
|
165
|
-
toolDef.annotations = tool.metadata.annotations;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return toolDef;
|
|
169
|
-
}),
|
|
161
|
+
tools: toolRegistry.map(({ meta }) => meta),
|
|
170
162
|
}));
|
|
171
163
|
|
|
172
|
-
// Register call tool handler
|
|
173
164
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
});
|
|
178
|
-
if (!tool) {
|
|
179
|
-
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');
|
|
180
168
|
}
|
|
181
169
|
|
|
182
170
|
try {
|
|
183
|
-
const
|
|
184
|
-
const result = await
|
|
185
|
-
|
|
186
|
-
// Handle both string and object responses
|
|
171
|
+
const validated = entry.module.schema.parse(request.params.arguments);
|
|
172
|
+
const result = await entry.module.TOOL(validated);
|
|
187
173
|
if (typeof result === 'string') {
|
|
188
|
-
return {
|
|
189
|
-
content: [{ type: 'text', text: result }],
|
|
190
|
-
isError: false,
|
|
191
|
-
};
|
|
192
|
-
} else if (result && typeof result === 'object' && result.content) {
|
|
193
|
-
return {
|
|
194
|
-
content: result.content,
|
|
195
|
-
isError: result.isError || false,
|
|
196
|
-
};
|
|
197
|
-
} else {
|
|
198
|
-
return {
|
|
199
|
-
content: [{ type: 'text', text: String(result) }],
|
|
200
|
-
isError: false,
|
|
201
|
-
};
|
|
174
|
+
return { content: [{ type: 'text', text: result }], isError: false };
|
|
202
175
|
}
|
|
176
|
+
return { content: result.content, isError: result.isError || false };
|
|
203
177
|
} catch (error) {
|
|
178
|
+
const message = (error && error.message) || String(error);
|
|
204
179
|
return {
|
|
205
|
-
content: [{ type: 'text', text:
|
|
180
|
+
content: [{ type: 'text', text: 'Error: ' + message }],
|
|
206
181
|
isError: true,
|
|
207
182
|
};
|
|
208
183
|
}
|
|
209
184
|
});
|
|
210
185
|
|
|
211
|
-
// Start server with stdio transport
|
|
212
186
|
async function main() {
|
|
213
187
|
const transport = new StdioServerTransport();
|
|
214
188
|
await server.connect(transport);
|
|
@@ -218,277 +192,32 @@ if (require.main === module) {
|
|
|
218
192
|
main().catch(console.error);
|
|
219
193
|
}
|
|
220
194
|
|
|
221
|
-
module.exports = { server
|
|
195
|
+
module.exports = { server };
|
|
222
196
|
`;
|
|
223
|
-
const mcpServerPath = path.join(config.outputDir, "mcp-server.js");
|
|
224
|
-
fs.writeFileSync(mcpServerPath, mcpServerCode);
|
|
225
|
-
// Make executable
|
|
226
|
-
fs.chmodSync(mcpServerPath, 0o755);
|
|
227
197
|
}
|
|
228
|
-
async function
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// Use the same temp compilation approach as in loadTools
|
|
234
|
-
const tempDir = path.join(sourceDir, ".opentool-temp");
|
|
235
|
-
if (fs.existsSync(tempDir)) {
|
|
236
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
237
|
-
}
|
|
238
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
239
|
-
try {
|
|
240
|
-
const files = fs.readdirSync(sourceDir);
|
|
241
|
-
const tsFiles = files.filter((file) => file.endsWith(".ts"));
|
|
242
|
-
if (tsFiles.length > 0) {
|
|
243
|
-
console.log(` Compiling ${tsFiles.length} TypeScript files to JavaScript...`);
|
|
244
|
-
// Copy all files to temp directory
|
|
245
|
-
for (const file of files) {
|
|
246
|
-
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
247
|
-
fs.copyFileSync(path.join(sourceDir, file), path.join(tempDir, file));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
// Compile TypeScript files
|
|
251
|
-
try {
|
|
252
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --outDir ${tempDir} ${tsFiles
|
|
253
|
-
.map((f) => path.join(tempDir, f))
|
|
254
|
-
.join(" ")}`);
|
|
255
|
-
}
|
|
256
|
-
catch (tscError) {
|
|
257
|
-
console.warn("TypeScript compilation failed, trying with relaxed settings...");
|
|
258
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --noImplicitAny false --strict false --outDir ${tempDir} ${tsFiles
|
|
259
|
-
.map((f) => path.join(tempDir, f))
|
|
260
|
-
.join(" ")}`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
// Copy compiled JavaScript files to output
|
|
264
|
-
for (const file of files) {
|
|
265
|
-
if (file.endsWith(".ts")) {
|
|
266
|
-
const jsFile = file.replace(".ts", ".js");
|
|
267
|
-
const sourcePath = path.join(tempDir, jsFile);
|
|
268
|
-
const outputPath = path.join(toolsOutputDir, jsFile);
|
|
269
|
-
if (fs.existsSync(sourcePath)) {
|
|
270
|
-
fs.copyFileSync(sourcePath, outputPath);
|
|
271
|
-
console.log(` Compiled and copied ${jsFile}`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
else if (file.endsWith(".js")) {
|
|
275
|
-
const sourcePath = path.join(sourceDir, file);
|
|
276
|
-
const outputPath = path.join(toolsOutputDir, file);
|
|
277
|
-
fs.copyFileSync(sourcePath, outputPath);
|
|
278
|
-
console.log(` Copied ${file}`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
finally {
|
|
283
|
-
// Clean up temp directory
|
|
284
|
-
if (fs.existsSync(tempDir)) {
|
|
285
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
286
|
-
}
|
|
287
|
-
}
|
|
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);
|
|
288
203
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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}`));
|
|
300
215
|
}
|
|
301
|
-
return {};
|
|
302
216
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const projectRoot = path.dirname(config.toolsDir);
|
|
309
|
-
// Try to load metadata from metadata.ts (or fall back to discovery.ts for backwards compatibility)
|
|
310
|
-
let rootMetadata = {};
|
|
311
|
-
const metadataTsPath = path.join(projectRoot, "metadata.ts");
|
|
312
|
-
const metadataJsPath = path.join(projectRoot, "metadata.js");
|
|
313
|
-
const discoveryPath = path.join(projectRoot, "discovery.ts"); // backwards compatibility
|
|
314
|
-
const discoveryJsPath = path.join(projectRoot, "discovery.js");
|
|
315
|
-
// Check for metadata.ts first, then discovery.ts for backwards compatibility
|
|
316
|
-
const metadataFilePath = fs.existsSync(metadataTsPath)
|
|
317
|
-
? metadataTsPath
|
|
318
|
-
: fs.existsSync(discoveryPath)
|
|
319
|
-
? discoveryPath
|
|
320
|
-
: null;
|
|
321
|
-
const metadataJsFilePath = fs.existsSync(metadataJsPath)
|
|
322
|
-
? metadataJsPath
|
|
323
|
-
: fs.existsSync(discoveryJsPath)
|
|
324
|
-
? discoveryJsPath
|
|
325
|
-
: null;
|
|
326
|
-
if (metadataFilePath) {
|
|
327
|
-
try {
|
|
328
|
-
// Use the same temp compilation approach as tools
|
|
329
|
-
const tempDir = path.join(projectRoot, ".opentool-temp");
|
|
330
|
-
if (!fs.existsSync(tempDir)) {
|
|
331
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
332
|
-
}
|
|
333
|
-
// Copy metadata file to temp directory
|
|
334
|
-
const tempFileName = path.basename(metadataFilePath);
|
|
335
|
-
const tempFilePath = path.join(tempDir, tempFileName);
|
|
336
|
-
fs.copyFileSync(metadataFilePath, tempFilePath);
|
|
337
|
-
// Compile TypeScript file
|
|
338
|
-
try {
|
|
339
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --outDir ${tempDir} ${tempFilePath}`);
|
|
340
|
-
}
|
|
341
|
-
catch (tscError) {
|
|
342
|
-
console.warn(`TypeScript compilation failed for ${tempFileName}, trying with relaxed settings...`);
|
|
343
|
-
await execAsync(`npx tsc --target es2020 --module commonjs --esModuleInterop --skipLibCheck --moduleResolution node --noImplicitAny false --strict false --outDir ${tempDir} ${tempFilePath}`);
|
|
344
|
-
}
|
|
345
|
-
// Load the compiled JS file
|
|
346
|
-
const compiledFileName = tempFileName.replace(".ts", ".js");
|
|
347
|
-
const compiledPath = path.join(tempDir, compiledFileName);
|
|
348
|
-
if (fs.existsSync(compiledPath)) {
|
|
349
|
-
delete require.cache[require.resolve(compiledPath)];
|
|
350
|
-
const metadataModule = require(compiledPath);
|
|
351
|
-
// Support both 'metadata' and 'discovery' exports for backwards compatibility
|
|
352
|
-
rootMetadata =
|
|
353
|
-
metadataModule.metadata || metadataModule.discovery || {};
|
|
354
|
-
console.log(` Loaded metadata from ${tempFileName}`);
|
|
355
|
-
}
|
|
356
|
-
// Clean up temp directory
|
|
357
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
358
|
-
}
|
|
359
|
-
catch (error) {
|
|
360
|
-
console.warn(` Failed to load ${path.basename(metadataFilePath)}:`, error);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else if (metadataJsFilePath) {
|
|
364
|
-
try {
|
|
365
|
-
// For JavaScript files, use require directly
|
|
366
|
-
delete require.cache[require.resolve(metadataJsFilePath)];
|
|
367
|
-
const metadataModule = require(metadataJsFilePath);
|
|
368
|
-
// Support both 'metadata' and 'discovery' exports for backwards compatibility
|
|
369
|
-
rootMetadata = metadataModule.metadata || metadataModule.discovery || {};
|
|
370
|
-
console.log(` Loaded metadata from ${path.basename(metadataJsFilePath)}`);
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
console.warn(` Failed to load ${path.basename(metadataJsFilePath)}:`, error);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
377
|
-
console.log(" No metadata.ts found, using smart defaults");
|
|
378
|
-
}
|
|
379
|
-
// Read package.json for fallback values
|
|
380
|
-
const packageInfo = readPackageJson(projectRoot);
|
|
381
|
-
// Generate smart defaults from folder name and package.json
|
|
382
|
-
const folderName = path.basename(projectRoot);
|
|
383
|
-
const smartDefaults = {
|
|
384
|
-
name: rootMetadata.name || packageInfo.name || folderName,
|
|
385
|
-
displayName: rootMetadata.displayName ||
|
|
386
|
-
(packageInfo.name
|
|
387
|
-
? packageInfo.name
|
|
388
|
-
.split("-")
|
|
389
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
390
|
-
.join(" ")
|
|
391
|
-
: folderName
|
|
392
|
-
.split("-")
|
|
393
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
394
|
-
.join(" ")),
|
|
395
|
-
version: rootMetadata.version || parseFloat(packageInfo.version || "1.0"),
|
|
396
|
-
description: rootMetadata.description ||
|
|
397
|
-
packageInfo.description ||
|
|
398
|
-
`OpenTool agent built from ${folderName}`,
|
|
399
|
-
author: rootMetadata.author || packageInfo.author || "Unknown",
|
|
400
|
-
repository: rootMetadata.repository ||
|
|
401
|
-
packageInfo.repository?.url ||
|
|
402
|
-
packageInfo.repository ||
|
|
403
|
-
"",
|
|
404
|
-
website: rootMetadata.website || packageInfo.homepage || "",
|
|
405
|
-
category: rootMetadata.category || rootMetadata.categories?.[0] || "utility",
|
|
406
|
-
termsOfService: rootMetadata.termsOfService || "Please review terms before use.",
|
|
407
|
-
};
|
|
408
|
-
// Convert tools to metadata format
|
|
409
|
-
const metadataTools = tools.map((tool) => {
|
|
410
|
-
// Use tool metadata name, fallback to filename without extension
|
|
411
|
-
const toolName = tool.metadata?.name || tool.filename.replace(/\.(ts|js)$/, "");
|
|
412
|
-
const toolDescription = tool.metadata?.description || `${toolName} tool`;
|
|
413
|
-
// Build metadata tool object
|
|
414
|
-
const metadataTool = {
|
|
415
|
-
name: toolName,
|
|
416
|
-
description: toolDescription,
|
|
417
|
-
inputSchema: tool.inputSchema,
|
|
418
|
-
};
|
|
419
|
-
// Add annotations if they exist
|
|
420
|
-
if (tool.metadata?.annotations) {
|
|
421
|
-
metadataTool.annotations = tool.metadata.annotations;
|
|
422
|
-
}
|
|
423
|
-
// Add payment config (tool-level overrides agent-level)
|
|
424
|
-
if (tool.metadata?.payment) {
|
|
425
|
-
metadataTool.payment = tool.metadata.payment;
|
|
426
|
-
}
|
|
427
|
-
else if (rootMetadata.payment) {
|
|
428
|
-
// Use agent-level payment as default
|
|
429
|
-
metadataTool.payment = rootMetadata.payment;
|
|
430
|
-
}
|
|
431
|
-
// Add discovery metadata if it exists
|
|
432
|
-
if (tool.metadata?.discovery) {
|
|
433
|
-
metadataTool.discovery = tool.metadata.discovery;
|
|
434
|
-
}
|
|
435
|
-
return metadataTool;
|
|
436
|
-
});
|
|
437
|
-
// Build complete metadata JSON with new structure
|
|
438
|
-
const metadataJson = {
|
|
439
|
-
// Core fields using smart defaults
|
|
440
|
-
name: smartDefaults.name,
|
|
441
|
-
displayName: smartDefaults.displayName,
|
|
442
|
-
version: smartDefaults.version,
|
|
443
|
-
description: smartDefaults.description,
|
|
444
|
-
author: smartDefaults.author,
|
|
445
|
-
repository: smartDefaults.repository,
|
|
446
|
-
website: smartDefaults.website,
|
|
447
|
-
category: smartDefaults.category,
|
|
448
|
-
termsOfService: smartDefaults.termsOfService,
|
|
449
|
-
// Tools array (always populated by build process)
|
|
450
|
-
tools: metadataTools,
|
|
451
|
-
// UI Enhancement fields
|
|
452
|
-
...(rootMetadata.promptExamples && {
|
|
453
|
-
promptExamples: rootMetadata.promptExamples,
|
|
454
|
-
}),
|
|
455
|
-
...(rootMetadata.iconPath && { iconPath: rootMetadata.iconPath }),
|
|
456
|
-
...(rootMetadata.videoPath && { videoPath: rootMetadata.videoPath }),
|
|
457
|
-
// Agent-level payment defaults (create from pricing if exists)
|
|
458
|
-
...(rootMetadata.pricing && {
|
|
459
|
-
payment: {
|
|
460
|
-
amountUSDC: rootMetadata.pricing.defaultAmount || 0.01,
|
|
461
|
-
description: rootMetadata.pricing.description || "",
|
|
462
|
-
x402: true,
|
|
463
|
-
openpondDirect: true,
|
|
464
|
-
acceptedMethods: ["ETH", "USDC"],
|
|
465
|
-
chainIds: [8453], // Base
|
|
466
|
-
},
|
|
467
|
-
}),
|
|
468
|
-
// Discovery section (only include if metadata has discovery fields)
|
|
469
|
-
...((rootMetadata.keywords ||
|
|
470
|
-
rootMetadata.categories ||
|
|
471
|
-
rootMetadata.useCases ||
|
|
472
|
-
rootMetadata.capabilities ||
|
|
473
|
-
rootMetadata.requirements ||
|
|
474
|
-
rootMetadata.pricing ||
|
|
475
|
-
rootMetadata.compatibility ||
|
|
476
|
-
rootMetadata.discovery) && {
|
|
477
|
-
discovery: {
|
|
478
|
-
keywords: rootMetadata.keywords || [],
|
|
479
|
-
category: rootMetadata.categories?.[0] || smartDefaults.category,
|
|
480
|
-
useCases: rootMetadata.useCases || [],
|
|
481
|
-
capabilities: rootMetadata.capabilities || [],
|
|
482
|
-
requirements: rootMetadata.requirements || {},
|
|
483
|
-
pricing: rootMetadata.pricing || {},
|
|
484
|
-
compatibility: rootMetadata.compatibility || {},
|
|
485
|
-
...(rootMetadata.discovery || {}), // Include any nested discovery fields too
|
|
486
|
-
},
|
|
487
|
-
}),
|
|
488
|
-
};
|
|
489
|
-
// Write metadata JSON to output directory
|
|
490
|
-
const outputMetadataPath = path.join(config.outputDir, "metadata.json");
|
|
491
|
-
fs.writeFileSync(outputMetadataPath, JSON.stringify(metadataJson, null, 2));
|
|
492
|
-
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, "\\'");
|
|
493
222
|
}
|
|
494
223
|
//# sourceMappingURL=build.js.map
|