add_coco_server Data Payload Structure and Validation in the Coco App

The add_coco_server Tauri command accepts only a base URL string from the frontend, then constructs a complete Server data payload by querying the remote provider/_info endpoint and validates it through duplicate detection, HTTP health checks, and strict Serde deserialization before persisting the entry.

The add_coco_server function in the infinilabs/coco-app repository serves as the primary backend interface for registering new Coco search servers in the desktop application. Rather than receiving a complete data object from the frontend, the command orchestrates a sophisticated validation pipeline that fetches, transforms, and verifies server metadata before storage.

Input Parameters: Minimal Frontend Contract

The frontend invocation supplies only one argument: the server’s base URL (endpoint). The command signature in src-tauri/src/server/servers.rs accepts this single string and immediately begins the payload construction process.

// Frontend invocation (TypeScript)
import { invoke } from '@tauri-apps/api/tauri';

const server = await invoke<Server>('add_coco_server', { 
  endpoint: 'https://my.coco.server' 
});

Data Payload Construction Pipeline

The backend constructs the full data payload through a sequence of network requests and transformations. This occurs in the add_coco_server implementation at lines 1000–1069 of src-tauri/src/server/servers.rs.

Endpoint Sanitization and Duplicate Detection

First, the command trims trailing slashes from the supplied URL and checks for existing entries via check_endpoint_exists. If the endpoint already exists in the local store, the command aborts immediately with an error response.

// servers.rs:1000-1008
let endpoint = trim_endpoint_last_forward_slash(&endpoint);
if check_endpoint_exists(&endpoint) {
    return Err("Server already exists".to_string());
}

Fetching Provider Metadata

The command constructs the URL <endpoint>/provider/_info using provider_info_url(endpoint) and sends a GET request via HttpClient::send_raw_request. This fetches the server’s public metadata including provider details, version information, and authentication configuration.

HTTP Response Validation

If the remote server returns any status other than 200 OK, the command returns the error message "This Coco server is possibly down" and terminates. The response body is then read as text using get_response_body_text, with I/O errors converted to user-friendly messages via report_error.

JSON Deserialization into Server Struct

The response body is parsed using Serde (serde_json::from_str) into the Server struct. Deserialization failures propagate as "Failed to deserialize the response", enforcing strict schema compliance.

// servers.rs:1030-1032
let mut server: Server = serde_json::from_str(&body)
    .map_err(|e| format!("Failed to deserialize the response: {}", e))?;

The Server Struct: Complete Payload Definition

The final data payload structure is defined in src-tauri/src/common/server.rs at lines 40–74. This struct represents the complete server configuration persisted to local storage.

Field Type Description
id String Unique identifier (auto-generated UUID if absent)
builtin bool Flag for internal system servers
name String Human-readable display name (defaults to Coco Server)
endpoint String Base URL of the remote server
provider Provider Metadata including name, icon, website, EULA, privacy policy
version Version Server version string
minimal_client_version Option<MinimalClientVersion> Minimum compatible client version
updated String ISO timestamp of last provider-info fetch
enabled bool UI visibility flag (default true)
public bool Indicates if server requires authentication
available bool Calculated availability status
health Option<Health> Runtime health-check data
profile Option<UserProfile> Authenticated user profile
auth_provider AuthProvider SSO configuration URL
priority u32 Display ordering hint
stats Option<HashMap<String, Value>> Runtime statistics

Validation Logic Implementation

The command performs four distinct validation layers to ensure data integrity before persistence.

Duplicate Endpoint Prevention

The check_endpoint_exists function queries the local server registry to prevent duplicate registrations. This occurs before any network requests, ensuring idempotent behavior.

Network Health Verification

The command strictly validates that the provider/_info endpoint returns HTTP 200. Any other status code—including redirects or authentication challenges—results in immediate failure with a descriptive error message.

Schema Validation via Serde

The deserialization step enforces type safety through Rust’s type system. Required fields must be present and correctly typed. Optional fields utilize #[serde(default = ...)] attributes to populate sensible defaults when missing from the remote response.

Logical Consistency and Normalization

Post-deserialization, the command applies business logic validation:

  1. ID Generation: If the remote response lacks an id, the command generates a new UUID via Uuid::new
  2. Name Fallback: Empty name fields default to "Coco Server"
  3. Availability Calculation:
    • Public servers (public: true) automatically set available: true
    • Private servers check the token cache via get_server_token(&server.id) and assert that no token exists for new servers, forcing available: false until authentication occurs
// servers.rs:1046-1058
if server.public {
    server.available = true;
} else {
    assert!(get_server_token(&server.id).is_none(), "New private server should not have existing token");
    server.available = false;
}

Code Implementation Examples

Frontend TypeScript Integration

import { invoke } from '@tauri-apps/api/tauri';
import type { Server } from '@/types';

async function registerCocoServer(endpoint: string): Promise<Server> {
  try {
    const server = await invoke<Server>('add_coco_server', { endpoint });
    console.log('Server registered:', server.id, server.name);
    return server;
  } catch (err) {
    console.error('Registration failed:', err);
    throw err;
  }
}

Backend Rust Command Signature

// src-tauri/src/lib.rs
#[tauri::command]
pub async fn add_coco_server(
    app_handle: AppHandle, 
    endpoint: String
) -> Result<Server, String> {
    // Implementation in src-tauri/src/server/servers.rs
}

Summary

  • Single Input: The command requires only a base URL endpoint from the frontend, constructing the full payload server-side
  • Network Dependency: Validation requires successful HTTP 200 response from the remote provider/_info endpoint
  • Strict Schema: The Server struct in common/server.rs defines the complete payload shape with Serde enforcing type safety
  • Auto-Generation: Missing id fields receive UUIDs and empty names default to "Coco Server" during normalization
  • Availability Logic: Public servers are immediately available; private servers require authentication before becoming available
  • Persistence: Valid servers are saved via save_server and persist_servers after passing all validation checks

Frequently Asked Questions

What data does the frontend need to send to add_coco_server?

The frontend sends only a single string parameter: endpoint. This is the base URL of the Coco server (e.g., https://search.example.com). The backend handles all metadata retrieval and payload construction by querying the server’s provider/_info endpoint.

How does add_coco_server prevent duplicate server entries?

Before making network requests, the command calls check_endpoint_exists to verify the trimmed URL is not already registered. If a match is found, the function returns an error immediately without contacting the remote server.

What determines if a server is marked as available?

The available boolean is set based on the server’s public flag and token cache state. Public servers are automatically marked available (true). Private servers must not have an existing token in the cache and are forced to available: false until the user authenticates.

Where is the Server data structure defined?

The Server struct is defined in src-tauri/src/common/server.rs at lines 40–74. This file contains the complete payload schema including nested types like Provider, Version, Health, and AuthProvider that populate the final server object returned to the frontend.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →