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