Democratizing Internal Data — Building an MCP Server That Lets You Search 991 Tables in Natural Language

System Overview

Hi, I’m Ryan Tsuji, CTO at airCloset — Japan’s leading fashion rental subscription service.

Today I want to share something I’m genuinely proud of: DB Graph and DB Graph MCP — a Model Context Protocol (MCP) server that lets anyone in our company search and query 15 schemas, 991 tables, 11 SQL databases, and 6 MongoDB instances using natural language through Claude Code.

You don’t need to know a single table name. Ask “find tables related to returns” and it gives you the answer — across schemas, across database engines. And yes, it can query production data safely.

In this post, I’ll walk through everything: what it does, how it works, the tool design, actual response formats, how we built the graph, how we operate it, and how we handle permissions and security.

The Problem: Nobody Knows All 991 Tables

airCloset has been running since 2015 — that’s 10 years of accumulated database schema.

Resource Count
SQL Databases 11 (MySQL 8 + PostgreSQL 3)
MongoDB Databases 6 (DocumentDB 5 + Atlas 1)
Schemas 15
Tables/Collections 991
ORMs 4 (TypeORM, Sequelize, Drizzle, Mongoose)
Repositories 28

Nobody in the company knows all of them. Not even close.

Here’s a real scenario. Customer support asks: “This customer’s app shows the return as completed, but has the warehouse actually confirmed receiving it?”

Think about what you need to investigate this.

The app-side return status lives in the aircloset schema’s delivery order table. If the delivery status is “RETURNED”, the app considers it done. Some people might know this much.

But the warehouse-side confirmation lives in the bridge schema. A receive record table’s status being “COMPLETE” means the warehouse has physically processed the returned package.

The problem? These two live in completely separate databases. No foreign key connects them. To bridge the gap, there’s an intermediate mapping table in aircloset that holds a warehouse order code (varchar) — which corresponds to a shipping order code in bridge. No FK, just a varchar match across schemas.

aircloset delivery order table (status = RETURNED)
  ↓ order_id
aircloset warehouse mapping table
  ↓ warehouse_order_code (varchar)
bridge shipping order table (matched by code — no FK!)
  ↓ shipping_order_id
bridge receive record table (status = COMPLETE = warehouse confirmed)

Table names are generalized for this article.

Four tables, two schemas, a foreign-key-less varchar join. How many people in the company know this path? You could count them on one hand. And if they’re on vacation, the investigation stalls.

This is daily life in a 991-table × 15-schema world. It’s not just “I don’t know the table name.” It’s that the connections between schemas exist only in specific people’s heads. That was the real problem.

DB Graph MCP — The Big Picture

This is what we built to solve it.

System Overview

Four components:

  1. DB Dictionary Graph Builder — A daily batch job that parses ORM definitions from 28 repositories and stores table/column/relationship info as a graph in BigQuery
  2. DB Dictionary Review UI — A web app where humans verify AI-generated descriptions, mark deprecated columns, and add annotations. Review data survives daily rebuilds
  3. DB Graph MCP Server — An MCP server (Cloud Run) that combines graph search with live DB querying
  4. DB Account Pipeline — Fully automated DB access provisioning: application → approval → account creation → notification

Seeing It in Action

Let’s solve the return investigation from above using DB Graph MCP.

Tool response examples below use generalized table/column names. The response format reflects actual output.

Step 1: Natural Language Table Search

Ask Claude Code: “Find tables related to return processing confirmation.” Under the hood, search_tables runs a semantic search.

> search_tables(query: "return processing confirmation", search_type: "semantic")

5 tables found (by vector similarity):

bridge.return_packages (postgresql) (distance: 0.2557)
bridge.receive_records (postgresql) (distance: 0.2720)
cella.receive_confirmation_results (mysql) (distance: 0.2921)
bridge.receive_record_details (postgresql) (distance: 0.2951)
aircloset.return_status_change_histories (mysql) (distance: 0.3170)

A single search returns tables across three schemas (bridge, cella, aircloset). The table name “receive_records” doesn’t contain the word “return” — but the AI-generated description includes “rental return processing” and “warehouse receiving”, so it matches semantically.

Step 2: Table Detail

The second hit in bridge looks promising. Let’s get the details.

> get_table_detail(table_name: "bridge.receive_records")

# bridge.receive_records
DB: POSTGRESQL / ORM: typeorm / Repository: bridge-api

## Columns (9)
- id: int [PK, AI, NOT NULL]
- code: varchar [NOT NULL]
- shipping_order_id: varchar [NOT NULL]
- status: enum [NOT NULL, default=IN_PROGRESS]
- type: enum [NOT NULL]
- receive_datetime: varchar [NOT NULL]
- operated_by: varchar [NOT NULL]
- created_at / updated_at: datetime

## References (2)
- shipping_order_id → bridge.shipping_orders.id (explicit)
- operated_by → bridge.users.id (explicit)

## Referenced By (1)
- bridge.receive_record_details.record_id → id (explicit)

## Enum Definitions (2)
- Status: COMPLETE=Received, IN_PROGRESS=Processing
- Type: RENTAL_RETURN=Rental return, BUSINESS_RETURN=Business return,
        RENTAL_RETURN_LACK=Rental return (missing items), BUSINESS_RETURN_LACK=Business return (missing items)

status = COMPLETE means “the warehouse has finished receiving.” Exactly what we needed. Plus type = RENTAL_RETURN distinguishes rental returns from business returns. Enum definitions with human-readable labels — visible at a glance.

Step 3: Discovering the Cross-Schema Path

Now the question: how do we connect the aircloset delivery order (app side) to the bridge receive record (warehouse side)? Let’s use trace_relationships.

> trace_relationships(table_name: "bridge.shipping_orders", direction: "both", max_depth: 1)

# Relationship trace: bridge.shipping_orders
Nodes: 23, Edges: 22

