# Directory Structure ``` ├── .gitignore ├── assets │ └── logo.svg ├── docker-compose.yml ├── package-lock.json ├── package.json ├── prisma │ └── schema.prisma ├── README.md ├── src │ ├── index.ts │ └── tools.ts └── tsconfig.json ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` 1 | node_modules/ 2 | build/ 3 | *.log 4 | .env* ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # MCP PostgreSQL Server 2 | 3 | -<img src="assets/logo.svg" width="256" height="256" alt="MCP Postgres Logo" /> 4 | 5 | A Model Context Protocol (MCP) server that provides PostgreSQL database operations through MCP tools. 6 | 7 | ## Features 8 | 9 | - CRUD operations for User and Post entities 10 | - Type-safe database operations using Prisma 11 | - MCP-compatible tool interface 12 | - Built with TypeScript for type safety 13 | 14 | ## Installation 15 | 16 | 1. Clone the repository 17 | 2. Install dependencies: 18 | 19 | ```bash 20 | git clone https://github.com/a21071/mcp-postgres.git 21 | cd mcp-postgres 22 | npm install 23 | ``` 24 | 25 | 3. Set up PostgreSQL database: 26 | 27 | ```bash 28 | docker-compose up -d 29 | ``` 30 | 31 | 4. Run database migrations: 32 | 33 | ```bash 34 | npx prisma migrate dev 35 | ``` 36 | 37 | 5. Build the project: 38 | 39 | ```bash 40 | npm run build 41 | ``` 42 | 43 | ## Usage 44 | 45 | Run the server: 46 | 47 | ```bash 48 | npm start 49 | ``` 50 | 51 | ### Available MCP Tools 52 | 53 | - **getData**: Retrieve user data from PostgreSQL 54 | 55 | ```json 56 | { 57 | "tableName": "user" 58 | } 59 | ``` 60 | 61 | - **addUserData**: Add new user to database 62 | 63 | ```json 64 | { 65 | "email": "[email protected]", 66 | "name": "John Doe", 67 | "age": 30 68 | } 69 | ``` 70 | 71 | - **deleteUserData**: Delete user by ID, email or name 72 | 73 | ```json 74 | { 75 | "id": "clxyz...", 76 | "email": "[email protected]", 77 | "name": "John Doe" 78 | } 79 | ``` 80 | 81 | - **updateUserData**: Update user information 82 | ```json 83 | { 84 | "id": "clxyz...", 85 | "email": "[email protected]", 86 | "name": "New Name" 87 | } 88 | ``` 89 | 90 | ## Database Schema 91 | 92 | The server uses the following Prisma schema: 93 | 94 | ```prisma 95 | model User { 96 | id String @id @default(cuid()) 97 | email String @unique 98 | name String? 99 | age Int? 100 | createdAt DateTime @default(now()) 101 | posts Post[] 102 | } 103 | 104 | ``` 105 | 106 | ## Development 107 | 108 | - Watch mode: 109 | 110 | ```bash 111 | npm run watch 112 | ``` 113 | 114 | ## Dependencies 115 | 116 | - [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk) - MCP server SDK 117 | - [Prisma](https://www.prisma.io/) - Type-safe database client 118 | - [TypeScript](https://www.typescriptlang.org/) - Type checking 119 | 120 | ## License 121 | 122 | MIT 123 | ``` -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- ```yaml 1 | services: 2 | postgres: 3 | image: "postgres:latest" 4 | container_name: mcp-postgres-db 5 | ports: 6 | - "5432:5432" 7 | environment: 8 | - POSTGRES_USER=postgres 9 | - POSTGRES_HOST=localhost 10 | - POSTGRES_PASSWORD=postgres 11 | - POSTGRES_DB=test 12 | volumes: 13 | - ./db-data/:/var/lib/postgresql/data/ 14 | ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "Node16", 5 | "moduleResolution": "Node16", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "src/**/__tests__/**"] 15 | } 16 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "mcp-postgres", 3 | "version": "0.1.0", 4 | "description": "Repeats back whatever it is prompted for testing", 5 | "private": true, 6 | "type": "module", 7 | "bin": { 8 | "echo-server": "./build/index.js" 9 | }, 10 | "files": [ 11 | "build" 12 | ], 13 | "scripts": { 14 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", 15 | "prepare": "npm run build", 16 | "watch": "tsc --watch", 17 | "inspector": "npx @modelcontextprotocol/inspector build/index.js", 18 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", 19 | "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch", 20 | "test:name": "node --experimental-vm-modules node_modules/jest/bin/jest.js -t" 21 | }, 22 | "dependencies": { 23 | "@modelcontextprotocol/sdk": "0.6.0", 24 | "@prisma/client": "^6.5.0", 25 | "prisma": "^6.5.0" 26 | }, 27 | "devDependencies": { 28 | "@types/jest": "^29.5.14", 29 | "@types/node": "^20.11.24", 30 | "jest": "^29.7.0", 31 | "ts-jest": "^29.2.5", 32 | "typescript": "^5.3.3" 33 | } 34 | } 35 | ``` -------------------------------------------------------------------------------- /src/tools.ts: -------------------------------------------------------------------------------- ```typescript 1 | // Tool Definitions 2 | export const getDataTool = { 3 | name: "getData", 4 | description: "Retrieve data from PostgreSQL database", 5 | inputSchema: { 6 | type: "object", 7 | properties: { 8 | tableName: { 9 | type: "string", 10 | description: "Name of the table to query", 11 | }, 12 | }, 13 | required: ["tableName"], 14 | }, 15 | }; 16 | 17 | export const addUserDataTool = { 18 | name: "addUserData", 19 | description: "Add user data to PostgreSQL database", 20 | inputSchema: { 21 | type: "object", 22 | properties: { 23 | email: { 24 | type: "string", 25 | description: "User email address", 26 | }, 27 | name: { 28 | type: "string", 29 | description: "User name", 30 | }, 31 | age: { 32 | type: "number", 33 | description: "User age", 34 | }, 35 | }, 36 | required: ["tableName", "email", "name", "age"], 37 | }, 38 | }; 39 | 40 | export const deleteUserDataTool = { 41 | name: "deleteUserData", 42 | description: "Delete user data from PostgreSQL database", 43 | inputSchema: { 44 | type: "object", 45 | properties: { 46 | id: { 47 | type: "string", 48 | description: "User id", 49 | }, 50 | email: { 51 | type: "string", 52 | description: "User email address", 53 | }, 54 | name: { 55 | type: "string", 56 | description: "User name", 57 | }, 58 | }, 59 | required: [], 60 | }, 61 | }; 62 | 63 | export const updateUserDataTool = { 64 | name: "updateUserData", 65 | description: "Delete user data from PostgreSQL database", 66 | inputSchema: { 67 | type: "object", 68 | properties: { 69 | id: { 70 | type: "string", 71 | description: "User id", 72 | }, 73 | email: { 74 | type: "string", 75 | description: "User email address", 76 | }, 77 | name: { 78 | type: "string", 79 | description: "User name", 80 | }, 81 | }, 82 | required: [], 83 | }, 84 | }; 85 | ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 2 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 3 | import { 4 | CallToolRequestSchema, 5 | ListToolsRequestSchema, 6 | Result, 7 | } from "@modelcontextprotocol/sdk/types.js"; 8 | import { z } from "zod"; 9 | import { PrismaClient } from "@prisma/client"; 10 | import { 11 | addUserDataTool, 12 | deleteUserDataTool, 13 | getDataTool, 14 | updateUserDataTool, 15 | } from "./tools.js"; 16 | 17 | // Database Client 18 | export const prismaClient = new PrismaClient(); 19 | 20 | const TableNameSchema = z.object({ 21 | tableName: z.string().describe("Name of the table to retrieve data from"), 22 | }); 23 | 24 | const AddUserSchema = z.object({ 25 | email: z.string().email().describe("User email address"), 26 | name: z.string().describe("User name"), 27 | age: z.number().int().positive().describe("User age"), 28 | }); 29 | 30 | const DeleteUserSchema = z.object({ 31 | id: z.string().describe("User Id").optional(), 32 | email: z.string().email().describe("User email address").optional(), 33 | name: z.string().describe("User name").optional(), 34 | }); 35 | 36 | const tools = [ 37 | getDataTool, 38 | addUserDataTool, 39 | deleteUserDataTool, 40 | updateUserDataTool, 41 | ]; 42 | 43 | // Tool Handlers 44 | class DatabaseToolHandlers { 45 | async getData(tableName: string) { 46 | // Validate input 47 | // TableNameSchema.parse({ tableName }); 48 | 49 | const data = await prismaClient.user.findMany({ 50 | take: 100, // Limit results 51 | orderBy: { createdAt: "desc" }, 52 | }); 53 | 54 | return { 55 | content: data.map((user) => ({ 56 | type: "text", 57 | text: JSON.stringify(user), 58 | })), 59 | }; 60 | } 61 | 62 | async addUserData(params: z.infer<typeof AddUserSchema>) { 63 | // Validate input 64 | AddUserSchema.parse(params); 65 | 66 | const newUser = await prismaClient.user.create({ 67 | data: { 68 | name: params.name, 69 | email: params.email, 70 | age: params.age, 71 | }, 72 | }); 73 | 74 | return { 75 | content: [ 76 | { 77 | type: "text", 78 | text: JSON.stringify(newUser), 79 | }, 80 | ], 81 | }; 82 | } 83 | 84 | async deleteUserData(params: z.infer<typeof DeleteUserSchema>) { 85 | DeleteUserSchema.parse(params); 86 | const { count } = await prismaClient.user.deleteMany({ 87 | where: { 88 | id: params.id, 89 | email: params.email, 90 | name: params.name, 91 | }, 92 | }); 93 | return { 94 | content: [{ type: "text", text: `${count} has been deleted` }], 95 | }; 96 | } 97 | } 98 | 99 | // Server Configuration 100 | const server = new Server( 101 | { 102 | name: "mcp-postgres", 103 | version: "0.1.0", 104 | }, 105 | { 106 | capabilities: { 107 | tools: {}, 108 | }, 109 | } 110 | ); 111 | 112 | // Request Handlers 113 | server.setRequestHandler(ListToolsRequestSchema, async () => ({ 114 | tools, 115 | })); 116 | 117 | const databaseToolHandlers = new DatabaseToolHandlers(); 118 | 119 | server.setRequestHandler( 120 | CallToolRequestSchema, 121 | async (request): Promise<Result> => { 122 | const { name, arguments: args } = request.params; 123 | 124 | if (name === "getData") { 125 | return await databaseToolHandlers.getData( 126 | (args?.tableName as string) ?? "user" 127 | ); 128 | } 129 | if (name === "addUserData") { 130 | return await databaseToolHandlers.addUserData({ 131 | email: args?.email as string, 132 | name: args?.name as string, 133 | age: args?.age as number, 134 | }); 135 | } 136 | if (name === "deleteUserData") { 137 | return await databaseToolHandlers.deleteUserData({}); 138 | } 139 | throw new Error("Unknown tool"); 140 | } 141 | ); 142 | 143 | async function main() { 144 | const transport = new StdioServerTransport(); 145 | await server.connect(transport); 146 | } 147 | 148 | main().catch((error) => { 149 | console.error("Server error:", error); 150 | process.exit(1); 151 | }); 152 | ``` -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- ``` 1 | <svg height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m22.839 0c-1.245.011-2.479.188-3.677.536l-.083.027c-.751-.131-1.516-.203-2.276-.219-1.573-.027-2.923.353-4.011.989-1.073-.369-3.297-1.016-5.641-.885-1.629.088-3.411.583-4.735 1.979-1.312 1.391-2.009 3.547-1.864 6.485.041.807.271 2.124.656 3.837.38 1.709.917 3.709 1.589 5.537.672 1.823 1.405 3.463 2.552 4.577.572.557 1.364 1.032 2.296.991.652-.027 1.24-.313 1.751-.735.249.328.516.468.755.599.308.167.599.281.907.355.552.14 1.495.323 2.599.135.375-.063.771-.187 1.167-.359.016.437.032.869.047 1.307.057 1.38.095 2.656.505 3.776.068.183.251 1.12.969 1.953.724.833 2.129 1.349 3.739 1.005 1.131-.24 2.573-.677 3.532-2.041.948-1.344 1.375-3.276 1.459-6.412.02-.172.047-.312.072-.448l.224.021h.027c1.208.052 2.521-.12 3.62-.631.968-.448 1.703-.901 2.239-1.708.131-.199.281-.443.319-.86.041-.411-.199-1.063-.595-1.364-.791-.604-1.291-.375-1.828-.26-.525.115-1.063.176-1.599.192 1.541-2.593 2.645-5.353 3.276-7.792.375-1.443.584-2.771.599-3.932.021-1.161-.077-2.187-.771-3.077-2.177-2.776-5.235-3.548-7.599-3.573-.073 0-.145 0-.219 0zm-.063.855c2.235-.021 5.093.604 7.145 3.228.464.589.6 1.448.584 2.511s-.213 2.328-.573 3.719c-.692 2.699-2.011 5.833-3.859 8.652.063.047.135.088.208.115.385.161 1.265.296 3.025-.063.443-.095.767-.156 1.105.099.167.14.255.349.244.568-.02.161-.077.317-.177.448-.339.509-1.009.995-1.869 1.396-.76.353-1.855.536-2.817.547-.489.005-.937-.032-1.319-.152l-.02-.004c-.147 1.411-.484 4.203-.704 5.473-.176 1.025-.484 1.844-1.072 2.453-.589.615-1.417.979-2.537 1.219-1.385.297-2.391-.021-3.041-.568s-.948-1.276-1.125-1.719c-.124-.307-.187-.703-.249-1.235-.063-.531-.104-1.177-.136-1.911-.041-1.12-.057-2.24-.041-3.365-.577.532-1.296.88-2.068 1.016-.921.156-1.739 0-2.228-.12-.24-.063-.475-.151-.693-.271-.229-.12-.443-.255-.588-.527-.084-.156-.109-.337-.073-.509.041-.177.145-.328.287-.443.265-.215.615-.333 1.14-.443.959-.199 1.297-.333 1.5-.496.172-.135.371-.416.713-.828 0-.015 0-.036-.005-.052-.619-.02-1.224-.181-1.771-.479-.197.208-1.224 1.292-2.468 2.792-.521.624-1.099.984-1.713 1.011-.609.025-1.163-.281-1.631-.735-.937-.912-1.688-2.48-2.339-4.251s-1.177-3.744-1.557-5.421c-.375-1.683-.599-3.037-.631-3.688-.14-2.776.511-4.645 1.625-5.828s2.641-1.625 4.131-1.713c2.672-.151 5.213.781 5.724.979.989-.672 2.265-1.088 3.859-1.063.756.011 1.505.109 2.24.292l.027-.016c.323-.109.651-.208.984-.28.907-.215 1.833-.324 2.76-.339zm.203.89h-.197c-.76.009-1.527.099-2.271.26 1.661.735 2.916 1.864 3.801 3 .615.781 1.12 1.64 1.505 2.557.152.355.251.651.303.88.031.115.047.213.057.312 0 .052.005.105-.021.193 0 .005-.005.016-.005.021.043 1.167-.249 1.957-.287 3.072-.025.808.183 1.756.235 2.792.047.973-.072 2.041-.703 3.093.052.063.099.125.151.193 1.672-2.636 2.88-5.547 3.521-8.032.344-1.339.525-2.552.541-3.509.016-.959-.161-1.657-.391-1.948-1.792-2.287-4.213-2.871-6.24-2.885zm-6.391.343c-1.572.005-2.703.48-3.561 1.193-.887.74-1.48 1.745-1.865 2.781-.464 1.224-.625 2.411-.688 3.219l.021-.011c.475-.265 1.099-.536 1.771-.687.667-.157 1.391-.204 2.041.052.657.249 1.193.848 1.391 1.749.939 4.344-.291 5.959-.744 7.177-.172.443-.323.891-.443 1.349.057-.011.115-.027.172-.032.323-.025.572.079.719.141.459.192.771.588.943 1.041.041.12.072.244.093.38.016.052.027.109.027.167-.052 1.661-.048 3.323.015 4.984.032.719.079 1.349.136 1.849.057.495.135.875.188 1.005.171.427.421.984.875 1.364.448.381 1.093.631 2.276.381 1.025-.224 1.656-.527 2.077-.964.423-.443.672-1.052.833-1.984.245-1.401.729-5.464.787-6.224-.025-.579.057-1.021.245-1.36.187-.344.479-.557.735-.672.124-.057.244-.093.343-.125-.104-.145-.213-.291-.323-.432-.364-.443-.667-.937-.891-1.463-.104-.22-.219-.439-.344-.647-.176-.317-.4-.719-.635-1.172-.469-.896-.979-1.989-1.245-3.052-.265-1.063-.301-2.161.376-2.932.599-.688 1.656-.973 3.233-.812-.047-.141-.072-.261-.151-.443-.359-.844-.828-1.636-1.391-2.355-1.339-1.713-3.511-3.412-6.859-3.469zm-8.853.068c-.167 0-.339.005-.505.016-1.349.079-2.62.468-3.532 1.432-.911.969-1.509 2.547-1.38 5.167.027.5.24 1.885.609 3.536.371 1.652.896 3.595 1.527 5.313.629 1.713 1.391 3.208 2.12 3.916.364.349.681.495.968.485.287-.016.636-.183 1.063-.693.776-.937 1.579-1.844 2.412-2.729-1.199-1.047-1.787-2.629-1.552-4.203.135-.984.156-1.907.135-2.636-.015-.708-.063-1.176-.063-1.473 0-.011 0-.016 0-.027v-.005l-.005-.009c0-1.537.272-3.057.792-4.5.375-.996.928-2 1.76-2.819-.817-.271-2.271-.676-3.843-.755-.167-.011-.339-.016-.505-.016zm16.53 7.041c-.905.016-1.411.251-1.681.552-.376.433-.412 1.193-.177 2.131.233.937.719 1.984 1.172 2.855.224.437.443.828.619 1.145.183.323.313.547.391.745.073.177.157.333.24.479.349-.74.412-1.464.375-2.224-.047-.937-.265-1.896-.229-2.864.037-1.136.261-1.876.277-2.751-.324-.041-.657-.068-.985-.068zm-10.978.158c-.276 0-.552.036-.823.099-.537.131-1.052.328-1.537.599-.161.088-.317.188-.463.303l-.032.025c.011.199.047.667.063 1.365.016.76 0 1.728-.145 2.776-.323 2.281 1.333 4.167 3.276 4.172.115-.469.301-.944.489-1.443.541-1.459 1.604-2.521.708-6.677-.145-.677-.437-.953-.839-1.109-.224-.079-.457-.115-.697-.109zm10.557.27h.068c.083.005.167.011.239.031.068.016.131.037.183.073.052.031.088.083.099.145v.011c0 .063-.016.125-.047.183-.041.072-.088.14-.145.197-.136.151-.319.251-.516.281-.193.027-.385-.025-.547-.135-.063-.048-.125-.1-.172-.157-.047-.047-.073-.109-.084-.172-.004-.061.011-.124.052-.171.048-.048.1-.089.157-.12.129-.073.301-.125.5-.152.072-.009.145-.015.213-.02zm-10.428.224c.068 0 .147.005.22.015.208.032.385.084.525.167.068.032.131.084.177.141.052.063.077.14.073.224-.016.077-.048.151-.1.208-.057.068-.119.125-.192.172-.172.125-.385.177-.599.151-.215-.036-.412-.14-.557-.301-.063-.068-.115-.141-.157-.219-.047-.073-.067-.156-.057-.24.021-.14.141-.219.256-.26.131-.043.271-.057.411-.052zm12.079 9.791h-.005c-.192.073-.353.1-.489.163-.14.052-.251.156-.317.285-.089.152-.156.423-.136.885.057.043.125.073.199.095.224.068.609.115 1.036.109.849-.011 1.896-.208 2.453-.469.453-.208.88-.489 1.255-.817-1.859.38-2.905.281-3.552.016-.156-.068-.307-.157-.443-.267zm-10.708.125h-.027c-.072.005-.172.032-.375.251-.464.52-.625.848-1.005 1.151-.385.307-.88.469-1.875.672-.312.063-.495.135-.615.192.036.032.036.043.093.068.147.084.333.152.485.193.427.104 1.124.229 1.859.104.729-.125 1.489-.475 2.141-1.385.115-.156.124-.391.031-.641-.093-.244-.297-.463-.437-.52-.089-.043-.183-.068-.276-.084z"/></svg> ```