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

@nabyltmt/teachmeto-mcp

v1.0.8

Published

Model Context Protocol server for TeachMeTo API - Access 76+ TeachMeTo tools via MCP

Readme

TeachMeTo MCP Full-Stack Application

A comprehensive three-tier application featuring Claude AI with full TeachMeTo platform integration:

  • MCP Server: TeachMeTo API integration with OAuth 2.1 authentication (103 tools, 76 enabled by default)
  • FastAPI Backend: Claude Sonnet 4 + MCP integration with LangSmith tracing
  • Next.js Frontend: React chat interface with TeachMeTo phone/OTP authentication

Architecture Overview

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Frontend      │    │    Backend      │    │   MCP Server    │
│   (Next.js)     │    │   (FastAPI)     │    │   (Node.js)     │
├─────────────────┤    ├─────────────────┤    ├─────────────────┤
│ • React Chat UI │    │ • Claude Sonnet │    │ • OAuth 2.1     │
│ • Phone/OTP Auth│◄──►│ • HTTP MCP      │◄──►│ • Token Service │
│ • JWT Storage   │    │ • LangSmith     │    │ • 103 API Tools │
│ • TailwindCSS   │    │ • FastAPI       │    │ • Registry      │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Key Features

MCP Server (Node.js/TypeScript)

  • 103 TeachMeTo API Tools across 10 categories (76 enabled by default, 3 disabled for security)
  • Registry-Based Architecture - Auto-discovery and registration with definitive operation type mapping
  • OAuth 2.1 Authentication - Full MCP specification compliance
  • User Delegation - Phone/OTP authentication with JWT tokens
  • Rate Limiting - Configurable per-minute and burst limits
  • Type-Safe - Full TypeScript with strict mode

Backend (Python/FastAPI)

  • Claude Sonnet 4 - Latest AI model integration
  • HTTP MCP Client - Direct communication with MCP server
  • LangSmith Tracing - Full observability and debugging
  • JWT Authentication - User-level permissions
  • Conversation Memory - Track JWT across tool calls

Frontend (Next.js/React)

  • Phone/OTP Authentication - Seamless TeachMeTo login
  • Real-time Chat - Streaming responses from Claude
  • State Management - Zustand for auth and conversation state
  • Responsive Design - Mobile-first with Tailwind CSS

Authentication Flow

The application implements a complete authentication flow from frontend through to the TeachMeTo API:

┌─────────────┐
│   User      │
└──────┬──────┘
       │ 1. Enters phone number
       ▼
┌─────────────────────┐
│   Frontend (Next)   │
│   ┌───────────────┐ │
│   │ AuthForm.tsx  │ │  2. POST /auth/request-otp
│   └───────┬───────┘ │       {phoneNumber: "+1..."}
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│   Backend (FastAPI) │  3. Forward to MCP Server
│   ┌───────────────┐ │     POST /tools/request_otp
│   │ main.py       │ │
│   └───────┬───────┘ │
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│   MCP Server        │  4. Call TeachMeTo API
│   ┌───────────────┐ │     POST /auth/request-otp
│   │ auth.ts       │ │
│   └───────┬───────┘ │
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│  TeachMeTo API      │  5. Send SMS with OTP
│  ┌───────────────┐  │
│  │ Send SMS      │  │
│  └───────────────┘  │
└─────────────────────┘

User receives OTP: "366002"

┌─────────────┐
│   User      │
└──────┬──────┘
       │ 6. Enters OTP code
       ▼
┌─────────────────────┐
│   Frontend          │  7. POST /auth/verify-otp
│   ┌───────────────┐ │     {phoneNumber, OTP: "366002"}
│   │ AuthForm      │ │
│   └───────┬───────┘ │
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│   Backend           │  8. Forward to MCP
│   ┌───────────────┐ │     POST /tools/verify_otp
│   │ claude_service│ │
│   └───────┬───────┘ │
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│   MCP Server        │  9. Verify with TeachMeTo
│   ┌───────────────┐ │     POST /auth/verify-otp
│   │ auth.ts       │ │
│   └───────┬───────┘ │     Returns JWT token
└───────────┼─────────┘
            │
            │ 10. JWT: "eyJhbGc..."
            ▼
┌─────────────────────┐
│   Backend           │  11. Store JWT for session
│   ┌───────────────┐ │      Extract from response
│   │ Conversation  │ │      Use for future calls
│   └───────┬───────┘ │
└───────────┼─────────┘
            │ 12. Return to Frontend
            ▼
┌─────────────────────┐
│   Frontend          │  13. Store JWT in state
│   ┌───────────────┐ │      User is authenticated
│   │ useAuthStore  │ │      Show chat interface
│   └───────────────┘ │
└─────────────────────┘

Subsequent Tool Calls:

┌─────────────┐
│   User      │  "Get my profile"
└──────┬──────┘
       ▼
┌─────────────────────┐
│   Frontend          │  POST /chat
│                     │  {message: "Get my profile"}
└──────┬──────────────┘
       ▼
┌─────────────────────┐
│   Backend           │  Claude decides: student_get_profile
│   ┌───────────────┐ │  POST /tools/student_get_profile
│   │ Claude+MCP    │ │  Header: Authorization: Bearer JWT
│   └───────┬───────┘ │
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│   MCP Server        │  Validate JWT token
│   ┌───────────────┐ │  Extract userId from JWT
│   │ Registry      │ │  Call TeachMeTo API
│   │ executeTool   │ │  GET /student/profile
│   └───────┬───────┘ │  Header: Authorization: Bearer JWT
└───────────┼─────────┘
            ▼
┌─────────────────────┐
│  TeachMeTo API      │  Verify JWT signature
│  ┌───────────────┐  │  Check user permissions
│  │ Profile Data  │  │  Return user profile
│  └───────┬───────┘  │
└───────────┼─────────┘
            │ {id, name, email, ...}
            ▼
       [Returns through chain back to User]

Key Points:

  • User Delegation: Users authenticate with their own phone/OTP
  • OAuth 2.1 Compliance: Full MCP specification-compliant authentication flow
  • Two-Tier Tokens:
    • TeachMeTo JWT: Long-lived (30 days) user identity token from TeachMeTo API
    • MCP Access Token: Short-lived (15 minutes) OAuth 2.1 token signed with RS256
  • Token Exchange: Backend exchanges TeachMeTo JWT for MCP access token per tool call
  • Embedded JWT Pattern: MCP tokens contain embedded TeachMeTo JWT for API calls
  • Bearer Authentication: All API calls use user's JWT (not admin keys)
  • RS256 Signing: 2048-bit RSA asymmetric key signing for MCP tokens
  • Stateless: No server-side token storage, all validation via signature verification
  • Automatic Tool Selection: Claude decides which tools to call based on user intent

OAuth 2.1 Authentication Details

The application implements full MCP specification-compliant OAuth 2.1 authentication:

Token Exchange Flow

┌──────────────────────────────────────────────────────────────┐
│                    Token Exchange Flow                        │
└──────────────────────────────────────────────────────────────┘

Backend Startup:
┌─────────────────────┐
│ Backend (FastAPI)   │  1. Register as OAuth client
│ HTTPMCPClient       │     POST /oauth/register
└──────────┬──────────┘     {client_name: "TeachMeTo Backend"}
           │
           ▼
┌─────────────────────┐
│   MCP Server        │  2. Return client credentials
│   OAuth Server      │     {client_id, client_secret}
└─────────────────────┘

Per Tool Call:
┌─────────────────────┐
│ Backend             │  3. Exchange TeachMeTo JWT
│ exchange_token()    │     POST /oauth/token
│                     │     {
│                     │       grant_type: "teachmeto_jwt",
│                     │       teachmeto_jwt: "eyJhbGc...",
│                     │       client_id: "...",
│                     │       client_secret: "...",
│                     │       resource: "teachmeto://api",
│                     │       scope: "tools:read tools:write"
│                     │     }
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│   MCP Server        │  4. Validate TeachMeTo JWT signature
│   Token Service     │     jwt.verify(teachmeto_jwt, PUBLIC_KEY)
│                     │
│                     │  5. Create MCP access token payload:
│                     │     {
│                     │       iss: "http://localhost:3001",
│                     │       sub: userId,
│                     │       aud: ["teachmeto://api"],
│                     │       client_id: "...",
│                     │       exp: now + 900,  // 15 minutes
│                     │       iat: now,
│                     │       embedded_jwt: "eyJhbGc...",
│                     │       scope: "tools:read tools:write",
│                     │       role: "student"
│                     │     }
│                     │
│                     │  6. Sign with RS256 private key
│                     │     jwt.sign(payload, PRIVATE_KEY, RS256)
└──────────┬──────────┘
           │
           │  7. Return MCP access token
           ▼
┌─────────────────────┐
│ Backend             │  8. Call tool with MCP token
│ call_tool()         │     POST /tools/student_get_profile
│                     │     Header: Authorization: Bearer <MCP_TOKEN>
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│   MCP Server        │  9. Validate MCP token signature
│   executeTool()     │     jwt.verify(mcp_token, PUBLIC_KEY)
│                     │
│                     │  10. Extract embedded TeachMeTo JWT
│                     │      Verify embedded JWT not expired
│                     │
│                     │  11. Call TeachMeTo API
│                     │      GET /student/profile
│                     │      Header: Authorization: Bearer <TEACHMETO_JWT>
└─────────────────────┘

Key Security Features

  1. RS256 Asymmetric Signing:

    • MCP server generates 2048-bit RSA key pair on startup
    • Private key signs MCP tokens
    • Public key verifies MCP tokens
    • No shared secrets between components
  2. Short-lived Tokens:

    • MCP access tokens expire in 15 minutes (OAuth 2.1 best practice)
    • TeachMeTo JWTs remain valid for 30 days
    • Backend exchanges tokens per tool call to maintain security
  3. Audience Binding (RFC 8707):

    • MCP tokens bound to resource teachmeto://api
    • Prevents token misuse across different resources
    • Validated on every tool call
  4. Embedded JWT Verification:

    • MCP token contains original TeachMeTo JWT
    • Both tokens validated on each request
    • TeachMeTo JWT used for actual API calls
    • If either token invalid/expired, request rejected
  5. OAuth 2.1 Compliance:

    • Dynamic client registration (RFC 7591)
    • Custom grant type teachmeto_jwt
    • Bearer token authorization
    • Proper error responses