## Relationships (excerpt)
- shipping_orders.shop_id → shops.id (explicit)
- shipping_orders.warehouse_id → warehouses.id (explicit)
- receive_records.shipping_order_id → shipping_orders.id (explicit)     ← warehouse confirmation!
- return_packages.shipping_order_id → shipping_orders.id (explicit)     ← return shipment
- shipping_packages.shipping_order_id → shipping_orders.id (explicit)   ← outbound shipment
- shipping_inspections.shipping_order_id → shipping_orders.id (explicit) ← inspection
...

Found the path from bridge.shipping_orders to receive_records. Next, we find the mapping table connecting aircloset and bridge.

> search_tables(query: "warehouse_mapping", search_type: "table", adjacent_depth: 1)

aircloset.warehouse_shipping_relations (mysql)

### Related Tables
  → aircloset.delivery_orders (order_id → id)
> get_table_detail(table_name: "aircloset.warehouse_shipping_relations")

## Columns (4)
- order_id: int [PK, NOT NULL]              ← aircloset delivery order ID
- warehouse_order_code: varchar [NOT NULL]   ← bridge shipping order code

Found it. order_id links to the aircloset side, warehouse_order_code links to the bridge side. No FK, but this varchar is the only key connecting two schemas.

Step 4: Querying Real Data

Now we build cross-schema queries. First, get the delivery order and warehouse code from aircloset.

> sql_query_database(database: "aircloset", sql: "SELECT ... WHERE user_id = 12345 AND status = 'RETURNED'")

**aircloset** (staging) — 1 row

| id     | status   | returned_date       | warehouse_order_code |
|--------|----------|---------------------|----------------------|
| 98765  | RETURNED | 2026-03-20 10:30:00 | SO-2026-00012345     |

> **Table**: Manages the full lifecycle of delivery orders — styling → shipping → return status tracking

### Column Descriptions
- **status**: Delivery status (1=Awaiting shipment, 2=Ready, 3=Delivered, 4=Returned, 5=Cancelled)
- **returned_date**: Date/time the warehouse received the customer's return
- **warehouse_order_code**: Mapping code to bridge shipping order

### Related Tables
- → **aircloset.users** (user_id → id): Customer profile...
- → **aircloset.plans** (plan_id → id): Subscription plan definitions...
- ← **aircloset.styling_feedbacks** (delivery_id → id): Customer feedback on styling...
- ← **aircloset.rental_items** (delivery_id → id): Items in this order...

Notice that column descriptions and related tables are automatically appended below the query result. This metadata is pulled from the graph data cached in Redis (cache-invalidated on graph updates). AI can read this enrichment to determine its next step — like “use the warehouse code to query bridge.”

Now check the warehouse side:

> sql_query_database(database: "bridge", sql: "SELECT ... WHERE code = 'SO-2026-00012345'")

**bridge** (staging) — 1 row

| code             | status  | receive_status | type          | receive_datetime    |
|------------------|---------|---------------|---------------|---------------------|
| SO-2026-00012345 | SHIPPED | COMPLETE      | RENTAL_RETURN | 2026-03-21 14:22:00 |

> **Table**: Records warehouse receiving operations — arrival confirmation and inspection status

### Column Descriptions
- **status**: Shipping order status (ORDERED→ALLOCATED→PICKED→INSPECTED→SHIPPED→CANCELED)
- **receive_status**: Receive status (IN_PROGRESS=Processing, COMPLETE=Received)
- **type**: Receive type (RENTAL_RETURN=Rental return, BUSINESS_RETURN=Business return)

### Related Tables
- → **bridge.warehouses** (warehouse_id → id): Source warehouse...
- → **bridge.shops** (shop_id → id): Source shop...
- ← **bridge.receive_record_details** (record_id → id): Individual item details...
- ← **bridge.shipping_packages** (order_id → id): Outbound package info...

receive_status = COMPLETE — the warehouse has confirmed receipt. Both the app-side return status and the warehouse-side physical confirmation are verified.

This enrichment is the key to AI-powered investigation. Claude Code reads the column descriptions and related tables to autonomously decide “what to query next” and “how to interpret these values.” No human guidance needed.

Beyond Operations: Cross-Service Analytics

This isn’t limited to operational investigations. It works for business analytics too.

Try asking Claude Code:

How many customers used our spot rental service last week, what percentage of them are airCloset monthly subscribers, and how frequently do those subscribers use the main service?

Answering this requires crossing the spot rental order table (occasiondress schema) with the main service’s member and usage tables (aircloset schema).

Claude Code uses DB Graph MCP to identify the relevant tables via search_tables, discover join keys via trace_relationships, and run queries against both databases to produce the aggregated result. Cross-service analytics from a single natural language question — that’s the core value.

Without DB Graph MCP

Imagine doing these investigations without any tooling:

Return confirmation:

  1. You need to know the delivery order table exists in aircloset
  2. You need to know about the warehouse mapping table that bridges schemas
  3. You need to know that a varchar warehouse code maps to bridge‘s shipping code
  4. You need to know that bridge‘s receive record table is the warehouse confirmation
  5. You need to know what enum values like COMPLETE and RENTAL_RETURN mean

Cross-service analytics:

  1. You need to know the spot rental DB schema name and table structure
  2. You need to know the join key to the main service’s member table
  3. You need connection credentials for both databases
  4. You need to correctly interpret member statuses and usage counts

In both cases, the required knowledge spans multiple services and schemas. Probably fewer than five people hold all of it in their heads. With DB Graph MCP, anyone can get there through natural language search → table detail → relationship tracing → live queries.

Now let’s dive into how this works.

Tool Design: 7 Tools in 3 Categories

Dictionary Tools (no DB credentials required)

Tool Purpose
search_tables Name search + vector similarity search across tables/columns
get_table_detail Full table info: columns, FKs, enums, DEAD annotations
trace_relationships BFS traversal of table relationships

