implementation
Implementation Notes: Slack MCP Client
Current State (As of 2025-04-14)
Project Goal: Build a Slack bot that interacts with external tools and data sources via the Model Context Protocol (MCP), implemented in Go.
Architecture: See
README.md
for the high-level design. The core components are the Slack integration, the Go application (slack-mcp-client
), and external MCP servers.Slack Integration: Basic Slack client setup using
slack-go/slack
is in place (internal/slack/client.go
), listening for mentions and direct messages.MCP Client Configuration: Uses a flexible configuration approach for multiple MCP servers through
mcp-servers.json
following the schema defined inmcp-schema.json
.LLM Integration: The
internal/bridge/llm_mcp_bridge.go
component serves as the bridge between LLM models and the MCP client/server interaction.
Architecture & Implementation
Core Components
Configuration System
Configuration loaded from environment variables for Slack credentials and LLM settings
MCP server configurations from JSON file following the schema with
mcpServers
propertyEach server defined with
command
,args
, and optionalenv
properties
Slack Client (
internal/slack/client.go
)Connects to Slack using Socket Mode for secure, firewall-friendly communication
Handles app mentions and direct messages
Processes user prompts and forwards them to LLM
Returns responses and tool results back to Slack channels/DMs
MCP Client (
internal/mcp/client.go
)Support for multiple transport protocols:
SSE (Server-Sent Events): For real-time communication
HTTP: For request-response communication
stdio: For local development with command-line tools
Dynamic initialization with proper command line argument parsing
Runtime discovery of available tools from MCP servers
LLM-MCP Bridge (
internal/bridge/llm_mcp_bridge.go
)Inspects LLM responses and user prompts to detect tool invocation patterns
Translates detected patterns into MCP tool calls
Processes tool results and formats them for user consumption
Supports both structured JSON tool calls and natural language detection
Tool Implementations
Filesystem operations: For accessing and managing files
Hello tool: Simple demonstration tool
Ollama integration: Connect with Ollama models
MCP Server Configuration
MCP servers are configured using a JSON file following this structure:
Main Process Flow
Start-up Sequence:
Parse command-line arguments
Load environment variables and configuration file
Initialize MCP clients for each configured server
Connect to Slack using Socket Mode
Message Processing:
Receive messages from Slack (mentions or DMs)
Forward messages to LLM (Ollama)
Process LLM response through LLMMCPBridge
If tool invocation is detected:
Execute appropriate MCP tool call
Format tool results
Return final response to Slack
Tool Detection & Execution:
JSON pattern matching for structured tool invocations
Regular expression matching for natural language requests
Validate against available tools discovered from MCP servers
Execute tool call with appropriate parameters
Process and format tool results
Future Improvements
Enhanced Natural Language Tool Detection
Improve regex patterns for more natural interactions
Add support for contextual tool detection (understanding from conversation context)
Tool Authentication & Security
Implement proper authentication for secure tool access
Add permission controls for sensitive operations
Additional MCP Tool Integrations
Database tools
API connectors
Document processing tools
UI Enhancements
Rich Slack message formatting for tool results
Interactive components (buttons, dropdowns) for tool parameter selection
Progress indicators for long-running tool operations
Conversation Context Management
Maintain context between messages for more coherent interactions
Allow tools to access previous conversation history when relevant
Debugging Stdio Transport Issues
Problem: Significant challenges were encountered with
stdio
transport mode. Whilestdio
clients (likegithub
,mcp-trino
) would often successfully complete the initialInitialize
handshake, subsequent calls likeGetAvailableTools
orCallTool
would consistently fail withfile already closed
errors.Initial Investigation:
Code analysis initially focused on the
GetAvailableTools
implementation ininternal/mcp/client.go
, correcting flawed logic that checked for a non-existentsendRequest
method on the library'sStdioMCPClient
.Analysis of the
mcp-go
library'sclient/stdio.go
confirmed thatStdioMCPClient
does implement the standardListTools
method, but doesn't have obvious internal idle timeouts.
Manual Testing:
Running server commands (e.g.,
github-mcp-server stdio
) manually and pipinginitialize
followed immediately bytools/list
JSON-RPC requests worked correctly.Running the server command manually and letting it sit idle showed it did not exit automatically after a short period.
Hypothesis: The issue wasn't an inherent server crash or timeout, but rather the delay between the successful
Initialize
call and the subsequentGetAvailableTools
call in the original application flow (where all clients were initialized first, then all tools were discovered). This gap seemed to cause the library or the server to close the stdio pipes.Resolution: The
main
function incmd/slack-mcp-client/main.go
was refactored. Instead of separate loops for initialization and discovery, a single loop now processes each server sequentially:Create client instance.
Call
Initialize
.If initialization succeeds, immediately call
GetAvailableTools
.
Outcome: This sequential processing eliminated the delay and resolved the
file already closed
errors, allowingGetAvailableTools
to successfully retrieve tools from thestdio
servers.
Slack MCP Client Restructuring
This document outlines the architectural restructuring of the Slack MCP Client for improved maintainability and sustainability.
Key Changes
1. Modular Directory Structure
The codebase has been reorganized with a clear separation of concerns:
2. Interface-Based Design
Introduced a
ToolHandler
interface for all tool implementationsCreated a
BaseHandler
with common functionalityImplemented a
Registry
for centralized handler management
3. Standardized Error Handling
Created domain-specific error types for better error context
Implemented consistent error wrapping and propagation
Added status code to error mapping for HTTP errors
4. Robust HTTP Client
Developed a shared HTTP client with retry functionality
Implemented exponential backoff with jitter
Added request/response logging and customizable timeouts
5. Structured Logging
Implemented a hierarchical logger with log levels
Added context-aware logging with named loggers
Maintained compatibility with standard log.Logger
6. Server Refactoring
Moved server logic to dedicated package
Implemented handler registration system
Improved shutdown handling and error propagation
Benefits
Maintainability: Clear separation of concerns makes the codebase easier to understand and maintain
Scalability: Interface-based design allows for easy addition of new tool handlers
Robustness: Improved error handling and retry mechanisms increase reliability
Observability: Structured logging provides better insight into operation
Testability: Interface-based design makes unit testing easier
Implementation Details
Handler Interface
Error Handling
HTTP Client
Migration Guide
When implementing new features:
Create new handlers in the appropriate subdirectory of
internal/handlers/
Implement the
ToolHandler
interfaceRegister the handler in
internal/server/server.go
Use structured error handling with the
errors
packageLeverage the common HTTP client for external API calls
Use the structured logger for consistent logging
Next Steps
To complete the restructuring, the following tasks should be undertaken:
Update Main Application:
Modify
cmd/slack-mcp-client/main.go
to use the new server packageInitialize the structured logger
Migrate Configuration Logic:
Move environment variable loading to a central configuration service
Implement config validation
Refactor Slack Client:
Use the new structured logger
Integrate with the error handling system
Add Comprehensive Tests:
Unit tests for handlers
Integration tests for server functionality
Documentation Updates:
Update
README.md
with the new architectureCreate API documentation for the new interfaces
Monitoring & Observability:
Add metrics collection
Implement trace context propagation
This new architecture provides a solid foundation for future development and ensures the long-term sustainability of the Slack MCP Client.
Code Duplication Removal
As part of the restructuring, several duplicated components have been identified and removed:
Removed Duplicate Documentation:
RESTRUCTURING.md
was merged intoimplementation.md
to maintain a single source of documentation
Consolidated Logging System:
Removed the older logger implementation in
internal/logger
Standardized on the structured logger in
internal/common/logging
Updated all imports and function signatures across the codebase
Consolidated LLM Handlers:
Removed duplicate LLM handler implementations in
internal/llms
Standardized on the handler-based implementation in
internal/handlers/llm
Server Implementation Consolidation:
Removed the old server implementation in
internal/mcp/server.go
Now using the new implementation from
internal/server/server.go
Created a thin re-export layer in
internal/mcp/server.go
for backward compatibilityThis maintains the public API while using the new internal structure
Client Implementation Relocation:
Moved the client implementation from
internal/mcp/client.go
tointernal/client/client.go
Updated the package name from
mcp
toclient
for consistencyAdded re-export in
internal/mcp/server.go
to maintain backward compatibilityThe client still uses the current implementation but is now in the correct package structure
By removing these duplications, the codebase is now more maintainable, with clear responsibilities for each component and a consistent approach to common concerns like logging, error handling, and HTTP requests.
Last updated
Was this helpful?