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

@buildrlabs/mcp-registry-sdk

v0.1.3

Published

TypeScript SDK for the MCP Registry API

Readme

@buildrlabs/mcp-registry-sdk

Official TypeScript/JavaScript SDK for the Buildrlab MCP Registry - discover and integrate Model Context Protocol (MCP) servers into your applications.

Table of Contents

Installation

# npm
npm install @buildrlabs/mcp-registry-sdk

# yarn
yarn add @buildrlabs/mcp-registry-sdk

# pnpm
pnpm add @buildrlabs/mcp-registry-sdk

Getting Your API Key

  1. Visit the Buildrlab MCP Registry and sign in
  2. Navigate to your dashboard
  3. Generate an API key
  4. Store it securely (environment variable recommended)
# .env file
MCP_REGISTRY_API_KEY=your-api-key-here

Security: Never commit your API key to version control. Always use environment variables.

Quick Start

import { McpRegistryClient } from '@buildrlabs/mcp-registry-sdk';

// Initialize the client
const client = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!
});

// List all available MCP servers
const { items: servers } = await client.listServers();

console.log(`Found ${servers.length} servers:`);
servers.forEach(server => {
  console.log(`- ${server.name}: ${server.description}`);
});

Configuration

Constructor Options

const client = new McpRegistryClient({
  // Required: Your API key
  apiKey: process.env.MCP_REGISTRY_API_KEY!,

  // Optional: API environment (defaults to dev)
  baseUrl: process.env.MCP_REGISTRY_API_URL
});

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | apiKey | string | Yes | - | Your MCP Registry API key | | baseUrl | string | No | https://dev.mcp-registry.buildrlab.com | API base URL |

Environments

| Environment | URL | |-------------|-----| | Development | https://dev.mcp-registry.buildrlab.com (default) | | Production | https://mcp-registry.buildrlab.com |

// Development (default)
const devClient = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!
});

// Production
const prodClient = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!,
  baseUrl: 'https://mcp-registry.buildrlab.com'
});

// Using environment variable for flexibility
const client = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!,
  baseUrl: process.env.MCP_REGISTRY_API_URL // Set per environment
});

API Reference

listServers(options?)

Retrieve a list of MCP servers with optional filtering and pagination.

const response = await client.listServers(options);

Parameters

| Option | Type | Default | Description | |--------|------|---------|-------------| | limit | number | 50 | Items per page (1-100) | | cursor | string | - | Pagination cursor from previous response | | q | string | - | Search by name or description | | hasRemote | boolean | - | Filter servers with remote connections | | source | 'upstream' \| 'manual' | - | Filter by server source | | fetchAll | boolean | false | Fetch all servers (ignores pagination) |

Response

interface ServersListResponse {
  items: ServerSummary[];    // Array of server summaries
  nextCursor: string | null; // Cursor for next page, null if no more pages
}

interface ServerSummary {
  id: string;                // Unique server identifier
  name: string;              // Server name
  description: string;       // Server description
  version: string | null;    // Server version
  repository: string | null; // Source repository URL
  hasRemote: boolean;        // Has remote connection capability
  hasLocal: boolean;         // Has local installation option
  source: 'upstream' | 'manual'; // Server source
}

Examples

// Basic listing
const { items } = await client.listServers();

// Search for specific servers
const { items } = await client.listServers({ q: 'github' });

// Get servers with remote capability
const { items } = await client.listServers({ hasRemote: true });

// Paginate through results
const { items, nextCursor } = await client.listServers({ limit: 10 });
if (nextCursor) {
  const nextPage = await client.listServers({ limit: 10, cursor: nextCursor });
}

// Fetch all servers at once
const { items: allServers } = await client.listServers({ fetchAll: true });

getServer(id)

Retrieve detailed information about a specific MCP server.

const server = await client.getServer('server-id');

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | string | Yes | The server's unique identifier |

Response

interface ServerDetail {
  id: string;                    // Unique server identifier
  name: string;                  // Server name
  description: string;           // Server description
  version: string | null;        // Server version
  repository: string | null;     // Source repository URL
  remotes: unknown[];            // Remote connection configurations
  locals: unknown[];             // Local installation configurations
  source: 'upstream' | 'manual'; // Server source
  status: 'draft' | 'published'; // Publication status
  updatedAt: string;             // Last update timestamp (ISO 8601)
  overrides?: ServerOverrides;   // Custom overrides applied
}

