Tutorial 3: MCP Integration
Add external tools to your LLM application via Model Context Protocol.
Time: 30 minutes
Level: Intermediate
What You’ll Build
Section titled “What You’ll Build”A chatbot that can read and manipulate files using MCP filesystem tools.
What You’ll Learn
Section titled “What You’ll Learn”- Set up MCP servers
- Register external tools
- Enable automatic tool calling
- Handle tool execution
- Build tool-enabled agents
Prerequisites
Section titled “Prerequisites”- Completed Tutorial 2
- Node.js (for MCP servers)
Step 1: Install MCP Filesystem Server
Section titled “Step 1: Install MCP Filesystem Server”The filesystem server provides file operations as tools:
# Test the MCP servernpx -y @modelcontextprotocol/server-filesystem /tmp/allowedThis starts an MCP server that can access files in /tmp/allowed.
Step 2: Create Tool-Enabled Bot
Section titled “Step 2: Create Tool-Enabled Bot”package main
import ( "bufio" "context" "fmt" "log" "os" "strings"
"github.com/AltairaLabs/PromptKit/runtime/mcp" "github.com/AltairaLabs/PromptKit/runtime/pipeline" "github.com/AltairaLabs/PromptKit/runtime/pipeline/middleware" "github.com/AltairaLabs/PromptKit/runtime/providers/openai" "github.com/AltairaLabs/PromptKit/runtime/tools")
func main() { // Create MCP registry mcpRegistry := mcp.NewRegistry() defer mcpRegistry.Close()
// Register filesystem server err := mcpRegistry.RegisterServer(mcp.ServerConfig{ Name: "filesystem", Command: "npx", Args: []string{"-y", "@modelcontextprotocol/server-filesystem", "/tmp/allowed"}, }) if err != nil { log.Fatal(err) }
// Create tool registry toolRegistry := tools.NewRegistry() toolRegistry.RegisterExecutor(tools.NewMCPExecutor(mcpRegistry))
// Discover and register MCP tools ctx := context.Background() serverTools, err := mcpRegistry.ListAllTools(ctx) if err != nil { log.Fatal(err) }
for _, mcpTools := range serverTools { for _, mcpTool := range mcpTools { toolRegistry.Register(&tools.ToolDescriptor{ Name: mcpTool.Name, Description: mcpTool.Description, InputSchema: mcpTool.InputSchema, Mode: "mcp", }) fmt.Printf("Registered tool: %s\n", mcpTool.Name) } }
// Create provider provider := openai.NewOpenAIProvider( "openai", "gpt-4o-mini", os.Getenv("OPENAI_API_KEY"), openai.DefaultProviderDefaults(), false, ) defer provider.Close()
// Build pipeline with tools pipe := pipeline.NewPipeline( middleware.ProviderMiddleware(provider, toolRegistry, &pipeline.ToolPolicy{ ToolChoice: "auto", MaxRounds: 5, }, &middleware.ProviderMiddlewareConfig{ MaxTokens: 1500, Temperature: 0.7, }), ) defer pipe.Shutdown(context.Background())
// Interactive loop fmt.Println("\nTool-enabled chatbot ready! Type 'exit' to quit.") fmt.Print("\nYou: ")
scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input := strings.TrimSpace(scanner.Text())
if input == "exit" { break }
if input == "" { fmt.Print("You: ") continue }
result, err := pipe.Execute(ctx, "user", input) if err != nil { log.Printf("Error: %v\n", err) fmt.Print("You: ") continue }
fmt.Printf("\nBot: %s\n\n", result.Response.Content) fmt.Print("You: ") }
fmt.Println("Goodbye!")}Step 3: Test with Files
Section titled “Step 3: Test with Files”Create test directory and files:
mkdir -p /tmp/allowedecho "Hello from file!" > /tmp/allowed/test.txtecho "Shopping: milk, eggs, bread" > /tmp/allowed/shopping.txtRun the bot:
go run main.goTry these prompts:
You: Read the file /tmp/allowed/test.txtBot: The file contains: "Hello from file!"
You: List all files in /tmp/allowedBot: There are 2 files: test.txt and shopping.txt
You: What's in my shopping list?Bot: Your shopping list contains: milk, eggs, and bread
You: Create a new file called notes.txt with "Meeting at 3pm"Bot: I've created notes.txt with your message.The LLM automatically uses tools to complete tasks! 🎉
Understanding Tool Calling
Section titled “Understanding Tool Calling”How Tools Work
Section titled “How Tools Work”- Registration: Tools are registered with descriptions
- LLM Decision: LLM decides when to use tools
- Execution: Runtime executes tool calls
- Response: LLM sees results and responds to user
Tool Policy
Section titled “Tool Policy”policy := &pipeline.ToolPolicy{ ToolChoice: "auto", // "auto", "required", "none" MaxRounds: 5, // Max back-and-forth with tools}auto: LLM chooses when to use toolsrequired: LLM must use at least one toolnone: Tools disabled
Available Filesystem Tools
Section titled “Available Filesystem Tools”read_file: Read file contentswrite_file: Write to filelist_directory: List directory contentscreate_directory: Create directorymove_file: Move/rename filedelete_file: Delete file
Add Memory Server
Section titled “Add Memory Server”Install memory MCP server for persistent key-value storage:
// Register memory servermcpRegistry.RegisterServer(mcp.ServerConfig{ Name: "memory", Command: "npx", Args: []string{"-y", "@modelcontextprotocol/server-memory"},})Memory tools:
store_memory: Save data by keyretrieve_memory: Get data by key
Try:
You: Remember that my favorite color is blueBot: I've stored that information.
You: What's my favorite color?Bot: Your favorite color is blue.Complete Example with Multiple Servers
Section titled “Complete Example with Multiple Servers”package main
import ( "bufio" "context" "fmt" "log" "os" "strings"
"github.com/AltairaLabs/PromptKit/runtime/mcp" "github.com/AltairaLabs/PromptKit/runtime/pipeline" "github.com/AltairaLabs/PromptKit/runtime/pipeline/middleware" "github.com/AltairaLabs/PromptKit/runtime/providers/openai" "github.com/AltairaLabs/PromptKit/runtime/statestore" "github.com/AltairaLabs/PromptKit/runtime/tools")
func main() { // MCP setup mcpRegistry := mcp.NewRegistry() defer mcpRegistry.Close()
// Register servers servers := []mcp.ServerConfig{ { Name: "filesystem", Command: "npx", Args: []string{"-y", "@modelcontextprotocol/server-filesystem", "/tmp/allowed"}, }, { Name: "memory", Command: "npx", Args: []string{"-y", "@modelcontextprotocol/server-memory"}, }, }
for _, config := range servers { if err := mcpRegistry.RegisterServer(config); err != nil { log.Fatalf("Failed to register %s: %v", config.Name, err) } fmt.Printf("Registered MCP server: %s\n", config.Name) }
// Tool registry setup toolRegistry := tools.NewRegistry() toolRegistry.RegisterExecutor(tools.NewMCPExecutor(mcpRegistry))
// Discover tools ctx := context.Background() serverTools, _ := mcpRegistry.ListAllTools(ctx) for serverName, mcpTools := range serverTools { fmt.Printf("\n%s tools:\n", serverName) for _, tool := range mcpTools { toolRegistry.Register(&tools.ToolDescriptor{ Name: tool.Name, Description: tool.Description, InputSchema: tool.InputSchema, Mode: "mcp", }) fmt.Printf(" - %s: %s\n", tool.Name, tool.Description) } }
// Provider and pipeline provider := openai.NewOpenAIProvider( "openai", "gpt-4o-mini", os.Getenv("OPENAI_API_KEY"), openai.DefaultProviderDefaults(), false, ) defer provider.Close()
store := statestore.NewInMemoryStateStore()
pipe := pipeline.NewPipeline( middleware.StateMiddleware(store), middleware.ProviderMiddleware(provider, toolRegistry, &pipeline.ToolPolicy{ ToolChoice: "auto", MaxRounds: 5, }, &middleware.ProviderMiddlewareConfig{ MaxTokens: 1500, Temperature: 0.7, }), ) defer pipe.Shutdown(ctx)
sessionID := "tool-session"
fmt.Println("\n=== Tool-Enabled Agent ===") fmt.Println("Available: filesystem and memory tools") fmt.Println("Type 'exit' to quit\n")
scanner := bufio.NewScanner(os.Stdin) fmt.Print("You: ")
for scanner.Scan() { input := strings.TrimSpace(scanner.Text())
if input == "exit" { break }
if input == "" { fmt.Print("You: ") continue }
result, err := pipe.ExecuteWithContext(ctx, sessionID, "user", input) if err != nil { log.Printf("\nError: %v\n\n", err) fmt.Print("You: ") continue }
fmt.Printf("\nAgent: %s\n\n", result.Response.Content) fmt.Printf("[Cost: $%.6f]\n\n", result.Cost.TotalCost) fmt.Print("You: ") }
fmt.Println("Goodbye!")}Common Issues
Section titled “Common Issues”MCP server won’t start
Section titled “MCP server won’t start”Problem: npx command fails.
Solution: Install Node.js or specify full path to npx.
Tools not working
Section titled “Tools not working”Problem: LLM doesn’t use tools.
Solution: Use clear prompts: “Read the file test.txt” not “What’s in that file?”
Permission errors
Section titled “Permission errors”Problem: Can’t access files.
Solution: Ensure path is within allowed directory: /tmp/allowed/file.txt
What You’ve Learned
Section titled “What You’ve Learned”✅ Set up MCP servers
✅ Register external tools
✅ Enable automatic tool calling
✅ Handle tool execution
✅ Build tool-enabled agents
✅ Use multiple MCP servers
Next Steps
Section titled “Next Steps”Continue to Tutorial 4: Validation & Guardrails to add content safety.
See Also
Section titled “See Also”- Integrate MCP - More MCP patterns
- Tools & MCP Reference - Complete API