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

toolset-registry

v0.0.8

Published

[![npm version](https://badge.fury.io/js/toolset-registry.svg)](https://badge.fury.io/js/toolset-registry) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/ba

Readme

toolset-registry

npm version License: MIT TypeScript

Manage and execute tool collections with type-safe interfaces and flexible authentication.

🚀 Quick Start

npm install toolset-registry
import { ToolsetRegistry, calculatorToolset } from "toolset-registry";

// Create a registry with toolsets
const registry = new ToolsetRegistry([calculatorToolset]);

// Register a toolset instance
const calc = await registry.set("my-calc", "calculator");

// Execute a tool
const result = await calc.execute("add", { a: 5, b: 3 });
console.log(result); // { result: 8 }

💡 Key Features

1. Type-Safe Tool Execution

Full TypeScript support with Zod schema validation:

const calc = await registry.set("calc", "calculator");

// TypeScript knows the input/output types
const sum = await calc.execute("add", { a: 10, b: 20 }); // { result: 30 }
const product = await calc.execute("multiply", { a: 5, b: 6 }); // { result: 30 }

// Type errors are caught at compile time
// calc.execute('add', { x: 1 }); // ❌ TypeScript error

2. Flexible Authentication

Support for multiple auth methods per toolset:

// API Key authentication
await registry.set("my-search", "exa", {
  type: "api_key",
  apiKey: process.env.EXA_API_KEY,
});

// OAuth2 authentication
await registry.set("my-oauth", "oauth-toolset", {
  type: "oauth2",
  accessToken: "token",
  refreshToken: "refresh",
  expiresAt: new Date(),
});

// Bearer token
await registry.set("my-bearer", "api-toolset", {
  type: "bearer_token",
  token: "bearer-token",
});

// No authentication
await registry.set("calc", "calculator");

3. Tool Discovery

Find tools using keywords or natural language:

// Search by keyword
const results = registry.search("calculator");
for (const result of results) {
  console.log(`Found: ${result.tool.name} in ${result.toolset.name}`);
}

// Ask in natural language (requires AI model)
import { openai } from "@ai-sdk/openai";

const registry = new ToolsetRegistry([calculatorToolset], {
  model: openai("gpt-4-turbo"),
});

const recommendations = await registry.ask(
  "I need to calculate the sum of two numbers",
);
// Returns tools ranked by relevance with reasoning

4. Pluggable Storage

Choose your storage backend:

// In-memory (default)
const registry = new ToolsetRegistry([]);

// SQLite for persistence
import { SqliteAdapter } from "toolset-registry";
import Database from "better-sqlite3";

const db = new Database("registry.db");
const storage = new SqliteAdapter(db);
const registry = new ToolsetRegistry([], { storage });

// PostgreSQL for production
import { PostgresAdapter } from "toolset-registry";
import { Pool } from "pg";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const storage = new PostgresAdapter(pool);
const registry = new ToolsetRegistry([], { storage });

📖 Core API

ToolsetRegistry

class ToolsetRegistry {
  constructor(toolsets?: Toolset[], options?: RegistryOptions);

  // Toolset management
  addToolset(toolset: Toolset): void;
  getAvailableToolsets(): Toolset[];

  // Registration management
  async set(
    id: string,
    toolsetId: string,
    auth?: AuthConfig,
  ): Promise<RegisteredToolset>;
  async get(id: string): Promise<RegisteredToolset | undefined>;
  async has(id: string): Promise<boolean>;
  async remove(id: string): Promise<boolean>;
  async list(): Promise<RegisteredToolset[]>;
  async clear(): Promise<void>;

  // Tool discovery
  search(keyword: string): SearchResult[];
  async ask(query: string, limit?: number): Promise<AskResult[]>;
}

RegisteredToolset

interface RegisteredToolset {
  id: string;
  toolsetId: string;
  auth?: AuthConfig;

  execute(toolName: string, input: unknown): Promise<unknown>;
  getToolset(): Toolset | undefined;
  getTool(toolName: string): Tool | undefined;
}

🛠️ Built-in Toolsets

Calculator

Mathematical operations without authentication:

const calc = await registry.set("calc", "calculator");
await calc.execute("add", { a: 10, b: 20 }); // { result: 30 }
await calc.execute("subtract", { a: 10, b: 3 }); // { result: 7 }
await calc.execute("multiply", { a: 5, b: 6 }); // { result: 30 }
await calc.execute("divide", { a: 20, b: 4 }); // { result: 5 }

Exa AI Search

Neural search with API key authentication:

const exa = await registry.set("search", "exa", {
  type: "api_key",
  apiKey: process.env.EXA_API_KEY,
});

const results = await exa.execute("search", {
  query: "latest TypeScript features",
  numResults: 5,
});

const contents = await exa.execute("getContents", {
  ids: ["result-id-1", "result-id-2"],
});

Slack

Send messages to Slack channels:

const slack = await registry.set("slack-bot", "slack", {
  type: "api_key",
  apiKey: process.env.SLACK_TOKEN,
});

await slack.execute("sendMessage", {
  channel: "#general",
  text: "Hello from toolset-registry!",
});

await slack.execute("getUserByEmail", {
  email: "[email protected]",
});

Firecrawl

Web scraping and crawling tools:

const firecrawl = await registry.set("scraper", "firecrawl", {
  type: "api_key",
  apiKey: process.env.FIRECRAWL_API_KEY,
});

// Scrape a single page
const page = await firecrawl.execute("scrape", {
  url: "https://example.com",
  formats: ["markdown"],
  onlyMainContent: true,
});

// Search the web
const searchResults = await firecrawl.execute("search", {
  query: "web scraping best practices",
  limit: 5,
});

// Extract structured data
const extracted = await firecrawl.execute("extract", {
  urls: ["https://example.com/pricing"],
  prompt: "Extract pricing tiers and features",
});

// Crawl multiple pages
const pages = await firecrawl.execute("crawl", {
  url: "https://docs.example.com",
  limit: 10,
  maxDepth: 2,
});

// Get site map
const urls = await firecrawl.execute("map", {
  url: "https://example.com",
});

Notion

Interact with Notion workspaces:

const notion = await registry.set("workspace", "notion", {
  type: "api_key",
  apiKey: process.env.NOTION_API_KEY,
});

// Search for pages and databases
const searchResults = await notion.execute("search", {
  query: "project tasks",
  filter: { value: "page" },
  pageSize: 10,
});

// Create a new page
const page = await notion.execute("createPage", {
  parent: { database_id: "your-database-id" },
  properties: {
    Name: {
      title: [{ text: { content: "New Task" } }],
    },
  },
});

// Query a database
const tasks = await notion.execute("queryDatabase", {
  databaseId: "your-database-id",
  filter: {
    property: "Status",
    select: { equals: "In Progress" },
  },
});

// Append content to a page
await notion.execute("appendBlocks", {
  pageId: "your-page-id",
  children: [
    {
      object: "block",
      type: "paragraph",
      paragraph: {
        rich_text: [{ type: "text", text: { content: "New content" } }],
      },
    },
  ],
});

Google Sheets

Read and write Google Sheets spreadsheets:

const sheets = await registry.set("my-sheets", "spreadsheet", {
  type: "oauth2",
  accessToken: process.env.GOOGLE_ACCESS_TOKEN, // OAuth2 access token with spreadsheets scope
});

// Read rows from a sheet
const rows = await sheets.execute("getRows", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  range: "A1:C10",
  limit: 100,
});

// Append rows to a sheet
await sheets.execute("appendRows", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  rows: [
    { Name: "John Doe", Email: "[email protected]", Score: 85 },
    { Name: "Jane Smith", Email: "[email protected]", Score: 92 },
  ],
  valueInputOption: "USER_ENTERED",
});

