Skip to content

Change PostgreSQL to MySQL throughout the project #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Individually completed exercises for part 1 of the one-day workshop.
* Customize UX-friendly validation rules
```

### Model Context Protocol recap and Postgres MCP server installation
### Model Context Protocol recap and MySQL MCP server installation

* **Purpose:** Understand how MCP servers work and how they can be run locally
* **MCP Recap:**
Expand All @@ -123,38 +123,38 @@ Individually completed exercises for part 1 of the one-day workshop.
* **Steps:**
1. VS Code => Shift+Control+P (Win) or Shift+CMD+P (Mac)
2. \> MCP: Add server...
3. Docker image => mcp/postgres
4. "Install mcp/postgres from mcp?" => select "Allow"
5. Postgres URL:
* Mac: postgresql://postgres:postgres@host.docker.internal:5432/library_app
* Codespaces / Linux: postgresql://postgres:postgres@172.17.0.1:5432/library_app
3. Docker image => mcp/mysql
4. "Install mcp/mysql from mcp?" => select "Allow"
5. MySQL URL:
* Mac: mysql://mysql:mysql@host.docker.internal:3306/library_app
* Codespaces / Linux: mysql://mysql:mysql@172.17.0.1:3306/library_app
6. If you are next asked for port number, database name, username, and password: use values from the URL above
* Port: 5432
* Database name: library_app
* Username: postgres
* Password: postgres
7. "Enter Server ID" => "Postgres"
7. "Enter Server ID" => "MySQL"
8. "Choose where to save the configuration" => select "Workspace settings"
9. mcp.json should be opened by the IDE
10. Start the server by clicking on the play button in mcp.json
11. The tools provided by the MCP server should now be available in the tools menu in the Agent mode prompt box (make sure Agent mode is selected, then click on the wrench icon). You can enable or disable tools by ticking/unticking the boxes.


### Testing the PostgreSQL MCP server
* **Purpose:** Try out and test the PostgreSQL MCP server against a database
### Testing the MySQL MCP server
* **Purpose:** Try out and test the MySQL MCP server against a database
* **Prerequisites:**
* Docker installed.
* **Steps:**
* cd mcp-exercise
* docker compose up db
* Copilot Chat => Agent Mode Selected
* Make sure from the tools menu that the Postgres MCP Server and its tool "query" are enabled
* Make sure from the tools menu that the MySQL MCP Server and its tool "query" are enabled
* Prompt: "#query what's the schema of my database?"
* Prompt: "Show all book loans"
* Prompt: "Show all users who have at least one loan"
* Think about how the information provided by the MCP server could be utilized in prompts. How could it help build complete, AI-powered development flows?

### Using PostgreSQL MCP Server together with prompt files
### Using MySQL MCP Server together with prompt files
* **Purpose:** Use a prompt file to automate the generation of an ER diagram based on the database schema.
* **Steps:**
1. Create a new prompt file (see the instructions above)
Expand All @@ -165,7 +165,7 @@ Individually completed exercises for part 1 of the one-day workshop.
tools: ['query']
description: 'Generate or update the ER diagram of the database using Mermaid syntax.'
---
Use the #query tool to get a description of the PostgreSQL database schema.
Use the #query tool to get a description of the MySQL database schema.
Then generate an Entity Relationship diagram based on the schema. Use Mermaid
syntax to create the diagram. Create the diagram in a file called ER.md.
Create the file if it doesn't exist yet or update the existing file.
Expand All @@ -184,24 +184,24 @@ Individually completed exercises for part 1 of the one-day workshop.
* [Perplexity](https://mcp.so/server/perplexity/ppl-ai)
* [Slack](https://mcp.so/server/slack/modelcontextprotocol)

### PostgreSQL MCP Troubleshooting
### MySQL MCP Troubleshooting

Trouble using or connecting to the PostgreSQL MCP server?
Trouble using or connecting to the MySQL MCP server?

1. Make sure the configuration in mcp.json looks like this:

* Windows and Mac
```json
{
"servers": {
"postgres": {
"mysql": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"mcp/postgres",
"postgresql://postgres:postgres@host.docker.internal:5432/library_app"
"mcp/mysql",
"mysql://mysql:mysql@host.docker.internal:3306/library_app"
]
}
}
Expand All @@ -212,22 +212,22 @@ Trouble using or connecting to the PostgreSQL MCP server?
```json
{
"servers": {
"postgres": {
"mysql": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"mcp/postgres",
"postgresql://postgres:postgres@172.17.0.1:5432/library_app"]
"mcp/mysql",
"mysql://mysql:mysql@172.17.0.1:3306/library_app"]
}
}
}
```
2. Make sure the previous MCP Docker containers are stopped before running the server again:
```bash
% docker ps | grep mcp
db599e110c3f mcp/postgres "node dist/index.js …" 2 hours ago Up 2 hours
db599e110c3f mcp/mysql "node dist/index.js …" 2 hours ago Up 2 hours
% docker stop db599e110c3f
```

