In-Process Transport
In-process transport enables direct integration of MCP servers within the same process, eliminating network overhead and providing seamless integration for embedded scenarios.
Use Cases
In-process transport is perfect for:
- Embedded servers: MCP functionality within existing applications
- Testing and development: Fast, reliable testing without network overhead
- Library integrations: MCP as a library component
- Single-process architectures: Monolithic applications with MCP capabilities
- Desktop applications with plugin architectures
- Testing frameworks
- Embedded analytics engines
- Game engines with AI tool integration
Implementation
Basic In-Process Server
package main
import (
"context"
"fmt"
"log"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/mark3labs/mcp-go/client"
)
func main() {
// Create server
s := server.NewMCPServer("Calculator Server", "1.0.0",
server.WithToolCapabilities(true),
)
// Add calculator tool
s.AddTool(
mcp.NewTool("calculate",
mcp.WithDescription("Perform basic mathematical calculations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Enum("add", "subtract", "multiply", "divide"),
mcp.Description("The operation to perform"),
),
mcp.WithNumber("x", mcp.Required(), mcp.Description("First number")),
mcp.WithNumber("y", mcp.Required(), mcp.Description("Second number")),
),
handleCalculate,
)
// Create in-process client
mcpClient, err := client.NewInProcessClient(s)
if err != nil {
log.Fatal(err)
}
defer mcpClient.Close()
ctx := context.Background()
// Initialize
_, err = mcpClient.Initialize(ctx, mcp.InitializeRequest{
Params: mcp.InitializeRequestParams{
ProtocolVersion: "2024-11-05",
Capabilities: mcp.ClientCapabilities{
Tools: &mcp.ToolsCapability{},
},
ClientInfo: mcp.Implementation{
Name: "test-client",
Version: "1.0.0",
},
},
})
if err != nil {
log.Fatal(err)
}
// Use the calculator
result, err := mcpClient.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "calculate",
Arguments: map[string]interface{}{
"operation": "add",
"x": 10.0,
"y": 5.0,
},
},
})
if err != nil {
log.Fatal(err)
}
// Extract text from the first content item
if len(result.Content) > 0 {
if textContent, ok := mcp.AsTextContent(result.Content[0]); ok {
fmt.Printf("Result: %s\n", textContent.Text)
}
}
}
func handleCalculate(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
operation := req.GetString("operation", "")
x := req.GetFloat("x", 0)
y := req.GetFloat("y", 0)
var result float64
switch operation {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return mcp.NewToolResultError("division by zero"), nil
}
result = x / y
default:
return nil, fmt.Errorf("unknown operation: %s", operation)
}
return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
}
Embedded Application Integration
// Embedded MCP server in a larger application
type Application struct {
mcpServer *server.MCPServer
mcpClient *client.InProcessClient
config *Config
}
func NewApplication(config *Config) *Application {
app := &Application{
config: config,
}
// Create embedded MCP server
app.mcpServer = server.NewMCPServer("Embedded Server", "1.0.0",
server.WithToolCapabilities(true),
)
// Add application-specific tools
app.addApplicationTools()
// Create in-process client for internal use
var err error
app.mcpClient, err = client.NewInProcessClient(app.mcpServer)
if err != nil {
panic(err)
}
return app
}
type Config struct {
AppName string
Debug bool
}
func (app *Application) addApplicationTools() {
// Application status tool
app.mcpServer.AddTool(
mcp.NewTool("get_app_status",
mcp.WithDescription("Get current application status"),
),
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return mcp.NewToolResultText(fmt.Sprintf(`{"app_name":"%s","debug":%t,"status":"running"}`,
app.config.AppName, app.config.Debug)), nil
},
)
// Configuration tool
app.mcpServer.AddTool(
mcp.NewTool("update_config",
mcp.WithDescription("Update application configuration"),
mcp.WithString("key", mcp.Required()),
mcp.WithString("value", mcp.Required()),
),
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
key := req.GetString("key", "")
value := req.GetString("value", "")
// Update configuration based on key
switch key {
case "debug":
app.config.Debug = value == "true"
case "app_name":
app.config.AppName = value
default:
return mcp.NewToolResultError(fmt.Sprintf("unknown config key: %s", key)), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Updated %s to %s", key, value)), nil
},
)
}
func (app *Application) ProcessWithMCP(ctx context.Context, operation string) (interface{}, error) {
// Use MCP tools internally for processing
result, err := app.mcpClient.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "calculate",
Arguments: map[string]interface{}{
"operation": operation,
"x": 10.0,
"y": 5.0,
},
},
})
if err != nil {
return nil, err
}
// Extract text from the first content item
if len(result.Content) > 0 {
if textContent, ok := mcp.AsTextContent(result.Content[0]); ok {
return textContent.Text, nil
}
}
return "no result", nil
}
// Usage example
func main() {
config := &Config{
AppName: "My App",
Debug: true,
}
app := NewApplication(config)
ctx := context.Background()
// Initialize the embedded MCP client
_, err := app.mcpClient.Initialize(ctx, mcp.InitializeRequest{
Params: mcp.InitializeRequestParams{
ProtocolVersion: "2024-11-05",
Capabilities: mcp.ClientCapabilities{
Tools: &mcp.ToolsCapability{},
},
ClientInfo: mcp.Implementation{
Name: "embedded-client",
Version: "1.0.0",
},
},
})
if err != nil {
log.Fatal(err)
}
// Use MCP functionality within the application
result, err := app.ProcessWithMCP(ctx, "add")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Application result: %v\n", result)
}
Next Steps
- Client Development - Build MCP clients for all transports
- HTTP Transport - Learn about web-based scenarios
- Server Advanced Features - Explore production-ready features