Why This Architecture?

  • MCP Specification Compliance: Follows MCP authorization spec exactly
  • Security: Short-lived tokens limit exposure, RS256 prevents tampering
  • Scalability: Stateless JWTs, no server-side session storage
  • Flexibility: Supports multiple OAuth clients (future: mobile apps, CLI)
  • API Compatibility: TeachMeTo API receives familiar JWT tokens

MCP Server Architecture

The MCP server uses a registry-based architecture that eliminates complex routing logic:

Registry System

// src/registry/tool-registry.ts
export class ToolRegistry {
  private tools: Map<string, ToolMetadata> = new Map();

  // Register a module with all its tools
  registerModule(module: ToolModule): void {
    const tools = module.createTools();
    for (const tool of tools) {
      this.tools.set(tool.name, {
        tool,
        handler: module.handler,
        requiresAuth: module.requiresAuth,
        category: module.category
      });
    }
  }

  // Direct lookup - no pattern matching
  getTool(toolName: string): ToolMetadata | undefined {
    return this.tools.get(toolName);
  }
}

Tool Module Pattern

Each tool category exports a module with metadata:

// src/tools/users.ts
export const userToolModule: ToolModule = {
  createTools: createUserTools,  // Returns Tool[] definitions
  handler: handleUserTool,        // Actual implementation
  requiresAuth: true,             // Requires JWT authentication
  category: 'users'               // Category for filtering
};

Benefits

  1. No Routing Logic - Direct lookup by tool name
  2. Type-Safe - Full TypeScript inference
  3. Auto-Discovery - Modules self-register
  4. Easy Extension - Add new module to src/registry/modules.ts
  5. Category Filtering - Support for DISABLED_TOOLS and DISABLED_CATEGORIES
  6. Single Source of Truth - Tools in registry = tools exposed = tools executable

Tool Categories (103 total, 76 enabled by default)

  • Authentication (10 tools): request_otp, verify_otp, OAuth management (3 OAuth tools disabled by default)
  • Users (5 tools): Profile management for students and coaches (2 admin tools disabled by default)
  • Bookings (18 tools): Lesson booking, scheduling, reviews
  • Listings (7 tools): Search services by location, skill, rating
  • Locations (18 tools): City/venue services, geographic data
  • Payments (3 tools): Checkout, Stripe webhooks
  • Subscriptions (16 tools): FFL, conversions, interventions
  • Skills (3 tools): Skill lookup, badges
  • Students (17 tools): Student-specific operations (profile, lessons, home screen)
  • Admin (6 tools): System status, user enablement

Tool Filtering

The MCP server supports flexible tool filtering via environment variables for controlling which tools are available:

Environment Variables:

  • DISABLE_WRITE_OPERATIONS - When set to true, disables all write operations (POST, PUT, DELETE, PATCH endpoints). Read operations (GET) remain available. Perfect for production environments where you want to limit data modifications.
  • DISABLED_TOOLS - Comma-separated list of specific tool names to disable (e.g., create_booking,cancel_booking)
  • DISABLED_CATEGORIES - Comma-separated list of entire categories to disable (e.g., admin,analytics)

Operation Types: Each tool is tagged as either:

  • read - GET operations that only retrieve data (safe to run anytime)
  • write - POST/PUT/DELETE/PATCH operations that modify data (can be disabled with DISABLE_WRITE_OPERATIONS=true)

Examples:

# Conservative production setup - disable all writes
DISABLE_WRITE_OPERATIONS=true npm run dev

# Disable specific dangerous tools
DISABLED_TOOLS=cancel_booking,delete_user npm run dev

# Disable entire categories
DISABLED_CATEGORIES=admin,analytics npm run dev

# Combine multiple filters
DISABLE_WRITE_OPERATIONS=true DISABLED_CATEGORIES=admin npm run dev

Default Configuration: By default, the following tools are disabled for security:

  • google_auth_student - OAuth integration (requires additional setup)
  • google_auth_coach - OAuth integration (requires additional setup)
  • google_auth_existing - OAuth integration (requires additional setup)
  • list_users - Admin function (requires admin privileges)
  • get_user - Admin function (requires admin privileges)

This results in 76/79 tools enabled out of the box. All existing tools default to read operations for backward compatibility.

Quick Start

📦 npm Installation (Recommended for MCP Clients)

The easiest way to use the TeachMeTo MCP server with Claude Desktop, Cursor, or other MCP clients:

# Test without installation
npx @nabyltmt/teachmeto-mcp

# Or install globally
npm install -g @nabyltmt/teachmeto-mcp

Configuration for Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "teachmeto": {
      "command": "npx",
      "args": ["-y", "@nabyltmt/teachmeto-mcp"],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "-----BEGIN CERTIFICATE-----\\nMIIFeTCCA2GgAwIBAgIUfvXD0peT...\\n-----END CERTIFICATE-----",
        "LOG_LEVEL": "info",
        "RATE_LIMIT_RPM": "100",
        "RATE_LIMIT_BURST": "10"
      }
    }
  }
}

