Text2SQL MCP Server
Converts natural language questions into SQL queries and executes them against SQLite databases, returning results as tables or strings.
README
Text2SQL MCP Server - Natural Language Database Queries
Convert natural language questions into SQL queries and execute them against SQLite database. Get results in table or string format.
Overview
Text2SQL is an MCP (Model Context Protocol) server that enables natural language querying of SQLite databases. Ask questions in plain English and get results formatted as tables or strings. Perfect for data analysis, reporting, and exploration without writing SQL.
Key Capabilities:
- Convert natural language to SQL automatically
- Support for COUNT, SELECT, AVG, SUM operations
- Smart condition parsing (age, price, category, rating, stock)
- Multiple result formats (string for single values, table for multiple rows)
- Works seamlessly with Kiro and Cline
- 9 comprehensive unit tests included
Quick Start (5 minutes)
# 1. Populate database with sample data
python populate_kinto_db.py
# 2. Run example client
python src/text2sql_example.py
# 3. Try questions like:
# "How many users do I have?"
# "Show me top 2 users aged above 70"
# "What is the average product price?"
Setup with Kiro
./setup_mcp.sh
# Restart Kiro
Then ask questions naturally:
"How many users do I have?"
"Show me top 2 users aged above 70"
"What is the average product price?"
"Show me products in Electronics category"
Setup with Cline
./setup_cline.sh
# Restart VSCode
Use the same natural language queries in Cline.
Query Examples
| Question | Answer |
|---|---|
| "How many users do I have?" | 50 |
| "Show me top 2 users aged above 70" | [Table with 2 rows] |
| "What is the average product price?" | 125.50 |
| "Show me products in Electronics category" | [Table with products] |
| "How many orders have been placed?" | 100 |
Database Schema
| Table | Columns |
|---|---|
| users | id, name, email, age, created_at |
| products | id, name, price, stock, category |
| orders | id, user_id, product_id, quantity, order_date |
| reviews | id, product_id, user_id, rating, comment, review_date |
| inventory | id, product_id, warehouse_location, quantity_available, last_updated |
Supported Query Types
- Count: "How many users?" → SELECT COUNT(*) FROM users
- Select: "Show me users" → SELECT * FROM users
- Conditional: "Users aged above 70" → SELECT * FROM users WHERE age > 70
- Limit: "Top 5 users" → SELECT * FROM users LIMIT 5
- Aggregate: "Average price?" → SELECT AVG(price) FROM products
Supported Conditions
- Age: "above 70", "over 70", "> 70", "below 30"
- Price: "above 100", "below 50"
- Category: "Electronics", "Books", etc.
- Rating: "above 4", "over 4"
- Stock: "above 100"
MCP Tools
query_database
Convert natural language to SQL and execute.
{"question": "How many users do I have?"}
get_database_schema
Get database schema information.
execute_sql
Execute raw SQL (advanced users).
{"sql": "SELECT * FROM users WHERE age > 70 LIMIT 5"}
Python Usage
from text2sql import Text2SQL
text2sql = Text2SQL(db_path="kinto.db")
result = text2sql.query("How many users do I have?")
if result.success:
print(f"SQL: {result.query}")
print(f"Answer: {text2sql.format_result(result)}")
Installation
Option 1: Manual installation
pip install -r requirements.txt
Option 2: Using Docker
docker-compose up -d
# or
make docker-build
make docker-run
Option 3: Using Makefile
make install # Install dependencies
make run # Run servers
make example # Run example client
make test # Run tests
make help # Show all commands
Testing
Quick Test
# Run the example client with pre-defined queries
python src/text2sql_example.py
This will show you example queries and their results, then enter interactive mode where you can ask your own questions.
Unit Tests
# Run all unit tests (9 test cases)
make test-text2sql
Or directly:
python -m unittest src.test_text2sql -v
Manual Testing with Kiro
- Run setup:
./setup_mcp.sh
-
Restart Kiro
-
Ask questions naturally:
"How many users do I have?"
"Show me top 2 users aged above 70"
"What is the average product price?"
Manual Testing with Cline
- Run setup:
./setup_cline.sh
-
Restart VSCode
-
Use Cline with same questions
Python Testing
from text2sql import Text2SQL
text2sql = Text2SQL(db_path="kinto.db")
# Test a query
result = text2sql.query("How many users do I have?")
print(f"Success: {result.success}")
print(f"SQL: {result.query}")
print(f"Answer: {text2sql.format_result(result)}")
Check Database
# Verify database exists and has data
python -c "import sqlite3; conn = sqlite3.connect('kinto.db'); print('Users:', conn.execute('SELECT COUNT(*) FROM users').fetchone()[0])"
File Structure
src/
├── text2sql.py # Core module (400+ lines)
├── text2sql_server.py # MCP server
├── text2sql_example.py # Example client
└── test_text2sql.py # Unit tests (9 tests)
mcp_text2sql_config.json # MCP configuration
kinto.db # SQLite database
How It Works
- Parse natural language query
- Extract conditions (age, price, category, etc.)
- Generate SQL query
- Execute against SQLite database
- Format results (string or table)
Result Formats
String Format (single values):
Answer: 50
Table Format (multiple rows):
id | name | email | age
───────────────────────────────────
1 | Alice | alice@example.com | 75
2 | Bob | bob@example.com | 72
Troubleshooting
| Issue | Solution |
|---|---|
| Module not found | pip install -r requirements.txt |
| Database not found | python populate_kinto_db.py |
| Query not recognized | Try rephrasing: "Show me users aged above 70" |
| No results | Check table name and condition values |
| SQL error | Use execute_sql tool to debug |
Logs
Server logs: logs/text2sql_server.log
Performance
- Query parsing: < 1ms
- SQL execution: < 10ms (typical)
- Total response: < 20ms (typical)
Features
✅ Natural language queries
✅ Automatic SQL generation
✅ Multiple result formats
✅ Smart condition parsing
✅ Aggregate functions (COUNT, AVG, SUM)
✅ Kiro/Cline integration
✅ SQLite database support
✅ 9 comprehensive unit tests
Limitations
- Pattern-based parsing (not AI-powered)
- Supports SELECT, COUNT, AVG, SUM operations
- Complex JOINs not automatically generated
- Use
execute_sqltool for complex queries
Future Enhancements
- [ ] LLM-based query generation
- [ ] Support for JOIN operations
- [ ] INSERT/UPDATE/DELETE operations
- [ ] Query optimization suggestions
- [ ] Result caching
- [ ] Multi-language support
Architecture
System Flow
User Question
↓
Parse Query Type (count/select/aggregate/limit)
↓
Extract Conditions (age, price, category, etc.)
↓
Generate SQL Query
↓
Execute Against SQLite
↓
Format Results (string or table)
↓
Return Answer
Component Structure
text2sql_server.py (MCP Server)
├── query_database tool
├── get_database_schema tool
└── execute_sql tool
↓
text2sql.py (Core Module)
├── Query Parsing
├── Condition Extraction
├── SQL Generation
└── Result Formatting
↓
SQLite Database (kinto.db)
├── users (50 rows)
├── products (30 rows)
├── orders (100 rows)
├── reviews (75 rows)
└── inventory (30 rows)
Detailed Query Examples
Sample Questions
1. How many users do I have?
2. Show me top 5 products with price above 100
3. What is the average rating for all reviews?
4. Show me users aged above 70
5. How many orders have been placed in Electronics category?
6. What is the average product price?
7. Show me all products in Electronics category
8. How many reviews have rating above 4?
9. Show me top 10 users
10. What is the total stock available?
11. Show me products with stock below 20
12. How many products are in Books category?
13. What is the average age of users?
14. Show me orders with quantity above 5
15. How many inventory records do we have?
16. Show me top 3 products with highest price
17. What is the sum of all product prices?
18. Show me users aged below 30
19. How many products have price above 200?
20. Show me reviews with rating below 3
21. What is the average order quantity?
22. Show me products in Warehouse A location
23. How many users were created this year?
24. Show me top 5 most expensive products
25. What is the total quantity available in inventory?
Count Queries
Q: "How many users do I have?"
SQL: SELECT COUNT(*) as count FROM users
A: 50
Q: "How many products are in stock?"
SQL: SELECT COUNT(*) as count FROM products
A: 30
Select Queries
Q: "Show me all users"
SQL: SELECT * FROM users
A: [Table with all 50 users]
Q: "Get products"
SQL: SELECT * FROM products
A: [Table with all 30 products]
Conditional Queries
Q: "Show me users aged above 70"
SQL: SELECT * FROM users WHERE age > 70
A: [Table with users over 70]
Q: "Products with price below 50"
SQL: SELECT * FROM products WHERE price < 50
A: [Table with affordable products]
Q: "Show me products in Electronics category"
SQL: SELECT * FROM products WHERE category = 'Electronics'
A: [Table with Electronics products]
Limit Queries
Q: "Show me top 2 users"
SQL: SELECT * FROM users LIMIT 2
A: [Table with first 2 users]
Q: "Top 5 products"
SQL: SELECT * FROM products LIMIT 5
A: [Table with first 5 products]
Combined Queries
Q: "Show me top 2 users aged above 70"
SQL: SELECT * FROM users WHERE age > 70 LIMIT 2
A: [Table with 2 users over 70]
Q: "Top 10 products in Electronics with stock above 20"
SQL: SELECT * FROM products WHERE category = 'Electronics' AND stock > 20 LIMIT 10
A: [Table with matching products]
Aggregate Queries
Q: "What is the average product price?"
SQL: SELECT AVG(price) as result FROM products
A: 125.50
Q: "What is the total stock?"
SQL: SELECT SUM(stock) as result FROM products
A: 5000
Q: "Average user age?"
SQL: SELECT AVG(age) as result FROM users
A: 52.3
Advanced Usage
Using with Python
from text2sql import Text2SQL
# Initialize
text2sql = Text2SQL(db_path="kinto.db")
# Simple query
result = text2sql.query("How many users do I have?")
# Check result
if result.success:
print(f"Generated SQL: {result.query}")
print(f"Raw Data: {result.data}")
print(f"Formatted: {text2sql.format_result(result)}")
else:
print(f"Error: {result.message}")
# Access result data directly
for row in result.data:
print(row)
Using with MCP Client
import json
from mcp.client import Client
client = Client()
# Query database
response = client.use_tool(
"text2sql-mcp-server",
"query_database",
{"question": "How many users do I have?"}
)
# Get schema
schema = client.use_tool(
"text2sql-mcp-server",
"get_database_schema",
{}
)
# Execute raw SQL
result = client.use_tool(
"text2sql-mcp-server",
"execute_sql",
{"sql": "SELECT * FROM users WHERE age > 70 LIMIT 5"}
)
Custom Database
To use with your own database:
from text2sql import Text2SQL
# Point to your database
text2sql = Text2SQL(db_path="path/to/your/database.db")
# Query as normal
result = text2sql.query("Your question here")
Configuration
MCP Server Configuration
The MCP server is configured in mcp_text2sql_config.json:
{
"mcpServers": {
"text2sql-mcp-server": {
"command": "python",
"args": ["src/text2sql_server.py"],
"env": {
"PYTHONUNBUFFERED": "1"
},
"disabled": false,
"autoApprove": [
"query_database",
"get_database_schema",
"execute_sql"
]
}
}
}
Database Configuration
Default database: kinto.db
To use a different database, modify src/text2sql_server.py:
# Change this line:
text2sql = Text2SQL(db_path="kinto.db")
# To:
text2sql = Text2SQL(db_path="path/to/your/database.db")
Logging Configuration
Logs are written to logs/text2sql_server.log
To change log level in src/text2sql_server.py:
logging.basicConfig(
level=logging.DEBUG, # Change to DEBUG for verbose logging
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/text2sql_server.log'),
logging.StreamHandler()
]
)
Query Pattern Reference
Query Type Detection
| Pattern | Type | Example |
|---|---|---|
| "How many", "Count", "Total" | Count | "How many users?" |
| "Show", "Get", "List", "Find" | Select | "Show me users" |
| "Average", "Avg", "Sum" | Aggregate | "Average price?" |
| "Top", "First", "Limit" | Limit | "Top 5 users" |
| "Aged", "Priced", "Category" | Conditional | "Users aged above 70" |
Condition Patterns
| Condition | Patterns | Example |
|---|---|---|
| Age | above, over, >, below, under, < | "aged above 70" |
| Price | above, over, >, below, under, < | "price below 50" |
| Category | category name | "Electronics category" |
| Rating | above, over, > | "rating above 4" |
| Stock | above, over, > | "stock above 100" |
Real-World Scenarios
Scenario 1: Customer Analysis
Q: "How many customers are over 70 years old?"
A: 8
Q: "Show me top 5 oldest customers"
A: [Table with oldest customers]
Q: "What is the average age of our customers?"
A: 52.3
Scenario 2: Product Management
Q: "How many products do we have?"
A: 30
Q: "What is the average product price?"
A: 125.50
Q: "Show me products in Electronics category"
A: [Table with Electronics products]
Q: "How many products have stock above 50?"
A: 15
Scenario 3: Order Analysis
Q: "How many orders have been placed?"
A: 100
Q: "What is the average order quantity?"
A: 4.5
Q: "Show me top 10 orders"
A: [Table with top 10 orders]
Scenario 4: Inventory Management
Q: "What is the total quantity available?"
A: 8500
Q: "Show me inventory in Warehouse A"
A: [Table with Warehouse A inventory]
Q: "How many inventory records do we have?"
A: 30
Troubleshooting Guide
Issue: "Module not found" error
Cause: Dependencies not installed
Solution:
pip install -r requirements.txt
Issue: "Database file not found"
Cause: kinto.db doesn't exist
Solution:
python populate_kinto_db.py
Issue: Query not recognized
Cause: Query phrasing doesn't match patterns
Solution: Try rephrasing:
- ❌ "Give me users over 70"
- ✅ "Show me users aged above 70"
Issue: No results found
Cause: Condition values don't match data
Solution:
- Check table name is correct
- Verify condition values exist in database
- Try simpler query first
Issue: SQL execution error
Cause: Generated SQL is invalid
Solution:
- Check the generated SQL query in output
- Use
execute_sqltool to debug - Verify database file exists and is readable
Issue: Kiro doesn't recognize Text2SQL server
Cause: MCP configuration not loaded
Solution:
- Verify
mcp_text2sql_config.jsonexists - Check MCP configuration in Kiro settings
- Restart Kiro
- Check logs:
logs/text2sql_server.log
Issue: Unexpected query results
Cause: Query parsed differently than expected
Solution:
- Check the generated SQL query
- Use
execute_sqltool to test SQL directly - Verify database schema with
get_database_schema
Performance Characteristics
Query Execution Timeline
| Step | Time |
|---|---|
| Parse query | < 1ms |
| Extract conditions | < 1ms |
| Generate SQL | < 1ms |
| Execute SQL | < 10ms (typical) |
| Format results | < 5ms |
| Total | < 20ms (typical) |
Scalability
- Supports databases with thousands of rows
- Efficient pattern-based parsing
- No external API calls required
- Minimal memory footprint
Security Considerations
Input Validation
- Query pattern matching prevents invalid SQL
- Parameterized queries prevent SQL injection
- Safe error messages don't expose database details
Database Access
- Read-only operations by default
- Optional raw SQL execution with
execute_sqltool - Audit trail via logging
Best Practices
- Use
query_databasefor user-facing queries - Use
execute_sqlonly for trusted queries - Monitor logs for suspicious activity
- Restrict database file permissions
Development
Project Structure
Text2SQL/
├── src/
│ ├── __init__.py
│ ├── text2sql.py # Core module
│ ├── text2sql_server.py # MCP server
│ ├── text2sql_example.py # Example client
│ └── test_text2sql.py # Unit tests
├── logs/
│ └── text2sql_server.log # Server logs
├── kinto.db # SQLite database
├── mcp_text2sql_config.json # MCP config
├── populate_kinto_db.py # Database setup
├── README.md # This file
├── Makefile # Build commands
├── requirements.txt # Dependencies
└── setup.py # Package setup
Running Tests
# Run all tests
make test
# Run specific test
python -m unittest src.test_text2sql.TestText2SQL.test_count_query -v
# Run with coverage
python -m coverage run -m unittest src.test_text2sql
python -m coverage report
Test Coverage
The project includes 9 comprehensive unit tests:
test_count_query- Count queriestest_select_query- Select queriestest_age_condition- Age condition parsingtest_category_condition- Category condition parsingtest_limit_query- Limit queriestest_average_query- Average queriestest_format_result_string- String formattingtest_format_result_table- Table formattingtest_invalid_query- Error handling
Adding New Query Types
To add support for new query types:
- Add pattern detection in
_parse_query()method - Create parsing method (e.g.,
_parse_custom_query()) - Add condition extraction if needed
- Add unit tests
- Update documentation
Example:
def _parse_custom_query(self, query: str) -> Optional[str]:
"""Parse custom query type."""
# Your logic here
return sql_query
Extending Condition Support
To add new condition types:
- Add pattern matching in
_extract_conditions() - Build WHERE clause condition
- Add unit tests
- Update documentation
Example:
# In _extract_conditions()
if 'custom_field' in query:
match = re.search(r'custom_field\s+(?:above|over|>)\s+(\d+)', query)
if match:
conditions.append(f"custom_field > {match.group(1)}")
API Reference
Text2SQL Class
class Text2SQL:
def __init__(self, db_path: str = "kinto.db")
def query(self, natural_language: str) -> QueryResult
def format_result(self, result: QueryResult) -> str
QueryResult Dataclass
@dataclass
class QueryResult:
success: bool # Query executed successfully
query: str # Generated SQL query
data: List[Dict] # Query results
message: str # Status message
format_type: str # 'table' or 'string'
MCP Tools
query_database
Convert natural language to SQL and execute.
Input:
{
"question": "How many users do I have?"
}
Output:
Query: SELECT COUNT(*) as count FROM users
Result:
50
get_database_schema
Get database schema information.
Input: (empty)
Output:
Database Schema:
Table: users
Columns: id, name, email, age, created_at
Table: products
Columns: id, name, price, stock, category
...
execute_sql
Execute raw SQL query.
Input:
{
"sql": "SELECT * FROM users WHERE age > 70 LIMIT 5"
}
Output:
SQL: SELECT * FROM users WHERE age > 70 LIMIT 5
Result:
id | name | email | age
───────────────────────────────────
1 | Alice | alice@example.com | 75
2 | Bob | bob@example.com | 72
Deployment
Docker Deployment
# Build image
make docker-build
# Run container
make docker-run
# View logs
make docker-logs
# Stop container
make docker-stop
Local Deployment
# Install dependencies
make install
# Run example
make example
# Run tests
make test
Production Considerations
- Use environment variables for database path
- Enable logging for audit trail
- Restrict database file permissions
- Use read-only database user if possible
- Monitor server logs regularly
- Set up automated backups
Limitations & Future Work
Current Limitations
- Pattern-based parsing (not AI-powered)
- Supports SELECT, COUNT, AVG, SUM operations only
- Complex JOINs not automatically generated
- No support for subqueries
- No support for GROUP BY, ORDER BY
- No support for INSERT/UPDATE/DELETE
Future Enhancements
- [ ] LLM-based query generation for complex queries
- [ ] Support for JOIN operations
- [ ] Support for GROUP BY and ORDER BY
- [ ] INSERT/UPDATE/DELETE operations
- [ ] Query optimization suggestions
- [ ] Result caching for repeated queries
- [ ] Multi-language support
- [ ] Query history and analytics
- [ ] Custom function support
- [ ] Parameterized query templates
Contributing
To contribute to this project:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Update documentation
- Submit a pull request
Support & Documentation
- Quick Start: See "Quick Start" section above
- Examples: See "Query Examples" section
- Troubleshooting: See "Troubleshooting Guide" section
- API Reference: See "API Reference" section
- Logs: Check
logs/text2sql_server.log
FAQ
Q: Can I use this with my own database?
A: Yes! Just point to your database file: Text2SQL(db_path="your_db.db")
Q: Does it support complex queries?
A: For complex queries, use the execute_sql tool to run raw SQL directly.
Q: Is it secure? A: Yes, it uses parameterized queries and pattern-based parsing to prevent SQL injection.
Q: Can I modify the database?
A: By default, only SELECT operations are supported. Use execute_sql for other operations.
Q: How do I add new query types? A: See "Adding New Query Types" in the Development section.
Q: What databases are supported? A: Currently SQLite. Other databases can be added by modifying the database connection code.
Q: Can I use this in production? A: Yes, with proper configuration and monitoring. See "Production Considerations" section.
Q: How do I report bugs?
A: Check the logs in logs/text2sql_server.log and review the Troubleshooting Guide.
Screenshots

License
This project is licensed under the MIT License - see the LICENSE file for details.
sqlite-mcp-csp
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.