Creating A Kastrax Server ✅
When developing or deploying a Kastrax application, it runs as an HTTP server that exposes your agents, workflows, and other functionality as API endpoints. This page explains how to configure and customize the server behavior.
Server Architecture ✅
Kastrax uses Ktor as its underlying HTTP server framework. Ktor is a lightweight, high-performance framework specifically designed for Kotlin applications. When you build a Kastrax application, it configures a Ktor-based HTTP server with all the necessary components.
The server provides:
- REST API endpoints for all registered agents
- API endpoints for all registered workflows
- WebSocket support for real-time agent interactions
- Custom route configuration
- Flexible middleware pipeline
- Comprehensive configuration options
- Authentication and authorization support
- CORS configuration
Server Configuration ✅
You can configure the server using the Kastrax DSL. The server configuration is specified within the server
block of your Kastrax instance:
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
// Create a Kastrax instance with server configuration
val kastraxInstance = kastrax {
// Configure server
server {
port = 8080 // Default: 8080
host = "0.0.0.0" // Default: 0.0.0.0
callTimeout = 30000 // Default: 30000 (30s)
requestTimeout = 60000 // Default: 60000 (60s)
enableSwagger = true // Default: false
enableOpenAPI = true // Default: false
enableCompression = true // Default: true
enableMetrics = true // Default: false
enableTracing = true // Default: false
}
// Other Kastrax configuration...
}
You can also configure the server using environment variables:
kastrax {
server {
port = ${?KASTRAX_SERVER_PORT}
host = ${?KASTRAX_SERVER_HOST}
callTimeout = ${?KASTRAX_SERVER_CALL_TIMEOUT}
requestTimeout = ${?KASTRAX_SERVER_REQUEST_TIMEOUT}
}
}
Custom API Routes ✅
Kastrax automatically generates API routes for all registered agents and workflows. You can also define custom routes to extend the functionality of your server.
Custom routes can be defined within the server
block using the routing
function:
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
val kastraxInstance = kastrax {
server {
// Configure server settings
port = 8080
// Define custom routes
routing {
// Simple GET endpoint
get("/api/status") {
call.respond(HttpStatusCode.OK, mapOf("status" to "running"))
}
// Route with path parameters
get("/api/agents/{agentId}/info") {
val agentId = call.parameters["agentId"]
val agent = kastraxInstance.getAgent(agentId ?: "")
if (agent != null) {
call.respond(HttpStatusCode.OK, mapOf(
"name" to agent.name,
"description" to agent.description
))
} else {
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Agent not found"))
}
}
// POST endpoint with request body
post("/api/custom-generate") {
val request = call.receive<CustomGenerateRequest>()
val agent = kastraxInstance.getAgent(request.agentId)
if (agent != null) {
val response = agent.generate(request.prompt)
call.respond(HttpStatusCode.OK, response)
} else {
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Agent not found"))
}
}
}
}
// Other Kastrax configuration...
}
// Request data class
data class CustomGenerateRequest(
val agentId: String,
val prompt: String
)
You can also define routes in a separate file and include them in your server configuration:
import ai.kastrax.core.KastraX
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
// Define routes in a separate function
fun Application.configureRoutes(kastraxInstance: KastraX) {
routing {
get("/api/custom/health") {
call.respond(mapOf("status" to "healthy"))
}
// More routes...
}
}
Then include them in your server configuration:
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
val kastraxInstance = kastrax {
server {
// Include custom routes
install { application ->
application.configureRoutes(kastraxInstance)
}
}
}
CORS Configuration ✅
Kastrax allows you to configure CORS (Cross-Origin Resource Sharing) settings for your server. This is important when your frontend application is hosted on a different domain than your API server.
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
import io.ktor.http.*
val kastraxInstance = kastrax {
server {
// Configure CORS
cors {
allowHost("https://example.com")
allowHost("https://app.example.com")
allowMethod(HttpMethod.Get)
allowMethod(HttpMethod.Post)
allowMethod(HttpMethod.Options)
allowHeader(HttpHeaders.ContentType)
allowHeader(HttpHeaders.Authorization)
exposeHeader(HttpHeaders.ContentLength)
maxAgeInSeconds = 3600
allowCredentials = true
}
}
// Other Kastrax configuration...
}
Middleware Configuration ✅
Kastrax allows you to add custom middleware to the server pipeline. Middleware functions are executed in the order they are defined and can perform tasks like logging, authentication, and request transformation.
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
import io.ktor.server.application.*
import io.ktor.server.plugins.callloging.*
import io.ktor.server.plugins.compression.*
import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.plugins.ratelimit.*
import org.slf4j.event.Level
val kastraxInstance = kastrax {
server {
// Install middleware plugins
install { application ->
// Add default headers
application.install(DefaultHeaders) {
header("X-Engine", "Kastrax")
header("X-Version", "1.0.0")
}
// Add call logging
application.install(CallLogging) {
level = Level.INFO
filter { call -> call.request.path().startsWith("/api") }
}
// Add compression
application.install(Compression) {
gzip()
deflate()
}
// Add rate limiting
application.install(RateLimit) {
global {
rateLimiter(limit = 100, refillPeriod = 60000)
}
register(RateLimitName("critical-endpoints")) {
rateLimiter(limit = 10, refillPeriod = 60000)
}
}
// Custom authentication middleware
application.intercept(ApplicationCallPipeline.Plugins) {
val authHeader = call.request.headers["Authorization"]
if (call.request.path().startsWith("/api/protected") &&
(authHeader == null || !authHeader.startsWith("Bearer "))) {
throw UnauthorizedException("Invalid or missing authentication token")
}
}
}
}
// Other Kastrax configuration...
}
// Custom exception
class UnauthorizedException(message: String) : RuntimeException(message)
if you want to add a middleware to a single route, you can also specify that in the registerApiRoute using registerApiRoute
.
registerApiRoute("/my-custom-route", {
method: "GET",
middleware: [
async (c, next) => {
// Example: Add request logging
console.log(`${c.req.method} ${c.req.url}`);
await next();
},
],
handler: async (c) => {
// you have access to kastrax instance here
const kastrax = c.get("kastrax");
// you can use the kastrax instance to get agents, workflows, etc.
const agents = await kastrax.getAgent("my-agent");
return c.json({ message: "Hello, world!" });
},
});
Middleware Behavior
Each middleware function:
- Receives a Hono context object (
c
) and anext
function - Can return a
Response
to short-circuit the request handling - Can call
next()
to continue to the next middleware or route handler - Can optionally specify a path pattern (defaults to ‘/api/*’)
- Inject request specific data for agent tool calling or workflows
Authentication ✅
Kastrax supports various authentication methods through Ktor’s authentication features:
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
val kastraxInstance = kastrax {
server {
// Configure authentication
auth {
// Basic authentication
basic("auth-basic") {
realm = "Kastrax Server"
validate { credentials ->
if (credentials.name == "admin" && credentials.password == "password") {
UserIdPrincipal(credentials.name)
} else {
null
}
}
}
// JWT authentication
jwt("auth-jwt") {
realm = "Kastrax Server"
verifier(JwtConfig.verifier)
validate { credential ->
if (credential.payload.getClaim("username").asString() != "") {
JWTPrincipal(credential.payload)
} else {
null
}
}
}
}
}
// Other Kastrax configuration...
}
CORS Support
{
handler: async (c, next) => {
// Add CORS headers
c.header("Access-Control-Allow-Origin", "*");
c.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
c.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
// Handle preflight requests
if (c.req.method === "OPTIONS") {
return new Response(null, { status: 204 });
}
await next();
};
}
Request Logging
{
handler: async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
console.log(`${c.req.method} ${c.req.url} - ${duration}ms`);
};
}
Special Kastrax Headers
When integrating with Kastrax Cloud or building custom clients, there are special headers that clients send to identify themselves and enable specific features. Your server middleware can check for these headers to customize behavior:
{
handler: async (c, next) => {
// Check for Kastrax-specific headers in incoming requests
const isFromKastraxCloud = c.req.header("x-kastrax-cloud") === "true";
const clientType = c.req.header("x-kastrax-client-type"); // e.g., 'js', 'python'
const isDevPlayground = c.req.header("x-kastrax-dev-playground") === "true";
// Customize behavior based on client information
if (isFromKastraxCloud) {
// Special handling for Kastrax Cloud requests
}
await next();
};
}
These headers have the following purposes:
x-kastrax-cloud
: Indicates that the request is coming from Kastrax Cloudx-kastrax-client-type
: Specifies the client SDK type (e.g., ‘js’, ‘python’)x-kastrax-dev-playground
: Indicates that the request is from the development playground
You can use these headers in your middleware to implement client-specific logic or enable features only for certain environments.
Deployment ✅
Since Kastrax builds to a standard Node.js server, you can deploy to any platform that runs Node.js applications:
- Cloud VMs (AWS EC2, DigitalOcean Droplets, GCP Compute Engine)
- Container platforms (Docker, Kubernetes)
- Platform as a Service (Heroku, Railway)
- Self-hosted servers
Building
Build the application:
# Build from current directory ✅
kastrax build
# Or specify a directory ✅
kastrax build --dir ./my-project
The build process:
- Locates entry file (
src/kastrax/index.ts
orsrc/kastrax/index.js
) - Creates
.kastrax
output directory - Bundles code using Rollup with tree shaking and source maps
- Generates Hono HTTP server
See kastrax build
for all options.
Starting the Server ✅
To start the server, you can use the kastrax dev
command during development or deploy your application using one of the deployment methods described in the Deployment guide.
import ai.kastrax.core.kastrax
import ai.kastrax.server.server
fun main() {
// Create and configure Kastrax instance
val kastraxInstance = kastrax {
server {
port = 8080
host = "0.0.0.0"
}
// Configure agents, tools, etc.
agent("assistant") {
// Agent configuration
}
}
// Start the server
kastraxInstance.startServer()
// The server is now running and will block the current thread
// until the application is stopped
}
During development, you can use the kastrax dev
command, which will automatically restart the server when you make changes to your code.
Deployment Options ✅
Kastrax supports multiple deployment options:
- Standalone JVM Application: Deploy as a traditional Java application on any server
- Docker Container: Package your application as a Docker container
- Kubernetes: Deploy to a Kubernetes cluster for scalability and resilience
- GraalVM Native Image: Compile to a native executable for maximum performance
- Kastrax Cloud: Use the managed Kastrax Cloud service
See Deployment Options for detailed instructions on each deployment method.