Important Notes:

  • Replace TEACHMETO_JWT_PUBLIC_KEY with your actual TeachMeTo JWT certificate
  • Use \\n (double backslash) for newlines in JSON configuration
  • Restart Claude Desktop after configuration changes
  • The -y flag auto-confirms npx prompts

Available Environment Variables:

| Variable | Required | Default | Description | |----------|----------|---------|-------------| | TEACHMETO_API_URL | ✅ Yes | - | TeachMeTo API base URL (https://api.teachme.to) | | TEACHMETO_JWT_PUBLIC_KEY | ✅ Yes | - | JWT verification certificate (X.509 format) | | LOG_LEVEL | No | info | Logging level: debug, info, warn, error | | RATE_LIMIT_RPM | No | 100 | Requests per minute limit | | RATE_LIMIT_BURST | No | 10 | Burst request limit (requests per second) | | PORT | No | 3001 | HTTP server port (for HTTP mode) | | NODE_ENV | No | development | Environment: development, production | | DISABLE_WRITE_OPERATIONS | No | false | Set to true to disable all write operations (POST/PUT/DELETE/PATCH) | | DISABLED_TOOLS | No | - | Comma-separated list of tool names to disable (e.g., cancel_booking,delete_user) | | DISABLED_CATEGORIES | No | - | Comma-separated list of categories to disable (e.g., admin,analytics) |

Tool Filtering Examples:

// Conservative production setup - read-only mode
{
  "env": {
    "TEACHMETO_API_URL": "https://api.teachme.to",
    "TEACHMETO_JWT_PUBLIC_KEY": "...",
    "DISABLE_WRITE_OPERATIONS": "true"
  }
}
// Disable specific tools
{
  "env": {
    "DISABLED_TOOLS": "cancel_booking,delete_user,admin_disable_user"
  }
}
// Disable entire categories
{
  "env": {
    "DISABLED_CATEGORIES": "admin,analytics"
  }
}

See .env.example for complete configuration reference.

For Cursor, Cline, Continue, and other MCP clients, see the MCP Client Configuration section below.

🚀 AWS Lambda Deployment (Production)

Current Production Deployments (us-west-1):

  • MCP Server: mcp_http_server Lambda function with Function URL
  • Backend API: mcp_demo_backend Lambda function with Function URL
  • Frontend: Deployed to Vercel

See CLAUDE.md for detailed deployment URLs and troubleshooting

Prerequisites for Lambda Deployment

# 1. Install AWS CLI v2
# macOS: brew install awscli
# or download from: https://aws.amazon.com/cli/

# 2. Install Docker Desktop (for backend deployment)
# Download from: https://www.docker.com/products/docker-desktop/

# 3. Configure AWS credentials
aws configure
# Enter your AWS Access Key ID, Secret Access Key, and region (us-west-1)

# 4. Create environment files
cp .env.example .env
cp backend/.env.example backend/.env

# 5. Set required environment variables in .env files
# See "Environment Configuration" section below

Unified Deployment (Recommended)

The easiest way to deploy both MCP Server and Backend is using the unified deployment script:

# Make script executable (first time only)
chmod +x deploy-all.sh

# Run unified deployment
./deploy-all.sh

# The script will prompt you with options:
# 1) MCP Server only
# 2) Backend only
# 3) Both (MCP Server + Backend) [default]

What the script does:

  • ✅ Checks prerequisites (Docker running, AWS CLI configured)
  • ✅ Builds and deploys MCP Server to Lambda (~52MB)
  • ✅ Builds and deploys Backend to Lambda using Docker (~17MB)
  • ✅ Automatically configures Backend with MCP Server URL
  • ✅ Tests both deployments (/health endpoints)
  • ✅ Displays deployment URLs and monitoring commands

Example output:

$ ./deploy-all.sh

========================================
TeachMeTo MCP - Full Deployment
========================================

✅ Docker is running
✅ AWS CLI found
✅ AWS credentials configured (Account: 771417188474)

What would you like to deploy?
1) MCP Server only
2) Backend only
3) Both (MCP Server + Backend)

Enter choice [1-3] (default: 3): 3

========================================
Deploying MCP Server to Lambda
========================================
[... MCP deployment logs ...]

========================================
Deploying Backend to Lambda
========================================
[... Backend deployment logs ...]

========================================
✅ Deployment Complete!
========================================

MCP Server URL:
  https://oqderrsqrzi6curhigxchsqotm0lxxwa.lambda-url.us-west-1.on.aws/

Backend URL:
  https://xxxxxx.lambda-url.us-west-1.on.aws/

📊 Monitoring Commands:

MCP Server Logs:
  aws logs tail /aws/lambda/mcp_http_server --follow --region us-west-1

Backend Logs:
  aws logs tail /aws/lambda/mcp_demo_backend --follow --region us-west-1

✅ All deployments successful!

Troubleshooting Unified Deployment:

  1. ResourceConflictException - Lambda update already in progress

    • Wait 2-3 minutes for previous update to complete
    • Run script again
  2. Missing ANTHROPIC_API_KEY - Backend deployment fails

    • Add ANTHROPIC_API_KEY=sk-ant-api03-your-key-here to backend/.env
    • Run script again
  3. Docker not running - Backend deployment fails

    • Start Docker Desktop
    • Run script again

