toolset-registry
v0.0.8
Published
[](https://badge.fury.io/js/toolset-registry) [](https://opensource.org/licenses/MIT) [;
// 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 error2. 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 reasoning4. 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:
- 00-quickstart.ts - Complete overview
- 01-calculator.ts - Basic math operations
- 02-exa.ts - Web search integration
- 03-slack.ts - Team messaging
- 04-firecrawl.ts - Web scraping and crawling
- 04-search.ts - Tool discovery
- 05-ask.ts - Natural language search
📄 License
MIT © Yuta Nishimori
