Overview
Follow these best practices to get the most out of Agentflare while ensuring optimal performance, security, and reliability.
Connection Management
Connection Pooling Enable connection pooling for better performance
Keep-Alive Use persistent connections to reduce latency
// Optimal connection configuration
import { Client } from "@modelcontextprotocol/sdk/client/index.js" ;
import { HTTPTransport } from "@modelcontextprotocol/sdk/client/http.js" ;
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
},
// Connection options
timeout: 30000 , // 30 second timeout
keepAlive: true , // Enable persistent connections
})
});
Batching and Sampling
For high-volume applications, Agentflare automatically handles batching and sampling on the server side. Configure these settings in your dashboard:
Sampling Rate : Adjust in Dashboard → Settings → Observability
Smart Sampling : Automatically enabled (prioritizes errors and slow calls)
Batching : Handled automatically by the proxy
Caching Strategy
Agentflare provides intelligent caching at the proxy level. Configure caching in your dashboard:
Metadata Caching : Tool schemas and server info (5-minute TTL)
Response Caching : Deterministic tool responses (configurable per tool)
Cache Invalidation : Automatic on schema changes
Security Best Practices
API Key Management
Never commit API keys to version control or expose them in client-side code.
Environment Variables
Store API keys in environment variables # .env file (never commit this)
API_JWT_SECRET = your_jwt_secret_here
AGENTFLARE_PROJECT_ID = proj_abc123
Key Rotation
Rotate API keys regularly // Set up key rotation reminder
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
keyRotationWarning: true , // Warn before key expires
keyRotationDays: 30 // Rotate every 30 days
});
Scope Limitation
Use the minimum required scopes // Create keys with specific scopes in dashboard
const scopes = [
'tools:read' , // Read tool call data
'servers:read' , // Read server configurations
'analytics:read' // Read analytics data
// Avoid 'admin' or 'write' scopes unless necessary
];
Network Security
Restrict network access when possible const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
allowedIPs: [ '192.168.1.0/24' ], // Restrict to specific networks
requireTLS: true , // Enforce TLS 1.3
verifyCertificates: true // Verify SSL certificates
});
Double Authentication
For highly sensitive environments, implement double authentication:
// Primary authentication (Agentflare)
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
projectId: process . env . AGENTFLARE_PROJECT_ID
});
// Secondary authentication (Your MCP servers)
const servers = [{
name: "secure-server" ,
endpoint: "https://secure.yourcompany.com/mcp" ,
authentication: {
type: "bearer" ,
token: process . env . YOUR_SERVER_TOKEN ,
headers: {
"X-Client-ID" : "agentflare-telepathy" ,
"X-Request-Signature" : computeSignature ( request )
}
}
}];
Reliability and Error Handling
Comprehensive Error Handling
// Standard error handling with try/catch
async function robustToolCall ( client , toolName , args , options = {}) {
const maxRetries = options . maxRetries || 3 ;
const retryDelay = options . retryDelay || 1000 ;
for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
try {
const result = await client . callTool ({
name: toolName ,
arguments: args ,
timeout: options . timeout || 30000 ,
metadata: {
attempt: attempt ,
maxRetries: maxRetries ,
reasoning: options . reasoning || `Calling ${ toolName } `
}
});
return result ;
} catch ( error ) {
if ( error instanceof NetworkError && attempt < maxRetries ) {
console . warn ( `Network error on attempt ${ attempt } , retrying...` );
await new Promise ( resolve => setTimeout ( resolve , retryDelay * attempt ));
continue ;
}
if ( error instanceof ToolCallError ) {
console . error ( `Tool call failed: ${ error . message } ` , {
tool: toolName ,
arguments: args ,
error: error . details
});
throw error ;
}
// Re-throw for unexpected errors
throw error ;
}
}
}
Circuit Breaker Pattern
class CircuitBreaker {
constructor ( threshold = 5 , timeout = 60000 ) {
this . failureThreshold = threshold ;
this . timeout = timeout ;
this . failureCount = 0 ;
this . lastFailureTime = null ;
this . state = 'CLOSED' ; // CLOSED, OPEN, HALF_OPEN
}
async call ( fn ) {
if ( this . state === 'OPEN' ) {
if ( Date . now () - this . lastFailureTime < this . timeout ) {
throw new Error ( 'Circuit breaker is OPEN' );
}
this . state = 'HALF_OPEN' ;
}
try {
const result = await fn ();
this . onSuccess ();
return result ;
} catch ( error ) {
this . onFailure ();
throw error ;
}
}
onSuccess () {
this . failureCount = 0 ;
this . state = 'CLOSED' ;
}
onFailure () {
this . failureCount ++ ;
this . lastFailureTime = Date . now ();
if ( this . failureCount >= this . failureThreshold ) {
this . state = 'OPEN' ;
}
}
}
// Usage
const circuitBreaker = new CircuitBreaker ( 5 , 60000 );
async function protectedToolCall ( client , toolName , args ) {
return circuitBreaker . call (() =>
client . callTool ({ name: toolName , arguments: args })
);
}
Health Monitoring
// Add health checks to your application
class HealthMonitor {
constructor ( client ) {
this . client = client ;
this . healthy = true ;
this . lastCheck = null ;
this . startMonitoring ();
}
async checkHealth () {
try {
await this . client . ping ();
this . healthy = true ;
this . lastCheck = new Date ();
return true ;
} catch ( error ) {
this . healthy = false ;
console . error ( 'Health check failed:' , error );
return false ;
}
}
startMonitoring () {
setInterval (() => {
this . checkHealth ();
}, 30000 ); // Check every 30 seconds
}
getStatus () {
return {
healthy: this . healthy ,
lastCheck: this . lastCheck
};
}
}
const healthMonitor = new HealthMonitor ( client );
// Expose health endpoint
app . get ( '/health' , ( req , res ) => {
const status = healthMonitor . getStatus ();
res . status ( status . healthy ? 200 : 503 ). json ( status );
});
Observability Best Practices
Structured Reasoning
Provide structured reasoning for better observability:
// Good: Structured reasoning
await client . callTool ({
name: "database_query" ,
arguments: {
table: "users" ,
filters: { active: true },
limit: 100
},
metadata: {
reasoning: "Fetching active users for dashboard display" ,
context: {
userRole: "admin" ,
requestId: "req_abc123" ,
feature: "user_management"
},
confidence: 0.95 ,
alternatives: [ "cache_lookup" , "api_call" ],
expectedCost: 0.001 ,
expectedDuration: 500
}
});
// Bad: Minimal context
await client . callTool ({
name: "database_query" ,
arguments: { table: "users" }
});
Cost Attribution
Track costs effectively:
// Track costs by feature/user/session
await client . callTool ({
name: "ai_analysis" ,
arguments: { data: analysisData },
metadata: {
costAttribution: {
userId: "user_123" ,
sessionId: "session_456" ,
feature: "data_analysis" ,
department: "engineering"
},
budgetTracking: {
category: "ai_operations" ,
maxCost: 0.50 ,
alertThreshold: 0.40
}
}
});
Add performance markers:
// Track performance with markers
const startTime = performance . now ();
await client . callTool ({
name: "complex_calculation" ,
arguments: { dataset: largeDataset },
metadata: {
performance: {
startTime: startTime ,
datasetSize: largeDataset . length ,
complexity: "high" ,
cacheable: false
},
timing: {
expectedDuration: 5000 ,
timeoutWarning: 4000 ,
maxAcceptableDuration: 10000
}
}
});
const endTime = performance . now ();
console . log ( `Tool call completed in ${ endTime - startTime } ms` );
Development Workflow
Environment Management
Development
Testing
Production
// Development configuration
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET_DEV ,
projectId: process . env . AGENTFLARE_PROJECT_ID_DEV ,
environment: 'development' ,
debug: true ,
logLevel: 'debug' ,
sampling: { rate: 1.0 }, // 100% sampling in dev
validateRequests: true , // Validate all requests
dryRun: false // Actually make calls
});
Testing Strategy
// Unit tests
describe ( 'Tool Calls' , () => {
beforeEach (() => {
// Use test client with mocking
client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : 'test-key' ,
dryRun: true ,
mockResponses: {
'search' : { results: [ 'test result' ] },
'database_query' : { rows: [{ id: 1 , name: 'test' }] }
}
});
});
it ( 'should handle search tool calls' , async () => {
const result = await client . callTool ({
name: 'search' ,
arguments: { query: 'test' }
});
expect ( result . results ). toHaveLength ( 1 );
expect ( result . results [ 0 ]). toBe ( 'test result' );
});
});
// Integration tests
describe ( 'Integration Tests' , () => {
it ( 'should connect to real services in staging' , async () => {
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET_STAGING ,
environment: 'staging'
});
const health = await client . ping ();
expect ( health . status ). toBe ( 'healthy' );
});
});
Monitoring and Alerting
Key Metrics to Monitor
Error Rate Monitor tool call failure rates
Latency Track response times and timeouts
Cost Monitor API usage costs
Throughput Track requests per second
Custom Alerting
// Set up custom alerting
const client = new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
alerting: {
enabled: true ,
webhookUrl: process . env . SLACK_WEBHOOK_URL ,
rules: [
{
metric: 'error_rate' ,
threshold: 0.05 , // 5% error rate
window: '5m' , // Over 5 minutes
severity: 'critical'
},
{
metric: 'avg_latency' ,
threshold: 2000 , // 2 second avg latency
window: '10m' ,
severity: 'warning'
},
{
metric: 'cost_per_hour' ,
threshold: 10.00 , // $10/hour
window: '1h' ,
severity: 'warning'
}
]
}
});
Scaling Considerations
Load Balancing
// Multiple client instances for load balancing
const clients = [
new Client ({
transport: new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
region: 'us-east-1'
}),
new Client ({
transport : new HTTPTransport ({
baseUrl: process . env . AGENTFLARE_PROXY_URL ,
headers: {
"Authorization" : `Bearer ${ process . env . AGENTFLARE_API_KEY } `
}
apiKey : process . env . API_JWT_SECRET ,
region: 'us-west-2'
})
];
function getClient () {
// Simple round-robin load balancing
return clients [ Math . floor ( Math . random () * clients . length )];
}
async function scaledToolCall ( toolName , args ) {
const client = getClient ();
return client . callTool ({ name : toolName , arguments : args });
}
Resource Management
// Resource management for high-volume applications
class ResourceManager {
constructor () {
this . activeConnections = 0 ;
this . maxConnections = 100 ;
this . queue = [];
}
async acquireConnection () {
if ( this . activeConnections < this . maxConnections ) {
this . activeConnections ++ ;
return true ;
}
// Queue the request
return new Promise (( resolve ) => {
this . queue . push ( resolve );
});
}
releaseConnection () {
this . activeConnections -- ;
if ( this . queue . length > 0 ) {
const next = this . queue . shift ();
this . activeConnections ++ ;
next ( true );
}
}
}
Next Steps
Following these best practices will help you build reliable, performant, and secure applications with Agentflare.