Deploy MCP Server to Lambda (Individual)

# Deploy MCP Server
./scripts/deploy-mcp-lambda.sh

# The script will:
# 1. Build TypeScript to JavaScript
# 2. Create deployment package (~52MB with node_modules)
# 3. Update Lambda function code
# 4. Update handler to build/lambda-handler.handler
# 5. Test deployment (/health and /tools endpoints)
# 6. Save deployment info to mcp-deployment-info.json

# Verify deployment
curl <MCP_SERVER_URL>/health
curl <MCP_SERVER_URL>/tools | jq '.tools | length'
# Should return: 103

Deploy Backend to Lambda

# Deploy Backend (requires Docker)
./scripts/deploy-backend-lambda.sh

# The script will:
# 1. Build Docker image with AWS Lambda Python 3.11 base
# 2. Install dependencies with correct Linux architecture
# 3. Create deployment package (~17MB)
# 4. Update Lambda function code
# 5. Update environment variables (including MCP_SERVER_BASE_URL from mcp-deployment-info.json)
# 6. Test deployment (/health endpoint)
# 7. Save deployment info to backend-deployment-info.json

# Verify deployment
curl <BACKEND_URL>/health | jq
# Should return: {"status":"healthy","mcp_tools_available":103,"claude_model":"claude-sonnet-4-20250514"}

Environment Configuration

Root .env (for MCP Server):

TEACHMETO_API_URL=https://api.teachme.to
TEACHMETO_API_KEY=""
TEACHMETO_JWT_PUBLIC_KEY='-----BEGIN CERTIFICATE-----
MIIFeTCCA2GgAwIBAgIUfvXD0peT8ijEJj6jt9HLxSgBC58wDQYJKoZIhvcNAQEL
[Your TeachMeTo JWT public key certificate - contact TeachMeTo team]
-----END CERTIFICATE-----'

MCP_SERVER_BASE_URL=http://localhost:3001
LOG_LEVEL=info
RATE_LIMIT_RPM=100
RATE_LIMIT_BURST=10
PORT=3001
NODE_ENV=development

# Tool Filtering (optional)
DISABLE_WRITE_OPERATIONS=false          # Set to 'true' to disable all write operations (POST/PUT/DELETE/PATCH)
DISABLED_TOOLS=                         # Comma-separated list of tool names to disable (e.g., "create_booking,cancel_booking")
DISABLED_CATEGORIES=                    # Comma-separated list of categories to disable (e.g., "admin,analytics")

backend/.env (for Backend):

ANTHROPIC_API_KEY=sk-ant-api03-your-anthropic-key-here
CLAUDE_MODEL=claude-sonnet-4-20250514
MCP_SERVER_PATH=../build/index.js
MCP_SERVER_BASE_URL=http://localhost:3001
TEACHMETO_API_URL=https://api.teachme.to
TEACHMETO_JWT_PUBLIC_KEY='-----BEGIN CERTIFICATE-----
[MUST be identical to MCP server certificate]
-----END CERTIFICATE-----'

SECRET_KEY=your_secret_key_here
CORS_ORIGINS=http://localhost:3000,http://localhost:3001
DEBUG=true
MAX_TOOL_ITERATIONS=20

# LangSmith Configuration (optional)
LANGCHAIN_TRACING_V2="true"
LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
LANGCHAIN_API_KEY="your_langsmith_key_here"
LANGCHAIN_PROJECT="mcp-demo"

Critical Requirements:

  • TEACHMETO_JWT_PUBLIC_KEY must be identical in both .env files
  • Must include -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- headers
  • In Lambda, environment variables have escaped newlines (\\n) which are automatically converted by the code

Troubleshooting Lambda Deployment

JWT Authentication Failures:

  • Symptom: "Unknown tool" or "Authentication required" errors
  • Cause: JWT public key mismatch or incorrect format
  • Solution:
    # 1. Verify both Lambda functions have identical JWT keys
    aws lambda get-function-configuration --function-name mcp_http_server --region us-west-1 --query 'Environment.Variables.TEACHMETO_JWT_PUBLIC_KEY'
    aws lambda get-function-configuration --function-name mcp_demo_backend --region us-west-1 --query 'Environment.Variables.TEACHMETO_JWT_PUBLIC_KEY'
    
    # 2. Check MCP server logs for JWT errors
    aws logs tail /aws/lambda/mcp_http_server --follow --region us-west-1 | grep JWT

Handler Path Issues:

  • Symptom: "Cannot find module 'lambda-handler'"
  • Cause: Lambda handler not set to build/lambda-handler.handler
  • Solution:
    aws lambda update-function-configuration \
      --function-name mcp_http_server \
      --handler build/lambda-handler.handler \
      --region us-west-1

Registry Not Initialized:

  • Symptom: "Unknown tool: student_get_profile"
  • Cause: Old code without registry deployed
  • Solution: Rebuild and redeploy with ./scripts/deploy-mcp-lambda.sh

Docker Issues (Backend):

# Check if Docker is running
docker ps

# Start Docker if not running (macOS)
open /Applications/Docker.app

# Test Docker with Lambda base image
docker run --rm public.ecr.aws/lambda/python:3.11 python --version

Monitoring Deployments:

# Monitor MCP Server logs
aws logs tail /aws/lambda/mcp_http_server --follow --region us-west-1

# Monitor Backend logs
aws logs tail /aws/lambda/mcp_demo_backend --follow --region us-west-1

# Check function status
aws lambda get-function --function-name mcp_http_server --region us-west-1
aws lambda get-function --function-name mcp_demo_backend --region us-west-1

🏠 Local Development Setup

1. Prerequisites

  • Node.js 18+
  • Python 3.11+ (for backend)
  • Poetry (Python package manager)
  • TeachMeTo API credentials
  • Claude API key (Anthropic)
  • LangSmith API key (optional, for tracing)

2. Setup MCP Server

# Install dependencies
npm install

# Configure environment
cp .env.example .env
# Edit .env with your TeachMeTo credentials

# Build MCP server
npm run build

# Start MCP HTTP server (recommended for development)
npm run dev

# Or use the HTTP server for testing
node build/http-server.js

# Test locally
curl http://localhost:3001/health
curl http://localhost:3001/tools | jq '.tools | length'

3. Setup Backend

cd backend

# Install dependencies with Poetry
poetry install

# Configure environment
cp .env.example .env
# Edit backend/.env with your API keys

# Start backend server
./start-server.sh

# Or manually:
poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

# Test locally
curl http://localhost:8000/health

4. Setup Frontend (Optional)

cd frontend

# Install dependencies
npm install

# Configure environment
cp .env.local.example .env.local
# Edit .env.local with backend URL

# Start development server
npm run dev

# Open browser
open http://localhost:3000

Development Commands

MCP Server (Root)

  • npm run build - Compile TypeScript to JavaScript
  • npm run dev - Run MCP server in HTTP mode for development
  • npm start - Start compiled MCP server (stdio mode)
  • npm test - Run Jest test suite
  • npm run type-check - TypeScript type checking
  • npm run lint - Run ESLint

Backend (FastAPI)

  • cd backend && ./start-server.sh - Start backend with auto-setup
  • poetry install - Install Python dependencies
  • poetry run uvicorn app.main:app --reload - Start with hot reload
  • curl http://localhost:8000/health - Health check

Frontend (Next.js)

  • cd frontend && npm run dev - Start development server
  • npm run build - Build for production
  • npm run lint - ESLint check

API Endpoints

MCP Server (Port 3001)

Core Endpoints

  • GET /health - Health check with tool count
  • GET /tools - List all available MCP tools
  • POST /tools/{tool_name} - Execute a specific tool
    • Header: Authorization: Bearer <MCP_ACCESS_TOKEN> (for authenticated tools)
    • Body: Tool-specific parameters

OAuth 2.1 Endpoints

  • GET /.well-known/oauth-authorization-server - OAuth metadata discovery
  • POST /oauth/register - Register OAuth client (RFC 7591)
    • Body: {client_name, redirect_uris, grant_types, response_types}
    • Returns: {client_id, client_secret, client_id_issued_at}
  • POST /oauth/token - Token exchange endpoint
    • Body: {grant_type: "teachmeto_jwt", teachmeto_jwt, client_id, client_secret, resource, scope}
    • Returns: {access_token, token_type: "Bearer", expires_in: 900, scope, resource}

Backend (Port 8000)

  • GET /health - Health check with MCP connection status
  • POST /auth/request-otp - Request OTP for phone number
  • POST /auth/verify-otp - Verify OTP and get JWT token
  • POST /chat - Send message to Claude with full tool access
  • GET /tools - List all available MCP tools

Testing

Test MCP Server

# Test health endpoint
curl http://localhost:3001/health

# Test tool listing
curl http://localhost:3001/tools | jq '.tools | length'

# Test OAuth metadata discovery
curl http://localhost:3001/.well-known/oauth-authorization-server | jq

# Test OAuth client registration
curl -X POST http://localhost:3001/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Test Client",
    "grant_types": ["teachmeto_jwt"],
    "response_types": ["code"]
  }' | jq

# Test request_otp (no auth required)
curl -X POST http://localhost:3001/tools/request_otp \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber": "+1234567890"}'

# Test token exchange (requires TeachMeTo JWT)
curl -X POST http://localhost:3001/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "teachmeto_jwt",
    "teachmeto_jwt": "YOUR_TEACHMETO_JWT",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "resource": "teachmeto://api",
    "scope": "tools:read tools:write"
  }' | jq

# Test student_get_profile (requires MCP access token)
curl -X POST http://localhost:3001/tools/student_get_profile \
  -H "Authorization: Bearer YOUR_MCP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

Test Backend

# Test health endpoint
curl http://localhost:8000/health | jq

# Test OTP request
curl -X POST http://localhost:8000/auth/request-otp \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber": "+1234567890"}' | jq

# Test chat endpoint (after authentication)
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Get my profile"}' | jq

Project Structure