Example

const server = await client.getServer('github-mcp-server');

console.log(`Server: ${server.name}`);
console.log(`Description: ${server.description}`);
console.log(`Version: ${server.version}`);
console.log(`Repository: ${server.repository}`);
console.log(`Last Updated: ${new Date(server.updatedAt).toLocaleDateString()}`);

// Check connection options
if (server.remotes.length > 0) {
  console.log('Remote connections available');
}
if (server.locals.length > 0) {
  console.log('Local installation available');
}

Working with Results

Iterating Over Servers

const { items: servers } = await client.listServers();

// Using forEach
servers.forEach(server => {
  console.log(`${server.name} - ${server.description}`);
});

// Using for...of
for (const server of servers) {
  console.log(`${server.name} v${server.version || 'unknown'}`);
}

// Using map to transform
const serverNames = servers.map(server => server.name);

Filtering Results

const { items: servers } = await client.listServers();

// Find servers with repositories
const withRepos = servers.filter(server => server.repository !== null);

// Find servers with both remote and local options
const flexible = servers.filter(server => server.hasRemote && server.hasLocal);

// Group by source
const bySource = servers.reduce((acc, server) => {
  acc[server.source] = acc[server.source] || [];
  acc[server.source].push(server);
  return acc;
}, {} as Record<string, typeof servers>);

Pagination Helper

async function getAllServers(client: McpRegistryClient) {
  const allServers: ServerSummary[] = [];
  let cursor: string | undefined;

  do {
    const { items, nextCursor } = await client.listServers({
      limit: 100,
      cursor
    });
    allServers.push(...items);
    cursor = nextCursor ?? undefined;
  } while (cursor);

  return allServers;
}

// Or simply use fetchAll
const { items: allServers } = await client.listServers({ fetchAll: true });

Error Handling

The SDK provides detailed error information through the McpRegistryError class.

Basic Error Handling

import { McpRegistryClient, McpRegistryError } from '@buildrlabs/mcp-registry-sdk';

const client = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!
});

try {
  const { items } = await client.listServers();
  console.log(`Found ${items.length} servers`);
} catch (error) {
  if (error instanceof McpRegistryError) {
    console.error(`API Error: ${error.message}`);
    console.error(`Status Code: ${error.statusCode}`);
  } else {
    console.error('Unexpected error:', error);
  }
}

Error Properties

class McpRegistryError extends Error {
  message: string;      // Human-readable error message
  statusCode: number;   // HTTP status code
  isAuthError: boolean; // True for 401/403 errors
  isNotFound: boolean;  // True for 404 errors
}

Handling Specific Errors

try {
  const server = await client.getServer('non-existent-id');
} catch (error) {
  if (error instanceof McpRegistryError) {
    if (error.isAuthError) {
      // 401 or 403 - Authentication/Authorization issue
      console.error('API key is invalid or missing');
      console.error('Please check your MCP_REGISTRY_API_KEY environment variable');
    } else if (error.isNotFound) {
      // 404 - Server not found
      console.error('The requested server does not exist');
    } else {
      // Other API errors (500, etc.)
      console.error(`API error (${error.statusCode}): ${error.message}`);
    }
  }
}

Missing API Key

The SDK validates the API key at initialization:

// This throws immediately - no API call made
try {
  const client = new McpRegistryClient({ apiKey: '' });
} catch (error) {
  // McpRegistryError: "MCP Registry API key is required.
  //                    Get your API key from the MCP Registry dashboard."
}

Error Reference

| Status Code | isAuthError | isNotFound | Common Cause | |-------------|---------------|--------------|--------------| | 400 | false | false | Invalid request parameters | | 401 | true | false | Missing or invalid API key | | 403 | true | false | API key lacks permission | | 404 | false | true | Server not found | | 429 | false | false | Rate limit exceeded | | 500 | false | false | Server error |

TypeScript Support

The SDK is written in TypeScript and exports all types for full type safety.

Importing Types

import {
  McpRegistryClient,
  McpRegistryError,
  createMcpRegistryClient,
} from '@buildrlabs/mcp-registry-sdk';

import type {
  // Client options
  McpRegistryClientOptions,
  ListServersOptions,

  // Response types
  ServerSummary,
  ServerDetail,
  ServersListResponse,
  ServerDetailResponse,

  // Enums
  ServerSource,   // 'upstream' | 'manual'
  ServerStatus,   // 'draft' | 'published'

  // Other
  ServerOverrides,
  ErrorResponse,
} from '@buildrlabs/mcp-registry-sdk';

