Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to Large Language Models (LLMs). It enables AI applications like Claude, IDEs, and other tools to connect to external data sources and tools through a unified interface.
Official Documentation: https://modelcontextprotocol.io/docs/learn/architecture
┌─────────────────┐
│ MCP Host │ (Our go-mcp-host service)
│ (AI App) │
└────────┬────────┘
│ manages
▼
┌─────────────────┐
│ MCP Client │ (1:1 with each server)
│ (per server) │
└────────┬────────┘
│ connects to
▼
┌─────────────────┐
│ MCP Server │ (Filesystem, Sentry, etc.)
│ (provides │
│ context) │
└─────────────────┘
Key Point: Our go-mcp-host is an MCP Host that creates MCP Clients to connect to external MCP Servers.
Two transport mechanisms:
// Example: Launch filesystem server via stdio
cmd := exec.Command("npx", "-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()
// Example: Connect to remote server
client := NewHTTPMCPClient("https://api.example.com/mcp", bearerToken)
Uses JSON-RPC 2.0 for all communication.
Request (expects response):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [...]
}
}
Notification (no response):
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}
Executable functions that AI can invoke to perform actions.
Methods:
tools/list - Discover available toolstools/call - Execute a toolExample Tool:
{
"name": "read_file",
"description": "Read contents of a file",
"inputSchema": {
"type": "object",
"properties": {
"path": { "type": "string" }
},
"required": ["path"]
}
}
Use Case: File operations, API calls, database queries, web searches
Data sources that provide contextual information to AI.
Methods:
resources/list - Discover available resourcesresources/read - Retrieve a resourceExample Resource:
{
"uri": "file:///path/to/schema.sql",
"name": "Database Schema",
"description": "PostgreSQL database schema",
"mimeType": "text/plain"
}
Use Case: File contents, database schemas, API documentation, configuration data
Reusable templates for structuring LLM interactions.
Methods:
prompts/list - Discover available promptsprompts/get - Retrieve a promptExample Prompt:
{
"name": "code_review",
"description": "Review code changes",
"arguments": [
{
"name": "language",
"description": "Programming language",
"required": true
}
]
}
Use Case: System prompts, few-shot examples, templated instructions
Allows servers to request LLM completions from the client.
Method: sampling/createMessage
Use Case: Server needs AI assistance but wants to stay model-agnostic
Allows servers to request file system roots from the client.
Method: roots/list
Use Case: File system servers need to know what directories to access
initialized notification// 1. Client → Server: Initialize request
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": { "listChanged": true },
"sampling": {}
},
"clientInfo": {
"name": "go-mcp-host",
"version": "1.0.0"
}
}
}
// 2. Server → Client: Initialize response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true }
},
"serverInfo": {
"name": "filesystem-server",
"version": "1.0.0"
}
}
}
// 3. Client → Server: Initialized notification
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
Both client and server declare what they support:
Client Capabilities:
sampling - Can provide LLM completionsroots - Can provide file system rootsServer Capabilities:
tools - Provides tools (with listChanged for notifications)resources - Provides resources (with subscribe for updates)prompts - Provides promptslogging - Supports loggingServers can notify clients about changes:
notifications/tools/list_changed - Tool list updatednotifications/resources/list_changed - Resource list updatednotifications/resources/updated - Specific resource content changedClient should respond by re-fetching the list.
User: "What files are in my project directory?"
// List all available tools from all connected MCP servers
tools := mcpManager.ListAllTools(ctx, conversationID)
// Tools: [list_directory, read_file, write_file, ...]
// Check for relevant resources
resources := mcpManager.ListAllResources(ctx, conversationID)
// Resources: [project_structure.md, README.md, ...]
// Convert MCP tools to OpenAI function format
llmTools := []Tool{
{
Name: "list_directory",
Description: "List contents of a directory",
Parameters: {...}
},
...
}
// Build messages
messages := []Message{
{Role: "system", Content: "You are a helpful assistant with access to filesystem tools."},
{Role: "user", Content: "What files are in my project directory?"},
}
// Send to LLM
response := ollamaClient.Chat(ctx, messages, llmTools)
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_1",
"type": "function",
"function": {
"name": "list_directory",
"arguments": "{\"path\": \"/project\"}"
}
}
]
}
// Find which MCP server provides this tool
mcpClient := mcpManager.GetClientForTool("list_directory")
// Execute tool via MCP protocol
result := mcpClient.CallTool(ctx, "list_directory", map[string]interface{}{
"path": "/project",
})
// Result: {content: [{type: "text", text: "file1.go\nfile2.go\n..."}]}
// Add tool result to conversation
messages = append(messages, Message{
Role: "tool",
ToolCallID: "call_1",
Content: "file1.go\nfile2.go\nREADME.md\n...",
})
// Ask LLM to synthesize response
finalResponse := ollamaClient.Chat(ctx, messages, llmTools)
Assistant: "Your project directory contains the following files:
- file1.go
- file2.go
- README.md
..."
npx -y @modelcontextprotocol/server-filesystem /path/to/allowed/dir
npx -y @modelcontextprotocol/server-postgres postgresql://localhost/dbname
npx -y @modelcontextprotocol/server-puppeteer
Remote HTTP server: https://mcp.sentry.io
Registry: https://github.com/modelcontextprotocol/servers
export GO_SVC_TEMPLATE_DEBUG=true
Use the official MCP Inspector tool:
npx @modelcontextprotocol/inspector [server-command]
Log all messages sent/received for debugging:
logging.LogDebugf("MCP Request: %s", string(requestJSON))
logging.LogDebugf("MCP Response: %s", string(responseJSON))