npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opentool

v0.8.28

Published

OpenTool framework for building serverless MCP tools

Readme

OpenTool

npm version License: MIT

Build serverless TypeScript tools that work with AI assistants, handle crypto payments, and deploy to AWS Lambda automatically.

For LLMs/AI Code Generation: context/opentool-context.ts

What is it?

OpenTool lets you write simple TypeScript functions that can be called by other agents, monetized with crypto payments, and deployed as serverless functions. It handles the boring stuff like:

Tools are either Public or Private. Public tools are accessible to the public and are monetized with crypto payments using x402. Private tools are accessible only to the app developer and are mainly for trading and onchain interaction use cases.

Installation

npm install opentool

Quick Start

1. Create a new project

mkdir my-opentool-project
cd my-opentool-project
npm install opentool
npx opentool init

2. Create your first tool

Create a tools/ directory and add your first tool:

// tools/greet.ts
import { z } from "zod";

export const schema = z.object({
  name: z.string().describe("The name of the user to greet"),
});

export const metadata = {
  name: "greet",
  description: "Simple greeting tool",
};

export async function POST(request: Request) {
  const payload = await request.json();
  const { name } = schema.parse(payload);

  return Response.json({
    message: `Hello, ${name}!`,
  });
}

3. Test locally

# Validate your tools
npx opentool validate

# Start development server
npx opentool dev

Private tools: GET-only and POST-only

For private tools, say for internal trading apps:

  • GET-only (scheduled default profile)
  • POST-only (one-off, parameterized with Zod)
  • profile.category defaults to tracker if omitted; set to strategy or orchestrator for PnL/automation tools.
  • Strategy tools must define profile.templatePreview with:
  • subtitle (required short line)
  • description (required multi-line summary, 3-8 non-empty lines; target ~5)
  • title is optional and defaults to the tool name when omitted.

GET-only (scheduled default)

// tools/aave-stake.ts
export const profile = {
  description: "Stake 100 USDC daily at 12:00 UTC",
  category: "strategy",
  schedule: { cron: "0 12 * * *", enabled: false },
  templatePreview: {
    subtitle: "Automated daily staking strategy",
    description: [
      "Runs once per day on your configured schedule.",
      "Uses fixed, explicit sizing controls from template config.",
      "Designed for long-running automated execution.",
      "Keeps logic deterministic and easy to audit.",
      "Best for hands-off recurring onchain actions.",
    ].join("\\n"),
  },
};

export async function GET(_req: Request) {
  return Response.json({
    ok: true,
    action: "stake",
  });
}

POST-only (one-off)

// tools/aave-unstake.ts
import { z } from "zod";

export const profile = {
  description: "Unstake USDC on demand",
  category: "tracker",
  notifyEmail: true,
};

export const schema = z.object({
  amount: z.string(),
  token: z.string().default("USDC"),
});

export async function POST(req: Request) {
  const body = await req.json();
  const { amount, token } = schema.parse(body);
  return Response.json({ ok: true, action: "unstake", amount, token });
}

Email notifications for one-off tools

  • POST-only tools can set profile.notifyEmail = true to request an email when the tool runs.
  • Scheduled tools should continue to use profile.schedule.notifyEmail.

Cron schedules (profile.schedule)

  • GET-only tools require profile.schedule with a standard 5–6 field cron expression (e.g., 0 12 * * * or 0 0 ? * MON-FRI *).
  • Build validates the cron shape and emits dist/tools.json with schedule data per tool. Enabled defaults to false even if authors set it to true in code. Deployment targets can translate these cron strings to their provider format (e.g., EventBridge) downstream.
  • Use profile.schedule.notifyEmail = true to request email delivery on schedule runs.

Public tools: Add x402 payments (optional)

Protect your public tools with crypto payments using x402:

// tools/premium-report.ts
import { z } from "zod";
import { defineX402Payment } from "opentool/x402";

export const schema = z.object({
  symbol: z.string().describe("Crypto symbol (e.g., BTC)"),
});

export const payment = defineX402Payment({
  amount: "0.001",
  payTo: process.env.WALLET_ADDRESS!,
  currency: "USDC",
  network: "base-sepolia",
  message: "Premium analytics require payment",
});

export async function POST(request: Request) {
  const payload = await request.json();
  const { symbol } = schema.parse(payload);

  return Response.json({
    report: `Premium analytics for ${symbol}`,
  });
}

Test the payment flow:

# Start dev server
WALLET_ADDRESS=0x... npx opentool dev --input tools

# Test with the x402 client
PRIVATE_KEY=0x... bun examples/full-metadata/test-x402.ts

Or test manually:

# Get 402 response with payment requirements
curl -X POST http://localhost:7000/premium-report \
  -H "content-type: application/json" \
  -d '{"symbol":"BTC"}'

# Pay and retry with X-PAYMENT header (generated by x402 client)
curl -X POST http://localhost:7000/premium-report \
  -H "content-type: application/json" \
  -H "X-PAYMENT: ${X402_HEADER}" \
  -d '{"symbol":"BTC"}'

MCP

