opentool 0.6.3 → 0.6.5
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 +31 -0
- package/dist/cli/index.d.ts +12 -2
- package/dist/cli/index.js +182 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -6
- package/dist/index.js.map +1 -1
- package/dist/{validate-DiIOFUU5.d.ts → validate-BLlooEBK.d.ts} +14 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -113,6 +113,37 @@ npx mcp-inspector --config inspector.json --server opentool-dev
|
|
|
113
113
|
|
|
114
114
|
Copy `.env.example` to `.env` and add your credentials if you're using wallet/payment features. The inspector starts `opentool dev` automatically, so you only need one terminal. Only tools with `mcp = { enabled: true }` show up in the inspector - HTTP-only tools keep running on localhost.
|
|
115
115
|
|
|
116
|
+
### Quick x402 test with curl
|
|
117
|
+
|
|
118
|
+
1. Start the dev server against the example tools:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npx opentool dev --input examples/full-metadata/tools
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
2. Trigger the paywall and inspect the returned payment requirements:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
curl -i \
|
|
128
|
+
-X POST http://localhost:7000/premium-report \
|
|
129
|
+
-H "content-type: application/json" \
|
|
130
|
+
-d '{"symbol":"BTC"}'
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The response includes a `402 Payment Required` status and JSON body with an `x402.accepts[0]` object describing the payment request.
|
|
134
|
+
|
|
135
|
+
3. Submit a follow-up request with an `X-PAYMENT` header produced by your x402 facilitator (for example, by using the Coinbase [x402](https://github.com/coinbase/x402) tooling or your own signing flow):
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
curl -i \
|
|
139
|
+
-X POST http://localhost:7000/premium-report \
|
|
140
|
+
-H "content-type: application/json" \
|
|
141
|
+
-H "X-PAYMENT: ${X402_HEADER}" \
|
|
142
|
+
-d '{"symbol":"BTC"}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Replace `${X402_HEADER}` with the base64-encoded payment payload returned by your facilitator’s `/verify` or `/pay` workflow. If the payment is valid the server responds with `200 OK`; otherwise it returns a new `402` with failure details.
|
|
146
|
+
|
|
116
147
|
### 5. Build for deployment
|
|
117
148
|
|
|
118
149
|
```bash
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { h as Metadata, I as InternalToolDefinition } from '../validate-
|
|
3
|
-
export { G as GenerateMetadataOptions, i as GenerateMetadataResult, V as ValidateOptions, g as generateMetadata, a as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, j as validateFullCommand } from '../validate-
|
|
2
|
+
import { h as Metadata, I as InternalToolDefinition } from '../validate-BLlooEBK.js';
|
|
3
|
+
export { G as GenerateMetadataOptions, i as GenerateMetadataResult, V as ValidateOptions, g as generateMetadata, a as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, j as validateFullCommand } from '../validate-BLlooEBK.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import '../index-D3DaM5Rs.js';
|
|
6
6
|
|
|
@@ -15,6 +15,7 @@ interface BuildArtifacts {
|
|
|
15
15
|
defaultsApplied: string[];
|
|
16
16
|
tools: InternalToolDefinition[];
|
|
17
17
|
compiledTools: CompiledToolArtifact[];
|
|
18
|
+
workflowBundles: WorkflowBundleArtifact | null;
|
|
18
19
|
}
|
|
19
20
|
interface CompiledToolArtifact {
|
|
20
21
|
name: string;
|
|
@@ -25,6 +26,15 @@ interface CompiledToolArtifact {
|
|
|
25
26
|
defaultMcpMethod?: string;
|
|
26
27
|
hasWallet: boolean;
|
|
27
28
|
}
|
|
29
|
+
interface WorkflowBundleArtifact {
|
|
30
|
+
sourceDir: string;
|
|
31
|
+
outputDir: string;
|
|
32
|
+
stepsBundlePath: string;
|
|
33
|
+
workflowsBundlePath: string;
|
|
34
|
+
webhookBundlePath: string;
|
|
35
|
+
clientBundlePath?: string;
|
|
36
|
+
manifestPath?: string;
|
|
37
|
+
}
|
|
28
38
|
declare function buildCommand(options: BuildOptions): Promise<void>;
|
|
29
39
|
declare function buildProject(options: BuildOptions): Promise<BuildArtifacts>;
|
|
30
40
|
|
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,7 @@ async function transpileWithEsbuild(options) {
|
|
|
79
79
|
};
|
|
80
80
|
return { outDir: tempBase, cleanup };
|
|
81
81
|
}
|
|
82
|
-
var METADATA_SPEC_VERSION = "1.
|
|
82
|
+
var METADATA_SPEC_VERSION = "1.1.0";
|
|
83
83
|
var McpAnnotationsSchema = z.object({
|
|
84
84
|
title: z.string().optional(),
|
|
85
85
|
readOnlyHint: z.boolean().optional(),
|
|
@@ -113,7 +113,8 @@ var ToolMetadataOverridesSchema = z.object({
|
|
|
113
113
|
description: z.string().optional(),
|
|
114
114
|
annotations: McpAnnotationsSchema.optional(),
|
|
115
115
|
payment: PaymentConfigSchema.optional(),
|
|
116
|
-
discovery: DiscoveryMetadataSchema.optional()
|
|
116
|
+
discovery: DiscoveryMetadataSchema.optional(),
|
|
117
|
+
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
117
118
|
}).catchall(z.any());
|
|
118
119
|
var ToolSchema = z.object({
|
|
119
120
|
name: z.string(),
|
|
@@ -121,7 +122,8 @@ var ToolSchema = z.object({
|
|
|
121
122
|
inputSchema: z.any(),
|
|
122
123
|
annotations: McpAnnotationsSchema.optional(),
|
|
123
124
|
payment: PaymentConfigSchema.optional(),
|
|
124
|
-
discovery: DiscoveryMetadataSchema.optional()
|
|
125
|
+
discovery: DiscoveryMetadataSchema.optional(),
|
|
126
|
+
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
125
127
|
}).strict();
|
|
126
128
|
var AuthoredMetadataSchema = z.object({
|
|
127
129
|
metadataSpecVersion: z.string().optional(),
|
|
@@ -148,7 +150,8 @@ var AuthoredMetadataSchema = z.object({
|
|
|
148
150
|
capabilities: z.array(z.string()).optional(),
|
|
149
151
|
requirements: z.record(z.any()).optional(),
|
|
150
152
|
pricing: z.record(z.any()).optional(),
|
|
151
|
-
compatibility: z.record(z.any()).optional()
|
|
153
|
+
compatibility: z.record(z.any()).optional(),
|
|
154
|
+
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
152
155
|
}).catchall(z.any());
|
|
153
156
|
var MetadataSchema = z.object({
|
|
154
157
|
metadataSpecVersion: z.string().default(METADATA_SPEC_VERSION),
|
|
@@ -169,7 +172,8 @@ var MetadataSchema = z.object({
|
|
|
169
172
|
iconPath: z.string().optional(),
|
|
170
173
|
videoPath: z.string().optional(),
|
|
171
174
|
image: z.string().optional(),
|
|
172
|
-
animation_url: z.string().optional()
|
|
175
|
+
animation_url: z.string().optional(),
|
|
176
|
+
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
173
177
|
}).strict();
|
|
174
178
|
createRequire(import.meta.url);
|
|
175
179
|
function resolveCompiledPath(outDir, originalFile, extension = ".js") {
|
|
@@ -305,6 +309,7 @@ async function buildMetadataArtifact(options) {
|
|
|
305
309
|
defaultsApplied.push(`tool ${toolName} payment \u2192 agent payment`);
|
|
306
310
|
}
|
|
307
311
|
const toolDiscovery = overrides.discovery ?? void 0;
|
|
312
|
+
const toolChains = overrides.chains ?? authored.chains ?? void 0;
|
|
308
313
|
const toolDefinition = {
|
|
309
314
|
name: toolName,
|
|
310
315
|
description: toolDescription,
|
|
@@ -319,6 +324,9 @@ async function buildMetadataArtifact(options) {
|
|
|
319
324
|
if (toolDiscovery) {
|
|
320
325
|
toolDefinition.discovery = toolDiscovery;
|
|
321
326
|
}
|
|
327
|
+
if (toolChains) {
|
|
328
|
+
toolDefinition.chains = toolChains;
|
|
329
|
+
}
|
|
322
330
|
return toolDefinition;
|
|
323
331
|
});
|
|
324
332
|
const metadata = MetadataSchema.parse({
|
|
@@ -340,7 +348,8 @@ async function buildMetadataArtifact(options) {
|
|
|
340
348
|
iconPath: authored.iconPath,
|
|
341
349
|
videoPath: authored.videoPath,
|
|
342
350
|
image: baseImage,
|
|
343
|
-
animation_url: animation
|
|
351
|
+
animation_url: animation,
|
|
352
|
+
chains: authored.chains
|
|
344
353
|
});
|
|
345
354
|
return {
|
|
346
355
|
metadata,
|
|
@@ -1658,6 +1667,10 @@ async function buildProject(options) {
|
|
|
1658
1667
|
projectRoot,
|
|
1659
1668
|
outputDir
|
|
1660
1669
|
});
|
|
1670
|
+
const workflowBundles = await buildWorkflowsIfPresent({
|
|
1671
|
+
projectRoot,
|
|
1672
|
+
outputDir
|
|
1673
|
+
});
|
|
1661
1674
|
const shouldBuildMcpServer = compiledTools.some((artifact) => artifact.mcpEnabled);
|
|
1662
1675
|
if (shouldBuildMcpServer) {
|
|
1663
1676
|
await writeMcpServer({
|
|
@@ -1675,7 +1688,8 @@ async function buildProject(options) {
|
|
|
1675
1688
|
metadata,
|
|
1676
1689
|
defaultsApplied,
|
|
1677
1690
|
tools,
|
|
1678
|
-
compiledTools
|
|
1691
|
+
compiledTools,
|
|
1692
|
+
workflowBundles
|
|
1679
1693
|
};
|
|
1680
1694
|
}
|
|
1681
1695
|
async function emitTools(tools, config) {
|
|
@@ -1834,6 +1848,18 @@ function logBuildSummary(artifacts, options) {
|
|
|
1834
1848
|
console.log(` - ${tool.name} [${methods}]${walletBadge}`);
|
|
1835
1849
|
});
|
|
1836
1850
|
console.log(" \u2022 metadata.json (registry artifact)");
|
|
1851
|
+
if (artifacts.workflowBundles) {
|
|
1852
|
+
console.log(" \u2022 .well-known/workflow/v1/ (workflow bundles)");
|
|
1853
|
+
console.log(" - flow.js");
|
|
1854
|
+
console.log(" - step.js");
|
|
1855
|
+
console.log(" - webhook.js");
|
|
1856
|
+
if (artifacts.workflowBundles.clientBundlePath) {
|
|
1857
|
+
console.log(" - client.js");
|
|
1858
|
+
}
|
|
1859
|
+
if (artifacts.workflowBundles.manifestPath) {
|
|
1860
|
+
console.log(" - manifest.json");
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1837
1863
|
if (artifacts.defaultsApplied.length > 0) {
|
|
1838
1864
|
console.log("\nDefaults applied during metadata synthesis:");
|
|
1839
1865
|
artifacts.defaultsApplied.forEach((entry) => console.log(` \u2022 ${entry}`));
|
|
@@ -1842,6 +1868,155 @@ function logBuildSummary(artifacts, options) {
|
|
|
1842
1868
|
console.log("\n\u2139\uFE0F MCP adapter skipped (no tools opted in)");
|
|
1843
1869
|
}
|
|
1844
1870
|
}
|
|
1871
|
+
async function buildWorkflowsIfPresent(options) {
|
|
1872
|
+
const workflowsDir = options.workflowsDir ?? path5.join(options.projectRoot, "workflows");
|
|
1873
|
+
if (!fs4.existsSync(workflowsDir)) {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1876
|
+
if (!hasWorkflowSourceFiles(workflowsDir)) {
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
const nodeVersion = process.versions?.node ?? "0.0.0";
|
|
1880
|
+
const nodeMajor = Number(nodeVersion.split(".")[0] ?? 0);
|
|
1881
|
+
if (!Number.isFinite(nodeMajor) || nodeMajor < 22) {
|
|
1882
|
+
console.warn(
|
|
1883
|
+
`[${timestamp()}] Workflow bundles skipped (requires Node >= 22, current ${nodeVersion})`
|
|
1884
|
+
);
|
|
1885
|
+
return null;
|
|
1886
|
+
}
|
|
1887
|
+
const { BaseBuilder } = await import('@workflow/cli/dist/lib/builders/base-builder.js');
|
|
1888
|
+
class OpenToolWorkflowBuilder extends BaseBuilder {
|
|
1889
|
+
async build() {
|
|
1890
|
+
const inputFiles = await this.getInputFiles();
|
|
1891
|
+
const tsConfig = await this.getTsConfigOptions();
|
|
1892
|
+
const shared = {
|
|
1893
|
+
inputFiles,
|
|
1894
|
+
...tsConfig.baseUrl ? { tsBaseUrl: tsConfig.baseUrl } : {},
|
|
1895
|
+
...tsConfig.paths ? { tsPaths: tsConfig.paths } : {}
|
|
1896
|
+
};
|
|
1897
|
+
await this.buildStepsBundle(shared);
|
|
1898
|
+
await this.buildWorkflowsBundle(shared);
|
|
1899
|
+
await this.buildWebhookRoute();
|
|
1900
|
+
await this.buildClientLibrary();
|
|
1901
|
+
}
|
|
1902
|
+
async buildStepsBundle(options2) {
|
|
1903
|
+
console.log(
|
|
1904
|
+
"Creating OpenTool workflow steps bundle at",
|
|
1905
|
+
this.config.stepsBundlePath
|
|
1906
|
+
);
|
|
1907
|
+
const stepsBundlePath2 = path5.resolve(
|
|
1908
|
+
this.config.workingDir,
|
|
1909
|
+
this.config.stepsBundlePath
|
|
1910
|
+
);
|
|
1911
|
+
await fs4.promises.mkdir(path5.dirname(stepsBundlePath2), { recursive: true });
|
|
1912
|
+
await this.createStepsBundle({
|
|
1913
|
+
outfile: stepsBundlePath2,
|
|
1914
|
+
...options2
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
async buildWorkflowsBundle(options2) {
|
|
1918
|
+
console.log(
|
|
1919
|
+
"Creating OpenTool workflow bundle at",
|
|
1920
|
+
this.config.workflowsBundlePath
|
|
1921
|
+
);
|
|
1922
|
+
const workflowBundlePath = path5.resolve(
|
|
1923
|
+
this.config.workingDir,
|
|
1924
|
+
this.config.workflowsBundlePath
|
|
1925
|
+
);
|
|
1926
|
+
await fs4.promises.mkdir(path5.dirname(workflowBundlePath), {
|
|
1927
|
+
recursive: true
|
|
1928
|
+
});
|
|
1929
|
+
await this.createWorkflowsBundle({
|
|
1930
|
+
outfile: workflowBundlePath,
|
|
1931
|
+
bundleFinalOutput: false,
|
|
1932
|
+
...options2
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
async buildWebhookRoute() {
|
|
1936
|
+
console.log(
|
|
1937
|
+
"Creating OpenTool workflow webhook bundle at",
|
|
1938
|
+
this.config.webhookBundlePath
|
|
1939
|
+
);
|
|
1940
|
+
const webhookBundlePath2 = path5.resolve(
|
|
1941
|
+
this.config.workingDir,
|
|
1942
|
+
this.config.webhookBundlePath
|
|
1943
|
+
);
|
|
1944
|
+
await fs4.promises.mkdir(path5.dirname(webhookBundlePath2), {
|
|
1945
|
+
recursive: true
|
|
1946
|
+
});
|
|
1947
|
+
await this.createWebhookBundle({ outfile: webhookBundlePath2 });
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
const relativeSourceDir = path5.relative(options.projectRoot, workflowsDir) || ".";
|
|
1951
|
+
const outputBase = path5.join(
|
|
1952
|
+
options.outputDir,
|
|
1953
|
+
".well-known",
|
|
1954
|
+
"workflow",
|
|
1955
|
+
"v1"
|
|
1956
|
+
);
|
|
1957
|
+
const stepsBundlePath = path5.join(outputBase, "step.js");
|
|
1958
|
+
const workflowsBundlePath = path5.join(outputBase, "flow.js");
|
|
1959
|
+
const webhookBundlePath = path5.join(outputBase, "webhook.js");
|
|
1960
|
+
const manifestPath = path5.join(outputBase, "manifest.json");
|
|
1961
|
+
const builder = new OpenToolWorkflowBuilder({
|
|
1962
|
+
workingDir: options.projectRoot,
|
|
1963
|
+
dirs: [relativeSourceDir],
|
|
1964
|
+
buildTarget: "standalone",
|
|
1965
|
+
stepsBundlePath,
|
|
1966
|
+
workflowsBundlePath,
|
|
1967
|
+
webhookBundlePath,
|
|
1968
|
+
...{},
|
|
1969
|
+
workflowManifestPath: manifestPath,
|
|
1970
|
+
externalPackages: [
|
|
1971
|
+
"workflow",
|
|
1972
|
+
"workflow/internal/builtins",
|
|
1973
|
+
"workflow/internal/private",
|
|
1974
|
+
"workflow/runtime",
|
|
1975
|
+
"workflow/api"
|
|
1976
|
+
]
|
|
1977
|
+
});
|
|
1978
|
+
console.log(
|
|
1979
|
+
`[${timestamp()}] Building workflows from ${workflowsDir} -> ${outputBase}`
|
|
1980
|
+
);
|
|
1981
|
+
await builder.build();
|
|
1982
|
+
return {
|
|
1983
|
+
sourceDir: workflowsDir,
|
|
1984
|
+
outputDir: outputBase,
|
|
1985
|
+
stepsBundlePath,
|
|
1986
|
+
workflowsBundlePath,
|
|
1987
|
+
webhookBundlePath,
|
|
1988
|
+
...{},
|
|
1989
|
+
manifestPath
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
function hasWorkflowSourceFiles(directory) {
|
|
1993
|
+
const entries = fs4.readdirSync(directory, { withFileTypes: true });
|
|
1994
|
+
for (const entry of entries) {
|
|
1995
|
+
if (entry.isDirectory()) {
|
|
1996
|
+
if (hasWorkflowSourceFiles(path5.join(directory, entry.name))) {
|
|
1997
|
+
return true;
|
|
1998
|
+
}
|
|
1999
|
+
continue;
|
|
2000
|
+
}
|
|
2001
|
+
if (entry.isFile()) {
|
|
2002
|
+
const extension = path5.extname(entry.name).toLowerCase();
|
|
2003
|
+
if (WORKFLOW_SOURCE_EXTENSIONS.has(extension)) {
|
|
2004
|
+
return true;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
var WORKFLOW_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2011
|
+
".ts",
|
|
2012
|
+
".tsx",
|
|
2013
|
+
".js",
|
|
2014
|
+
".jsx",
|
|
2015
|
+
".mjs",
|
|
2016
|
+
".cjs",
|
|
2017
|
+
".mts",
|
|
2018
|
+
".cts"
|
|
2019
|
+
]);
|
|
1845
2020
|
function timestamp() {
|
|
1846
2021
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
1847
2022
|
}
|