Dictionary tools read pre-built graph data from BigQuery — no individual DB credentials needed. Anyone with a Google OAuth login can use them immediately, with no access request.

Query Tools (DB credentials required)

Tool Purpose
list_databases List databases you have access to
sql_query_database Execute SELECT queries against MySQL/PostgreSQL
describe_database_table Get live schema from actual DB
mongo_query_database Execute find/aggregate against DocumentDB/Atlas

Query tools use per-user credentials stored in Firestore. You only see databases you’ve been granted access to.

This separation is intentional. The dictionary is open to everyone; data access is permission-controlled. “Everyone should know what tables exist, but accessing the data requires authorization.”

Why BigQuery? — Technology Choices

We use BigQuery as the graph store. “Shouldn’t a graph DB use Neo4j?” you might ask.

We chose BigQuery because one store handles graph + vector search + analytics:

  • VECTOR_SEARCH: Store 768-dimensional embeddings and run cosine similarity search natively. No separate vector DB needed
  • Graph traversal: Node + edge table design enables BFS traversal through simple recursive JOINs
  • JSON type: JSON_SET on a properties column lets us flexibly append review data without schema changes
  • Serverless: No instance management. Pay only for queries, not idle time
  • Vertex AI integration: Gemini 3 Flash for description generation and embedding models connect seamlessly within GCP
  • Google Workspace integration: OAuth uses Google Accounts directly. Domain restriction, nickname resolution, and permission management all flow through the same identity — no separate IdP needed

A dedicated graph DB like Neo4j has superior traversal performance, but at 991 tables, BigQuery is more than sufficient. The operational simplicity of “vector search, JSON, analytics, and graph all in one place” far outweighs the performance difference.

How Natural Language Search Works

How does “return processing confirmation” find a receive records table?

Step 1: Generate Table Descriptions

The DB Dictionary Graph Builder runs daily at 6:00 AM JST, generating AI descriptions for each table using Gemini 3 Flash:

Example: bridge.receive_records
→ "Records warehouse receiving operations. Tracks rental returns
   and business returns with completion/in-progress status.
   Links to shipping orders to trace which order a return belongs to."

Step 2: Generate Embeddings

Each description is converted to a 768-dimensional vector using Vertex AI’s embedding model and stored in BigQuery.

Step 3: VECTOR_SEARCH

The user’s query is also converted to a 768-dimensional vector, then matched via BigQuery’s VECTOR_SEARCH using cosine distance:

SELECT base.qualifiedName, distance
FROM VECTOR_SEARCH(
  TABLE `project.db_graph_nodes`,
  'embedding',
  (SELECT @query_embedding AS embedding),
  top_k => 20,
  distance_type => 'COSINE'
)
WHERE base.nodeType = 'Table'
ORDER BY distance ASC

Even if “return” doesn’t appear in the table name, the AI description’s mention of “rental return processing” places it close in vector space. That’s the core of natural language search.

Building the Graph

6-Phase Pipeline

The builder runs six phases daily:

System Overview
(See the Builder section of the diagram)

① ORM Parsing — Parse 4 ORM types (TypeORM, Sequelize, Drizzle, Mongoose) across 28 repositories to extract table definitions.

② Live DB Validation — Query actual staging DBs via Lambda to compare code definitions against real schemas. Auto-exclude tables that exist in code but not in the database.

③ AI Description — Generate table/column descriptions with Gemini 3 Flash. Incremental detection regenerates only changed tables to minimize AI cost.

④ Graph Construction — Generate 4 node types (Schema/Table/Column/Enum) and 5 edge types (HAS_TABLE/HAS_COLUMN/REFERENCES/USES_ENUM/SAME_ENTITY).

⑤ Embedding Generation — Generate 768-dimensional vectors per table via Vertex AI.

⑥ BQ MERGE — Load into BigQuery using MERGE, preserving human-written descriptions and DEAD flags. Auto-generated data never overwrites manual annotations.

Relationship Confidence Levels

Foreign key detection has varying confidence:

Confidence Detection Method Reliability
explicit Directly from ORM @JoinColumn() or belongsTo() Certain
inferred Naming convention: xxx_id → xxx table High probability
manual Added by human reviewers Certain

This lets AI judge the reliability of suggested JOIN conditions before using them.

SAME_ENTITY Edges

The same logical entity sometimes exists in both SQL and MongoDB — for example, a MySQL users table and a MongoDB user statistics collection both represent the same user. SAME_ENTITY edges express these cross-engine correspondences, enabling seamless cross-database discovery.

Human Review: AI Alone Isn’t Enough

“Are AI-generated descriptions actually accurate?” Honestly — not always.

Gemini 3 Flash produces decent high-level descriptions, but 10 years of business context — “this column was migrated 3 years ago but never dropped from the schema”, “enum value 5 is actually never used” — that kind of tacit knowledge can’t be filled by AI alone.

That’s why we built human review into the system from day one.

Review Web UI

We have a dedicated review web app for the DB Dictionary.

The schema list shows review progress bars. The table list supports filtering by “unchecked”, “checked”, and “has deprecated items.”

The table detail screen displays columns with type badges, FK targets, and enum definitions — with inline editing for descriptions and deprecation flags.

Review UI — Table Detail
Review UI: FK targets and enum definitions shown as badges. Descriptions can be edited inline.

Available review actions:

Action Description
Edit table description Supplement or rewrite the AI-generated description
Edit column description Per-column annotations (“deprecated”, “use XX instead”, etc.)
Mark as DEAD Deprecation flag + reason + empty percentage, at table or column level
Mark as Checked Review completion flag — records who checked and when
Bulk DEAD marking Mark up to 500 tables/columns as deprecated at once

DEAD Flags: Surfacing 10 Years of Tacit Knowledge

After 10 years, deprecated columns accumulate. A flag that once represented member type — migrated years ago, now NULL in every row — still sits in the schema.