tmt-api-mcp/
├── src/                          # MCP Server source (TypeScript)
│   ├── core/                     # Core MCP server logic
│   │   └── mcp-server.ts        # Main MCP Core with registry
│   ├── registry/                 # Registry-based architecture
│   │   ├── tool-registry.ts     # Tool registry class
│   │   └── modules.ts           # All tool modules list
│   ├── tools/                    # Tool implementations
│   │   ├── auth.ts              # Authentication (10 tools)
│   │   ├── users.ts             # User management (5 tools)
│   │   ├── bookings.ts          # Booking operations (18 tools)
│   │   ├── listings.ts          # Listing search (3 tools)
│   │   ├── locations.ts         # Location services (10 tools)
│   │   ├── payments.ts          # Payment processing (3 tools)
│   │   ├── subscriptions.ts     # Subscription management (16 tools)
│   │   ├── skills.ts            # Skills (3 tools)
│   │   ├── admin.ts             # Admin functions (2 tools)
│   │   └── analytics.ts         # Analytics (10 tools)
│   ├── services/                 # Core services
│   │   ├── api-client.ts        # TeachMeTo API client
│   │   ├── auth.ts              # Authentication service
│   │   ├── token-service.ts     # MCP token management
│   │   └── mcp-auth-server.ts   # OAuth 2.1 server
│   ├── types/                    # TypeScript type definitions
│   ├── utils/                    # Utility functions
│   ├── index.ts                  # stdio MCP server entry
│   ├── http-server.ts            # HTTP MCP server entry
│   └── lambda-handler.ts         # AWS Lambda handler
├── backend/                      # FastAPI Backend (Python)
│   ├── app/
│   │   ├── main.py              # FastAPI app with endpoints
│   │   ├── claude_service.py    # Claude + MCP integration
│   │   ├── http_mcp_client.py   # HTTP MCP client
│   │   ├── models.py            # Pydantic models
│   │   └── config.py            # Settings
│   ├── lambda_handler.py         # AWS Lambda handler (Mangum)
│   └── scripts/
│       └── deploy-lambda.sh     # Backend deployment script
├── frontend/                     # Next.js Frontend (React)
│   ├── src/
│   │   ├── app/                 # Next.js app directory
│   │   ├── components/          # React components
│   │   └── lib/                 # Utilities and state
│   └── package.json
├── scripts/
│   ├── deploy-mcp-lambda.sh     # MCP deployment script
│   └── deploy-backend-lambda.sh # Backend deployment script
├── .env                          # MCP Server environment
├── backend/.env                  # Backend environment
└── README.md                     # This file

MCP Client Configuration

The TeachMeTo MCP server can be integrated with any MCP-compatible client. Below are configuration instructions for popular clients.

Claude Code (Desktop App)

Claude Code supports MCP servers via claude_desktop_config.json:

Location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Configuration:

{
  "mcpServers": {
    "teachmeto": {
      "command": "node",
      "args": [
        "/absolute/path/to/tmt-api-mcp/build/index.js"
      ],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "-----BEGIN CERTIFICATE-----\nMIIFeTCCA2GgAwIBAgIUfvXD0peT...\n-----END CERTIFICATE-----",
        "LOG_LEVEL": "info",
        "RATE_LIMIT_RPM": "100",
        "RATE_LIMIT_BURST": "10"
      }
    }
  }
}

Important:

  1. Replace /absolute/path/to/tmt-api-mcp with your actual project path
  2. Ensure the project is built: npm run build
  3. Replace TEACHMETO_JWT_PUBLIC_KEY with your actual certificate (newlines as \n)
  4. Restart Claude Desktop after configuration changes

Verification:

  • Open Claude Desktop
  • Look for "MCP" indicator in the UI
  • Type: "List available TeachMeTo tools"
  • Should see 76 tools (or 79 if you enabled all tools)

Cursor IDE

Cursor supports MCP servers via .cursor/mcp.json in your project directory:

Location: your-project/.cursor/mcp.json

Configuration:

{
  "mcpServers": {
    "teachmeto": {
      "command": "node",
      "args": [
        "/absolute/path/to/tmt-api-mcp/build/index.js"
      ],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "-----BEGIN CERTIFICATE-----\nMIIFeTCCA2GgAwIBAgIUfvXD0peT...\n-----END CERTIFICATE-----",
        "LOG_LEVEL": "info"
      }
    }
  }
}

Important:

  1. Create .cursor directory in your project root if it doesn't exist
  2. Use absolute paths for the MCP server
  3. Build the project first: npm run build
  4. Restart Cursor after configuration changes

Verification:

  • Open Cursor
  • Use the AI chat feature
  • Type: "Use TeachMeTo MCP to get my profile"
  • Should see MCP tools being called

Cline (VS Code Extension)

Cline (formerly Claude Dev) supports MCP servers via VS Code settings:

Location: .vscode/settings.json in your project directory

Configuration:

{
  "cline.mcpServers": {
    "teachmeto": {
      "command": "node",
      "args": [
        "/absolute/path/to/tmt-api-mcp/build/index.js"
      ],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "-----BEGIN CERTIFICATE-----\nMIIFeTCCA2GgAwIBAgIUfvXD0peT...\n-----END CERTIFICATE-----",
        "LOG_LEVEL": "info"
      }
    }
  }
}

Important:

  1. Install the Cline extension from VS Code marketplace
  2. Build the MCP server: npm run build
  3. Reload VS Code window after configuration changes

