Validating User Input in AI Agents with MCP

Your AI agent just accepted "john@gmial.com" as a valid email and processed a payment to a credit card number that fails the Luhn check. Now you're dealing with bounced emails and failed transactions. Here's how to build validation into your AI workflows that actually works.

Input Validation Challenges in AI Agents

Traditional software has well-defined input paths with explicit validation. AI agents are different - users provide freeform input that the agent must parse, validate, and act on. This creates unique challenges.

Why LLMs Fail at Validation

  • Pattern approximation: LLMs recognize patterns but don't apply validation algorithms
  • No checksum verification: Credit cards use Luhn algorithm; LLMs can't compute it
  • RFC complexity: Email rules are complex; LLMs simplify them incorrectly
  • Regional variations: Phone formats vary by country in complex ways

Real-World Validation Failures

LLM Validation Mistakes
// LLM says valid, but actually invalid:
"test@domain"           // Missing TLD
"4111111111111112"      // Fails Luhn check
"+1-555-1234"           // Invalid US number (555 prefix)

// LLM says invalid, but actually valid:
"user+tag@example.com"  // Plus addressing is valid!
"o'connor@email.com"    // Apostrophes are allowed
"+91 98765 43210"       // Valid Indian mobile format
The Problem: LLMs are trained on examples, not specifications. They'll accept inputs that "look right" and reject inputs that "look unusual" - the opposite of proper validation.

Email, Phone, and Credit Card Validation

Email Validation

Email validation is more complex than most developers realize. The RFC 5321 specification allows many surprising characters and formats.

Email Validation API
GET https://api.tinyfn.io/v1/validate/email?email=user@example.com
Response
{
  "email": "user@example.com",
  "is_valid": true,
  "parts": {
    "local": "user",
    "domain": "example.com"
  },
  "checks": {
    "syntax_valid": true,
    "domain_format_valid": true
  }
}

Phone Number Validation

Phone validation must handle international formats, country codes, and regional numbering rules.

Phone Validation API
GET https://api.tinyfn.io/v1/validate/phone
  ?phone=+1-212-555-1234
  &country=US
Response
{
  "phone": "+1-212-555-1234",
  "is_valid": true,
  "country_code": "1",
  "national_number": "2125551234",
  "formatted": {
    "international": "+1 212-555-1234",
    "national": "(212) 555-1234",
    "e164": "+12125551234"
  },
  "type": "fixed_line_or_mobile"
}

Credit Card Validation

Credit card validation uses the Luhn algorithm and card type detection based on BIN ranges.

Credit Card Validation API
GET https://api.tinyfn.io/v1/validate/credit-card?number=4111111111111111
Response
{
  "number": "4111111111111111",
  "is_valid": true,
  "luhn_valid": true,
  "card_type": "visa",
  "card_brand": "Visa",
  "length_valid": true,
  "masked": "4111 **** **** 1111"
}

Using TinyFn Validation Tools

Available Validation Tools

Tool Validates
validate/email Email addresses (RFC 5321 compliant)
validate/phone Phone numbers (international formats)
validate/credit-card Credit/debit cards (Luhn + BIN)
validate/url URLs (protocol, domain, path)
validate/uuid UUIDs (all versions)
validate/iban IBANs (international bank accounts)
validate/ssn US Social Security Numbers
validate/vin Vehicle Identification Numbers
validate/isbn Book ISBNs (10 and 13 digit)
validate/zip-code Postal/ZIP codes by country

MCP Configuration

mcp.json
{
  "mcpServers": {
    "tinyfn-validate": {
      "url": "https://api.tinyfn.io/mcp/validate/",
      "headers": {
        "X-API-Key": "your-api-key"
      }
    }
  }
}

Building Robust Agent Workflows

Pattern: Validate Before Processing

Never process user input without validation. Build your agent to validate first, then proceed only if valid.

Agent System Prompt
When collecting user information:

1. Email addresses: ALWAYS validate using validate/email before proceeding
2. Phone numbers: ALWAYS validate using validate/phone before proceeding
3. Credit cards: ALWAYS validate using validate/credit-card before processing

If validation fails:
- Explain what's wrong with the input
- Ask the user to provide a corrected value
- Do NOT proceed until valid input is received

Pattern: Graceful Correction Flow

Validation Dialog Flow
User: "My email is john@gmial.com"

// Agent validates via MCP
Tool call: validate/email { "email": "john@gmial.com" }
Result: { "is_valid": true, "domain": "gmial.com" }

// Agent recognizes common typo in domain
Agent: "I see your email is john@gmial.com. Did you mean
        john@gmail.com? The domain 'gmial.com' looks like
        it might be a typo."

User: "Oh yes, john@gmail.com"

// Agent re-validates
Tool call: validate/email { "email": "john@gmail.com" }
Result: { "is_valid": true }

Agent: "Perfect! I've noted your email as john@gmail.com."

Pattern: Multi-Field Validation

Order Form Validation
// User provides multiple fields at once
User: "Ship to john@example.com, call me at 555-1234,
       and charge card 4111111111111112"

// Agent validates all fields
validate/email { "email": "john@example.com" }
// Result: valid

validate/phone { "phone": "555-1234", "country": "US" }
// Result: invalid - 555 is not a real exchange

validate/credit-card { "number": "4111111111111112" }
// Result: invalid - fails Luhn check

Agent: "I found some issues with your information:

        Email: john@example.com - Valid
        Phone: 555-1234 - Invalid. US phone numbers can't
               use the 555 prefix. Please provide your real
               phone number.
        Card: ending in 1112 - Invalid card number. Please
              double-check and re-enter.

        Please correct the phone and card to proceed."

Error Handling Best Practices

Clear Error Messages

When validation fails, tell users exactly what's wrong and how to fix it.

Good vs Bad Error Messages
// Bad: Vague
"Invalid email address"

// Good: Specific and helpful
"The email 'john@domain' is missing a domain extension
like .com or .org. Did you mean john@domain.com?"

// Bad: Technical
"Phone validation failed: E164 format error"

// Good: Human-friendly
"The phone number format isn't recognized. Please include
your country code, like +1 for US or +44 for UK."

Fallback Handling

If the validation API is temporarily unavailable, have a fallback strategy:

Fallback Strategy
async function validateEmailWithFallback(email) {
  try {
    const result = await validateEmail(email); // TinyFn API
    return result;
  } catch (error) {
    // API unavailable - use basic regex as fallback
    const basicValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    return {
      is_valid: basicValid,
      warning: "Full validation unavailable. Basic check only.",
      needs_verification: true
    };
  }
}

Complete Examples

Customer Onboarding Agent

Python Implementation
import requests

class ValidationAgent:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://api.tinyfn.io/v1"

    def validate(self, validation_type, value, **kwargs):
        params = {validation_type.split('/')[-1]: value, **kwargs}
        response = requests.get(
            f"{self.base_url}/{validation_type}",
            params=params,
            headers={"X-API-Key": self.api_key}
        )
        return response.json()

    def collect_customer_info(self, email, phone, country="US"):
        errors = []
        validated = {}

        # Validate email
        email_result = self.validate("validate/email", email)
        if not email_result["is_valid"]:
            errors.append(f"Invalid email: {email}")
        else:
            validated["email"] = email

        # Validate phone
        phone_result = self.validate(
            "validate/phone", phone, country=country
        )
        if not phone_result["is_valid"]:
            errors.append(f"Invalid phone for {country}: {phone}")
        else:
            validated["phone"] = phone_result["formatted"]["e164"]

        return {
            "valid": len(errors) == 0,
            "errors": errors,
            "validated_data": validated
        }

# Usage
agent = ValidationAgent("your-api-key")
result = agent.collect_customer_info(
    email="john@example.com",
    phone="212-555-1234"
)

if result["valid"]:
    print("All inputs valid:", result["validated_data"])
else:
    print("Errors found:", result["errors"])

Payment Processing Agent

JavaScript Implementation
class PaymentAgent {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.tinyfn.io/v1';
  }

  async validateCard(number, expiryMonth, expiryYear) {
    // Validate card number
    const cardResult = await this.callApi('validate/credit-card', {
      number: number.replace(/\s/g, '')
    });

    if (!cardResult.is_valid) {
      return {
        valid: false,
        error: 'Invalid card number. Please check and try again.',
        details: cardResult
      };
    }

    // Check expiry (basic check - could use datetime tools too)
    const now = new Date();
    const expiry = new Date(expiryYear, expiryMonth - 1);

    if (expiry < now) {
      return {
        valid: false,
        error: 'Card has expired.',
        card_type: cardResult.card_type
      };
    }

    return {
      valid: true,
      card_type: cardResult.card_type,
      masked: cardResult.masked
    };
  }

  async callApi(endpoint, params) {
    const url = new URL(`${this.baseUrl}/${endpoint}`);
    Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));

    const response = await fetch(url, {
      headers: { 'X-API-Key': this.apiKey }
    });
    return response.json();
  }
}

// Usage
const agent = new PaymentAgent('your-api-key');
const result = await agent.validateCard(
  '4111 1111 1111 1111',
  12,
  2026
);

if (result.valid) {
  console.log(`Valid ${result.card_type}: ${result.masked}`);
} else {
  console.log(`Error: ${result.error}`);
}

Build Bulletproof AI Agent Workflows

Add reliable input validation to your AI agents with TinyFn MCP tools.

Get Free API Key

Ready to try TinyFn?

Get your free API key and start building in minutes.

Get Free API Key