Company Data MCP Server
by Sidrahhh
README.md
# Company Data MCP Demo
A multi-source Model Context Protocol (MCP) demo that connects a LangChain/OpenAI chatbot to four company data sources through one read-only MCP server:
- PostgreSQL
- MongoDB Atlas
- Local flat files
- A private GitHub repository
The chatbot can investigate business records, application logs, operational guidance, and source-code implementation in one workflow.
---
## Architecture
```text
User
|
v
chatbot.py
LangChain Agent + OpenAI
|
v
MCP Client
|
| Streamable HTTP
v
MCP Server
|
+------------------+------------------+------------------+------------------+
| | | |
v v v v
PostgreSQL MongoDB Atlas Flat Files GitHub
employees application_logs error_codes.csv payment-service-demo
payments
```
The MCP server is independent of the chatbot. Any compatible MCP client can connect to it.
---
## Current MCP Tools
### PostgreSQL
```text
list_sql_tables
describe_sql_table
query_sql_table
```
### MongoDB
```text
list_mongo_collections
find_mongo_documents
```
### Flat files
```text
list_data_files
read_data_file
search_data_files
```
### GitHub
```text
list_github_repository_files
read_github_repository_file
search_github_repository
```
The tools are generic but constrained. The server does not expose unrestricted SQL, arbitrary MongoDB commands, unrestricted filesystem access, or GitHub write operations.
---
## Project Structure
```text
company-data-mcp-demo/
|
|-- .env
|-- .env.example
|-- .gitignore
|-- requirements.txt
|-- README.md
|-- chatbot.py
|
|-- data/
| |-- error_codes.csv
| |-- notes.txt
| `-- runbook.json
|
`-- mcp_server/
|-- __init__.py
|-- server.py
|
`-- connectors/
|-- __init__.py
|-- sql_connector.py
|-- mongo_connector.py
|-- file_connector.py
`-- github_connector.py
```
---
## Prerequisites
Install or have access to:
- Python
- PostgreSQL
- Node.js
- MongoDB Atlas account
- OpenAI API key
- GitHub account
- VS Code or another editor
Useful checks:
```bash
python --version
node --version
npm --version
psql --version
```
---
## Python Environment
Create a virtual environment:
```bash
python -m venv .venv
```
Activate on Windows CMD:
```bash
.venv\Scripts\activate
```
Activate on PowerShell:
```powershell
.venv\Scripts\Activate.ps1
```
Install dependencies:
```bash
python -m pip install -r requirements.txt
```
Validate:
```bash
python -m pip check
```
Expected:
```text
No broken requirements found.
```
---
## requirements.txt
Use the pinned environment for the MCP/LangChain stack:
```text
# MCP
mcp==1.29.0
langchain-mcp-adapters==0.3.2
# LLM / Agent
langchain==1.3.14
langchain-openai==1.4.0
openai==2.47.0
# Environment variables
python-dotenv==1.2.1
# PostgreSQL
psycopg[binary]==3.3.4
# MongoDB Atlas
pymongo==3.12.0
dnspython>=1.16.0
# GitHub REST API
httpx
```
This project intentionally remains on MCP 1.x because `langchain-mcp-adapters==0.3.2` requires MCP below 2.
The MCP server uses:
```python
from mcp.server.fastmcp import FastMCP
```
and starts with Streamable HTTP.
---
## Environment Variables
Create `.env` in the project root:
```text
OPENAI_API_KEY=your_openai_api_key
# PostgreSQL
DB_HOST=localhost
DB_PORT=5432
DB_NAME=company_demo
DB_USER=mcp_user
DB_PASSWORD=your_postgresql_password
# MongoDB Atlas
MONGODB_USER=mongo_mcp_user
MONGODB_PASSWORD=your_mongodb_password
MONGODB_HOST=your_cluster_host.mongodb.net
MONGODB_DB=company_demo
# GitHub
GITHUB_TOKEN=your_fine_grained_github_token
GITHUB_OWNER=your_github_username
GITHUB_REPO=payment-service-demo
GITHUB_BRANCH=main
```
Create `.env.example` with placeholders only:
```text
OPENAI_API_KEY=your_openai_api_key_here
DB_HOST=localhost
DB_PORT=5432
DB_NAME=company_demo
DB_USER=mcp_user
DB_PASSWORD=your_postgres_password_here
MONGODB_USER=mongo_mcp_user
MONGODB_PASSWORD=your_mongodb_password_here
MONGODB_HOST=your_cluster_host.mongodb.net
MONGODB_DB=company_demo
GITHUB_TOKEN=your_github_token_here
GITHUB_OWNER=your_github_username
GITHUB_REPO=payment-service-demo
GITHUB_BRANCH=main
```
Recommended `.gitignore`:
```text
.env
.venv/
venv/
__pycache__/
*.pyc
*.pyo
*.pyd
.vscode/
.DS_Store
Thumbs.db
```
Never commit `.env`.
---
# PostgreSQL Setup
## Create the database
Start PostgreSQL and connect as an administrator:
```bash
psql -U postgres
```
Create:
```sql
CREATE DATABASE company_demo;
```
Connect:
```sql
\c company_demo
```
---
## Create the employees table
```sql
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department VARCHAR(100),
role VARCHAR(100),
email VARCHAR(255)
);
```
---
## Create the payments table
```sql
CREATE TABLE payments (
id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES employees(id),
payment_id VARCHAR(100) UNIQUE NOT NULL,
amount NUMERIC(10,2),
status VARCHAR(50),
error_code VARCHAR(50)
);
```
---
## Insert sample employee data
```sql
INSERT INTO employees (
name,
department,
role,
email
)
VALUES
(
'Alice',
'Engineering',
'Developer',
'alice@example.com'
),
(
'Bob',
'Finance',
'Analyst',
'bob@example.com'
),
(
'Charlie',
'Security',
'Security Engineer',
'charlie@example.com'
);
```
Verify:
```sql
SELECT * FROM employees;
```
Expected records include:
```text
1 | Alice | Engineering | Developer
2 | Bob | Finance | Analyst
3 | Charlie | Security | Security Engineer
```
---
## Insert sample payment data
```sql
INSERT INTO payments (
employee_id,
payment_id,
amount,
status,
error_code
)
VALUES
(
1,
'PAY-001',
5000.00,
'FAILED',
'E109'
),
(
2,
'PAY-002',
2500.00,
'SUCCESS',
NULL
),
(
1,
'PAY-003',
1200.00,
'SUCCESS',
NULL
);
```
Verify:
```sql
SELECT * FROM payments;
```
Important demo relationship:
```text
Alice -> PAY-001 -> 5000.00 -> FAILED -> E109
Bob -> PAY-002 -> 2500.00 -> SUCCESS
Alice -> PAY-003 -> 1200.00 -> SUCCESS
```
---
## Create a dedicated read-only PostgreSQL user
Do not use the `postgres` administrator account from the MCP server.
Create:
```sql
CREATE USER mcp_user WITH PASSWORD 'choose_a_strong_password';
```
Grant database access:
```sql
GRANT CONNECT ON DATABASE company_demo TO mcp_user;
```
Grant schema access:
```sql
GRANT USAGE ON SCHEMA public TO mcp_user;
```
Grant read-only table access:
```sql
GRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_user;
```
Ensure future tables also receive read access:
```sql
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO mcp_user;
```
---
## Verify read-only behavior
Exit:
```sql
\q
```
Connect as the MCP user:
```bash
psql -U mcp_user -d company_demo -h localhost
```
Reading should work:
```sql
SELECT * FROM employees;
```
A write should fail:
```sql
DELETE FROM employees WHERE id = 1;
```
That failure is expected.
---
# MongoDB Atlas Setup
## Create or select a deployment
In MongoDB Atlas:
- Sign in
- Create or select a project
- Create or select a cluster/deployment
- Wait until it is ready
---
## Configure Network Access
Open the Atlas Network Access area.
Add your current public IP address.
For production, avoid unnecessarily broad network rules such as:
```text
0.0.0.0/0
```
unless that exposure is intentional.
---
## Create the database and collection
In Atlas Data Explorer create:
```text
Database:
company_demo
Collection:
application_logs
```
---
## Insert sample application logs
### PAY-001
```json
{
"payment_id": "PAY-001",
"service": "payment-service",
"error_code": "E109",
"message": "Gateway timeout while contacting payment provider",
"retry_count": 0,
"severity": "ERROR"
}
```
### PAY-002
```json
{
"payment_id": "PAY-002",
"service": "payment-service",
"message": "Payment completed successfully",
"retry_count": 0,
"severity": "INFO"
}
```
### PAY-003
```json
{
"payment_id": "PAY-003",
"service": "payment-service",
"message": "Payment completed successfully",
"retry_count": 0,
"severity": "INFO"
}
```
The important correlation is:
```text
PostgreSQL:
PAY-001 -> FAILED -> E109
MongoDB:
PAY-001 -> Gateway timeout -> retry_count 0
```
---
## Create a read-only MongoDB database user
Do not use an Atlas admin/database setup account from the MCP application.
Create a new database user:
```text
Username:
mongo_mcp_user
```
Use password/SCRAM authentication.
Assign:
```text
Role:
read
Database:
company_demo
```
Avoid broad permissions such as:
```text
atlasAdmin
readWriteAnyDatabase
```
---
## Test the MongoDB read-only user
Connect using `mongosh`:
```bash
mongosh "mongodb+srv://YOUR_CLUSTER_HOST/" --username mongo_mcp_user
```
Select:
```javascript
use company_demo
```
Reading should work:
```javascript
db.application_logs.find()
```
A write should fail:
```javascript
db.application_logs.insertOne({
test: "should fail"
})
```
---
## MongoDB passwords with special characters
If the username or password contains reserved URI characters such as:
```text
@
:
/
?
#
%
&
+
```
they must be URL encoded.
The connector handles this by encoding credentials before placing them into the MongoDB URI.
---
# Flat-File Setup
Create:
```text
data/
```
inside the project root.
---
## error_codes.csv
Create:
```text
data/error_codes.csv
```
Contents:
```csv
error_code,meaning,recommended_action
E109,Gateway timeout,Retry up to 3 times with exponential backoff
E201,Invalid account details,Verify account information before retrying
E305,Provider unavailable,Wait and retry later
```
This provides the documented operational guidance used in the demo.
The key relationship is:
```text
PostgreSQL
PAY-001 -> FAILED -> E109
MongoDB
PAY-001 -> Gateway timeout
Flat file
E109 -> Retry up to 3 times with exponential backoff
```
---
## notes.txt
Optional:
```text
Payment failures must be investigated using transaction records,
application logs, and documented error handling guidance.
```
---
## runbook.json
Optional:
```json
{
"payment_service": {
"owner": "Payments Team",
"critical_severity": "ERROR"
}
}
```
---
## Supported file types
The current connector supports:
```text
.csv
.json
.txt
.log
.md
.yaml
.yml
```
The connector is sandboxed to the project's `data/` directory and should reject attempts to leave that directory.
---
# GitHub Repository Setup
The GitHub connector reads a separate repository representing the application implementation.
Recommended repository:
```text
payment-service-demo
```
Keep this repository separate from the MCP server repository.
Example structure:
```text
payment-service-demo/
|
|-- README.md
|
|-- app/
| |-- __init__.py
| |-- config.py
| |-- gateway.py
| `-- payment.py
|
`-- tests/
`-- test_payment.py
```
The demo repository intentionally implements three retry attempts but uses a fixed delay instead of exponential backoff.
That gives the MCP agent a meaningful implementation mismatch to detect.
---
## Repository visibility
For this demo, use:
```text
Private
```
A private repository proves that the GitHub connector is authenticating successfully rather than simply reading public files.
---
## Create a fine-grained GitHub Personal Access Token
In GitHub:
```text
Settings
-> Developer settings
-> Personal access tokens
-> Fine-grained tokens
-> Generate new token
```
Configure:
```text
Repository access:
Only select repositories
```
Select:
```text
payment-service-demo
```
Grant:
```text
Repository permissions:
Contents -> Read-only
```
Do not give write permissions.
Copy the generated token and store it only in the MCP project's `.env`:
```text
GITHUB_TOKEN=your_token_here
```
Do not place the real token in:
```text
README.md
.env.example
source code
Git commits
chat prompts
```
---
## GitHub environment configuration
Add:
```text
GITHUB_TOKEN=your_fine_grained_github_token
GITHUB_OWNER=your_github_username
GITHUB_REPO=payment-service-demo
GITHUB_BRANCH=main
```
to `.env`.
The GitHub token is used by the MCP server to access the private repository. It is not passed to the LLM.
---
## GitHub connector behavior
The connector:
- lists approved repository files
- reads approved source/text files
- searches approved files for text
- limits file extensions
- limits file sizes
- uses the configured repository and branch
- performs read-only GitHub operations
No GitHub write, commit, pull-request, merge, or delete functionality is exposed.
---
## Test the GitHub connector directly
Run:
```bash
python -m mcp_server.connectors.github_connector
```
Expected output should include files such as:
```text
README.md
app/__init__.py
app/config.py
app/gateway.py
app/payment.py
tests/test_payment.py
```
If this works, the following are confirmed:
```text
GitHub PAT
->
private repository access
->
GitHub REST API
->
Python connector
```
---
# Start the MCP Server
Activate the virtual environment:
```bash
.venv\Scripts\activate
```
Start:
```bash
python -m mcp_server.server
```
The endpoint is:
```text
http://localhost:8000/mcp
```
Keep this terminal open.
---
# MCP Inspector
Start Inspector in another terminal:
```bash
npx @modelcontextprotocol/inspector@latest
```
Choose:
```text
Transport:
Streamable HTTP
```
Use:
```text
http://localhost:8000/mcp
```
Expected tools:
```text
list_sql_tables
describe_sql_table
query_sql_table
list_mongo_collections
find_mongo_documents
list_data_files
read_data_file
search_data_files
list_github_repository_files
read_github_repository_file
search_github_repository
```
---
## Suggested Inspector Tests
### PostgreSQL
List tables:
```text
list_sql_tables
```
Query Alice:
```json
{
"table_name": "employees",
"filter_column": "name",
"filter_value": "Alice",
"limit": 20
}
```
---
### MongoDB
Find PAY-001:
```json
{
"collection_name": "application_logs",
"field": "payment_id",
"value": "PAY-001",
"limit": 20
}
```
---
### Flat files
Search:
```json
{
"query": "E109",
"max_results": 50
}
```
Expected match:
```text
E109,Gateway timeout,Retry up to 3 times with exponential backoff
```
---
### GitHub
List repository files:
```text
list_github_repository_files
```
Read:
```json
{
"path": "app/payment.py"
}
```
Search:
```json
{
"query": "retry",
"max_results": 50
}
```
Useful searches include:
```text
retry
sleep
backoff
timeout
E109
```
---
# Start the Chatbot
Keep the MCP server running.
In another terminal:
```bash
.venv\Scripts\activate
python chatbot.py
```
The chatbot should discover all 11 MCP tools.
The terminal trace shows:
```text
[AGENT SELECTED TOOL]
Tool: ...
[TOOL RESULT]
Tool: ...
Result: ...
```
This provides observable tool-selection and tool-result logging.
---
# Main End-to-End Demo
Ask:
```text
Investigate Alice's failed payment,
explain why it failed,
tell me the documented recommended action,
and check whether our payment-service code implements that recommendation.
```
Expected investigation:
```text
PostgreSQL
|
| Alice -> employee id 1
| PAY-001 -> FAILED -> E109
v
MongoDB
|
| Gateway timeout while contacting payment provider
| retry_count = 0
v
Flat files
|
| E109
| Retry up to 3 times with exponential backoff
v
GitHub
|
| Inspect payment-service-demo
| Three retry attempts implemented
| Fixed delay implemented
| Exponential backoff missing
v
Final grounded answer
```
Expected conclusion:
```text
Alice's PAY-001 payment failed with error code E109.
The application log shows that the payment service encountered
a gateway timeout while contacting the payment provider.
The documented recommendation for E109 is to retry up to three
times with exponential backoff.
The payment-service implementation does retry up to three times,
but it uses a fixed retry delay instead of exponential backoff.
Therefore, the code only partially implements the documented
E109 remediation guidance.
```
---
# Grounding Rules
The chatbot may say:
```text
PAY-001 failed.
```
because PostgreSQL contains that fact.
It may say:
```text
The application logged a gateway timeout.
```
because MongoDB contains that fact.
It may say:
```text
The documented recommendation is to retry up to three times
with exponential backoff.
```
because `error_codes.csv` contains that guidance.
It may say:
```text
The implementation retries three times using a fixed delay.
```
only after retrieving the relevant GitHub source.
The chatbot should not claim:
```text
The external provider definitely had an outage.
```
The available evidence only establishes a gateway timeout.
It should not claim:
```text
I retried the payment.
```
No write/retry tool exists.
It should not claim:
```text
I changed the repository.
```
The GitHub connector is read-only.
---
# Security Summary
## PostgreSQL
```text
Credential:
mcp_user
Database permissions:
read only
```
The connector also restricts allowed tables and columns.
## MongoDB
```text
Credential:
mongo_mcp_user
Role:
read on company_demo
```
The connector also restricts collections and fields.
## Flat Files
Only the approved:
```text
data/
```
directory is accessible.
## GitHub
```text
Credential:
Fine-grained PAT
Repository:
payment-service-demo
Permission:
Contents -> Read-only
```
No GitHub write operations are exposed.
## Secrets
All real credentials belong only in:
```text
.env
```
Never commit `.env`.
Rotate any secret immediately if it is accidentally exposed.
---
# Recommended Testing Order
```text
Direct connector test
|
v
MCP Inspector
|
v
Chatbot
```
This makes failures easy to isolate:
```text
Connector fails
-> source / credentials / API problem
Connector works but Inspector fails
-> MCP server/tool registration problem
Inspector works but chatbot fails
-> MCP client / agent / prompt problem
```
---
# Project Status
```text
OpenAI chatbot DONE
LangChain agent DONE
MCP server DONE
MCP Inspector DONE
PostgreSQL connector DONE
MongoDB Atlas connector DONE
Flat-file connector DONE
GitHub repository connector DONE
Agent/tool trace logging DONE
Four-source investigation READY
```
The current demo supports:
```text
Business records
+
application logs
+
documented remediation
+
source-code verification
```
through one MCP server.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues