Welcome to the MCP (Model Context Protocol) Server Workshop! In this workshop, you'll learn how to build and deploy an MCP server that connects to PostgreSQL databases, expose tools and prompts, and integrate it with AI agents using n8n.
This workshop is divided into four parts:
- Part 1: Basic MCP Server - Learn MCP fundamentals with a minimal example
- Part 2: Full MCP Server - Connect to PostgreSQL database and expose database tools
- Part 3: AI Agent Integration - Build an AI agent in n8n that uses your MCP server
- Part 4: Claude Desktop Integration - Connect your MCP server to Claude Desktop app
Before starting the workshop, ensure you have:
- Python 3.10 or higher installed on your system
- PostgreSQL database (Azure PostgreSQL or local instance)
- Modern web browser (Chrome, Firefox, or Edge)
- n8n (we'll install this in Part 3)
- Basic knowledge of Python and SQL
- A code editor (VS Code, PyCharm, or similar)
In this part, you'll set up your Python environment, understand MCP basics, and run a simple MCP server.
-
Clone or navigate to the workshop directory:
cd /path/to/AIBA_MCP -
Create a Python virtual environment:
python3 -m venv venv
-
Activate the virtual environment:
On macOS/Linux:
source venv/bin/activateOn Windows:
venv\Scripts\activate
-
Install required dependencies:
pip install -r requirements.txt
This will install:
mcp>=1.0.0- Model Context Protocol libraryasyncpg>=0.29.0- PostgreSQL async driverstarlette>=0.27.0- Web frameworkuvicorn>=0.23.0- ASGI serverrequests- HTTP library
What is MCP (Model Context Protocol)?
MCP is a protocol that allows AI models to interact with external tools, prompts, and resources in a standardized way. It enables:
- Tools: Functions that AI can call to perform actions (e.g., database queries, API calls)
- Prompts: Predefined instructions or templates for AI models
- Resources: Access to external data sources
MCP Server Components:
- Server: Hosts the MCP implementation
- Transport Layer: How messages are exchanged (stdio, SSE, HTTP)
- Tools: Callable functions with defined schemas
- Prompts: Reusable instructions for AI models
Key Concepts:
- JSON-RPC Protocol: MCP uses JSON-RPC 2.0 for message exchange
- Tool Schema: Each tool has a defined input schema (similar to OpenAPI)
- Async Operations: MCP servers are asynchronous for better performance
-
Examine the minimal server code:
cat minimal_server.py
Notice:
- One simple tool:
greet- says hello to a person - One prompt:
simple_assistant- provides instructions for AI - HTTP Streamable transport for easy testing
- One simple tool:
-
Start the minimal MCP server:
python minimal_server.py --host 127.0.0.1 --port 8000
You should see:
Starting minimal MCP server with HTTP Streamable transport on http://127.0.0.1:8000 INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 -
Keep this terminal open - the server is now running!
Open a new terminal and test the server with curl commands.
-
Test 1: Initialize the connection
curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {} }'
Expected response:
{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {}, "prompts": {} }, "serverInfo": { "name": "minimal-mcp-example", "version": "1.0.0" } } } -
Test 2: List available tools
curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }'
This shows the
greettool with its schema. -
Test 3: Call the greet tool
curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "greet", "arguments": { "name": "Workshop Participant" } } }'
Expected response:
{ "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "Hello, Workshop Participant! Welcome to the minimal MCP server." } ] } } -
Test 4: List available prompts
curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "prompts/list", "params": {} }'
-
Test 5: Get a specific prompt
curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 5, "method": "prompts/get", "params": { "name": "simple_assistant" } }'
✅ Part 1 Complete! You've successfully:
- Set up your Python environment
- Learned MCP basics
- Run a minimal MCP server
- Tested it with curl commands
In this part, you'll work with a full-featured MCP server that connects to a PostgreSQL database.
-
Stop the minimal server (Ctrl+C in the first terminal)
-
Open and review server.py:
cat server.py
Key components to notice:
A. Database Connection (lines 78-99):
- Uses
asyncpgfor async PostgreSQL connections - Connection pool for efficient resource management
- Reads connection string from environment variable
B. Available Tools (lines 102-176):
execute_select- Execute SELECT queriesexecute_insert- Execute INSERT querieslist_tables- List all tables in schemadescribe_table- Get table structure and columns
C. Query Validation (lines 34-75):
- Validates SQL queries before execution
- Only allows safe operations (SELECT, INSERT)
- Prevents SQL injection and dangerous operations
D. Prompt (lines 321-418):
postgresql_assistant- Instructions for AI to use database tools- Provides guidelines for safe database operations
E. Transport Modes (lines 421-616):
- stdio: For integration with Claude Desktop and other apps
- SSE (Server-Sent Events): For real-time streaming
- streamable: For simple HTTP POST requests (we'll use this!)
- Uses
-
Prepare your PostgreSQL connection string:
Review the
config.templatefile:cat config.template
Format:
postgresql://username:password@hostname:port/database?sslmode=requireExample for Azure PostgreSQL:
postgresql://admin@myserver:MyP@[email protected]:5432/mydatabase?sslmode=requireExample for local PostgreSQL:
postgresql://postgres:password@localhost:5432/testdb -
Set the environment variable:
On macOS/Linux:
export POSTGRES_CONNECTION_STRING="postgresql://your_user:your_password@your_host:5432/your_db"
On Windows (Command Prompt):
set POSTGRES_CONNECTION_STRING=postgresql://your_user:your_password@your_host:5432/your_db
On Windows (PowerShell):
$env:POSTGRES_CONNECTION_STRING="postgresql://your_user:your_password@your_host:5432/your_db"
-
Verify the environment variable is set:
echo $POSTGRES_CONNECTION_STRING
-
Start the server in streamable mode:
python server.py --transport streamable --host 127.0.0.1 --port 8000
You should see:
Starting MCP server with HTTP Streamable transport on http://127.0.0.1:8000 INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 -
The server is now ready to receive requests at
http://127.0.0.1:8000/mcp
-
Open the HTML client:
In your file browser, navigate to the workshop directory and double-click on:
example_streamable_client.htmlOr open it directly in your browser:
open example_streamable_client.html # macOS xdg-open example_streamable_client.html # Linux start example_streamable_client.html # Windows
-
The client interface:
You should see a web page titled "MCP HTTP Streamable Client" with:
- Server URL input (should be
http://localhost:8000/mcp) - Prompt buttons (List Prompts, Get Prompt)
- Quick action buttons (SELECT Example, INSERT Example, List Tables, Describe Table)
- SQL Query textarea
- Response output area
- Server URL input (should be
-
Test 1: List available prompts:
- Click the "List Prompts" button
- You should see the
postgresql_assistantprompt in the response
-
Test 2: Get the postgresql_assistant prompt:
- Click the "Get Prompt" button
- When prompted, enter:
postgresql_assistant - You'll see the full prompt text with instructions for AI
-
Test 3: List all tables:
- Click the "List Tables" button
- You should see a list of tables in your database
- Example response:
{ "success": true, "schema": "public", "table_count": 3, "tables": [ {"table_name": "users", "table_type": "BASE TABLE"}, {"table_name": "products", "table_type": "BASE TABLE"} ] }
-
Test 4: Describe a table:
- Click the "Describe Table" button
- Enter a table name from your database (e.g.,
users) - You'll see the table structure with columns, types, and constraints
-
Test 5: Execute a SELECT query:
- Click the "SELECT Example" button (or type your own query)
- Example query:
SELECT * FROM users LIMIT 10 - Click "Execute Query"
- You should see the query results in JSON format
-
Test 6: Execute an INSERT query (optional):
- Click the "INSERT Example" button
- Modify the query for your table structure
- Click "Execute Query"
- You should see a success message with rows inserted count
-
Test 7: Try an invalid query:
- Type:
DELETE FROM users WHERE id = 1 - Click "Execute Query"
- You should see an error: "Operation 'DELETE' not allowed"
- This demonstrates the query validation in action!
- Type:
✅ Part 2 Complete! You've successfully:
- Analyzed the full MCP server code
- Connected to a PostgreSQL database
- Run the server in streamable mode
- Tested database operations using the HTML client
- Understood query validation and security
In this part, you'll set up n8n and create an AI agent that connects to your MCP server.
n8n is a workflow automation tool that can create AI agents with tool access.
Option A: Run n8n with Docker (Recommended)
-
Install Docker (if not already installed):
- Download from: https://www.docker.com/products/docker-desktop
-
Run n8n with Docker:
docker run -it --rm \ --name n8n \ -p 5678:5678 \ -v ~/.n8n:/home/node/.n8n \ n8nio/n8n -
Access n8n:
- Open your browser and go to: http://localhost:5678
- Create an account (local, no signup required)
Option B: Run n8n with npm
-
Install Node.js (if not already installed):
- Download from: https://nodejs.org/ (LTS version)
-
Install n8n globally:
npm install -g n8n
-
Start n8n:
n8n
-
Access n8n:
- Open your browser and go to: http://localhost:5678
- Create an account (local, no signup required)
-
Create a new workflow:
- In n8n, click "Create Workflow" or "New Workflow"
- Give it a name:
MCP Database Agent
-
Understand the workflow concept:
- Workflows in n8n are visual automations
- Nodes represent actions (trigger, AI agent, tools, etc.)
- Connections show the flow of data
-
Add a Chat Trigger (for manual testing):
- Click the "+" button to add a node
- Search for "Chat Trigger" or "When chat message received"
- Add it to your workflow
- This node will allow you to send messages to test the agent
-
Add an AI Agent node:
- Click the "+" button after the trigger
- Search for "AI Agent"
- Add the "AI Agent" node
- This is the core of your AI agent
-
Configure the AI Agent:
a. Select AI Model:
- In the AI Agent node settings, find "Model"
- Choose your preferred model:
- OpenAI GPT-4 (requires OpenAI API key)
- OpenAI GPT-3.5-turbo
- Anthropic Claude (requires Anthropic API key)
- Or any other supported model
b. Add API Credentials:
- Click "Create New Credential"
- Enter your API key for the chosen model
- Save the credentials
c. Set System Prompt:
- In the "System Message" field, you can enter:
You are a helpful database assistant. You have access to PostgreSQL database tools via the MCP server. Use the available tools to help users query and understand their database.
- Add an MCP client Request Tool:
- Click the "+" button after the AI Agent
- Search for "MCP client"
- Add the "MCP client" node
- Configure it to call the remote MCP server
-
Save the workflow:
- Click "Save" in the top right corner
-
Activate the workflow:
- Toggle the "Active" switch to ON
-
Test the agent:
Test 1: List tables
- Send a message: "What tables are in the database?"
- The AI should call the
list_tablestool and show you the results
Test 2: Describe a table
- Send: "Can you describe the structure of the users table?"
- The AI should call the
describe_tabletool
Test 3: Query data
- Send: "Show me the first 5 users from the users table"
- The AI should call the
execute_selecttool with a SELECT query
Test 4: Complex request
- Send: "How many records are in each table?"
- The AI should:
- First list all tables
- Then execute COUNT queries for each table
- Present the results in a nice format
-
Monitor the execution:
- In n8n, you can see the execution log
- Click on "Executions" tab to see past runs
- You can see which tools were called and the responses
- Fetch the MCP prompt:
- Install MCP community node
- Configure it to call:
prompts/getmethod - Use the response to enhance the AI Agent's system prompt
✅ Part 3 Complete! You've successfully:
- Set up n8n environment
- Created a new workflow
- Built an AI agent with model integration
- Connected your MCP server tools to the agent
- Tested the complete system with natural language queries
In this part, you'll integrate your MCP server directly with Claude Desktop app, allowing Claude to access your database tools natively.
-
Download Claude Desktop:
Visit the official Claude website and download the desktop app for your operating system:
- macOS: https://claude.ai/download
- Windows: https://claude.ai/download
- Linux: Currently not officially supported, use web version
-
Install the application:
macOS:
- Open the downloaded
.dmgfile - Drag Claude to your Applications folder
- Open Claude from Applications
- Sign in with your Anthropic account
Windows:
- Run the downloaded
.exeinstaller - Follow the installation wizard
- Launch Claude Desktop
- Sign in with your Anthropic account
- Open the downloaded
-
Verify installation:
- Open Claude Desktop
- Ensure you can send messages and receive responses
- The app should be working normally before adding MCP servers
Claude Desktop uses a configuration file to define MCP servers.
-
Locate the Claude configuration directory:
macOS:
~/Library/Application Support/Claude/Windows:
%APPDATA%\Claude\ -
Open the configuration file:
The configuration file is named
claude_desktop_config.json.macOS:
# Open in default text editor open ~/Library/Application\ Support/Claude/claude_desktop_config.json # Or use nano/vim nano ~/Library/Application\ Support/Claude/claude_desktop_config.json
Windows:
# Open in Notepad notepad %APPDATA%\Claude\claude_desktop_config.json
If the file doesn't exist, create it:
macOS:
mkdir -p ~/Library/Application\ Support/Claude/ touch ~/Library/Application\ Support/Claude/claude_desktop_config.json
Windows (PowerShell):
New-Item -ItemType Directory -Force -Path "$env:APPDATA\Claude" New-Item -ItemType File -Force -Path "$env:APPDATA\Claude\claude_desktop_config.json"
-
Understand the configuration structure:
The
claude_desktop_config.jsonfile defines MCP servers that Claude can connect to. Each server runs instdiomode, where Claude communicates with it through standard input/output. -
Configure environment variables:
First, make sure you know the full path to:
- Your Python virtual environment's Python executable
- Your
server.pyfile - Your PostgreSQL connection string
Find your paths:
# Get Python path (while venv is activated) which python # macOS/Linux where python # Windows # Get project directory pwd # macOS/Linux cd # Windows
-
Edit the configuration file:
Add your MCP server configuration to
claude_desktop_config.json:Example for macOS/Linux:
{ "mcpServers": { "postgres-mcp": { "command": "/Users/yourname/Documents/chmurowisko/AIBA_MCP/venv/bin/python", "args": [ "/Users/yourname/Documents/chmurowisko/AIBA_MCP/server.py", "--transport", "stdio" ], "env": { "POSTGRES_CONNECTION_STRING": "postgresql://user:password@host:5432/database" } } } }Example for Windows:
{ "mcpServers": { "postgres-mcp": { "command": "C:\\Users\\YourName\\Documents\\chmurowisko\\AIBA_MCP\\venv\\Scripts\\python.exe", "args": [ "C:\\Users\\YourName\\Documents\\chmurowisko\\AIBA_MCP\\server.py", "--transport", "stdio" ], "env": { "POSTGRES_CONNECTION_STRING": "postgresql://user:password@host:5432/database" } } } } -
Configuration explained:
mcpServers: Object containing all MCP server definitionspostgres-mcp: A unique name for your server (you can choose any name)command: Full path to your Python executable in the virtual environmentargs: Arguments to pass to Python (the server.py script and transport mode)env: Environment variables needed by the server (database connection string)
-
Multiple servers example (optional):
You can add both the minimal and full servers:
{ "mcpServers": { "minimal-mcp": { "command": "/Users/yourname/Documents/chmurowisko/AIBA_MCP/venv/bin/python", "args": [ "/Users/yourname/Documents/chmurowisko/AIBA_MCP/minimal_server.py" ] }, "postgres-mcp": { "command": "/Users/yourname/Documents/chmurowisko/AIBA_MCP/venv/bin/python", "args": [ "/Users/yourname/Documents/chmurowisko/AIBA_MCP/server.py", "--transport", "stdio" ], "env": { "POSTGRES_CONNECTION_STRING": "postgresql://user:password@host:5432/database" } } } } -
Save the configuration file.
-
Restart Claude Desktop:
- Completely quit Claude Desktop (not just close the window)
- macOS: Cmd+Q or Claude → Quit Claude
- Windows: File → Exit or close from system tray
- Reopen Claude Desktop
-
Verify MCP server connection:
When Claude Desktop starts, it should automatically connect to your MCP servers defined in the configuration.
-
Check for MCP tools:
In Claude Desktop, you should see an indicator that MCP tools are available. This might appear as:
- A tool icon in the interface
- A message about available tools
- Look for a hammer/tool icon or "MCP" indicator
-
Test 1: Ask about available tools:
Send a message to Claude:
What tools do you have access to?Claude should respond mentioning the database tools:
- execute_select
- execute_insert
- list_tables
- describe_table
-
Test 2: List database tables:
Send a message:
Can you list all the tables in my database?Claude should:
- Recognize your request
- Use the
list_tablestool - Display the results in a formatted way
-
Test 3: Describe a table:
Send a message:
Please describe the structure of the users tableClaude should:
- Call the
describe_tabletool - Show you the columns, types, and constraints
- Call the
-
Test 4: Query data:
Send a message:
Show me the first 5 records from the users tableClaude should:
- Construct a SELECT query
- Use the
execute_selecttool - Display the results in a nice table format
-
Test 5: Complex multi-step task:
Send a message:
I need a summary of my database. Please tell me: 1. What tables exist 2. How many records are in each table 3. Show me the structure of the largest tableClaude should:
- First call
list_tables - Then execute SELECT COUNT queries for each table
- Then call
describe_tablefor the table with most records - Present everything in a clear summary
- First call
-
Test 6: Use the prompt:
Send a message:
Can you load the postgresql_assistant prompt?If your server supports prompts (which it does), Claude should be able to access and use the predefined prompt.
Issue: MCP tools not appearing in Claude
Solutions:
- Check the configuration file for syntax errors (valid JSON)
- Verify all paths are absolute and correct
- Ensure Python path points to the virtual environment's Python
- Make sure Claude Desktop was completely restarted
- Check Claude Desktop logs:
- macOS:
~/Library/Logs/Claude/ - Windows:
%APPDATA%\Claude\logs\
- macOS:
Issue: "Failed to start MCP server" error
Solutions:
- Test the server manually in stdio mode:
python server.py --transport stdio
- Check if the virtual environment has all required packages:
source venv/bin/activate pip install -r requirements.txt - Verify the POSTGRES_CONNECTION_STRING is correct
- Check file permissions on server.py
Issue: Database connection errors in Claude
Solutions:
- Verify the connection string in the config file
- Test the connection string separately:
python test_connection.py
- Ensure the database is accessible from your machine
- Check firewall and network settings
Issue: JSON syntax error in configuration file
Solutions:
- Validate your JSON using an online validator: https://jsonlint.com
- Common mistakes:
- Missing commas between properties
- Trailing commas (not allowed in JSON)
- Unescaped backslashes in Windows paths (use
\\or/) - Missing quotes around strings
Viewing logs for debugging:
To see what's happening with your MCP server:
macOS:
# View Claude logs
tail -f ~/Library/Logs/Claude/mcp*.log
# Or use Console app
open -a Console
# Then search for "Claude" or "MCP"Windows:
# View logs in PowerShell
Get-Content "$env:APPDATA\Claude\logs\mcp*.log" -WaitYou can customize your MCP server further:
-
Add custom prompts specific to your database schema:
Edit the
get_promptfunction inserver.pyto include your table structures. -
Add more tools:
Add UPDATE, DELETE, or custom stored procedure tools (with proper validation).
-
Add logging:
Configure the server to log to a file for easier debugging:
import logging logging.basicConfig( filename='/tmp/mcp_server.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' )
-
Multiple database connections:
Modify the server to support multiple databases and add a tool to switch between them.
✅ Part 4 Complete! You've successfully:
- Installed Claude Desktop app
- Configured the MCP server integration
- Added your PostgreSQL MCP server to Claude Desktop
- Tested database operations through Claude's natural language interface
- Learned to troubleshoot common integration issues
Now you can use Claude Desktop to interact with your database using natural language, and Claude will automatically use the appropriate MCP tools to fulfill your requests!
Solution: Make sure you've set the environment variable before starting the server:
export POSTGRES_CONNECTION_STRING="postgresql://user:pass@host:5432/db"
python server.py --transport streamableSolutions:
- Verify the server is running
- Check if the port 8000 is already in use:
lsof -i :8000 # macOS/Linux netstat -ano | findstr :8000 # Windows
- Try a different port:
python server.py --transport streamable --port 8001
This is expected! The server validates queries for security. Only SELECT and INSERT operations are allowed by default. To modify this, edit the validate_query function in server.py.
Solutions:
- Make sure MCP server is running
- If using Docker for n8n, use
host.docker.internalinstead oflocalhost:- URL:
http://host.docker.internal:8000/mcp
- URL:
- Check firewall settings
Solutions:
- Verify tool descriptions are clear and detailed
- Check that the HTTP Request configuration is correct
- Test the HTTP Request separately first
- Ensure API keys are valid for the AI model
- Official MCP Docs: https://modelcontextprotocol.io
- MCP Python SDK: https://github.com/modelcontextprotocol/python-sdk
- Claude Desktop MCP Guide: https://docs.anthropic.com/claude/docs/mcp
- n8n Docs: https://docs.n8n.io
- AI Agents in n8n: https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/
Congratulations on completing the MCP Server Workshop! You've learned:
✅ How to build an MCP server from scratch
✅ How to expose database tools through MCP
✅ How to test MCP servers with multiple methods
✅ How to integrate MCP with AI agents in n8n
✅ How to connect MCP servers to Claude Desktop app
✅ Best practices for secure database access
✅ How to build production-ready AI applications
You now have the skills to build sophisticated AI agents that can interact with databases and other external systems using the Model Context Protocol. Whether you're using n8n, Claude Desktop, or custom integrations, you can leverage MCP to create powerful AI-driven database applications.
Happy coding! 🚀