When a reviewer marks a column as deprecated, the MCP table detail shows:

- old_member_flag: int [NOT NULL, default=0, DEAD] ⚠ Deprecated. Use membership_status instead
- cancel_date: datetime [DEAD] ⚠ All rows NULL
- legacy_import_id: varchar [DEAD] ⚠ Legacy CSV import field. No longer used

This matters because it prevents AI from writing code that references the wrong column. When Claude Code loads table details into context and sees a DEAD flag, it knows to avoid that column.

Change Detection and Diff Review

When the daily build detects changes in table structure or AI descriptions, they’re recorded as “pending changes.” Reviewers can view before/after diffs in the web UI and mark them as reviewed.

This ensures nothing slips through — if yesterday’s build changed something, someone will see it.

Review Data Persistence

Review data is stored in Firestore and never overwritten by daily builds.

The daily build follows this sequence:

  1. ORM parsing → graph construction — Re-extract table definitions from latest code
  2. BQ MERGE — Merge while preserving human-written textForEmbedding and embedding
  3. Re-apply Firestore reviews — Write humanDescription, isDead, deadNote, checkedAt back to BQ properties

Reviews survive unlimited daily rebuild cycles. Firestore is the source of truth; BQ is its reflection.

Crossing the VPC Wall: Cross-Cloud Architecture

Now for the security design I’m most proud of.

Problem: The MCP server runs on Google Cloud (Cloud Run). The databases are inside AWS VPCs. Cloud Run can’t directly reach VPC-internal RDS/DocumentDB instances.

Solution: A three-stage authentication chain — GCP OIDC → AWS STS → VPC Lambda — enables secure cross-cloud connectivity.

Query Dataflow

Authentication Flow

1. Cloud Run (GCP) → Get OIDC token from GCP metadata server
2. OIDC token → AWS STS AssumeRoleWithWebIdentity
3. STS → Return temporary AWS credentials (1-hour TTL)
4. Temporary credentials → Invoke VPC-internal Lambda
5. Lambda → Execute query against VPC-internal RDS/DocumentDB

Key points:

  • Zero static AWS credentials. Dynamically obtained from GCP service account.
  • Temporary credentials cached for 5 minutes. Avoids per-request STS overhead.
  • Lambda executes inside VPC. DB connections never leave the VPC.
  • Production queries use Read Replicas only. Never connects to the master.

SQL Validation (Defense in Depth)

Query safety is enforced at two layers:

MCP layer (1st):

Allowed: SELECT, SHOW, DESCRIBE, DESC, EXPLAIN, WITH...SELECT
Blocked: INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE, multi-statement via semicolons

Lambda layer (2nd):
The same validation runs inside Lambda. Even if the MCP layer is somehow bypassed, Lambda blocks it.

Protecting Production Data — PII Anonymization

Querying production data is powerful, but handling personally identifiable information (PII) requires the most care.

Automatic Anonymization Rules

For production + view permission queries, PII column values are automatically anonymized:

Column Pattern Replacement
Email fields ***@***.com
Name fields ***
Phone fields ***-****-****
Postal code fields ***-****
Address fields ***
Password fields [REDACTED]
Date of birth fields ****-**-**
Card number fields [REDACTED]

Table-specific rules handle ambiguous columns. For example, a generic name column isn’t PII globally, but users.name or orders.buyer_name clearly is. These are configured per-table.

Staging vs Production

Environment PII Anonymization Connection Target
Staging None Master DB
Production (view) Auto-applied Read Replica
Production (edit) None Read Replica

Staging uses test data, so no anonymization needed. Only production view queries get automatic PII protection.

Fully Automated Access Management — DB Account Pipeline

“Who do I talk to about getting database access?”

This question doesn’t get asked anymore. The DB Account Pipeline automates everything.

Credential Flow

Flow

  1. User submits a workflow request — nickname, email, desired databases (multiple allowed)
  2. Manager approves
  3. Cloud Run Job processes automatically — reads approved requests, generates CREATE USER statements per DB, executes via Lambda
  4. Credentials saved to Firestore + Secret Manager — passwords never stored in plaintext
  5. Slack DM with connection info — includes bastion server guide

Zero Plaintext Passwords

Passwords are stored only in Secret Manager.

Firestore db_credentials:
  host: "xxx.rds.amazonaws.com"
  port: 3306
  username: "ryan_view_user"
  passwordSecretId: "db-cred-xxxxx"  ← Reference to Secret Manager only
  permLevel: "view"

When the MCP Server executes a query, it decrypts the password from Secret Manager via passwordSecretId and caches it in memory for 5 minutes. Cloud Run restarts clear the cache.

No plaintext password exists anywhere — this was a deliberate design decision we’re particularly proud of.

Operations

Daily Cron

A cron job fires at 6:00 AM JST daily, triggering a Cloud Run Job:

6:00 AM JST — Cron fires
├── ORM parsing (28 repos × 4 ORMs)
├── Live DB validation (11 staging DBs)
├── Gemini description generation (incremental only)
├── Graph construction + Embedding
├── BQ MERGE (preserving annotations)
└── Slack notification

Cost

Resource Cost
Gemini 3 Flash (daily, incremental) ~$0.10-0.20/day
Vertex AI Embedding ~$0.01/day
Cloud Run Job Near-free (once daily)
BQ Storage A few GB
Lambda Shared with DB Account Pipeline

Thanks to incremental detection, we maintain an AI-powered dictionary for 991 tables at under $10/month.

Incremental Detection

Regenerating all table descriptions daily would spike Gemini costs. So we introduced change detection:

1. Compare previous property hashes
2. Detect column structure changes (additions/removals/type changes)
3. Identify affected tables via enum dependency graph
→ Regenerate only changed tables

If a status enum changes, all tables using that enum are regenerated. No changes? Skip. This cuts AI costs by roughly 90%.

Security Summary

Layer Protection
OAuth Google Account + corporate domain restriction
Credential Resolution email → nickname → per-user DB credentials
Permission Filter Per-user × database × environment × permission level
SQL Validation (MCP) SELECT-only enforcement
SQL Validation (Lambda) Same validation (defense in depth)
PII Anonymization Production + view queries only
Production Connection Read Replicas only
Passwords Secret Manager only, 5-min TTL memory cache
Cross-Cloud Auth GCP OIDC → AWS STS (zero static credentials)
Logging Passwords and query results never logged

Takeaways

DB Graph MCP goes beyond solving the fundamental database problem of “you can’t use what you don’t know exists.” It enables anyone to search real data without knowing SQL at all.

  • As a dictionary — Search 991 tables’ structure, relationships, and enum definitions in natural language
  • As a query tool — Securely query staging and production data with automatic PII protection
  • As a knowledge base — DEAD flags and column annotations surface 10 years of tacit knowledge

The biggest lesson from building this: the real value of MCP is giving AI context. Table structure, relationships, enum definitions, column warnings — when these enter AI’s context window, the SQL and code Claude Code writes become dramatically more accurate.

Making that happen required building the graph, securing cross-cloud access, automating permission management, and protecting PII — unglamorous but essential infrastructure, built with care.

I hope this helps anyone wrestling with internal database management at scale.

I’m CTO at airCloset, a fashion rental subscription service in Japan. We’re building the future of AI-powered development. If you’re interested, check out our engineering careers page.

Top 12 Automated Test Case Generation Tools in 2026

agent B

Here’s what actually happens in most QA teams: a sprint ends, features ship, and someone still has to figure out which test cases cover the new flows and which existing ones just broke because the UI changed.
That cycle doesn’t just waste time. It’s how test coverage quietly degrades over time.

According to the Katalon State of Quality Report 2025, 55% of teams lack sufficient time for thorough testing, while 44% report high workload as a core challenge.

At the same time, automation and AI adoption are accelerating. Over 60% of teams now integrate automated testing into CI/CD pipelines, and AI-driven tools are increasingly being used to reduce the effort required for test creation and maintenance, according to reports from Testlio and PractiTest.

Tools like CoTester AI Test Agent reflect that shift, focusing not just on generating test cases but reducing the effort required to keep them updated as applications evolve.

The tools in this guide represent the sharpest end of that shift. Some are genuinely AI-native. Others are proven open-source workhorses that still belong in the conversation. All 12 are worth understanding before you make a decision.

What Automated Test Case Generation Actually Means?

Test case generation isn’t one thing. Different tools generate tests in very different ways, and that difference directly impacts how useful (or painful) they are in real projects.
Some approaches focus on generating tests from requirements. Others analyze the application itself. Some optimize for coverage, while others prioritize speed and ease of use.
Here’s how the main approaches break down:

Technique How It Works When to Use It
NLP / LLM-Based Generation Parses user stories or requirements and writes executable test steps Agile teams using Jira, Confluence, or plain documentation
Vision-Language Model (VLM) Interprets the live UI visually and contextually like a human tester UI-heavy applications with frequent changes
Model-Based Testing Builds a behavioral model of the app and generates test scenarios Complex workflows with multiple branching paths
Data-Driven Generation Uses varied inputs systematically to expand test coverage Forms, APIs, and input-sensitive functionalities
Search-Based (Genetic) Testing Uses algorithms to optimize test coverage Unit testing and coverage-focused projects
Record-and-Play + AI Repair Records actions and uses AI to maintain scripts as UI evolves Teams new to automation needing quick setup

No single approach is “best.” The right one depends on what problem you’re actually trying to solve.

Top Automated Test Case Generation Tools

1. CoTester by TestGrid

What it is: An AI-driven test generation and execution platform built for complex applications.
Most tools generate test scripts. CoTester AI Test Agent focuses on generating and executing tests by combining natural language input with a visual understanding of the application.
Instead of relying only on DOM-level selectors, it uses a vision-based approach to interpret UI elements and workflows. That makes it more resilient to UI changes compared to traditional script-heavy tools.
Where it stands out is during execution. Its self-healing capability adapts to tests when UI elements change, reducing manual maintenance in many common scenarios.
It also supports multiple usage modes:

  • No-code for business users
  • Low-code for QA teams
  • Full-code flexibility for engineers
    For teams working in regulated environments, deployment options (cloud, private cloud, on-prem) and data isolation become important—and CoTester supports all three.
    Where it’s not a fit: Overkill for small teams with simple apps and infrequent releases.
    Best for: Enterprise teams dealing with complex workflows, frequent UI changes, and mixed-skill contributors.
    Pricing:

  • Starter: Starts at ~$199 per user/month (minimum seats apply)

  • Growth / Enterprise: Custom pricing based on scale, integrations, and deployment model

2. Katalon Studio

What it is: A multi-purpose automation platform covering web, mobile, API, and desktop testing.
Katalon is popular because it doesn’t force teams into a single approach. You can generate, execute, and manage tests across different layers without stitching together multiple tools.
Its AI features—like smart locators and test suggestions—help reduce maintenance, though they’re not as advanced as newer AI-native platforms.
Best for: Teams that want a single tool for multiple testing types without building a custom stack.
Pricing:

  • Free tier available
  • Paid plans start from ~$69/month (node-locked license)
  • Enterprise / floating licenses priced annually (~$1,500+/year depending on usage)

3. mabl

What it is: A low-code platform focused on self-healing and ease of use.
mabl is built for teams that don’t want to spend time maintaining test scripts. Tests can be created in plain language, and its auto-healing handles common UI changes well.
It’s strong for web and API flows, but mobile support is still limited.
Best for: Product and QA teams prioritizing speed and low maintenance over deep customization.
Pricing:

  • Custom pricing based on test volume and usage

4. Tricentis Tosca

What it is: A model-based testing platform designed for enterprise environments.
Tosca is widely used in industries where traceability and compliance matter. It generates test cases from application models and links them directly to requirements.
Recent updates include AI-assisted test creation and visual automation features, but the core strength is still model-based testing.

Best for: Enterprises with complex systems (SAP, Salesforce) and strict audit requirements.
Pricing:

  • Enterprise licensing only
  • Custom pricing based on users, modules, and integrations

5. Testim

What it is: A machine learning-based web testing tool focused on stability.
Testim reduces test breakage by generating smarter element locators based on patterns, not just static attributes.
It allows both low-code and code-based customization, which helps teams scale without losing control.
Best for: Teams struggling with flaky UI tests and frequent frontend changes.
Pricing:

  • Starts around ~$450/month
  • Scales based on the number of tests and parallel executions
    Free trial available

6. Functionize

What it is: A cloud-based AI testing platform that generates tests from plain English inputs.
Functionize is built for speed. You describe what needs to be tested, and it generates executable tests that can run at scale on its cloud infrastructure.
The tradeoff is flexibility—it’s less suited for highly customized or complex logic.
Best for: Teams needing fast test coverage expansion without scaling QA headcount.
Pricing:

  • Custom quotes based on usage, test volume, and infrastructure needs

7. QA Wolf

What it is: A hybrid model combining automation tooling with a managed QA service.
QA Wolf doesn’t just give you tools—it helps build and maintain your test suite. This reduces internal effort but comes at a higher cost.
It’s built on Playwright and focuses primarily on web testing.
Best for: Teams that want reliable test coverage without building a full QA automation team in-house.
Pricing:

  • Custom pricing (includes platform + managed QA service)
  • Typically higher than pure tooling due to the service component

8. Applitools

What it is: A visual testing platform powered by AI.
Applitools doesn’t generate test cases. Instead, it validates the visual correctness of your application across browsers and devices.
It integrates with tools like Selenium, Playwright, and Cypress to enhance existing tests with visual validation.
Best for: Teams where UI consistency is critical.
Pricing:

  • Free tier available (limited usage)
  • Paid plans based on the number of checkpoints, tests, and users
  • Enterprise pricing for large-scale usage

9. EvoSuite

What it is: An open-source tool for automated Java unit test generation.
EvoSuite uses search-based techniques (genetic algorithms) to generate test cases that maximize code coverage.
It’s highly effective within its scope—but that scope is limited to Java unit testing.
Best for: Java teams looking to improve coverage without manual test writing.
Pricing:

  • Open source (free)

10. Diffblue Cover

What it is: An AI-powered unit test generator for Java, built for CI/CD integration.
Diffblue automatically generates unit tests as part of the development pipeline. Every code change can trigger new test generation.
It’s more production-ready than research tools like EvoSuite, but still focused strictly on Java.
Best for: Dev teams that want automated unit test generation integrated into their pipeline.
Pricing:
Community Edition: Free
Enterprise: Custom pricing based on team size and CI/CD integration

11. Selenium

What it is: A foundational web automation framework.
Selenium doesn’t generate test cases, but many tools generate tests for Selenium.
It gives full control, but also comes with setup and maintenance overhead. Newer tools like Playwright and Cypress have simplified parts of this workflow, but Selenium is still widely used.
Best for: Teams that want full control or need a base layer for custom frameworks.
Pricing:

  • Open source (free)
  • Infrastructure and maintenance costs depend on implementation

12. Cucumber

What it is: A BDD framework that turns plain English scenarios into executable tests.
Cucumber enables teams to define tests using Gherkin syntax (Given/When/Then), aligning business requirements with test cases.
It’s powerful when used correctly, but requires discipline across teams.
Best for: Teams practicing BDD with strong collaboration between product, QA, and engineering.
Pricing:

  • Open source (free)
  • Paid options available via CucumberStudio / enterprise integrations

How to Pick the Automated Test Case Generation Tool

  • Don’t start by comparing features. Start with the actual problem:
  • Are you spending too much time writing test cases?
  • Are your tests breaking constantly?
  • Is coverage too low?
  • Or is maintenance the real bottleneck?

Once that’s clear, evaluate tools based on what actually affects your workflow:

  1. Ease of Adoption: If your team needs weeks of training, the tool will slow you down instead of helping. Prioritize tools your team can start using immediately.
  2. Integration with Your Stack: A tool that doesn’t plug cleanly into your CI/CD pipeline will create friction. Make sure it works seamlessly with your existing development and testing ecosystem.
  3. Support for Your Application Type: Web, mobile, APIs, or enterprise apps—your tool must align with what you’re testing. Cross-platform support matters only if you actually need it.
  4. Test Generation Accuracy (AI Capabilities): AI features should reduce manual effort and improve coverage not just generate noisy or redundant test cases.
  5. Scalability and Maintenance Effort: The real cost isn’t creating tests, it’s maintaining them. Choose a tool that minimizes test breakage and ongoing upkeep.
    Tools that combine AI-driven test generation, strong CI/CD integration, and reliable cross-platform support can significantly reduce manual effort and improve release speed, but only if they align with your actual testing bottlenecks.

Final Take

There’s a clear shift happening: teams are moving away from manually writing and maintaining large test suites toward tools that generate and adapt tests automatically.

But most tools don’t eliminate effort; they just move it around.

The ones worth investing in are the ones that:

  • Reduce maintenance
  • Improve coverage without adding noise
  • Fit into your existing workflow

If you’re dealing with complex systems and frequent changes, AI-driven tools like CoTester represent where the space is heading.

If you’re earlier in the journey, tools like Katalon or mabl give you a more gradual path into automation.
Either way, the tools aren’t the bottleneck anymore.
Implementation is.

Stop Searching Your Tabs: Auto-Rename Terminator Tabs with Neovim & Zsh

If you’re like me, you usually have ten different terminal tabs open: one for the server, one for Neovim, a folder, one for the database, and maybe a few others for “vibe coding” sessions.

