The Modal Context Protocol: Bridging Applications and AI

Introduction to MCP
The Modal Context Protocol (MCP) establishes a transformative open standard enabling rich interactions between applications and Large Language Models (LLMs). By providing a common interface, MCP allows diverse applications to expose their data and functionality to AI systems in a consistent, secure manner. This article explores key MCP components and demonstrates implementations across three application types: database systems, filesystems, and email servers.
Core Components of MCP
Core Verbs
MCP defines standardized verbs forming the foundation of all context operations:
LOAD: Retrieves context from an application
STORE: Persists context data for future use
QUERY: Requests specific context information based on criteria
UPDATE: Modifies existing context
CLEAR: Removes specific context
MERGE: Combines multiple context sources
TRANSFORM: Converts context from one format to another
PRIORITIZE: Assigns importance levels to context elements
CAPABILITIES: Discovers supported features and operations
Example: PostgreSQL QUERY Implementation
Here's how an MCP QUERY might be implemented in PostgreSQL:
CREATE FUNCTION mcp_query(collection TEXT, filter JSONB) RETURNS JSONB AS $$
DECLARE
result JSONB;
BEGIN
-- Validate query schema
IF NOT validate_query_schema(collection, filter) THEN
RETURN jsonb_build_object(
'status', 'error',
'data', jsonb_build_object('message', 'Invalid query schema', 'code', '400'),
'metadata', jsonb_build_object(
'operation', 'QUERY',
'timestamp', current_timestamp,
'version', '1.0'
)
);
END IF;
-- Execute query and format response
EXECUTE 'SELECT jsonb_agg(row_to_json(t)) FROM ' || collection ||
' t WHERE ' || jsonb_build_sql_filter(filter) INTO result;
RETURN jsonb_build_object(
'status', 'success',
'data', COALESCE(result, '[]'::jsonb),
'metadata', jsonb_build_object(
'operation', 'QUERY',
'timestamp', current_timestamp,
'version', '1.0'
)
);
END;
$$ LANGUAGE plpgsql;
Example: Email Server TRANSFORM Implementation
Email server implementations can transform content between formats:
json_object* mcp_transform_email(struct mail *mail, const char *transform_type) {
json_object *response = json_object_new_object();
json_object *data = json_object_new_object();
// Apply transformation based on transform_type
if (strcmp(transform_type, "summarize") == 0) {
char *summary = generate_email_summary(mail);
json_object_object_add(data, "summary", json_object_new_string(summary));
free(summary);
}
else if (strcmp(transform_type, "extract_entities") == 0) {
json_object *entities = extract_entities_from_email(mail);
json_object_object_add(data, "entities", entities);
}
// Add standard response structure
json_object_object_add(response, "status", json_object_new_string("success"));
json_object_object_add(response, "data", data);
json_object_object_add(response, "metadata", create_standard_metadata("TRANSFORM"));
return response;
}
Context Scoping
MCP defines three scopes for contextual information:
Global: Persists across all sessions and users
Session: Persists for the duration of a user session
Request: Exists only for the current request
Example: Filesystem STORE with Scoping
json_object* mcp_store_context(const char *data_json, const char *context_name, const char *scope) {
json_object *response = json_object_new_object();
// Determine base directory based on scope
char *base_dir;
if (strcmp(scope, "global") == 0) {
base_dir = "/var/lib/mcp/global/";
}
else if (strcmp(scope, "session") == 0) {
base_dir = "/var/lib/mcp/sessions/";
// Append session ID
char session_path[PATH_MAX];
snprintf(session_path, PATH_MAX, "%s%s/", base_dir, get_session_id());
base_dir = session_path;
}
else if (strcmp(scope, "request") == 0) {
base_dir = "/tmp/mcp/requests/";
char request_path[PATH_MAX];
snprintf(request_path, PATH_MAX, "%s%s/", base_dir, get_request_id());
base_dir = request_path;
}
// Store data to appropriate location
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s%s.json", base_dir, context_name);
write_json_file(path, data_json);
// Format standard response
json_object_object_add(response, "status", json_object_new_string("success"));
json_object_object_add(response, "data",
json_object_new_object_add("context_id", json_object_new_string(context_name)));
json_object_object_add(response, "metadata", create_standard_metadata("STORE"));
return response;
}
Capability Negotiation
MCP's capability negotiation allows clients and servers to advertise and discover supported operations.
Example: Database CAPABILITIES Implementation
CREATE FUNCTION mcp_capabilities() RETURNS JSONB AS $$
BEGIN
RETURN jsonb_build_object(
'status', 'success',
'data', jsonb_build_object(
'supported_verbs', jsonb_build_object(
'LOAD', jsonb_build_object('supported', true),
'STORE', jsonb_build_object('supported', true),
'QUERY', jsonb_build_object(
'supported', true,
'filter_operations', jsonb_build_array('eq', 'gt', 'lt', 'contains')
),
'UPDATE', jsonb_build_object('supported', true),
'CAPABILITIES', jsonb_build_object('supported', true)
),
'supported_versions', jsonb_build_array('1.0', '1.1'),
'system_limits', jsonb_build_object(
'max_payload_size', 10485760,
'max_results_per_query', 1000
)
),
'metadata', jsonb_build_object(
'operation', 'CAPABILITIES',
'timestamp', current_timestamp,
'version', '1.0'
)
);
END;
$$ LANGUAGE plpgsql;
Content Type Negotiation
MCP supports different content representations through content type negotiation.
Example: Filesystem Content Type Handler
json_object* handle_request_with_content_type(const char *operation,
const char *params_json,
const char *accept_header) {
// Default is JSON
const char *content_type = "application/json";
// Parse Accept header
if (accept_header && strstr(accept_header, "text/csv")) {
content_type = "text/csv";
}
// Process operation and get result
json_object *result = process_operation(operation, params_json);
// Convert result to requested format if needed
if (strcmp(content_type, "text/csv") == 0) {
char *csv_data = convert_json_to_csv(result);
json_object_put(result);
// Create new result with CSV data
result = create_formatted_response("success",
json_object_new_string(csv_data),
"text/csv",
operation);
free(csv_data);
}
return result;
}
Prompt Templates
MCP includes a system for prompt templates that can be filled with context-specific information.
Example: Email Server PROMPT_LIST
json_object* mcp_prompt_list() {
json_object *response = json_object_new_object();
json_object *templates_array = json_object_new_array();
// Define email reply template
json_object *reply_template = json_object_new_object();
json_object_object_add(reply_template, "template_id", json_object_new_string("email_reply"));
json_object_object_add(reply_template, "description",
json_object_new_string("Generate a reply to an email"));
json_object_object_add(reply_template, "version", json_object_new_string("1.0"));
// Add parameters summary
json_object *params = json_object_new_object();
json_object_object_add(params, "count", json_object_new_int(3));
json_object_object_add(params, "required_count", json_object_new_int(2));
json_object_object_add(reply_template, "parameters", params);
json_object_array_add(templates_array, reply_template);
// Format response
json_object_object_add(response, "status", json_object_new_string("success"));
json_object_object_add(response, "data",
json_object_new_object_add("templates", templates_array));
json_object_object_add(response, "metadata", create_standard_metadata("PROMPT_LIST"));
return response;
}
Example: PostgreSQL PROMPT_GET
CREATE FUNCTION mcp_prompt_get(template_id TEXT) RETURNS JSONB AS $$
DECLARE
template JSONB;
BEGIN
-- Look up template by ID
SELECT prompt_template INTO template
FROM mcp_prompt_templates
WHERE id = template_id;
IF template IS NULL THEN
RETURN jsonb_build_object(
'status', 'error',
'data', jsonb_build_object('message', 'Template not found', 'code', '404'),
'metadata', jsonb_build_object(
'operation', 'PROMPT_GET',
'timestamp', current_timestamp,
'version', '1.0'
)
);
END IF;
RETURN jsonb_build_object(
'status', 'success',
'data', template,
'metadata', jsonb_build_object(
'operation', 'PROMPT_GET',
'timestamp', current_timestamp,
'version', '1.0'
)
);
END;
$$ LANGUAGE plpgsql;
Tools & Function Calling
MCP provides a standardized mechanism for exposing application functionality as tools.
Example: Filesystem TOOL_LIST
json_object* mcp_tool_list() {
json_object *response = json_object_new_object();
json_object *tools_array = json_object_new_array();
// Define file search tool
json_object *search_tool = json_object_new_object();
json_object_object_add(search_tool, "tool_id", json_object_new_string("file_search"));
json_object_object_add(search_tool, "name", json_object_new_string("File Search"));
json_object_object_add(search_tool, "description",
json_object_new_string("Search files by name and content"));
// Define parameters
json_object *params = json_object_new_array();
json_object *param1 = json_object_new_object();
json_object_object_add(param1, "name", json_object_new_string("query"));
json_object_object_add(param1, "type", json_object_new_string("string"));
json_object_object_add(param1, "required", json_object_new_boolean(true));
json_object_array_add(params, param1);
json_object_object_add(search_tool, "parameters", params);
json_object_array_add(tools_array, search_tool);
// Format response
json_object_object_add(response, "status", json_object_new_string("success"));
json_object_object_add(response, "data",
json_object_new_object_add("tools", tools_array));
json_object_object_add(response, "metadata", create_standard_metadata("TOOL_LIST"));
return response;
}
Example: Email Server TOOL_EXECUTE
json_object* mcp_tool_execute(const char *tool_id, const char *params_json) {
json_object *response = json_object_new_object();
json_object *params_obj = json_tokener_parse(params_json);
if (strcmp(tool_id, "find_conversation") == 0) {
// Extract parameters
const char *participant = json_get_string(params_obj, "participant");
const char *subject = json_get_string(params_obj, "subject_contains");
int days = json_get_int(params_obj, "days_back", 7); // Default to 7 days
// Validate required parameters
if (!participant) {
return create_error_response("Missing required parameter: participant", "400");
}
// Execute tool logic
json_object *conversation = find_email_conversation(participant, subject, days);
// Return results
json_object_object_add(response, "status", json_object_new_string("success"));
json_object_object_add(response, "data",
json_object_new_object_add("conversation", conversation));
json_object_object_add(response, "metadata", create_standard_metadata("TOOL_EXECUTE"));
}
else {
return create_error_response("Unknown tool", "404");
}
json_object_put(params_obj);
return response;
}
Context Retrieval Patterns
MCP supports multiple patterns for retrieving and updating context:
Pull pattern: Client explicitly requests context
Push pattern: Server proactively provides context
Streaming pattern: Context delivered incrementally
Event-based pattern: Context updates based on triggers
Example: PostgreSQL Streaming Pattern
CREATE FUNCTION mcp_stream_query(collection TEXT, filter JSONB, batch_size INTEGER DEFAULT 10)
RETURNS SETOF JSONB AS $$
DECLARE
cursor_name TEXT;
batch_data JSONB;
batch_num INTEGER := 0;
total_rows INTEGER;
BEGIN
-- Count total rows for metadata
EXECUTE 'SELECT COUNT(*) FROM ' || collection ||
' WHERE ' || jsonb_build_sql_filter(filter) INTO total_rows;
-- Set up cursor for streaming
cursor_name := 'mcp_stream_' || md5(random()::text);
OPEN cursor_name FOR EXECUTE 'SELECT row_to_json(t) FROM ' || collection ||
' t WHERE ' || jsonb_build_sql_filter(filter);
-- Stream results in batches
LOOP
batch_data := jsonb_build_array();
-- Fetch batch
FOR i IN 1..batch_size LOOP
FETCH cursor_name INTO batch_data;
EXIT WHEN NOT FOUND;
batch_data := batch_data || batch_data;
END LOOP;
-- Exit if batch is empty
IF jsonb_array_length(batch_data) = 0 THEN
EXIT;
END IF;
-- Return batch with metadata
batch_num := batch_num + 1;
RETURN NEXT jsonb_build_object(
'status', 'success',
'data', batch_data,
'metadata', jsonb_build_object(
'operation', 'QUERY_STREAM',
'batch', batch_num,
'total_records', total_rows,
'is_last', jsonb_array_length(batch_data) < batch_size
)
);
-- Exit if this was the last batch
IF jsonb_array_length(batch_data) < batch_size THEN
EXIT;
END IF;
END LOOP;
CLOSE cursor_name;
RETURN;
END;
$$ LANGUAGE plpgsql;
Example: Email Server Event-Based Pattern
// Event listener setup
void setup_mcp_event_listeners(struct mail_user *user) {
mail_user_hook_register(user, "mail-new", mcp_handle_new_mail_event, NULL);
mail_user_hook_register(user, "mail-read", mcp_handle_mail_read_event, NULL);
}
// Event handler for new mail
void mcp_handle_new_mail_event(struct mail *mail, void *context) {
// Check if any clients are subscribed
if (!has_active_subscriptions("mail-new")) {
return;
}
// Create event notification
json_object *event = json_object_new_object();
json_object *data = json_object_new_object();
// Add mail information
const char *subject = get_mail_header(mail, "Subject");
const char *from = get_mail_header(mail, "From");
json_object_object_add(data, "subject", json_object_new_string(subject));
json_object_object_add(data, "from", json_object_new_string(from));
json_object_object_add(data, "id", json_object_new_string(get_mail_id(mail)));
// Format and send notification
json_object_object_add(event, "status", json_object_new_string("success"));
json_object_object_add(event, "data", data);
json_object_object_add(event, "metadata",
json_object_new_object_add("event_type",
json_object_new_string("mail-new")));
// Send to subscribed clients
notify_subscribers("mail-new", event);
json_object_put(event);
}
Implementation in Practice
PostgreSQL Database MCP
Key aspects of a PostgreSQL MCP implementation:
Schema Exposure: Generate context about database schema structure
-- Function to expose table schema CREATE FUNCTION mcp_get_table_schema(table_name TEXT) RETURNS JSONB AS $$ BEGIN RETURN (SELECT jsonb_agg(row_to_json(cols)) FROM (SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = $1) cols); END; $$ LANGUAGE plpgsql;
Query Translation: Map MCP QUERY operations to SQL queries
Transaction Support: Ensure ACID properties for context operations
Row-Level Security: Apply existing database security to MCP operations
Tools Integration: Expose database functions as MCP tools
Filesystem MCP Implementation
Key aspects of a filesystem MCP implementation:
Content Extraction: Extract text and metadata from various file formats
// Example content extraction function json_object* extract_file_content(const char *path) { const char *extension = get_file_extension(path); if (strcmp(extension, "txt") == 0) { return extract_text_file_content(path); } else if (strcmp(extension, "pdf") == 0) { return extract_pdf_content(path); } // Support for other formats return json_object_new_object(); // Empty if unsupported }
Path-Based Context: Use directory hierarchy to structure context
Permission Mapping: Respect file system permissions for MCP operations
File Monitoring: Implement event-based updates for file changes
Search Integration: Leverage existing file indexing for fast context retrieval
Email Server MCP Implementation
Key aspects of an email server MCP implementation:
Thread Analysis: Reconstruct email threads as conversational context
// Thread reconstruction example json_object* reconstruct_thread(const char *message_id) { json_object *thread = json_object_new_array(); // Find root message of thread const char *root_id = find_thread_root(message_id); // Get all messages in thread struct mail_list *messages = get_messages_in_thread(root_id); // Sort by date sort_messages_by_date(messages); // Convert to JSON array for (int i = 0; i < messages->count; i++) { json_object *msg = convert_mail_to_json(messages->items[i]); json_object_array_add(thread, msg); } free_mail_list(messages); return thread; }
Contact Management: Provide relationship context about correspondents
Content Prioritization: Surface important messages through PRIORITIZE
Template Integration: Offer prompt templates for email composition
Tool Support: Implement tools for email analysis and management
Security Considerations
MCP implementations must address several security concerns:
Authentication: Use OAuth 2.0 or equivalent
bool verify_auth_token(const char *token, const char *required_permission) { // Validate token format if (!is_valid_token_format(token)) { return false; } // Verify token signature if (!verify_token_signature(token)) { return false; } // Check expiration if (is_token_expired(token)) { return false; } // Check permissions return token_has_permission(token, required_permission); }
Authorization: Implement fine-grained access control
Data Protection: Ensure sensitive data is properly protected
Audit Logging: Maintain comprehensive logs of all operations
Rate Limiting: Protect against denial of service attacks
Transport Security: Use TLS for all MCP communications
Conclusion
The Modal Context Protocol provides a comprehensive framework for applications to expose their data and functionality to LLMs in a standardized way. Through code samples from PostgreSQL databases, filesystems, and email servers, we've seen how MCP enables context-aware AI interactions while maintaining security and control.
The protocol's standardized verbs, content negotiation mechanisms, and security features enable a new generation of AI tools that can seamlessly integrate with existing applications. As the MCP ecosystem grows, we can expect increasingly sophisticated AI interactions that leverage deep application context while respecting security and privacy boundaries.
Subscribe to my newsletter
Read articles from Dove-Wing directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