Expand All @@ -237,19 +237,19 @@ If you don't have Docker installed and can't install it, you can use npm to run
```json
{
"servers": {
"postgres": {
"mysql": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://localhost/mydb"
"@modelcontextprotocol/server-mysql",
"mysql://localhost/mydb"
]
}
}
}
```
To run the database locally without Docker, you can either use Podman to run the docker-compose.yml file
or install the database on your workstation using PostgreSQL installers. You can also use any test database
or install the database on your workstation using MySQL installers. You can also use any test database
you are currently using for work.

## Part 2: The Hackathon
Expand Down
15 changes: 8 additions & 7 deletions mcp-exercise/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
services:
db:
image: postgres:14-alpine
image: mysql:8
ports:
- "5432:5432"
- "3306:3306"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=library_app
- MYSQL_ROOT_PASSWORD=postgres
- MYSQL_USER=postgres
- MYSQL_PASSWORD=postgres
- MYSQL_DATABASE=library_app
volumes:
- library_app_postgres_data:/var/lib/postgresql/data
- library_app_mysql_data:/var/lib/mysql
- ./init_db.sql:/docker-entrypoint-initdb.d/init_db.sql
restart: unless-stopped

volumes:
library_app_postgres_data:
library_app_mysql_data:
70 changes: 37 additions & 33 deletions mcp-exercise/init_db.sql
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
-- Library Management System Database Schema

-- Create schema if it doesn't exist
-- DROP SCHEMA IF EXISTS library_app CASCADE;
-- CREATE SCHEMA library_app;

-- Set search path to our schema
-- SET search_path TO library_app;
-- MySQL equivalent to schema is database, already created in docker-compose.yml

-- Drop tables if they exist to allow re-running this script
DROP TABLE IF EXISTS book_returns;
Expand All @@ -21,40 +17,40 @@ DROP TABLE IF EXISTS publishers;

-- Create table for user roles (admin, librarian, member)
CREATE TABLE user_roles (
role_id SERIAL PRIMARY KEY,
role_id INT AUTO_INCREMENT PRIMARY KEY,
role_name VARCHAR(50) NOT NULL UNIQUE,
description TEXT
);

-- Create table for users
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
user_id INT AUTO_INCREMENT PRIMARY KEY,
role_id INTEGER REFERENCES user_roles(role_id),
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
phone_number VARCHAR(20),
address TEXT,
date_of_birth DATE,
membership_date DATE NOT NULL DEFAULT CURRENT_DATE,
membership_date DATE NOT NULL DEFAULT (CURRENT_DATE),
membership_expiry DATE,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Create table for book categories/genres
CREATE TABLE categories (
category_id SERIAL PRIMARY KEY,
category_id INT AUTO_INCREMENT PRIMARY KEY,
category_name VARCHAR(100) NOT NULL UNIQUE,
description TEXT
);

