public void subscribe(Class messageType, String fields) throws IOException {
        if (! KismetMessage.class.isAssignableFrom(messageType)) {
            throw new IllegalArgumentException("invalid message type: must implement KismetMessage interface");
        }
        
        Protocol protocol = (Protocol) messageType.getAnnotation(Protocol.class);
        
        if (protocol == null) {
            throw new IllegalArgumentException("invalid message type: must declare protocol via annotation");
        }
        
        if (connection != null) {
            this.checkServerSupport(connection);
        }
        
        Set<Class> messageSet = subscriptions.get(protocol.value());
        
        if (messageSet == null) {
            messageSet = new HashSet<Class>();
            subscriptions.put(protocol.value(), messageSet);
        }
        
        messageSet.add(messageType);
        
        Set<String> fieldSet = capabilities.get(messageType);
        
        if (fieldSet == null) {
            fieldSet = new HashSet<String>();
            capabilities.put(messageType, fieldSet);
        }
        
        for (String field : fields.split(",")) {
            field = field.trim();
            
            Capability capability = this.findCapability(messageType, field);
            
            if (capability == null) {
                throw new IllegalArgumentException("invalid field: " + field);
            }
            
            fieldSet.add(capability.value());
        }
        
        if (connection != null) {
            connection.updateServerSubscriptions();
        }
    }