Verification:

  • Open Command Palette (Cmd+Shift+P / Ctrl+Shift+P)
  • Run "Cline: Start New Task"
  • Ask: "Show me TeachMeTo tools"

Continue (VS Code Extension)

Continue supports MCP servers via ~/.continue/config.json:

Location: ~/.continue/config.json

Configuration:

{
  "mcpServers": [
    {
      "name": "teachmeto",
      "command": "node",
      "args": [
        "/absolute/path/to/tmt-api-mcp/build/index.js"
      ],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "-----BEGIN CERTIFICATE-----\nMIIFeTCCA2GgAwIBAgIUfvXD0peT...\n-----END CERTIFICATE-----",
        "LOG_LEVEL": "info"
      }
    }
  ]
}

Verification:

  • Open Continue panel in VS Code
  • Ask: "What TeachMeTo tools are available?"

HTTP Mode (Any MCP Client)

For clients that support HTTP-based MCP servers, you can run the server in HTTP mode:

Start HTTP Server:

# Development mode
npm run dev

# Production mode
node build/http-server.js

# Custom port
PORT=3001 node build/http-server.js

Client Configuration:

{
  "mcpServers": {
    "teachmeto": {
      "url": "http://localhost:3001",
      "transport": "http"
    }
  }
}

Available HTTP Endpoints:

  • GET /health - Health check
  • GET /tools - List all tools
  • POST /tools/{tool_name} - Execute tool
  • GET /.well-known/oauth-authorization-server - OAuth metadata
  • POST /oauth/register - Register OAuth client
  • POST /oauth/token - Token exchange

AWS Lambda Mode (Production)

For production deployments, use the deployed Lambda Function URL:

Client Configuration:

{
  "mcpServers": {
    "teachmeto": {
      "url": "https://your-function-url.lambda-url.us-west-1.on.aws",
      "transport": "http"
    }
  }
}

Important:

  • Lambda Function URL is public - ensure proper authentication
  • All tools requiring authentication need valid JWT tokens
  • See "AWS Lambda Deployment" section for deployment instructions

Environment Variables Reference

All MCP client configurations support these environment variables:

| Variable | Required | Default | Description | |----------|----------|---------|-------------| | TEACHMETO_API_URL | Yes | - | TeachMeTo API base URL | | TEACHMETO_JWT_PUBLIC_KEY | Yes | - | JWT verification certificate | | LOG_LEVEL | No | info | Logging level (debug, info, warn, error) | | RATE_LIMIT_RPM | No | 100 | Requests per minute limit | | RATE_LIMIT_BURST | No | 10 | Burst request limit | | DISABLE_WRITE_OPERATIONS | No | false | Disable all write operations | | DISABLED_TOOLS | No | - | Comma-separated list of tools to disable | | DISABLED_CATEGORIES | No | - | Comma-separated list of categories to disable |

Tool Filtering Examples

Conservative Production Setup:

{
  "mcpServers": {
    "teachmeto": {
      "command": "node",
      "args": ["/path/to/build/index.js"],
      "env": {
        "TEACHMETO_API_URL": "https://api.teachme.to",
        "TEACHMETO_JWT_PUBLIC_KEY": "...",
        "DISABLE_WRITE_OPERATIONS": "true"
      }
    }
  }
}

Disable Specific Tools:

{
  "env": {
    "DISABLED_TOOLS": "cancel_booking,delete_user,admin_disable_user"
  }
}

Disable Entire Categories:

{
  "env": {
    "DISABLED_CATEGORIES": "admin,analytics"
  }
}

Troubleshooting MCP Client Configuration

"Command not found" or "Cannot find module"

  • Ensure you've run npm run build to compile TypeScript
  • Use absolute paths in command and args
  • Verify Node.js is in your PATH: which node

"Authentication failed" or "Invalid JWT"

  • Verify TEACHMETO_JWT_PUBLIC_KEY is correctly formatted
  • Ensure certificate includes -----BEGIN CERTIFICATE----- headers
  • Check newlines are properly escaped as \n in JSON

"No tools available" or tool count mismatch

  • Check MCP server logs for registry initialization
  • Verify environment variables are loaded correctly
  • Test directly: curl http://localhost:3001/tools | jq '.tools | length'

"Rate limit exceeded"

  • Increase RATE_LIMIT_RPM and RATE_LIMIT_BURST values
  • Check for infinite loops in client configuration
  • Monitor MCP server logs: LOG_LEVEL=debug npm run dev

"Connection refused"

  • Verify MCP server is running: curl http://localhost:3001/health
  • Check port is not blocked by firewall
  • Ensure correct URL/port in client configuration

MCP Inspector (Debugging)

For debugging MCP server integration, use the MCP Inspector:

# Install MCP Inspector globally (one time)
npm install -g @modelcontextprotocol/inspector

# Run with your MCP server
npx @modelcontextprotocol/inspector node build/index.js

# Or in HTTP mode
npm run mcp:inspect

The inspector provides:

  • Interactive tool testing
  • Request/response inspection
  • Authentication flow debugging
  • OAuth 2.1 flow visualization

Inspector URL: Opens automatically in browser at http://localhost:5173

Additional Resources