Creating Your First Server | Agent Tool Protocol
Skip to main content

Creating Your First Server

Learn how to create and configure a production-ready Agent Tool Protocol server.

Basic Server Setup

Minimal Server

The simplest server requires just a few lines:

import { createServer } from '@mondaydotcomorg/atp-server';

const server = createServer();

server.listen(3333, () => {
console.log('Server running on http://localhost:3333');
});

This creates a server with default settings:

  • 30-second execution timeout
  • 128MB memory limit
  • 10 LLM calls per execution
  • No provenance tracking
  • Memory-based caching

Server with Configuration

For production use, you'll want to customize the configuration:

import { createServer, MB, HOUR, MINUTE } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
timeout: 60000, // 60 seconds
memory: 256 * MB, // 256 MB
llmCalls: 20, // Max 20 LLM calls per execution
provenanceMode: 'track', // Enable provenance tracking
},
clientInit: {
tokenTTL: 24 * HOUR, // Tokens valid for 24 hours
tokenRotation: 30 * MINUTE, // Rotate tokens every 30 minutes
},
executionState: {
ttl: 3600, // Execution state kept for 1 hour
maxPauseDuration: 3600, // Max pause duration: 1 hour
},
discovery: {
embeddings: true, // Enable embedding-based search
},
audit: {
enabled: true, // Enable audit logging
},
logger: 'info', // Log level: debug, info, warn, error
});

server.listen(3333);

Registering APIs

Custom TypeScript APIs

Register custom functions with full TypeScript support:

server.registerAPI('users', {
// Get a user by ID
getUser: {
description: 'Fetch a user by their ID',
inputSchema: {
type: 'object',
properties: {
userId: { type: 'string', description: 'User ID' },
},
required: ['userId'],
},
outputSchema: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
},
},
handler: async ({ userId }) => {
// Your implementation
return {
id: userId,
name: 'John Doe',
email: 'john@example.com',
};
},
keywords: ['user', 'profile', 'account'],
metadata: {
operationType: 'read',
sensitivityLevel: 'internal',
},
},

// Create a new user
createUser: {
description: 'Create a new user',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' },
},
required: ['name', 'email'],
},
handler: async ({ name, email }) => {
// Your implementation
const newUser = {
id: generateId(),
name,
email,
};
await database.users.insert(newUser);
return newUser;
},
metadata: {
operationType: 'write',
sensitivityLevel: 'internal',
requiresApproval: true, // Requires approval before execution
},
},
});

OpenAPI/Swagger Integration

Load and serve OpenAPI specifications:

import { loadOpenAPI } from '@mondaydotcomorg/atp-server';

// Load from URL
const petstoreAPI = await loadOpenAPI({
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
name: 'petstore',
});

server.addAPIGroup(petstoreAPI);

// Load from file
const myAPI = await loadOpenAPI({
path: './specs/my-api.yaml',
name: 'myapi',
baseURL: 'https://api.example.com',
});

server.addAPIGroup(myAPI);

Multiple API Groups

Organize APIs into logical groups:

// User management APIs
server.registerAPI('users', {
getUser: { /* ... */ },
createUser: { /* ... */ },
updateUser: { /* ... */ },
deleteUser: { /* ... */ },
});

// Product APIs
server.registerAPI('products', {
listProducts: { /* ... */ },
getProduct: { /* ... */ },
searchProducts: { /* ... */ },
});

// Order APIs
server.registerAPI('orders', {
createOrder: { /* ... */ },
getOrder: { /* ... */ },
listOrders: { /* ... */ },
});

Authentication & Authorization

Environment-based Authentication

The simplest approach uses environment variables:

// .env file
ATP_API_KEY=your-secret-key-here

Clients must provide this key:

const client = new AgentToolProtocolClient({
baseUrl: 'http://localhost:3333',
headers: {
'x-api-key': process.env.ATP_API_KEY,
},
});

Custom Authentication Provider

Implement custom authentication logic:

import { createServer } from '@mondaydotcomorg/atp-server';

class CustomAuthProvider {
name = 'custom-auth';

async validateToken(token: string): Promise<boolean> {
// Your validation logic
return token === 'valid-token';
}

async getUserInfo(token: string): Promise<any> {
// Return user information
return { userId: '123', role: 'admin' };
}
}

const server = createServer({
providers: {
auth: new CustomAuthProvider(),
},
});

OAuth Integration

For OAuth-based APIs:

server.registerAPI('github', {
getRepos: {
description: 'Get user repositories',
inputSchema: { type: 'object', properties: {} },
handler: async (params, context) => {
// Access OAuth token from context
const token = context.userAuth?.token;

// Call GitHub API with user's token
const response = await fetch('https://api.github.com/user/repos', {
headers: {
Authorization: `Bearer ${token}`,
},
});

return await response.json();
},
metadata: {
requiredScopes: ['repo'],
},
},
});

Caching Configuration

Memory Cache (Default)

import { MemoryCache } from '@mondaydotcomorg/atp-providers';

