AI Sales Query Agent MCP Server

AI Sales Query Agent MCP Server

Enables natural-language sales queries against a SQLite database, generating and executing read-only SQL through a secure MCP server with table listing, schema description, and query execution.

Category
Visit Server

README

AI Sales Query Agent

An AI-powered sales analytics API that converts natural-language questions into SQL and executes them against a SQLite sales database through a secure MCP-style database server.

The application is built with FastAPI and supports both an optional Claude API integration and a deterministic offline SQL planner.


๐Ÿ—๏ธ Architecture

                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚       Client        โ”‚
                         โ”‚  Swagger / Browser  โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
                                    โ”‚ POST /query
                                    โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚      FastAPI        โ”‚
                         โ”‚       main.py       โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
                                    โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚      SQLAgent       โ”‚
                         โ”‚      agent.py       โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚                         โ”‚
                       โ–ผ                         โ–ผ
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚ ClaudeSQLAgent โ”‚       โ”‚ LocalSQLPlanner  โ”‚
              โ”‚  Claude API    โ”‚       โ”‚   Offline Mode   โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚                         โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
                                    โ”‚ Generated SQL
                                    โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚      MCPServer      โ”‚
                         โ”‚   mcp_server.py     โ”‚
                         โ”‚                     โ”‚
                         โ”‚ list_tables()       โ”‚
                         โ”‚ describe_schema()   โ”‚
                         โ”‚ execute_query()     โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                    โ”‚
                             Read-only SQL
                                    โ”‚
                                    โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚   SQLite Database   โ”‚
                         โ”‚    data/sales.db    โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ”„ How It Works

The application follows this flow:

User Question
     โ”‚
     โ–ผ
POST /query
     โ”‚
     โ–ผ
SQLAgent
     โ”‚
     โ”œโ”€โ”€ Claude API
     โ”‚
     โ””โ”€โ”€ LocalSQLPlanner
     โ”‚
     โ–ผ
Generated SQL
     โ”‚
     โ–ผ
MCPServer
     โ”‚
     โ”œโ”€โ”€ Validate SQL
     โ”œโ”€โ”€ Check read-only operation
     โ”œโ”€โ”€ Reject dangerous keywords
     โ””โ”€โ”€ SQLite Authorizer
     โ”‚
     โ–ผ
SQLite Database
     โ”‚
     โ–ผ
Query Results
     โ”‚
     โ–ผ
JSON Response

๐Ÿ›ก๏ธ Database Security

The execute_query() method uses multiple security checks.

1. Only SELECT queries

The server accepts:

SELECT ...

and:

WITH ... SELECT ...

Write operations are rejected.

2. Multiple statements are rejected

For example:

SELECT * FROM customers;
DROP TABLE customers;

is rejected.

3. Dangerous keywords are blocked

The application checks for operations such as:

INSERT
UPDATE
DELETE
DROP
ALTER
CREATE
PRAGMA
ATTACH
DETACH

4. SQLite Authorizer

The application also uses SQLite's built-in authorizer callback.

This provides database-level protection against:

  • INSERT
  • UPDATE
  • DELETE
  • DROP
  • ALTER
  • CREATE
  • Other restricted database operations

Therefore, SQL execution is protected by both application-level validation and the SQLite engine.


๐Ÿค– SQL Generation

The application supports two modes.

Claude Mode

If ANTHROPIC_API_KEY is configured:

ANTHROPIC_API_KEY
       โ”‚
       โ–ผ
ClaudeSQLAgent
       โ”‚
       โ–ผ
Claude API
       โ”‚
       โ–ผ
Generated SQL
       โ”‚
       โ–ผ
MCPServer

The Claude agent receives the database schema and instructions for generating safe SQL.


Offline Mode

If ANTHROPIC_API_KEY is not configured:

User Question
      โ”‚
      โ–ผ
LocalSQLPlanner
      โ”‚
      โ–ผ
Pattern Matching
      โ”‚
      โ–ผ
SQL Query
      โ”‚
      โ–ผ
MCPServer

The offline planner supports common sales queries including:

  • Customer counts
  • Revenue calculations
  • Category revenue
  • Top-N products
  • Regional aggregations
  • Group-by queries
  • Products that were never ordered
  • Basic filtering
  • Aggregations

This means the project can run without an API key or internet connection.


๐Ÿ“Š Database Schema

The project uses SQLite.

Database location:

data/sales.db

๐Ÿ“ Project Structure

partnr-sales-agent/
โ”‚
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ main.py
โ”‚   โ”œโ”€โ”€ agent.py
โ”‚   โ””โ”€โ”€ mcp_server.py
โ”‚
โ”œโ”€โ”€ data/
โ”‚   โ””โ”€โ”€ sales.db
โ”‚
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ test_query.py
โ”‚
โ”œโ”€โ”€ generate_db.py
โ”œโ”€โ”€ evaluator.sh
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ .env.example
โ”œโ”€โ”€ .gitignore
โ””โ”€โ”€ README.md

โš™๏ธ Requirements

Required

  • Python 3.10+
  • pip
  • SQLite

Optional

  • Docker Desktop
  • Docker Compose
  • Anthropic API key

๐Ÿš€ Installation

Windows PowerShell

Step 1 โ€” Open the project

Step 2 โ€” Create virtual environment

python -m venv .venv

Step 3 โ€” Activate virtual environment

.\.venv\Scripts\Activate.ps1

Important: source .venv/bin/activate is a Linux/macOS command. Do not use it in Windows PowerShell.

Step 4 โ€” Upgrade pip

python -m pip install --upgrade pip

Step 5 โ€” Install dependencies

pip install -r requirements.txt

๐Ÿ—„๏ธ Generate the Database

If data/sales.db does not exist, run:

python generate_db.py

Verify:

data/
โ””โ”€โ”€ sales.db

โ–ถ๏ธ Run the Application

Start the FastAPI development server:

uvicorn app.main:app --reload

You should see:

Uvicorn running on http://127.0.0.1:8000

The API is now running at:

http://127.0.0.1:8000

๐Ÿ“– API Documentation

FastAPI automatically generates interactive documentation.

Open:

http://127.0.0.1:8000/docs

You can use Swagger UI to test the API without Postman.

Alternative documentation:

http://127.0.0.1:8000/redoc

๐Ÿ”Ž API Usage

POST /query

The endpoint accepts a natural-language question.

Request

{
  "question": "What is the total number of customers?"
}

Example Response

{
  "sql": "SELECT COUNT(*) AS total_customers FROM customers;",
  "results": [
    {
      "total_customers": 500
    }
  ],
  "chart_data": {
    "labels": [
      "500"
    ],
    "values": [
      500
    ]
  }
}

๐Ÿงช Example Queries

1. Total Customers

What is the total number of customers?

2. Technology Revenue

What is the total revenue from the Technology category?

3. Top Products

What are the top 5 products by revenue?

4. Regional Sales

What is the total sales amount by region?

5. Never Ordered Products

Which products have never been ordered?

6. Unsupported Question

What is the weather today?

The unsupported question should return:

HTTP 400

with an explanatory error message.


๐Ÿงช Testing

Run the complete test suite:

pytest tests/ -v

The tests cover:

  • API endpoint
  • Response format
  • Customer count
  • Revenue queries
  • Complex SQL joins
  • Unsupported questions
  • MCP security
  • SQL injection protection
  • list_tables()
  • describe_schema()
  • Read-only SQL execution

All tests use the offline planner and therefore do not require an API key.


๐Ÿ“‹ End-to-End Evaluation

The repository contains:

evaluator.sh

The script executes predefined questions against the API.

Git Bash

chmod +x evaluator.sh
./evaluator.sh

PowerShell

If you are using Git Bash on Windows:

./evaluator.sh

You can also test all queries manually using:

http://127.0.0.1:8000/docs

๐Ÿณ Docker

Docker can be used instead of installing Python dependencies locally.

Build and start

docker compose up --build -d

If your system uses the older Docker Compose command:

docker-compose up --build -d

Check the containers:

docker compose ps

View logs:

docker compose logs -f api

Open:

http://localhost:8000/docs

Run Tests in Docker

docker compose exec api pytest tests/ -v

Stop Docker

docker compose down

โŒ Error Handling

The application does not guess when a question cannot be answered.

For unsupported questions, the agent raises:

UnanswerableQuestionError

The API converts this into:

HTTP 400 Bad Request

Example:

Question:
What is the weather today?

Response:
400 Bad Request

This prevents unrelated questions from producing meaningless SQL.


๐Ÿ”’ Security Architecture

The security model follows defense in depth:

Natural Language Question
          โ”‚
          โ–ผ
       SQLAgent
          โ”‚
          โ–ผ
     Generated SQL
          โ”‚
          โ–ผ
   SQL Validation
          โ”‚
          โ”œโ”€โ”€ Single statement
          โ”œโ”€โ”€ SELECT / WITH only
          โ”œโ”€โ”€ Forbidden keyword check
          โ”‚
          โ–ผ
   SQLite Authorizer
          โ”‚
          โ”œโ”€โ”€ Reject writes
          โ”œโ”€โ”€ Reject DDL
          โ””โ”€โ”€ Reject restricted actions
          โ”‚
          โ–ผ
      SQLite DB

The important principle is:

The AI agent generates SQL, but it never directly controls the database.


๐Ÿงฉ Components

app/main.py

Responsible for:

  • FastAPI application
  • /query endpoint
  • Request validation
  • Agent orchestration
  • Response formatting
  • Error handling

app/agent.py

Responsible for:

  • Natural-language processing
  • SQL generation
  • Claude integration
  • Offline SQL planning
  • Unsupported-question detection

app/mcp_server.py

Responsible for:

  • Database connection
  • Table listing
  • Schema inspection
  • SQL validation
  • Read-only enforcement
  • SQLite authorizer

generate_db.py

Responsible for:

  • Creating the SQLite database
  • Generating customers
  • Generating orders
  • Generating products
  • Generating order items

tests/test_query.py

Responsible for:

  • API tests
  • SQL tests
  • Security tests
  • Schema tests

๐Ÿ› ๏ธ Technology Stack

Technology Purpose
Python Application development
FastAPI REST API
SQLite Database
Anthropic Claude Optional AI SQL generation
MCP-style Server Secure database gateway
Pydantic Data validation
Pytest Testing
Docker Containerization
Docker Compose Container orchestration

๐Ÿ“ˆ Example End-to-End Flow

For the question:

What is the total revenue from the Technology category?

The application performs:

1. User sends question
          โ†“
2. FastAPI receives /query
          โ†“
3. SQLAgent analyzes question
          โ†“
4. SQL is generated
          โ†“
5. MCPServer validates SQL
          โ†“
6. SQLite authorizer checks operation
          โ†“
7. Query executes
          โ†“
8. Results are returned
          โ†“
9. Chart data is generated

Example SQL:

SELECT
    SUM(p.price * oi.quantity) AS total_revenue
FROM order_items oi
JOIN products p
    ON p.id = oi.product_id
WHERE p.category = 'Technology';

๐Ÿ”ฎ Future Improvements

Potential improvements include:

  • Ollama/local LLM integration
  • Additional LLM providers
  • PostgreSQL support
  • Authentication
  • Rate limiting
  • Query caching
  • Conversation history
  • Advanced SQL generation
  • Automatic chart selection
  • Frontend dashboard
  • Production logging
  • Monitoring
  • Streaming responses

๐ŸŽฏ Project Objective

The main objective of this project is to demonstrate a secure architecture for querying structured sales data using natural language.

Instead of manually writing SQL:

"What is the total revenue from Technology?"

the user can ask a natural-language question and receive a structured result.

User
 โ”‚
 โ–ผ
FastAPI
 โ”‚
 โ–ผ
SQL Agent
 โ”‚
 โ–ผ
MCPServer
 โ”‚
 โ–ผ
SQLite
 โ”‚
 โ–ผ
Sales Result

The architecture keeps AI-generated SQL separate from database execution, making the system easier to test, secure, and extend.


๐Ÿ‘ฉโ€๐Ÿ’ป Running the Project โ€” Quick Start

For an existing local setup, these are the only commands normally required:

cd D:\partnr-sales-agent

.\.venv\Scripts\Activate.ps1

uvicorn app.main:app --reload

Then open:

http://127.0.0.1:8000/docs

Test:

{
  "question": "What is the total number of customers?"
}

๐Ÿ“„ License

This project is intended for educational, development, and demonstration purposes.

Recommended Servers

playwright-mcp

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured