Skip to main content
Every MentraOS app extends the AppServer class. It handles webhooks, manages WebSocket connections, and routes sessions to your code.

Basic Setup

import { AppServer, AppSession } from '@mentraos/sdk';

class MyApp extends AppServer {
  protected async onSession(session: AppSession, sessionId: string, userId: string) {
    // Your app logic goes here
  }
}

What AppServer Does

ResponsibilityDetails
HTTP ServerListens for webhooks from MentraOS Cloud
WebSocket ClientMaintains connection to MentraOS Cloud
Session ManagerCreates AppSession for each user connection
Lifecycle HandlerCalls onSession() and onStop() at appropriate times

Configuration

const server = new MyApp({
  packageName: 'com.example.myapp',    // From developer console
  apiKey: process.env.API_KEY,          // From developer console
  port: 3000,                            // Your server port
  webhookPath: '/webhook',               // Optional, defaults to '/webhook'
  mentraOSWebsocketUrl: 'wss://...'     // Optional, defaults to production
});

Required Settings

Unique identifier for your app.
  • Format: Reverse domain notation (e.g., com.company.appname)
  • Set in Developer Console
  • Used to route sessions to your app
Secret key for authentication.
  • Generated in Developer Console
  • Authenticates your server with MentraOS Cloud
  • Store in environment variables, never hardcode
apiKey: process.env.MENTRAOS_API_KEY  // ✅ Good
apiKey: 'sk_live_abc123...'           // ❌ Never do this
HTTP port for webhook server.
  • Your server listens on this port
  • MentraOS Cloud sends webhooks here
  • Must be accessible from the internet (production)

Getting Credentials

  1. Go to Developer Console
  2. Create or select your app
  3. Package Name: Set during app creation (e.g., com.example.myapp)
  4. API Key: Click “Generate API Key” or copy existing key
Keep your API key secret! Anyone with your API key can impersonate your app.

Starting Your Server

// Create server instance
const server = new MyApp({
  packageName: 'com.example.myapp',
  apiKey: process.env.API_KEY,
  port: 3000
});

// Start listening
server.start();
console.log('Server running on port 3000');
The server now:
  • Listens for webhooks on http://localhost:3000/webhook
  • Connects to MentraOS Cloud via WebSocket
  • Waits for users to start your app

Multiple Users

AppServer handles many users simultaneously. Each user gets their own AppSession:
class MyApp extends AppServer {
  private activeSessions = new Map<string, AppSession>();

  protected async onSession(session: AppSession, sessionId: string, userId: string) {
    // Each user gets their own session
    this.activeSessions.set(sessionId, session);
    
    session.layouts.showTextWall(`Active users: ${this.activeSessions.size}`);
  }

  protected async onStop(sessionId: string, userId: string, reason: string) {
    this.activeSessions.delete(sessionId);
  }
}
Each user has:
  • Unique sessionId
  • Separate AppSession instance
  • Isolated event subscriptions
  • Independent state

Key Methods

onSession() (Required)

Called when a user starts your app:
protected async onSession(
  session: AppSession,  // Interface to this user's session
  sessionId: string,    // Unique session ID
  userId: string        // User's ID
): Promise<void> {
  // Set up subscriptions, show initial UI
}

onStop() (Optional)

Called when a session ends:
protected async onStop(
  sessionId: string,  // Session that ended
  userId: string,     // User who disconnected
  reason: string      // Why it ended
): Promise<void> {
  // Clean up resources, save state
}

onToolCall() (Optional)

Called when AI assistant invokes your app’s tools:
protected async onToolCall(
  toolName: string,
  args: any,
  userId: string
): Promise<any> {
  // Execute AI-requested action
  // Return result to AI
}
Tool calls happen outside of active sessions. Learn more in AI Tools.

Complete Example

import { AppServer, AppSession } from '@mentraos/sdk';

class WeatherApp extends AppServer {
  protected async onSession(session: AppSession, sessionId: string, userId: string) {
    session.logger.info(`User ${userId} connected`);
    
    // Show welcome message
    session.layouts.showTextWall('Weather App Ready');
    
    // Listen for voice commands
    session.events.onTranscription((data) => {
      if (data.isFinal && data.text.includes('weather')) {
        this.showWeather(session);
      }
    });
  }

  protected async onStop(sessionId: string, userId: string, reason: string) {
    console.log(`Session ended: ${reason}`);
  }

  private async showWeather(session: AppSession) {
    session.layouts.showReferenceCard('Weather', 'Sunny, 72°F');
  }
}

// Start server
const server = new WeatherApp({
  packageName: 'com.example.weather',
  apiKey: process.env.MENTRAOS_API_KEY!,
  port: 3000
});

server.start();

Next Steps