By default, tools are HTTP-only. Want them accessible via MCP clients like Claude Desktop? Just add this to your tool file:

// tools/greet.ts
export const mcp = {
  enabled: true, // Now works with Claude Desktop, MCP Inspector, etc.
};

Tools without this export stay HTTP-only, which is useful when you want selective access. Mix and match as needed.

Testing with MCP Inspector

The examples/full-metadata project has an inspector.json config ready to go:

cd examples/full-metadata
npx mcp-inspector --config inspector.json --server opentool-dev

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.

Quick x402 test with curl

  1. Start the dev server against the example tools:

    npx opentool dev --input examples/full-metadata/tools
  2. Trigger the paywall and inspect the returned payment requirements:

    curl -i \
      -X POST http://localhost:7000/premium-report \
      -H "content-type: application/json" \
      -d '{"symbol":"BTC"}'

    The response includes a 402 Payment Required status and JSON body with an x402.accepts[0] object describing the payment request.

  3. Submit a follow-up request with an X-PAYMENT header produced by your x402 facilitator (for example, by using the Coinbase x402 tooling or your own signing flow):

    curl -i \
      -X POST http://localhost:7000/premium-report \
      -H "content-type: application/json" \
      -H "X-PAYMENT: ${X402_HEADER}" \
      -d '{"symbol":"BTC"}'

    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.

5. Build for deployment

# Build tools for Lambda deployment
npx opentool build

6. Deploy to OpenPond

Create an account on OpenPond and create a new project.

Add your project to the OpenPond project and connect it to your GitHub repository.

OpenPond will automatically detect the opentool dependency and deploy your tools to AWS Lambda.

CLI Commands

Build

Build your tools for deployment:

npx opentool build [options]

Options:
  -i, --input <dir>      Input directory containing tools (default: "tools")
  -o, --output <dir>     Output directory for built tools (default: "dist")
  --name <name>          Server name (default: "opentool-server")
  --version <version>    Server version (default: "1.0.0")

Development Server

Start a local development server:

npx opentool dev [options]

Options:
  -i, --input <dir>      Input directory containing tools (default: "tools")
  --watch                Watch for file changes (default: false)

Validate

Validate your tools:

npx opentool validate [options]

Options:
  -i, --input <dir>      Input directory containing tools (default: "tools")

Generate Metadata

Generate metadata.json without building:

npx opentool metadata [options]

Options:
  -i, --input <dir>      Input directory containing tools (default: "tools")
  -o, --output <file>    Output file path for metadata.json (default: "metadata.json")
  --name <name>          Server name (default: "opentool-server")
  --version <version>    Server version (default: "1.0.0")

Generates the metadata file with tool schemas, payment configs, and discovery info. Useful for inspecting or sharing metadata without a full build.

Tool Definition

Tools are just TypeScript files with a few exports:

import { z } from "zod";

// 1. Schema for input validation
export const schema = z.object({
  input: z.string().describe("Some input parameter"),
});

// 2. Metadata
export const metadata = {
  name: "my_tool",
  description: "What this tool does",
};

// 3. Optional: enable MCP mode
export const mcp = {
  enabled: true, // Makes it work with Claude Desktop, etc.
};

// 4. Handler (POST, GET, PUT, DELETE, etc.)
export async function POST(request: Request) {
  const payload = await request.json();
  const params = schema.parse(payload);

  // Your tool logic here
  return Response.json({
    result: "Tool response",
  });
}

Error Handling

Just return standard HTTP responses:

export async function POST(request: Request) {
  const payload = await request.json();
  const params = schema.parse(payload);

  if (someCondition) {
    return Response.json({ error: "Something went wrong" }, { status: 400 });
  }

  return Response.json({ result: "Success" });
}

Local Development

Run npx opentool dev to test your tools locally. It runs them via stdio (for MCP clients) or HTTP (for direct API calls). Good for:

  • Testing tool logic
  • Validating schemas
  • Debugging before deployment

Deployment

Push your repo to GitHub and connect it to OpenPond:

  1. OpenPond detects the opentool dependency
  2. Runs npx opentool build
  3. Deploys to AWS Lambda with Function URLs
  4. Done - your tools are live

Examples

Check examples/full-metadata/ for a complete example with payment and discovery features.

Testing Examples Locally

# Build and link the OpenTool package
npm run build
npm link

# Test the example
cd examples/full-metadata
npm link opentool
npm run build

# Check the output
cat dist/metadata.json

# Test the MCP server
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node dist/mcp-server.js

# Or from repo root:
npm run examples:build      # Build example (CJS+ESM)
npm run examples:validate   # Validate metadata and tools
npm run examples:metadata   # Regenerate metadata.json

Metadata System

OpenTool has three levels of metadata config:

  1. Default - pulls from your package.json automatically
  2. Project-level (optional) - add a metadata.ts file for branding, payments, etc.
  3. Tool-level - override metadata per tool

See METADATA.md for details on configuring metadata for on-chain registration and payments.

What's Next

  • Better watch mode that keeps metadata and tool artifacts synced during dev

Contributing

Contributions welcome! See the Contributing Guide.

License

MIT © OpenTool