const server = createServer({
providers: {
cache: new MemoryCache({
maxKeys: 1000,
defaultTTL: 3600, // 1 hour
}),
},
});

Redis Cache (Production)

import { RedisCache } from '@mondaydotcomorg/atp-providers';

const server = createServer({
providers: {
cache: new RedisCache({
url: process.env.REDIS_URL || 'redis://localhost:6379',
keyPrefix: 'atp:',
defaultTTL: 3600,
}),
},
});

Custom Cache Provider

class CustomCacheProvider {
name = 'custom-cache';

async get(key: string): Promise<any> {
// Your implementation
}

async set(key: string, value: any, ttl?: number): Promise<void> {
// Your implementation
}

async delete(key: string): Promise<void> {
// Your implementation
}

async clear(): Promise<void> {
// Your implementation
}
}

const server = createServer({
providers: {
cache: new CustomCacheProvider(),
},
});

Middleware

Add custom middleware to intercept requests:

server.use(async (context, next) => {
console.log(`Request: ${context.method}`);

// Add custom headers
context.setHeader('X-Server-Version', '1.0.0');

// Proceed with request
const result = await next();

console.log(`Response: ${context.method} completed`);

return result;
});

// Authentication middleware
server.use(async (context, next) => {
const apiKey = context.headers['x-api-key'];

if (!apiKey || apiKey !== process.env.API_KEY) {
throw new Error('Unauthorized');
}

return next();
});

Error Handling

Global Error Handler

server.on('error', (error, context) => {
console.error('Server error:', error);

// Log to external service
logToSentry(error, {
method: context.method,
clientId: context.clientId,
});
});

Execution Error Handling

server.registerAPI('risky', {
dangerousOperation: {
description: 'An operation that might fail',
inputSchema: { type: 'object', properties: {} },
handler: async (params) => {
try {
return await performDangerousOperation();
} catch (error) {
// Transform error for client
throw new Error(`Operation failed: ${error.message}`);
}
},
},
});

Lifecycle Hooks

Startup and Shutdown

// Before server starts
server.on('beforeStart', async () => {
console.log('Initializing database...');
await database.connect();
});

// After server starts
server.on('ready', () => {
console.log('Server is ready to accept connections');
});

// Before server stops
server.on('beforeStop', async () => {
console.log('Closing database connections...');
await database.disconnect();
});

// Graceful shutdown
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully...');
await server.stop();
process.exit(0);
});

Production Configuration

Complete Production Setup

import { createServer, MB, HOUR, MINUTE } from '@mondaydotcomorg/atp-server';
import { RedisCache } from '@mondaydotcomorg/atp-providers';

const server = createServer({
execution: {
timeout: 60000,
memory: 512 * MB,
llmCalls: 50,
provenanceMode: 'track',
securityPolicies: [
preventDataExfiltration(),
requireUserOrigin(['sensitive-api']),
],
},
clientInit: {
tokenTTL: 24 * HOUR,
tokenRotation: 30 * MINUTE,
},
executionState: {
ttl: 3600,
maxPauseDuration: 3600,
},
discovery: {
embeddings: true,
},
audit: {
enabled: true,
},
otel: {
enabled: true,
serviceName: 'atp-server',
traceEndpoint: process.env.OTEL_TRACE_ENDPOINT,
metricsEndpoint: process.env.OTEL_METRICS_ENDPOINT,
},
providers: {
cache: new RedisCache({
url: process.env.REDIS_URL,
}),
},
logger: process.env.NODE_ENV === 'production' ? 'warn' : 'info',
});

// Health check endpoint
server.use(async (context, next) => {
if (context.path === '/health') {
return { status: 'ok' };
}
return next();
});

// Start server
const PORT = parseInt(process.env.PORT || '3333');
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Next Steps

Common Patterns

Rate Limiting

import { RateLimiterMemory } from 'rate-limiter-flexible';

const rateLimiter = new RateLimiterMemory({
points: 100, // Number of requests
duration: 60, // Per 60 seconds
});

server.use(async (context, next) => {
try {
await rateLimiter.consume(context.clientId);
return next();
} catch (error) {
throw new Error('Rate limit exceeded');
}
});

Request Logging

server.use(async (context, next) => {
const startTime = Date.now();

try {
const result = await next();
const duration = Date.now() - startTime;

console.log({
method: context.method,
clientId: context.clientId,
duration,
success: true,
});

return result;
} catch (error) {
const duration = Date.now() - startTime;

console.error({
method: context.method,
clientId: context.clientId,
duration,
success: false,
error: error.message,
});

throw error;
}
});

Troubleshooting

Server Won't Start

  • Check if the port is already in use
  • Verify Node.js version (18+ required)
  • Check for syntax errors in your configuration

Memory Issues

  • Increase the memory limit in execution config
  • Monitor memory usage in production
  • Consider implementing cleanup for long-running operations

Performance Issues

  • Enable Redis caching
  • Implement rate limiting
  • Monitor with OpenTelemetry
  • Optimize API handler implementations
Agent Tool Protocol | ATP - Code Execution for AI Agents