The Discovery API allows clients to automatically detect Agent Server capabilities, available models, and health status. This enables dynamic configuration and server selection in distributed environments.

Overview

The Discovery API provides a standardized way for clients to:
  • Detect server capabilities and supported features
  • Discover available AI models and providers
  • Monitor server health and operational status
  • Configure applications dynamically based on server capabilities

Endpoint

GET /discover
No authentication required for the discovery endpoint.

Response Format

The discovery endpoint returns comprehensive server information:
{
  "server": {
    "id": "string",
    "name": "string", 
    "version": "string",
    "provider": "string",
    "endpoints": {
      "health": "/health",
      "discover": "/discover",
      "compose": "/compose"
    },
    "capabilities": {
      "streaming": true,
      "modes": ["plan", "act"],
      "formats": ["vercel", "sse"],
      "authentication": ["bearer", "none"],
      "orchestration": true,
      "generation": true,
      "execution": true,
      "refinement": true,
      "mcp_support": false
    },
    "limits": {
      "maxConcurrentExecutions": 10,
      "executionTimeout": 300000,
      "keepAliveInterval": 30000
    },
    "features": {
      "workflowGeneration": true,
      "workflowExecution": true,
      "workflowValidation": true,
      "intelligentComposition": true,
      "contextAware": true,
      "sseStreaming": true
    }
  },
  "models": [
    {
      "id": "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
      "name": "Llama 3.1 70B Instruct Turbo",
      "provider": "together",
      "providerId": "together"
    }
  ],
  "health": {
    "status": "healthy",
    "timestamp": "2024-01-15T10:30:00Z",
    "uptime": "running",
    "active_executions": 2,
    "max_executions": 10
  },
  "mcp_capabilities": {
    "available": false,
    "tools": [],
    "prompts": [],
    "resources": [],
    "protocol_version": "2024-11-05"
  },
  "supported_protocols": ["orchestration"],
  "discovery_version": "1.0"
}

Response Fields

Server Information

server.id
string
Unique server identifier
server.name
string
Human-readable server name
server.version
string
Server version following semantic versioning
server.provider
string
Primary orchestration provider (e.g., “adk”, “mcp”, “custom”)

Capabilities

capabilities.streaming
boolean
Whether the server supports Server-Sent Events (SSE) streaming
capabilities.modes
array
Supported execution modes: ["plan", "act"]
capabilities.orchestration
boolean
Whether the server supports intelligent workflow orchestration
capabilities.mcp_support
boolean
Whether the server supports Model Context Protocol (MCP)

Models

models
array
Array of available AI models with their metadata
models[].id
string
Model identifier (e.g., “meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo”)
models[].name
string
Human-readable model name
models[].provider
string
Model provider (e.g., “together”, “openai”, “anthropic”)

Health Status

health.status
string
Current server status: "healthy", "degraded", "unhealthy"
health.active_executions
number
Number of currently running workflow executions
health.max_executions
number
Maximum concurrent executions supported

Usage Examples

Basic Discovery

curl http://localhost:8001/discover

TypeScript Client

interface ServerDiscovery {
  server: {
    id: string;
    name: string;
    capabilities: {
      streaming: boolean;
      modes: string[];
      orchestration: boolean;
    };
  };
  models: Array<{
    id: string;
    name: string;
    provider: string;
  }>;
  health: {
    status: string;
    active_executions: number;
  };
}

export class AgentServerClient {
  async discover(serverUrl: string): Promise<ServerDiscovery> {
    const response = await fetch(`${serverUrl}/discover`);
    
    if (!response.ok) {
      throw new Error(`Discovery failed: ${response.status}`);
    }
    
    return response.json();
  }
  
  async findHealthyServers(serverUrls: string[]): Promise<ServerDiscovery[]> {
    const discoveries = await Promise.allSettled(
      serverUrls.map(url => this.discover(url))
    );
    
    return discoveries
      .filter((result): result is PromiseFulfilledResult<ServerDiscovery> => 
        result.status === 'fulfilled' && result.value.health.status === 'healthy'
      )
      .map(result => result.value);
  }
}

Python Client

import httpx
from typing import Dict, List, Optional

