MCP Protocol Implementation
This document describes how the Natural Language Agent implements the Model Context Protocol (MCP).
Protocol Version
This server implements MCP version 2024-11-05.
Transport Modes
The server supports two transport modes:
1. stdio Mode (Default)
Used by: Claude Desktop and other MCP clients
Communication: JSON-RPC 2.0 over standard input/output
How it works:
- Server reads JSON-RPC messages from
stdin - Server writes JSON-RPC responses to
stdout - Errors and diagnostics written to
stderr
Starting in stdio mode:
./bin/pgedge-postgres-mcp
2. HTTP/HTTPS Mode
Used by: Web applications, direct API access, custom integrations
Communication: JSON-RPC 2.0 over HTTP/HTTPS with streaming support
Endpoints:
POST /mcp/v1- JSON-RPC endpointGET /health- Health check endpoint
How it works:
- Client sends HTTP POST request with JSON-RPC payload
- Server processes request and returns JSON-RPC response
- Supports HTTP/1.1 with keep-alive
- Streaming responses for real-time data
Starting in HTTP mode:
./bin/pgedge-postgres-mcp -http -addr ":8080"
MCP Capabilities
The server advertises these capabilities during initialization:
{
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
}
}
Tools
Five callable functions for database interaction and management:
- query_database - Execute SQL queries against PostgreSQL
- get_schema_info - Get detailed database schema information
- similarity_search - Advanced hybrid search combining vector similarity with BM25 and MMR
- generate_embedding - Generate vector embeddings from text using AI models
- read_resource - Read MCP resources by URI
Note: Database connection is configured at server startup via environment variables, config file, or command-line flags. There are no runtime connection management tools.
For detailed tool documentation, see Tools Documentation.
Resources
Four read-only resources for system information and statistics:
- pg://system_info - PostgreSQL version and system information
- pg://settings - Server configuration parameters
- pg://stat/activity - Current activity and connections
- pg://stat/replication - Replication status
For detailed resource documentation, see Resources Documentation.
Prompts
Custom prompts for common database tasks (extensible).
JSON-RPC Messages
Request Format
{
"jsonrpc": "2.0",
"id": 1,
"method": "method_name",
"params": {
"param1": "value1",
"param2": "value2"
}
}
Response Format
Success:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"data": "..."
}
}
Error:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request"
}
}
MCP Methods
Initialize
Establish connection and negotiate capabilities.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
}
},
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"serverInfo": {
"name": "pgedge-postgres-mcp",
"version": "1.0.0-alpha2"
}
}
}
List Tools
Get available tools.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "query_database",
"description": "Execute a natural language query...",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Natural language question..."
}
},
"required": ["query"]
}
}
// ... more tools
]
}
}
Call Tool
Execute a tool.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"query": "Show me all active users"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Natural Language Query: Show me all active users\n\nGenerated SQL:\nSELECT * FROM users WHERE status = 'active';\n\nResults:\n..."
}
]
}
}
List Resources
Get available resources.
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"resources": [
{
"uri": "pg://system_info",
"name": "PostgreSQL System Information",
"description": "Returns PostgreSQL version...",
"mimeType": "application/json"
}
// ... more resources
]
}
}
Read Resource
Read a specific resource.
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "resources/read",
"params": {
"uri": "pg://system_info"
}
}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"contents": [
{
"uri": "pg://system_info",
"mimeType": "application/json",
"text": "{\"version\":\"PostgreSQL 16.0\",\"os\":\"Linux\",\"arch\":\"x86_64\"}"
}
]
}
}
Error Codes
Standard JSON-RPC error codes:
| Code | Message | Meaning |
|---|---|---|
| -32700 | Parse error | Invalid JSON |
| -32600 | Invalid Request | Invalid JSON-RPC request |
| -32601 | Method not found | Method doesn't exist |
| -32602 | Invalid params | Invalid method parameters |
| -32603 | Internal error | Server error |
Custom error codes:
| Code | Message | Meaning |
|---|---|---|
| -32001 | Database not ready | Database still initializing |
| -32002 | Tool not found | Requested tool doesn't exist |
| -32003 | Resource not found | Requested resource doesn't exist |
Streaming (HTTP Mode)
In HTTP mode, the server supports streaming responses for tools that generate large outputs.
How it works:
- Client sends request to
/mcp/v1 - Server processes request
- Server streams response chunks
- Client receives progressive updates
Example - Streaming Query Results:
The query_database tool can stream results as they're generated:
const response = await fetch('https://localhost:8080/mcp/v1', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'query_database',
arguments: { query: 'Show all users' }
}
})
});
// Stream response
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Process chunk
console.log(new TextDecoder().decode(value));
}
Authentication (HTTP Mode)
HTTP mode uses Bearer token authentication.
Request with authentication:
curl -X POST https://localhost:8080/mcp/v1 \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{...}'
Unauthenticated request returns 401:
{
"error": "Unauthorized"
}
For token management, see Authentication Guide.
Protocol Extensions
Multi-Database Support
The query_database tool supports querying multiple databases:
Temporary connection:
{
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"query": "Show users at postgres://otherhost/otherdb"
}
}
}
Change default connection:
{
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"query": "set default database to postgres://newhost/newdb"
}
}
}
Read-Only Transaction Enforcement
All queries via query_database are executed in read-only transactions:
BEGIN;
SET TRANSACTION READ ONLY;
-- User's query here
COMMIT;
This prevents data modification while allowing full read access.
Implementation Details
Server Lifecycle
-
Startup:
- Parse configuration
- Connect to PostgreSQL
- Load database metadata (tables, columns, types)
- Initialize tool and resource registries
- Start transport (stdio or HTTP)
-
Request Handling:
- Receive JSON-RPC message
- Validate request format
- Route to appropriate handler
- Execute tool/resource
- Return JSON-RPC response
-
Shutdown:
- Close database connections
- Clean up resources
- Exit gracefully
Metadata Loading
On startup, the server loads:
- All tables and views (excluding system schemas)
- Column names and data types
- Nullability constraints
- Table and column comments from
pg_description
This metadata is used for:
- Schema information tools
- Natural language to SQL conversion
- Query validation
Error Handling
The server provides detailed error messages in development:
- Database connection errors
- SQL syntax errors
- Permission errors
- API key errors
In production, errors are logged but sanitized in responses.
Testing MCP Protocol
With MCP Inspector
npx @modelcontextprotocol/inspector /path/to/bin/pgedge-postgres-mcp
The MCP Inspector provides a web UI for testing:
- Initialize connection
- List tools and resources
- Call tools interactively
- View request/response JSON
With curl (HTTP mode)
# Start server
./bin/pgedge-postgres-mcp -http -no-auth
# Initialize
curl -X POST http://localhost:8080/mcp/v1 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "curl", "version": "1.0"}
}
}'
# List tools
curl -X POST http://localhost:8080/mcp/v1 \
-H "Content-Type": "application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
Integration Tests
The project includes comprehensive integration tests for MCP protocol compliance:
go test ./test/... -v -run TestMCPCompliance
Tests verify:
- Protocol version negotiation
- Tool and resource registration
- Request/response format
- Error handling
- Streaming support (HTTP mode)
For more testing information, see Testing Guide.