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 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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { h as Metadata, I as InternalToolDefinition } from '../validate-DiIOFUU5.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-DiIOFUU5.js';
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.0.0";
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
  }