// Update specific cells
await sheets.execute("updateRows", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  range: "A2:C2",
  values: [["Updated Name", "[email protected]", 100]],
  valueInputOption: "USER_ENTERED",
});

// Delete rows
await sheets.execute("deleteRows", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  startIndex: 5,
  endIndex: 10, // Deletes rows 5-9 (0-based)
});

// Clear data from a range
await sheets.execute("clearRows", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  range: "A1:D10", // Optional - clears entire sheet if not specified
});

// Create a new sheet
await sheets.execute("createSheet", {
  spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
  title: "Q4 Results",
  rowCount: 1000,
  columnCount: 26,
});

🎯 Creating Custom Toolsets

import { z } from "zod";
import type { Tool, Toolset } from "toolset-registry";

// Define input/output schemas
const greetInputSchema = z.object({
  name: z.string(),
});

const greetOutputSchema = z.object({
  message: z.string(),
});

// Create a tool
const greetTool: Tool<typeof greetInputSchema, typeof greetOutputSchema> = {
  id: "greet",
  name: "Greet",
  description: "Greet someone by name",
  inputSchema: greetInputSchema,
  outputSchema: greetOutputSchema,
  execute: async (input) => {
    return { message: `Hello, ${input.name}!` };
  },
};

// Create a toolset
const greeterToolset: Toolset = {
  id: "greeter",
  name: "Greeter",
  description: "Simple greeting tools",
  authType: "none",
  tools: {
    greet: greetTool as unknown as Tool,
  },
};

// Use it
registry.addToolset(greeterToolset);
const greeter = await registry.set("my-greeter", "greeter");
const greeting = await greeter.execute("greet", { name: "World" });
console.log(greeting); // { message: 'Hello, World!' }

📚 Advanced Usage

Tool Discovery with AI

import { openai } from "@ai-sdk/openai";

const registry = new ToolsetRegistry(
  [calculatorToolset, exaToolset, slackToolset, firecrawlToolset],
  {
    model: openai("gpt-4-turbo"),
  },
);

// Natural language queries
const results = await registry.ask("How can I send notifications to my team?");

for (const result of results) {
  console.log(`${result.tool.name} (${result.relevanceScore})`);
  console.log(`Reason: ${result.reasoning}`);
}

Managing Registrations

// List all registered toolset instances
const registrations = await registry.list();
for (const reg of registrations) {
  console.log(`${reg.id}: ${reg.toolsetId}`);
}

// Check if a registration exists
if (await registry.has("my-calc")) {
  const calc = await registry.get("my-calc");
  // Use the calculator
}

// Remove a registration
await registry.remove("my-calc");

// Clear all registrations
await registry.clear();

🔗 Examples

Check out the examples directory:

📄 License

MIT © Yuta Nishimori