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

@objectstack/plugin-mcp-server

v7.9.0

Published

MCP Runtime Server Plugin for ObjectStack — exposes AI tools, data resources, and agent prompts via the Model Context Protocol

Downloads

5,407

Readme

@objectstack/plugin-mcp-server

MCP Runtime Server Plugin for ObjectStack — exposes AI tools, data resources, and agent prompts via the Model Context Protocol.

Features

  • Model Context Protocol (MCP): Expose ObjectStack resources to AI models via MCP
  • AI Tools: Auto-generate MCP tools from ObjectStack actions and flows
  • Data Resources: Expose objects, records, and metadata as MCP resources
  • Agent Prompts: Register prompt templates for AI agents
  • Type-Safe: Full Zod schema validation for tool inputs/outputs
  • Auto-Discovery: MCP clients automatically discover available tools and resources
  • Streaming Support: Stream large datasets and real-time updates
  • Security: Built-in permission checks for tool execution

What is MCP?

Model Context Protocol (MCP) is an open protocol that standardizes how AI applications provide context to Large Language Models (LLMs). It allows AI models to:

  • Access Tools: Execute functions and operations
  • Read Resources: Access data and content
  • Use Prompts: Leverage pre-defined prompt templates

Read more: MCP Specification

Installation

pnpm add @objectstack/plugin-mcp-server

Basic Usage

import { defineStack } from '@objectstack/spec';
import { PluginMCPServer } from '@objectstack/plugin-mcp-server';

const stack = defineStack({
  plugins: [
    PluginMCPServer.configure({
      serverName: 'objectstack-server',
      version: '1.0.0',
      autoRegisterTools: true,
    }),
  ],
});

Configuration

interface MCPServerConfig {
  /** Server name (shown to AI clients) */
  serverName?: string;

  /** Server version */
  version?: string;

  /** Auto-register tools from actions and flows */
  autoRegisterTools?: boolean;

  /** Auto-expose objects as resources */
  autoExposeObjects?: boolean;

  /** Enable streaming for large responses */
  enableStreaming?: boolean;

  /** Transport mechanism ('stdio' | 'http') */
  transport?: 'stdio' | 'http';

  /** HTTP port (if transport is 'http') */
  port?: number;
}

MCP Tools

Auto-Generated Tools

ObjectStack automatically exposes these operations as MCP tools:

// CRUD operations (auto-registered)
'objectstack_find'         // Query records
'objectstack_findOne'      // Get single record
'objectstack_create'       // Create record
'objectstack_update'       // Update record
'objectstack_delete'       // Delete record

// Metadata operations
'objectstack_describeObject'   // Get object schema
'objectstack_listObjects'      // List all objects
'objectstack_listFields'       // List object fields

Custom Tools

Register custom tools that AI models can call:

import { defineTool } from '@objectstack/spec';

const calculateRevenueTool = defineTool({
  name: 'calculate_revenue',
  description: 'Calculate total revenue for an account',
  inputSchema: {
    type: 'object',
    properties: {
      accountId: { type: 'string', description: 'Account ID' },
      startDate: { type: 'string', description: 'Start date (ISO 8601)' },
      endDate: { type: 'string', description: 'End date (ISO 8601)' },
    },
    required: ['accountId'],
  },
  async execute({ accountId, startDate, endDate }) {
    const opportunities = await kernel.getDriver().find({
      object: 'opportunity',
      filters: [
        { field: 'account_id', operator: 'eq', value: accountId },
        { field: 'stage', operator: 'eq', value: 'closed_won' },
        { field: 'close_date', operator: 'gte', value: startDate },
        { field: 'close_date', operator: 'lte', value: endDate },
      ],
    });

    const total = opportunities.reduce((sum, opp) => sum + opp.amount, 0);

    return {
      accountId,
      totalRevenue: total,
      opportunityCount: opportunities.length,
    };
  },
});

// Register with MCP server
kernel.getService('mcp').registerTool(calculateRevenueTool);

MCP Resources

Auto-Exposed Objects

All ObjectStack objects are automatically exposed as MCP resources:

objectstack://objects/opportunity           # Opportunity object schema
objectstack://objects/opportunity/records   # All opportunity records
objectstack://objects/opportunity/123       # Specific opportunity record

Custom Resources

Expose custom resources to AI models:

kernel.getService('mcp').registerResource({
  uri: 'objectstack://reports/sales-pipeline',
  name: 'Sales Pipeline Report',
  description: 'Current sales pipeline with stages and amounts',
  mimeType: 'application/json',
  async read() {
    const opportunities = await kernel.getDriver().find({
      object: 'opportunity',
      filters: [
        { field: 'stage', operator: 'neq', value: 'closed_won' },
        { field: 'stage', operator: 'neq', value: 'closed_lost' },
      ],
    });

    const pipeline = opportunities.reduce((acc, opp) => {
      acc[opp.stage] = (acc[opp.stage] || 0) + opp.amount;
      return acc;
    }, {});

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(pipeline, null, 2),
        },
      ],
    };
  },
});

MCP Prompts

Register prompt templates that AI models can use:

