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

@iflow-mcp/mastra-ai-mcp-server-workshop-best-practices

v1.0.0

Published

Workshop demonstrating Customer Analytics MCP server with multi-system workflows using Mastra

Readme

Mastra MCP Workshop: Best Practices

A hands-on workshop demonstrating MCP (Model Context Protocol) best practices using Mastra. Build a "Customer Analytics" MCP server that showcases workflow-oriented tools, authentication patterns, and multi-system integration.

🎯 Workshop Goals

  • Minimize surface area: 2 tools that handle many use cases
  • Workflow-shaped tools: Capabilities (explore schema, run queries) vs endpoints (getUsers)
  • Model compatibility: Test with multiple models, ensure consistent behavior
  • Exploration: Let AI discover capabilities through resources
  • Guardrails: Safe, deterministic, read-only by default

🏗️ What We'll Build

Customer Analytics MCP Server featuring:

  • 📊 2 Tools: compute_account_health (multi-system workflow), run_sql (database queries)
  • 📚 1 Resource: schema://main (discovery & exploration)
  • 🔄 Workflow Patterns: External API integration, data fusion, scoring algorithms
  • 🛡️ Built-in Safety: SELECT-only, implicit LIMIT, parsed queries, API rate limits
  • 🔐 Authentication: Transparent role-based access control (admin/user/readonly)

🚀 Quick Start

Prerequisites

# Required
node >= 20.9.0
pnpm >= 8.0.0

# Optional: OpenAI API key for demo
export OPENAI_API_KEY="your-key-here"

Installation

# Clone and install
git clone <this-repo>
cd mcp-server-workshop-best-practices
pnpm install
# Terminal 1: Start HTTP MCP server with real auth
pnpm mcp-http-server

# Terminal 2: Run HTTP workshop demo
pnpm workshop-demo-http

# Server runs on http://localhost:3001 with endpoints:
# - /mcp (MCP endpoint with auth)
# - /health (health check)

🛠️ Technical Deep Dive

MCP Server Implementation

// src/mastra/mcp/server.ts
import { MCPServer } from "@mastra/mcp";
import { computeAccountHealthTool, runSqlTool } from "../tools";

const server = new MCPServer({
  name: "customer-analytics",
  version: "0.5.0",
  description: "Customer analytics MCP server with multi-system workflows",
  tools: {
    compute_account_health: computeAccountHealthTool,
    run_sql: runSqlTool,
  },
  resources: resourceHandlers,
});

Key Features:

  • Multi-system workflows: compute_account_health combines database, external APIs, and business logic
  • Resource-based discovery: Schema exploration via schema://main resource
  • Transparent authentication: MCP-compliant auth context passed to tools
  • Role-based access: admin/user/readonly permissions enforced per tool call
  • Guardrails built-in: SELECT-only, auto-LIMIT, permission checking
  • Error teaching: Structured, helpful error messages

Mastra Integration

// src/workshop-demo.ts
import { MCPClient } from "@mastra/mcp";
import { Agent } from "@mastra/core/agent";

const mcpClient = new MCPClient({
  servers: {
    customerAnalytics: {
      command: "pnpm",
      args: ["mcp-server"],
      env: { DEMO_API_KEY: "api_key_user_456" }, // Auth context
    },
  },
});

const agent = new Agent({
  name: "Customer Analytics Agent",
  model: openai("gpt-4o-mini"),
});

// Use MCP tools with agent
const response = await agent.generate(task, {
  toolsets: await mcpClient.getToolsets(),
});

HTTP Authentication (Production Pattern)

The workshop includes a production-ready HTTP server with real authentication:

// src/mastra/mcp/http-server.ts
import { MCPServer } from "@mastra/mcp";
import { server } from "./server";
import type { AuthInfo, DemoUserInfo } from "./utils";

// Authentication middleware
function authenticateRequest(req: http.IncomingMessage): AuthInfo | null {
  const authHeader = req.headers.authorization;

  // Support JWT Bearer tokens
  if (authHeader?.startsWith("Bearer ")) {
    return validateJWT(authHeader.slice(7));
  }

  // Support API keys
  if (authHeader?.startsWith("ApiKey ")) {
    return validateApiKey(authHeader.slice(7));
  }

  return null;
}

// HTTP request handler with MCP-compliant auth
const handleRequest = async (req, res) => {
  const authInfo = authenticateRequest(req);

  if (!authInfo) {
    res.writeHead(401, { "Content-Type": "application/json" });
    res.end(
      JSON.stringify({
        error: "Authentication required",
        message: "Please provide a valid Authorization header",
      }),
    );
    return;
  }

  // Attach MCP-compliant auth to request
  (req as any).auth = authInfo;

  await server.startHTTP({
    url: new URL(`http://localhost:${PORT}`),
    httpPath: "/mcp",
    req,
    res,
  });
};

Key Features:

  • JWT & API Key Support: Multiple authentication methods
  • MCP-Compliant Auth: Uses official AuthInfo type from MCP specification
  • Real Auth Context: Authentication info passed to tools via options.extra.authInfo
  • Session Management: Unique session IDs for each connection
  • CORS Support: Web client compatibility
  • Structured Errors: Clear auth failure responses

Test Credentials:

# Health check (no auth required)
curl localhost:3001/health

# MCP endpoint (requires auth)
curl -H "Authorization: ApiKey sk-user-987654321" \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \
     localhost:3001/mcp