class AgentServerClient:
    async def discover(self, server_url: str) -> Dict:
        """Discover server capabilities."""
        async with httpx.AsyncClient() as client:
            response = await client.get(f"{server_url}/discover")
            response.raise_for_status()
            return response.json()
    
    async def find_servers_with_capability(
        self, 
        server_urls: List[str], 
        capability: str
    ) -> List[Dict]:
        """Find servers that support a specific capability."""
        servers = []
        
        for url in server_urls:
            try:
                discovery = await self.discover(url)
                if discovery["server"]["capabilities"].get(capability, False):
                    servers.append({
                        "url": url,
                        "discovery": discovery
                    })
            except Exception as e:
                print(f"Failed to discover {url}: {e}")
        
        return servers

Multi-Server Discovery

export class ServerDiscovery {
  private servers: Map<string, ServerDiscovery> = new Map();
  
  async discoverServers(serverUrls: string[]): Promise<void> {
    const discoveries = await Promise.allSettled(
      serverUrls.map(async (url) => {
        const discovery = await this.discover(url);
        return { url, discovery };
      })
    );
    
    discoveries.forEach((result) => {
      if (result.status === 'fulfilled') {
        const { url, discovery } = result.value;
        this.servers.set(url, discovery);
      }
    });
  }
  
  getHealthyServers(): Array<{ url: string; discovery: ServerDiscovery }> {
    return Array.from(this.servers.entries())
      .filter(([_, discovery]) => discovery.health.status === 'healthy')
      .map(([url, discovery]) => ({ url, discovery }));
  }
  
  getServersWithCapability(capability: string): Array<{ url: string; discovery: ServerDiscovery }> {
    return Array.from(this.servers.entries())
      .filter(([_, discovery]) => discovery.server.capabilities[capability] === true)
      .map(([url, discovery]) => ({ url, discovery }));
  }
}

Integration Patterns

Dynamic Server Selection

// Select the best server for a specific task
async function selectOptimalServer(
  servers: ServerDiscovery[],
  requirements: {
    needsExecution?: boolean;
    preferredModel?: string;
    maxLatency?: number;
  }
): Promise<ServerDiscovery | null> {
  const candidates = servers.filter(server => {
    // Filter by health
    if (server.health.status !== 'healthy') return false;
    
    // Filter by execution capability
    if (requirements.needsExecution && !server.server.capabilities.execution) {
      return false;
    }
    
    // Filter by model availability
    if (requirements.preferredModel) {
      const hasModel = server.models.some(m => m.id === requirements.preferredModel);
      if (!hasModel) return false;
    }
    
    return true;
  });
  
  // Sort by load (active executions)
  candidates.sort((a, b) => a.health.active_executions - b.health.active_executions);
  
  return candidates[0] || null;
}

Health Monitoring

export class ServerHealthMonitor {
  private servers: Map<string, ServerDiscovery> = new Map();
  private healthCheckInterval: NodeJS.Timeout;
  
  constructor(private serverUrls: string[], private intervalMs: number = 30000) {
    this.startHealthChecks();
  }
  
  private async startHealthChecks() {
    await this.checkAllServers();
    
    this.healthCheckInterval = setInterval(async () => {
      await this.checkAllServers();
    }, this.intervalMs);
  }
  
  private async checkAllServers() {
    const checks = this.serverUrls.map(async (url) => {
      try {
        const discovery = await this.discover(url);
        this.servers.set(url, discovery);
        console.log(`✅ ${url}: ${discovery.health.status}`);
      } catch (error) {
        console.log(`❌ ${url}: unreachable`);
        this.servers.delete(url);
      }
    });
    
    await Promise.allSettled(checks);
  }
  
  getHealthyServers(): ServerDiscovery[] {
    return Array.from(this.servers.values())
      .filter(server => server.health.status === 'healthy');
  }
}

Error Handling

HTTP StatusDescriptionHandling
200SuccessProcess discovery response
404Endpoint not foundServer doesn’t support discovery
500Server errorServer unhealthy, try again later
TimeoutNetwork timeoutServer unreachable

Best Practices

Cache Results

Cache discovery responses with appropriate TTL (5-10 minutes)

Handle Failures

Gracefully handle discovery failures and implement retries

Monitor Health

Regularly check server health for dynamic load balancing

Version Compatibility

Check discovery_version for compatibility with your client

Next Steps