The problem? Terminator (and most emulators) defaults to showing the process name like zsh or nvim. It’s a nightmare to find the right project!

Here is how I configured my Linux setup to automatically show the Folder Name in the tab whenever I run nvim . or move between projects.

The Goal

When I’m in /home/user/projects/project_name and I hit nvim ., I want my tab to say project_name, not nvim.

Step 1: Force Neovim to Talk to Your Terminal

Neovim is powerful enough to send “escape sequences” to your terminal emulator. We want it to set the titlestring to our current folder name on startup.

Open your Neovim config (e.g., init.lua or your custom config) and add this:

-- 1. Enable title support
vim.opt.title = true

-- 2. Create a function to grab the folder name and set the title
vim.api.nvim_create_autocmd({"VimEnter", "DirChanged"}, {
  callback = function()
    -- This gets the "tail" of the current working directory (the folder name)
    local folder_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
    vim.opt.titlestring = folder_name
  end,
})

-- 3. Reset the title when you quit Neovim
vim.api.nvim_create_autocmd("VimLeave", {
  callback = function()
    vim.opt.titlestring = "" 
  end,
})

Step 2: Fix Your Shell (Zsh)

What if you aren’t in Neovim? You still want your tabs to be labeled correctly. Add this “hook” to your ~/.zshrc:

# Auto-rename tab to current folder name
function chpwd() {
  # This escape sequence e]2; sets the window/tab title
  # ${PWD##*/} is a Zsh shortcut to get just the current folder name
  print -Pn "e]2;${PWD##*/}a"
}

# Set the title immediately when you open a new terminal
print -Pn "e]2;${PWD##*/}a"

Reload with source ~/.zshrc and you’re good to go!

Step 3: Check Your Terminator Preferences

If it’s still not working, Terminator might be overriding your titles.

  1. Right-click in Terminator > Preferences.
  2. Go to Profiles > General.
  3. Ensure “Show terminal title” is checked.
  4. Set “Title Bar” to “Initial Title” or ensure it isn’t set to a static string like “Terminal.”

How a request originates from client and reaches the server ?

When a user interacts with the internet a series of steps take place behind the scenes to ensure the request reaches the correct server and a response is returned. It involves identifying the server using an IP address, resolving domain names through DNS, routing the request across networks to efficiently handle traffic. Understanding how a request originates from the client and reaches the server requires breaking down each of these components and how they work together in the request response cycle.

User-Response Cycle:

User initiates request
The process starts when the user enters a URL like www.wikipedia.org in the browser.

Browser checks local cache
The system first checks:

  • Browser cache
  • OS cache
    If the IP is already known, it skips DNS lookup.

DNS query is initiated
If not found, a DNS query is triggered to find the IP address of the domain.

Local resolver (sub-resolver)
The request first goes to the local machine’s resolver which handles DNS queries.

Request goes to ISP resolver
The query is forwarded to the ISP DNS resolver.

Root Name Server
The ISP resolver contacts the Root Name Server, which doesn’t give the exact IP but directs to the correct TLD server (Top Level Domain).

TLD (Top Level Domain) server
Based on .org, .com, .in, etc., the request is sent to the respective TLD server.

Zone File
This server contains the actual records or zone file:

  • A record – IPv4 address
  • AAAA record – IPv6 address
  • CNAME – alias
  • MX – mail

It returns the correct IP address.

IP returned to client
The IP travels back:

NS – TLD – ISP – local resolver – browser

HTTP request sent
The browser sends an HTTP request to the server.

Server processes request
The backend server processes logic and fetches data.

Response sent back
The server sends an HTTP response.

Browser shows content
The browser receives the response and displays the webpage.

30 Years Ago, Robots Learned to Walk Without Falling

When you hear the term humanoid robot, you may think of C-3PO, the human-cyborg-relations android from Star Wars. C-3PO was designed to assist humans in communicating with robots and alien species. The droid, which first appeared on screen in 1977, joined the characters on their adventures, walking, talking, and interacting with the environment like a human. It was ahead of its time.

Before the release of Star Wars, a few androids did exist and could move and interact with their environment, but none could do so without losing its balance.

It wasn’t until 1996 that the first autonomous robot capable of walking without falling was developed in Japan. Honda’s Prototype 2 (P2) was nearly 183 centimeters tall and weighed 210 kilograms. It could control its posture to maintain balance, and it could move multiple joints simultaneously.

In recognition of that decades-old feat, P2 has been honored as an IEEE Milestone. The dedication ceremony is scheduled for 28 April at the Honda Collection Hall, located on the grounds of the Mobility Resort Motegi, in Japan. The machine is on display in the hall’s robotics exhibit, which showcases the evolution of Honda’s humanoid technology.

In support of the Milestone nomination, members of the IEEE Nagoya (Japan) Section wrote: “This milestone demonstrated the feasibility of humanlike locomotion in machines, setting a new standard in robotics.” The Milestone proposal is available on the Engineering Technology and History Wiki.

Developing a domestic android

In 1986 Honda researchers Kazuo Hirai, Masato Hirose, Yuji Haikawa, and Toru Takenaka set out to develop what they called a “domestic robot” to collaborate with humans. It would be able to climb stairs, remove impediments in its path, and tighten a nut with a wrench, according to their research paper on the project.

“We believe that a robot working within a household is the type of robot that consumers may find useful,” the authors wrote.

But to create a machine that would do household chores, it had to be able to move around obstacles such as furniture, stairs, and doorways. It needed to autonomously walk and read its environment like a human, according to the researchers.

But no robot could do that at the time. The closest technologists got was the WABOT-1. Built in 1973 at Waseda University, in Tokyo, the WABOT had eyes and ears, could speak Japanese, and used tactile sensors embedded on its hands as it gripped and moved objects. Although the WABOT could walk, albeit unsteadily, it couldn’t maneuver around obstacles or maintain its balance. It was powered by an external battery and computer.

To build an android, the Honda team began by analyzing how people move, using themselves as models.

That led to specifications for the robot that gave it humanlike dimensions, including the location of the leg joints and how far the legs could rotate.

Once they began building the machine, though, the engineers found it difficult to satisfy every specification. Adjustments were made to the number of joints in the robot’s hips, knees, and ankles, according to the research paper. Humans have four hip, two knee, and three ankle joints; P2’s predecessor had three hip, one knee, and two ankle joints. The arms were treated similarly. A human’s four shoulder and three elbow joints became three shoulder joints and one elbow joint in the robot.

The researchers installed existing Honda motors and hydraulics in the hips, knees, and ankles to enable the robot to walk. Each joint was operated by a DC motor with a harmonic-drive reduction gear system, which is compact and offered high torque capacity.

To test their ideas, the engineers built what they called E0. The robot, which was just a pair of connected legs, successfully walked. It took about 15 seconds to take each step, however, and it moved using static walking in a straight line, according to a post about the project on Honda’s website. (Static walking is when the body’s center of mass is always within the foot’s sole. Humans walk with their center of mass below their navel.)

The researchers created several algorithms to enable the robot to walk like a human, according to the Honda website. The codes allowed the robot to use a locomotion mechanism, dynamic walking, whereby the robot stays upright by constantly moving and adjusting its balance, rather than keeping its center of mass over its feet, according to a video on the YouTube channel Everything About Robotics Explained.

“P2 was not just a technical achievement; it was a catalyst that propelled the field of humanoid robotics forward, demonstrating the potential for robots to interact with and assist humans in meaningful ways.” —IEEE Nagoya Section

The Honda team installed rubber brushes on the bottom of the machine’s feet to reduce vibrations from the landing impacts (the force experienced when its feet touch the ground)—which had made the robot lose its balance.

Between 1987 and 1991, three more prototypes (E1, E2, and E3) were built, each testing a new algorithm. E3 was a success.

With the dynamic walking mechanism complete, the researchers continued their quest to make the robot stable. The team added 6-axis sensors to detect the force at which the ground pushed back against the robot’s feet and the movements of each foot and ankle, allowing the robot to adjust its gait in real time for stability.

The team also developed a posture-stabilizing control system to help the robot stay upright. A local controller directed how the electric motor actuators needed to move so the robot could follow the leg joint angles when walking, according to the research paper.

During the next three years, the team tested the systems and built three more prototypes (E4, E5, and E6), which had boxlike torsos atop the legs.

In 1993 the team was finally ready to build an android with arms and a head that looked more like C-3PO, dubbed Prototype 1 (P1). Because the machine was meant to help people at home, the researchers determined its height and limb proportions based on the typical measurements of doorways and stairs. The arm length was based on the ability of the robot to pick up an object when squatting.

When they finished building P1, it was 191.5 cm tall, weighed 175 kg, and used an external power source and computer. It could turn a switch on and off, grab a doorknob, and carry a 70 kg object.

P1 was not launched publicly but instead used to conduct research on how to further improve the design. The engineers looked at how to install an internal power source and computer, for example, as well as how to coordinate the movement of the arms and legs, according to Honda.

For P2, four video cameras were installed in its head—two for vision processing and the other two for remote operation. The head was 60 cm wide and connected to the torso, which was 75.6 cm deep.

A computer with four microSparc II processors running a real-time operating system was added into the robot’s torso. The processors were used to control the arms, legs, joints, and vision-processing cameras.

Also within the body were DC servo amplifiers, a 20-kg nickel-zinc battery, and a wireless Ethernet modem, according to the research paper. The battery lasted for about 15 minutes; the machine also could be charged by an external power supply.

The hardware was enclosed in white-and-gray casing.

P2, which was launched publicly in 1996, could walk freely, climb up and down stairs, push carts, and perform some actions wirelessly.

P2, which was launched publicly in 1996, could walk freely, climb up and down stairs, push carts, and perform some actions wirelessly.King Rose Archives

The following year, Honda’s engineers released the smaller and lighter P3. It was 160 cm tall and weighed 130 kg.

In 2000 the popular ASIMO robot was introduced. Although shorter than its predecessors at 130 cm, it could walk, run, climb stairs, and recognize voices and faces. The most recent version was released in 2011. Honda has retired the robot.

Honda P2’s influence

Thanks to P2, today’s androids are not just ideas in a laboratory. Robots have been deployed to work in factories and, increasingly, at home.

The machines are even being used for entertainment. During this year’s Spring Festival gala in Beijing, machines developed by Chinese startups Unitree Robotics, Galbot, Noetix, and MagicLab performed synchronized dances, martial arts, and backflips alongside human performers.

“P2’s development shifted the focus of robotics from industrial applications to human-centric designs,” the Milestone sponsors explained in the wiki entry. “It inspired subsequent advancements in humanoid robots and influenced research in fields like biomechanics and artificial intelligence.

“It was not just a technical achievement; it was a catalyst that propelled the field of humanoid robotics forward, demonstrating the potential for robots to interact with and assist humans in meaningful ways.”

To learn more about robots, check out IEEE Spectrum’s guide.

Recognition as an IEEE Milestone

A plaque recognizing Honda’s P2 robot as an IEEE Milestone is to be installed at the Honda Collection Hall. The plaque is to read:

In 1996 Prototype 2 (P2), a self-contained autonomous bipedal humanoid robot capable of stable dynamic walking and stair-climbing, was introduced by Honda. Its legged robotics incorporated real-time posture control, dynamic balance, gait generation, and multijoint coordination. Honda’s mechatronics and control algorithms set technical benchmarks in mobility, autonomy, and human-robot interaction. P2 inspired new research in humanoid robot development, leading to increasingly sophisticated successors.

Administered by the IEEE History Center and supported by donors, the Milestone program recognizes outstanding technical developments around the world.