Type-Safe Usage

import type { ServerSummary, ListServersOptions } from '@buildrlabs/mcp-registry-sdk';

// Options are fully typed
const options: ListServersOptions = {
  limit: 25,
  hasRemote: true,
  source: 'upstream', // TypeScript ensures valid values
};

const { items } = await client.listServers(options);

// Results are fully typed
items.forEach((server: ServerSummary) => {
  // TypeScript knows all available properties
  console.log(server.name);        // string
  console.log(server.version);     // string | null
  console.log(server.hasRemote);   // boolean
});

Examples

Express.js API Endpoint

import express from 'express';
import { McpRegistryClient, McpRegistryError } from '@buildrlabs/mcp-registry-sdk';

const app = express();
const client = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!
});

app.get('/api/mcp-servers', async (req, res) => {
  try {
    const { q, hasRemote } = req.query;

    const { items } = await client.listServers({
      q: q as string,
      hasRemote: hasRemote === 'true',
    });

    res.json({ servers: items });
  } catch (error) {
    if (error instanceof McpRegistryError) {
      res.status(error.statusCode).json({ error: error.message });
    } else {
      res.status(500).json({ error: 'Internal server error' });
    }
  }
});

Next.js Server Component

import { McpRegistryClient } from '@buildrlabs/mcp-registry-sdk';

const client = new McpRegistryClient({
  apiKey: process.env.MCP_REGISTRY_API_KEY!
});

export default async function McpServersPage() {
  const { items: servers } = await client.listServers({ limit: 20 });

  return (
    <div>
      <h1>MCP Servers</h1>
      <ul>
        {servers.map(server => (
          <li key={server.id}>
            <strong>{server.name}</strong>
            <p>{server.description}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

Search with Debounce (React)

import { useState, useEffect } from 'react';
import { McpRegistryClient, ServerSummary } from '@buildrlabs/mcp-registry-sdk';

const client = new McpRegistryClient({
  apiKey: process.env.NEXT_PUBLIC_MCP_REGISTRY_API_KEY!
});

function useServerSearch(query: string) {
  const [servers, setServers] = useState<ServerSummary[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!query.trim()) {
      setServers([]);
      return;
    }

    const timer = setTimeout(async () => {
      setLoading(true);
      setError(null);

      try {
        const { items } = await client.listServers({ q: query });
        setServers(items);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Search failed');
      } finally {
        setLoading(false);
      }
    }, 300);

    return () => clearTimeout(timer);
  }, [query]);

  return { servers, loading, error };
}

CLI Tool

#!/usr/bin/env node
import { McpRegistryClient, McpRegistryError } from '@buildrlabs/mcp-registry-sdk';

async function main() {
  const apiKey = process.env.MCP_REGISTRY_API_KEY;

  if (!apiKey) {
    console.error('Error: MCP_REGISTRY_API_KEY environment variable is required');
    process.exit(1);
  }

  const client = new McpRegistryClient({ apiKey });
  const [command, ...args] = process.argv.slice(2);

  try {
    switch (command) {
      case 'list':
        const { items } = await client.listServers({ fetchAll: true });
        console.log(`Found ${items.length} servers:\n`);
        items.forEach(s => console.log(`  ${s.name} - ${s.description}`));
        break;

      case 'get':
        if (!args[0]) {
          console.error('Usage: mcp-registry get <server-id>');
          process.exit(1);
        }
        const server = await client.getServer(args[0]);
        console.log(JSON.stringify(server, null, 2));
        break;

      case 'search':
        if (!args[0]) {
          console.error('Usage: mcp-registry search <query>');
          process.exit(1);
        }
        const { items: results } = await client.listServers({ q: args.join(' ') });
        console.log(`Found ${results.length} matching servers:\n`);
        results.forEach(s => console.log(`  ${s.name} - ${s.description}`));
        break;

      default:
        console.log('Usage: mcp-registry <command> [args]');
        console.log('Commands: list, get <id>, search <query>');
    }
  } catch (error) {
    if (error instanceof McpRegistryError) {
      console.error(`Error: ${error.message}`);
      process.exit(1);
    }
    throw error;
  }
}

main();

License

MIT

Links