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
Responsibility Details HTTP Server Listens for webhooks from MentraOS Cloud WebSocket Client Maintains connection to MentraOS Cloud Session Manager Creates AppSession for each user connection Lifecycle Handler Calls 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
Go to Developer Console
Create or select your app
Package Name : Set during app creation (e.g., com.example.myapp)
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
}
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