kernel.getService('mcp').registerPrompt({
  name: 'analyze_account',
  description: 'Analyze an account and its opportunities',
  arguments: [
    {
      name: 'accountId',
      description: 'Account ID to analyze',
      required: true,
    },
  ],
  async render({ accountId }) {
    const account = await kernel.getDriver().findOne({
      object: 'account',
      filters: [{ field: 'id', operator: 'eq', value: accountId }],
    });

    const opportunities = await kernel.getDriver().find({
      object: 'opportunity',
      filters: [{ field: 'account_id', operator: 'eq', value: accountId }],
    });

    return {
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Analyze this account and provide insights:

Account: ${account.name}
Industry: ${account.industry}
Total Opportunities: ${opportunities.length}
Total Value: $${opportunities.reduce((sum, o) => sum + o.amount, 0)}

Opportunities:
${opportunities.map(o => `- ${o.name} (${o.stage}): $${o.amount}`).join('\n')}

Please provide:
1. Key insights about this account
2. Risk assessment
3. Recommendations for next steps`,
          },
        },
      ],
    };
  },
});

Using with AI Clients

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "objectstack": {
      "command": "node",
      "args": ["/path/to/your/objectstack/server.js"],
      "env": {
        "DATABASE_URL": "your-database-url"
      }
    }
  }
}

Cursor IDE

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "objectstack": {
      "command": "node",
      "args": ["./server.js"]
    }
  }
}

Cline VS Code Extension

Configure in Cline settings:

{
  "cline.mcpServers": {
    "objectstack": {
      "command": "node",
      "args": ["./server.js"]
    }
  }
}

Server Implementation

Stdio Transport (Default)

// server.ts
import { defineStack } from '@objectstack/spec';
import { PluginMCPServer } from '@objectstack/plugin-mcp-server';
import { DriverSql } from '@objectstack/driver-sql';

const stack = defineStack({
  driver: DriverSql.configure({
    client: 'better-sqlite3',
    connection: { filename: process.env.DATABASE_URL ?? './data/app.db' },
  }),
  plugins: [
    PluginMCPServer.configure({
      serverName: 'my-crm',
      transport: 'stdio', // Claude Desktop, Cursor, Cline
    }),
  ],
});

await stack.boot();

HTTP Transport

const stack = defineStack({
  driver: DriverSql.configure({ /* ... */ }),
  plugins: [
    PluginMCPServer.configure({
      serverName: 'my-crm',
      transport: 'http',
      port: 3100,
    }),
  ],
});

await stack.boot();
// MCP server running on http://localhost:3100

Advanced Features

Streaming Resources

kernel.getService('mcp').registerResource({
  uri: 'objectstack://exports/opportunities-csv',
  name: 'Opportunities Export (CSV)',
  mimeType: 'text/csv',
  async *stream() {
    // Stream header
    yield 'Name,Stage,Amount,Close Date\n';

    // Stream records in batches
    let offset = 0;
    const batchSize = 100;

    while (true) {
      const batch = await kernel.getDriver().find({
        object: 'opportunity',
        limit: batchSize,
        offset,
      });

      if (batch.length === 0) break;

      for (const opp of batch) {
        yield `${opp.name},${opp.stage},${opp.amount},${opp.close_date}\n`;
      }

      offset += batchSize;
    }
  },
});

Tool Permissions

kernel.getService('mcp').registerTool({
  name: 'delete_opportunity',
  description: 'Delete an opportunity',
  permissions: ['opportunity:delete'], // Require permission
  inputSchema: {
    type: 'object',
    properties: {
      id: { type: 'string' },
    },
    required: ['id'],
  },
  async execute({ id }, context) {
    // context includes userId, permissions, etc.
    if (!context.hasPermission('opportunity:delete')) {
      throw new Error('Permission denied');
    }

    await kernel.getDriver().delete({
      object: 'opportunity',
      filters: [{ field: 'id', operator: 'eq', value: id }],
    });

    return { success: true, deleted: id };
  },
});

Dynamic Tool Registration

// Register tools from flow definitions
const flows = await kernel.getMetadata('flow');

for (const flow of flows) {
  kernel.getService('mcp').registerTool({
    name: `flow_${flow.name}`,
    description: flow.description,
    inputSchema: generateSchemaFromFlow(flow),
    async execute(inputs) {
      return await kernel.executeFlow(flow.name, inputs);
    },
  });
}

Server Capabilities

The MCP server exposes these capabilities:

{
  "capabilities": {
    "tools": {
      "listChanged": true
    },
    "resources": {
      "subscribe": true,
      "listChanged": true
    },
    "prompts": {
      "listChanged": true
    },
    "logging": {},
    "experimental": {
      "streaming": true
    }
  }
}

Best Practices

  1. Tool Design: Keep tools focused and well-documented
  2. Resource Naming: Use clear, hierarchical URI schemes
  3. Prompt Templates: Make prompts flexible with arguments
  4. Error Handling: Always return helpful error messages
  5. Permissions: Check permissions before tool execution
  6. Performance: Use streaming for large datasets
  7. Versioning: Version your server and tools

Debugging

Enable debug logging:

PluginMCPServer.configure({
  serverName: 'my-crm',
  debug: true, // Log all MCP messages
});

View MCP messages in client:

  • Claude Desktop: Check logs in ~/Library/Logs/Claude/mcp*.log
  • Cursor: Check Output panel → MCP Server
  • Cline: Check extension logs

Example: Complete CRM Server

import { defineStack, defineTool } from '@objectstack/spec';
import { PluginMCPServer } from '@objectstack/plugin-mcp-server';

const stack = defineStack({
  driver: /* ... */,
  plugins: [
    PluginMCPServer.configure({
      serverName: 'crm-assistant',
      autoRegisterTools: true,
    }),
  ],
});

await stack.boot();

const mcp = stack.kernel.getService('mcp');

// Register custom tools
mcp.registerTool(defineTool({
  name: 'forecast_revenue',
  description: 'Forecast revenue based on pipeline',
  async execute() {
    // Implementation
  },
}));

// Register custom resources
mcp.registerResource({
  uri: 'objectstack://dashboards/sales',
  name: 'Sales Dashboard',
  async read() {
    // Implementation
  },
});

// Register prompts
mcp.registerPrompt({
  name: 'weekly_report',
  description: 'Generate weekly sales report',
  async render() {
    // Implementation
  },
});

License

Apache-2.0. See LICENSING.md.

See Also