# Available credentials:
# API Keys: sk-admin-123456789, sk-user-987654321, sk-readonly-555666777
# JWT Tokens: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.admin, eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.user

🛠️ Tools Overview

1. compute_account_health - Multi-System Workflow

Purpose: Demonstrates complex workflow patterns that combine multiple data sources for business insights.

Data Flow:

Internal DB (orders) → External NPS API → External Support API → Risk Scoring → Actionable Insights

Key Features:

  • Multi-source data fusion: Order history + NPS scores + support tickets
  • Business logic: Configurable scoring weights (recency 30%, momentum 30%, satisfaction 25%, reliability 15%)
  • Segmentation: Filter by customer value, activity patterns, risk levels
  • External API simulation: Realistic delays, missing data, enterprise customer patterns
  • Role-based limits: Readonly users limited to 10 accounts

Input Parameters:

  • segment: "all" | "inactive" | "highValue"
  • windowDays: Analysis period (default 90 days)
  • limit: Maximum accounts to analyze (default 50)
  • includeReasons: Include risk factor explanations

Output Structure:

{
  "accounts": [
    {
      "accountId": "1",
      "name": "Alice Johnson",
      "healthScore": 85,
      "tier": "good",
      "metrics": { "lastOrderDays": 5, "spendDeltaPct": 15.2, "nps": 72 },
      "reasons": []
    }
  ],
  "summary": {
    "totalAnalyzed": 20,
    "segmentBreakdown": { "good": 15, "watch": 3, "at_risk": 2 },
    "avgHealthScore": 75,
    "externalDataCoverage": { "npsAvailable": 18, "supportDataAvailable": 20 }
  }
}

2. run_sql - Database Query Tool

Purpose: Safe, controlled database access with automatic guardrails.

Key Features:

  • SELECT-only validation
  • Automatic LIMIT injection
  • Role-based row limiting
  • Permission checking based on query content

🧪 Testing & Validation

Model Compatibility Test

Run the same task with multiple models:

Task: "Analyze customer health for high-value accounts and show database schema"

Expected flow:
1. Schema resource → understand available data structure
2. compute_account_health → multi-system customer analysis
3. run_sql → supplementary database queries if needed
4. Valid JSON response with insights and recommendations

Testing Matrix:

  • ✅ Right tool chosen? (compute_account_health for analysis, run_sql for queries)
  • ✅ Args valid? (proper segment filtering, reasonable limits)
  • ✅ Result shape? (structured health scores, actionable insights)
  • ✅ Authentication? (role-based access control working)

Demo Workflows

  1. Schema Exploration: "What data is available?" (via schema resource)
  2. Customer Health Analysis: "Show me at-risk customers" (compute_account_health)
  3. Database Queries: "Show me recent high-value orders" (run_sql)
  4. Multi-system Integration: "Combine order data with support tickets" (workflow tool)
  5. Guardrails Test: "Try to delete users" (safely fails with helpful error)
  6. Authentication Test: Different access levels (admin/user/readonly)

📊 Best Practices Demonstrated

✅ Tool Design

  • Capability-oriented: run_sql (workflow) vs getUserById (endpoint)
  • Self-documenting: Descriptions include examples
  • Composable: One general tool > many specific ones

✅ Safety & Reliability

  • Read-only default: Only SELECT operations allowed
  • Implicit limits: Auto-add LIMIT clauses
  • Structured errors: "Only SELECT queries allowed" (teaches the model)

✅ Model Compatibility

  • Cross-model testing: GPT-4, GPT-3.5, etc.
  • Consistent behavior: Same tools, same args, same output shape
  • Graceful degradation: Weaker models still succeed

✅ Exploration & Discovery

  • Resource-driven: Schema exposed via MCP resources
  • Progressive disclosure: Start simple, add complexity
  • Documentation: Examples and usage notes included

🎮 Try It Yourself

Extend the Demo

Add a third tool to show workflow composition:

const cityReportTool = createTool({
  id: "make_city_report",
  description: "Generate a comprehensive city analysis report",
  execute: async ({ context }) => {
    // Internally runs 2-3 SQL queries
    // Returns: { city, userCount, totalSpend, avgOrderValue }[]
  },
});

Connect to Your Own Database

Replace the in-memory data with real database connections:

// Update src/mcp-server/server.ts
import Database from "better-sqlite3";
const db = new Database("path/to/your/database.db");

// or with PostgreSQL
import postgres from "postgres";
const sql = postgres("postgresql://...");

// Update executeQuery function to use real SQL

Test with More Models

Add models to the compatibility test:

// src/workshop-demo.ts
const MODELS_TO_TEST = [
  { name: "GPT-4o Mini", model: openai("gpt-4o-mini") },
  { name: "GPT-4o", model: openai("gpt-4o") },
  { name: "Claude Sonnet", model: anthropic("claude-3-sonnet-20240229") },
  // Add your preferred models
];

🎯 Key Takeaways

  1. Tools are workflows, not APIs - Design for capabilities
  2. Fewer is better - 2 general tools > 10 specific ones
  3. Safety first - Guardrails built into every tool
  4. Test compatibility - Multiple models, same behavior
  5. Enable exploration - Resources help discovery

📚 Resources

🤝 Contributing

Found an issue or want to improve the workshop?

  • Report bugs via GitHub issues
  • Submit improvements via pull requests
  • Share your workshop experiences

Built with ❤️ using Mastra - The TypeScript AI Framework