analytics-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@analytics-mcp-serverList all tables with row counts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
analytics-mcp-server
A Model Context Protocol (MCP) server, built with FastMCP, that lets an LLM safely explore and analyse a SQLite database through well-designed tools — list tables, inspect schema, run guarded read-only SQL, compute aggregations, and import CSVs.
It ships with a seeded sample e-commerce dataset, so you can clone and run it in under a minute with zero API keys or external services.
Language: Python 3.10+
Framework: FastMCP (
fastmcp)Data: SQLite (stdlib) + pandas
Transport: stdio (local) — the standard for desktop MCP clients
Tested: 16 pytest cases, incl. read-only safety and pagination
Why this exists
MCP servers expose tools that an LLM can call. The hard parts are (1) safety — never letting a model mutate or exfiltrate data it shouldn't — and (2) ergonomics — tools with clear schemas, pagination, and actionable errors so the model uses them correctly. This project demonstrates both.
Related MCP server: mcp-sqlite-tools
Quick start
git clone https://github.com/kshitiz305/analytics-mcp-server.git
cd analytics-mcp-server
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -e .
python scripts/seed_data.py # generates sample.dbRun the server over stdio:
analytics-mcp # console script
# or: python -m analytics_mcp.serverTry it without an MCP client
Use the built-in MCP Inspector:
npx @modelcontextprotocol/inspector analytics-mcpRegister it with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"analytics": {
"command": "analytics-mcp",
"env": { "ANALYTICS_DB_PATH": "/absolute/path/to/sample.db" }
}
}
}Point ANALYTICS_DB_PATH at any SQLite file to analyse your own data.
Tools
Tool | Purpose | Write? |
| List tables with row counts | read-only |
| Column schema, row count, sample rows | read-only |
| Run a guarded, paginated | read-only |
| Group-by + | read-only |
| Load a CSV into a table (validated via pandas) | write |
Every tool supports response_format="markdown" (default, human-readable) or "json" (machine-readable, full precision), carries MCP annotations (readOnlyHint, destructiveHint, …), and returns actionable Error: … messages.
Example output
analytics_list_tables:
### Tables
| table | rows |
| --- | --- |
| customers | 200 |
| order_items | 2420 |
| orders | 800 |
| products | 40 |analytics_aggregate(table="orders", group_by="status", agg="count"):
### count(*) by status in orders
| status | value |
| --- | --- |
| completed | 379 |
| shipped | 175 |
| processing | 119 |
| cancelled | 87 |
| returned | 40 |analytics_run_query with a join + pagination (top customers by spend):
Returned 5 of 196 rows (offset 0, next_offset 5)
| name | country | spend |
| --- | --- | --- |
| Arjun Khan | Japan | 22462.72 |
| Hiro Gupta | Japan | 21656.45 |
| Fatima Lee | Japan | 21249.44 |
| Liam Gupta | Canada | 19013.48 |
| Liam Brown | India | 18822.85 |Attempting a write is rejected:
analytics_run_query(sql="DROP TABLE customers")
→ Error: Only read-only queries are permitted. The statement must start with SELECT or WITH.Safety model
User-supplied SQL is treated as untrusted and guarded on three independent layers:
Read-only connection — queries execute over a
file:…?mode=roSQLite URI, so writes are rejected at the storage engine level.Authorizer callback — an allow-list
set_authorizerpermits only read actions (SELECT/READ/FUNCTION), blockingATTACH,PRAGMAwrites, etc.Statement validation —
analytics_run_queryaccepts a singleSELECT/WITHstatement only, with fast, clear errors before touching the database.
Tools that build SQL internally (list_tables, describe_table, aggregate) never interpolate raw user text — table/column names are validated against the live schema and quoted, so they are injection-safe. The only write path, analytics_import_csv, validates the destination name against an identifier allow-list.
Sample dataset
scripts/seed_data.py generates a deterministic (seeded) e-commerce dataset:
customers (200) — id, name, email, country, signup_date
products (40) — id, name, category, price
orders (800) — id, customer_id, order_date, status
order_items (2420) — id, order_id, product_id, quantity, unit_price
Because the RNG is seeded, the numbers above are reproducible on any machine.
Testing
pip install -e ".[dev]"
pytestThe suite (tests/test_server.py) covers schema discovery, pagination, aggregation, CSV import, rejection of write/multi-statement SQL, and an end-to-end call through FastMCP's in-memory client.
Docker
docker build -t analytics-mcp .
docker run --rm -i analytics-mcp # serves MCP over stdioThe image installs the package and bundles a freshly seeded sample.db.
Project structure
analytics-mcp-server/
├── src/analytics_mcp/
│ ├── server.py # FastMCP server + tool definitions
│ ├── database.py # SQLite access layer (read-only safety)
│ ├── models.py # Enums for tool inputs
│ ├── formatting.py # JSON / Markdown formatting + pagination
│ └── sample_data.py # Deterministic dataset generator
├── scripts/seed_data.py # CLI to (re)build sample.db
├── tests/test_server.py # pytest suite
├── Dockerfile
└── pyproject.tomlLicense
MIT © 2026 Kshitiz Gupta
Available Tools
5 toolsanalytics_aggregateAggregate By ColumnARead-onlyIdempotent
Group a table by a column and compute an aggregate — no SQL required.
A convenience workflow tool over the most common analytics pattern.
Column and table names are validated against the schema, so it is safe
from injection. For anything more complex, use analytics_run_query.
| Name | Required | Description | Default |
|---|---|---|---|
| agg | No | One of ``count``, ``sum``, ``avg``, ``min``, ``max`` (default count). | count |
| limit | No | Maximum groups to return (1-200). | |
| order | No | Sort groups by the aggregate value, ``desc`` (default) or ``asc``. | desc |
| table | Yes | Table to aggregate. | |
| metric | No | Numeric column to aggregate. Required for sum/avg/min/max. | |
| group_by | Yes | Column to group rows by. | |
| response_format | No | ``markdown`` (default) or ``json``. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, establishing safety. The description adds that column/table names are validated against the schema and safe from injection, providing useful behavioral context beyond the annotations. However, it does not elaborate on other behavioral aspects like error handling or performance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the core purpose. Every sentence adds value: purpose, convenience context, safety note and alternative. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With rich annotations, a full output schema, and a simple use case, the description covers the essential aspects: purpose, safety, and alternative. It could mention the output format or that it returns aggregated data, but the output schema likely covers that. Overall it is complete for an AI agent to correctly select and invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage, so the schema fully documents each parameter. The description adds no additional parameter information, meaning it neither enhances nor detracts from the schema's explanations. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Group a table by a column and compute an aggregate — no SQL required,' providing a specific verb and resource. It also implicitly distinguishes from siblings by indicating this is a convenience wrapper for simple aggregations, while 'analytics_run_query' is for more complex queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says 'A convenience workflow tool over the most common analytics pattern' and explicitly directs to 'analytics_run_query' for anything more complex, offering clear context and an alternative. It lacks explicit 'when not to use' cases but the guidance is sufficient for an AI agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analytics_describe_tableDescribe TableARead-onlyIdempotent
Show a table's column schema, total row count and a few sample rows.
Use this after analytics_list_tables to understand a table's columns
(names, types, nullability, primary keys) before writing a query.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Exact table name (see analytics_list_tables). | |
| sample_limit | No | Number of sample rows to preview (0-50). | |
| response_format | No | ``markdown`` (default) or ``json``. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds that the tool returns column schema, row count, and sample rows, which gives behavioral context beyond annotations. No contradictions, but the annotations already cover safety.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description consists of two sentences: the first defines purpose, the second states usage. No extraneous words, well front-loaded, and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool simplicity (3 parameters, 1 required) and the presence of an output schema, the description sufficiently covers what the tool does and when to use it. No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter is documented in the schema. The description does not add significant new meaning beyond reminding to use exact table name from analytics_list_tables. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool shows a table's column schema, total row count, and sample rows. It uses a specific verb-resource combination ('Show a table's column schema...') and distinguishes from siblings by advising to use after analytics_list_tables.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says to use this tool after analytics_list_tables to understand columns before writing a query. This provides clear context and implicitly guides not to use it for other purposes like running queries or aggregates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analytics_import_csvImport CSV Into TableADestructive
Load a CSV file into a SQLite table (validated via pandas).
This is the only WRITE tool. Column types are inferred by pandas. The destination table name must be a valid SQL identifier.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Destination table name (letters, digits, underscores). | |
| csv_path | Yes | Path to a readable .csv file on disk. | |
| if_exists | No | ``fail`` (default — error if the table exists), ``replace`` (drop and recreate) or ``append`` (add rows). | fail |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds value beyond annotations by specifying pandas column type inference and requiring valid SQL identifiers. Annotations already mark destructiveHint true, but the description enriches understanding without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with core action, each sentence adding critical information without waste. Highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers key aspects: write action, validation, rule for table name, and if_exists behavior (via schema). Output schema exists, so return values are covered. Slightly more detail on validation process would be ideal, but overall sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description does not add significant new meaning for parameters beyond what's in the schema (e.g., valid SQL identifier is already in schema description).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states 'Load a CSV file into a SQLite table', specifying verb, resource, and validation via pandas. Distinguishes itself from siblings as 'the only WRITE tool', making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly notes it's the only write tool, providing clear context for when to use it. Does not directly list when not to use alternatives, but this is strongly implied by the write-vs-read distinction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analytics_list_tablesList TablesARead-onlyIdempotent
List all user tables in the database together with their row counts.
Use this first to discover what data is available before describing or querying a specific table. It does not read row contents, only metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | ``markdown`` (human-readable, default) or ``json``. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds context beyond this by specifying it reads only metadata (not row contents) and lists row counts. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose, then usage guidance. Every sentence serves a purpose; no fluff. Highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one optional parameter, output schema present, annotations clear), the description fully covers purpose, usage context, and behavioral limitations. No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description does not mention the response_format parameter, adding no additional semantic information beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it lists all user tables with row counts, using a specific verb ('List') and resource ('user tables'). It distinguishes from sibling tools like analytics_describe_table (describes specific table) and analytics_run_query (runs arbitrary queries).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly advises 'Use this first to discover what data is available before describing or querying a specific table,' providing clear when-to-use guidance. It also clarifies it does not read row contents, implying when not to use (if row contents are needed).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analytics_run_queryRun Read-Only SQLARead-onlyIdempotent
Run a guarded, read-only SQL SELECT query with pagination.
The query is executed over a read-only connection protected by a SQLite
authorizer, and is validated to be a single SELECT/WITH statement, so it
cannot modify data. Results are paginated via limit/offset.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | A single read-only SQL statement. Must start with SELECT or WITH. Writes and multiple statements are rejected. | |
| limit | No | Maximum rows to return (1-500). | |
| offset | No | Rows to skip, for pagination. | |
| response_format | No | ``markdown`` (default) or ``json``. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint. The description adds valuable context: the query runs on a read-only connection with a SQLite authorizer, is validated as a single SELECT/WITH, and results are paginated. This fully discloses behavior beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose, and every sentence adds value. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values are covered. The description addresses purpose, safety, pagination, and validation. It could mention error handling or result format, but overall it is complete for this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameter descriptions are already present. The description mentions pagination via limit/offset but does not add new meaning beyond the schema. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'Run a guarded, read-only SQL SELECT query with pagination,' clearly identifying the verb and resource. It distinguishes from sibling tools (like analytics_import_csv or analytics_describe_table) by emphasizing read-only execution and pagination.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains that the tool is for read-only queries and validates statements, implying it is safe to run. It does not explicitly list alternatives or when-not-to-use, but the context is clear enough for an agent to choose appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
5 tool updates
v0.1.0- First observed
analytics_aggregate - First observed
analytics_describe_table - First observed
analytics_import_csv - First observed
analytics_list_tables - First observed
analytics_run_query
TDQS
Each tool has a clear, distinct purpose: listing tables, describing schemas, importing data, running custom queries, and performing common aggregations. No overlap or ambiguity.
All tools use the 'analytics_' prefix and snake_case. Most follow a verb_noun pattern (e.g., describe_table, list_tables), but 'analytics_aggregate' lacks a noun, which is a minor inconsistency.
With 5 tools covering exploration (list, describe), querying (run, aggregate), and data loading (import), the count is well-scoped for an analytics server. Not too few, not too many.
Covers core analytics workflows: schema discovery, custom queries, common aggregations, and data import. Minor gaps include lack of an export tool or more advanced statistical functions, but these can be addressed via custom queries.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Explore, query, and inspect SQLite databases with ease. List tables, preview results, and view det…
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Explore your Messages SQLite database to browse tables and inspect schemas with ease. Run flexible…
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with SQLite databases through natural language, supporting SQL queries, CSV imports, and schema exploration.10-
- AlicenseCqualityAmaintenanceProvides comprehensive SQLite database operations for LLMs with security features, transaction support, and separation of read-only and destructive operations.2213319MIT
- AlicenseAqualityCmaintenanceEnables safe, read-only SQL access to SQLite databases for AI agents, allowing schema exploration and SELECT queries with defense-in-depth protections.3MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to explore and query SQLite databases through read-only tools, with defense-in-depth sandboxing preventing any data modifications.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kshitiz305/analytics-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server