#
tokens: 5880/50000 8/8 files
lines: off (toggle) GitHub
raw markdown copy
# 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:
--------------------------------------------------------------------------------

```
node_modules/
build/
*.log
.env*
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP PostgreSQL Server

-<img src="assets/logo.svg" width="256" height="256" alt="MCP Postgres Logo" />

A Model Context Protocol (MCP) server that provides PostgreSQL database operations through MCP tools.

## Features

- CRUD operations for User and Post entities
- Type-safe database operations using Prisma
- MCP-compatible tool interface
- Built with TypeScript for type safety

## Installation

1. Clone the repository
2. Install dependencies:

```bash
git clone https://github.com/a21071/mcp-postgres.git
cd mcp-postgres
npm install
```

3. Set up PostgreSQL database:

```bash
docker-compose up -d
```

4. Run database migrations:

```bash
npx prisma migrate dev
```

5. Build the project:

```bash
npm run build
```

## Usage

Run the server:

```bash
npm start
```

### Available MCP Tools

- **getData**: Retrieve user data from PostgreSQL

  ```json
  {
    "tableName": "user"
  }
  ```

- **addUserData**: Add new user to database

  ```json
  {
    "email": "[email protected]",
    "name": "John Doe",
    "age": 30
  }
  ```

- **deleteUserData**: Delete user by ID, email or name

  ```json
  {
    "id": "clxyz...",
    "email": "[email protected]",
    "name": "John Doe"
  }
  ```

- **updateUserData**: Update user information
  ```json
  {
    "id": "clxyz...",
    "email": "[email protected]",
    "name": "New Name"
  }
  ```

## Database Schema

The server uses the following Prisma schema:

```prisma
model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  age       Int?
  createdAt DateTime @default(now())
  posts     Post[]
}

```

## Development

- Watch mode:

```bash
npm run watch
```

## Dependencies

- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk) - MCP server SDK
- [Prisma](https://www.prisma.io/) - Type-safe database client
- [TypeScript](https://www.typescriptlang.org/) - Type checking

## License

MIT

```

--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
services:
  postgres:
    image: "postgres:latest"
    container_name: mcp-postgres-db
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_HOST=localhost
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=test
    volumes:
      - ./db-data/:/var/lib/postgresql/data/

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "src/**/__tests__/**"]
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-postgres",
  "version": "0.1.0",
  "description": "Repeats back whatever it is prompted for testing",
  "private": true,
  "type": "module",
  "bin": {
    "echo-server": "./build/index.js"
  },
  "files": [
    "build"
  ],
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
    "prepare": "npm run build",
    "watch": "tsc --watch",
    "inspector": "npx @modelcontextprotocol/inspector build/index.js",
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
    "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
    "test:name": "node --experimental-vm-modules node_modules/jest/bin/jest.js -t"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "0.6.0",
    "@prisma/client": "^6.5.0",
    "prisma": "^6.5.0"
  },
  "devDependencies": {
    "@types/jest": "^29.5.14",
    "@types/node": "^20.11.24",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.5",
    "typescript": "^5.3.3"
  }
}

```

--------------------------------------------------------------------------------
/src/tools.ts:
--------------------------------------------------------------------------------

```typescript
// Tool Definitions
export const getDataTool = {
  name: "getData",
  description: "Retrieve data from PostgreSQL database",
  inputSchema: {
    type: "object",
    properties: {
      tableName: {
        type: "string",
        description: "Name of the table to query",
      },
    },
    required: ["tableName"],
  },
};

export const addUserDataTool = {
  name: "addUserData",
  description: "Add user data to PostgreSQL database",
  inputSchema: {
    type: "object",
    properties: {
      email: {
        type: "string",
        description: "User email address",
      },
      name: {
        type: "string",
        description: "User name",
      },
      age: {
        type: "number",
        description: "User age",
      },
    },
    required: ["tableName", "email", "name", "age"],
  },
};

export const deleteUserDataTool = {
  name: "deleteUserData",
  description: "Delete user data from PostgreSQL database",
  inputSchema: {
    type: "object",
    properties: {
      id: {
        type: "string",
        description: "User id",
      },
      email: {
        type: "string",
        description: "User email address",
      },
      name: {
        type: "string",
        description: "User name",
      },
    },
    required: [],
  },
};

export const updateUserDataTool = {
  name: "updateUserData",
  description: "Delete user data from PostgreSQL database",
  inputSchema: {
    type: "object",
    properties: {
      id: {
        type: "string",
        description: "User id",
      },
      email: {
        type: "string",
        description: "User email address",
      },
      name: {
        type: "string",
        description: "User name",
      },
    },
    required: [],
  },
};

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Result,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { PrismaClient } from "@prisma/client";
import {
  addUserDataTool,
  deleteUserDataTool,
  getDataTool,
  updateUserDataTool,
} from "./tools.js";

// Database Client
export const prismaClient = new PrismaClient();

const TableNameSchema = z.object({
  tableName: z.string().describe("Name of the table to retrieve data from"),
});

const AddUserSchema = z.object({
  email: z.string().email().describe("User email address"),
  name: z.string().describe("User name"),
  age: z.number().int().positive().describe("User age"),
});

const DeleteUserSchema = z.object({
  id: z.string().describe("User Id").optional(),
  email: z.string().email().describe("User email address").optional(),
  name: z.string().describe("User name").optional(),
});

const tools = [
  getDataTool,
  addUserDataTool,
  deleteUserDataTool,
  updateUserDataTool,
];

// Tool Handlers
class DatabaseToolHandlers {
  async getData(tableName: string) {
    // Validate input
    // TableNameSchema.parse({ tableName });

    const data = await prismaClient.user.findMany({
      take: 100, // Limit results
      orderBy: { createdAt: "desc" },
    });

    return {
      content: data.map((user) => ({
        type: "text",
        text: JSON.stringify(user),
      })),
    };
  }

  async addUserData(params: z.infer<typeof AddUserSchema>) {
    // Validate input
    AddUserSchema.parse(params);

    const newUser = await prismaClient.user.create({
      data: {
        name: params.name,
        email: params.email,
        age: params.age,
      },
    });

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(newUser),
        },
      ],
    };
  }

  async deleteUserData(params: z.infer<typeof DeleteUserSchema>) {
    DeleteUserSchema.parse(params);
    const { count } = await prismaClient.user.deleteMany({
      where: {
        id: params.id,
        email: params.email,
        name: params.name,
      },
    });
    return {
      content: [{ type: "text", text: `${count} has been deleted` }],
    };
  }
}

// Server Configuration
const server = new Server(
  {
    name: "mcp-postgres",
    version: "0.1.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// Request Handlers
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools,
}));

const databaseToolHandlers = new DatabaseToolHandlers();

server.setRequestHandler(
  CallToolRequestSchema,
  async (request): Promise<Result> => {
    const { name, arguments: args } = request.params;

    if (name === "getData") {
      return await databaseToolHandlers.getData(
        (args?.tableName as string) ?? "user"
      );
    }
    if (name === "addUserData") {
      return await databaseToolHandlers.addUserData({
        email: args?.email as string,
        name: args?.name as string,
        age: args?.age as number,
      });
    }
    if (name === "deleteUserData") {
      return await databaseToolHandlers.deleteUserData({});
    }
    throw new Error("Unknown tool");
  }
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((error) => {
  console.error("Server error:", error);
  process.exit(1);
});

```

--------------------------------------------------------------------------------
/assets/logo.svg:
--------------------------------------------------------------------------------

```
<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>
```