-- Create table for publishers
CREATE TABLE publishers (
publisher_id SERIAL PRIMARY KEY,
publisher_id INT AUTO_INCREMENT PRIMARY KEY,
publisher_name VARCHAR(255) NOT NULL UNIQUE,
address TEXT,
phone_number VARCHAR(20),
Expand All @@ -64,7 +60,7 @@ CREATE TABLE publishers (

-- Create table for authors
CREATE TABLE authors (
author_id SERIAL PRIMARY KEY,
author_id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
date_of_birth DATE,
Expand All @@ -76,7 +72,7 @@ CREATE TABLE authors (

-- Create table for books
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
book_id INT AUTO_INCREMENT PRIMARY KEY,
isbn VARCHAR(20) UNIQUE,
title VARCHAR(255) NOT NULL,
subtitle VARCHAR(255),
Expand All @@ -88,59 +84,67 @@ CREATE TABLE books (
description TEXT,
cover_image_url VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Create junction table for books and authors (many-to-many)
CREATE TABLE book_authors (
book_id INTEGER REFERENCES books(book_id) ON DELETE CASCADE,
author_id INTEGER REFERENCES authors(author_id) ON DELETE CASCADE,
PRIMARY KEY (book_id, author_id)
book_id INTEGER,
author_id INTEGER,
PRIMARY KEY (book_id, author_id),
FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE CASCADE,
FOREIGN KEY (author_id) REFERENCES authors(author_id) ON DELETE CASCADE
);

-- Create table for physical copies of books
CREATE TABLE book_copies (
copy_id SERIAL PRIMARY KEY,
book_id INTEGER REFERENCES books(book_id) ON DELETE CASCADE,
copy_id INT AUTO_INCREMENT PRIMARY KEY,
book_id INTEGER,
copy_number VARCHAR(50) NOT NULL,
acquisition_date DATE NOT NULL,
price DECIMAL(10, 2),
condition VARCHAR(50), -- New, Good, Fair, Poor
`condition` VARCHAR(50), -- New, Good, Fair, Poor
location VARCHAR(100), -- Shelf location in the library
status VARCHAR(50) NOT NULL DEFAULT 'Available', -- Available, Loaned, Reserved, Under Repair, Lost
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(book_id, copy_number)
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE(book_id, copy_number),
FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE CASCADE
);

-- Create table for book loans
CREATE TABLE book_loans (
loan_id SERIAL PRIMARY KEY,
copy_id INTEGER REFERENCES book_copies(copy_id) ON DELETE RESTRICT,
user_id INTEGER REFERENCES users(user_id) ON DELETE RESTRICT,
checkout_date DATE NOT NULL DEFAULT CURRENT_DATE,
loan_id INT AUTO_INCREMENT PRIMARY KEY,
copy_id INTEGER,
user_id INTEGER,
checkout_date DATE NOT NULL DEFAULT (CURRENT_DATE),
due_date DATE NOT NULL,
return_date DATE,
renewed_count INTEGER DEFAULT 0,
fine_amount DECIMAL(10, 2) DEFAULT 0.00,
fine_paid BOOLEAN DEFAULT FALSE,
librarian_id INTEGER REFERENCES users(user_id), -- Librarian who processed the loan
librarian_id INTEGER, -- Librarian who processed the loan
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (copy_id) REFERENCES book_copies(copy_id) ON DELETE RESTRICT,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE RESTRICT,
FOREIGN KEY (librarian_id) REFERENCES users(user_id)
);

-- Create table for book returns (could be used for audit purposes)
CREATE TABLE book_returns (
return_id SERIAL PRIMARY KEY,
loan_id INTEGER REFERENCES book_loans(loan_id) ON DELETE CASCADE,
return_date DATE NOT NULL DEFAULT CURRENT_DATE,
return_id INT AUTO_INCREMENT PRIMARY KEY,
loan_id INTEGER,
return_date DATE NOT NULL DEFAULT (CURRENT_DATE),
condition_on_return VARCHAR(50),
librarian_id INTEGER REFERENCES users(user_id), -- Librarian who processed the return
librarian_id INTEGER, -- Librarian who processed the return
fine_assessed DECIMAL(10, 2) DEFAULT 0.00,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (loan_id) REFERENCES book_loans(loan_id) ON DELETE CASCADE,
FOREIGN KEY (librarian_id) REFERENCES users(user_id)
);

-- Insert default user roles
Expand Down