Skip to main content
Glama
Sidrahhh

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.