    /**
     * Configure the service with a host and port.
     * Creates a ServerConfig from JSON and applies it via the C FFI.
     */
    public void config(String host, int port) {
        try {
            // Build ServerConfig JSON from host and port
            String configJson = String.format(
                "{\"host\": \"%s\", \"port\": %d}",
                host.replace("\"", "\\\""),
                port
            );

            // Allocate and populate the config JSON string in the shared arena
            MemorySegment configSegment = arena.allocateFrom(configJson);

            // Look up the C function to create ServerConfig from JSON
            MemorySegment createAddr = LOOKUP.find("{{ ffi_prefix }}_server_config_from_json")
                .or(() -> LOOKUP.find("_{{ ffi_prefix }}_server_config_from_json"))
                .orElseThrow();
            FunctionDescriptor createDesc = FunctionDescriptor.of(
                ValueLayout.ADDRESS   // return: ServerConfig*
                , ValueLayout.ADDRESS  // param: config JSON string
            );
            MethodHandle createHandle = LINKER.downcallHandle(createAddr, createDesc);
            MemorySegment configHandle = (MemorySegment) createHandle.invoke(configSegment);

            if (configHandle == null || configHandle.address() == 0) {
                throw new RuntimeException("Failed to create ServerConfig from JSON");
            }

            // Look up the C function to apply config to the service
            MemorySegment applyAddr = LOOKUP.find("{{ ffi_prefix }}_{{ service_snake }}_config")
                .or(() -> LOOKUP.find("_{{ ffi_prefix }}_{{ service_snake }}_config"))
                .orElseThrow();
            FunctionDescriptor applyDesc = FunctionDescriptor.of(
                ValueLayout.ADDRESS,   // return: *mut opaque (updated owner)
                ValueLayout.ADDRESS,   // owner: *mut opaque
                ValueLayout.ADDRESS    // config: ServerConfig*
            );
            MethodHandle applyHandle = LINKER.downcallHandle(applyAddr, applyDesc);
            ownerHandle = (MemorySegment) applyHandle.invoke(ownerHandle, configHandle);

            // Free the ServerConfig handle
            MemorySegment freeAddr = LOOKUP.find("{{ ffi_prefix }}_server_config_free")
                .or(() -> LOOKUP.find("_{{ ffi_prefix }}_server_config_free"))
                .orElseThrow();
            FunctionDescriptor freeDesc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS);
            MethodHandle freeHandle = LINKER.downcallHandle(freeAddr, freeDesc);
            freeHandle.invoke(configHandle);

        } catch (Throwable e) {
            throw new RuntimeException("Failed to configure host and port", e);
        }
    }
