mcp_server

package
v0.9.339 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 14, 2026 License: MIT Imports: 20 Imported by: 0

README

StackQL MCP Server Package

This package implements a Model Context Protocol (MCP) server for StackQL, enabling LLMs to consume StackQL as a first-class information source.

Overview

The mcp_server package provides:

  1. Backend Interface Abstraction: A clean interface for executing queries that can be implemented for in-memory, TCP, or other communication methods
  2. Configuration Management: Comprehensive configuration structures with JSON and YAML support
  3. MCP Server Implementation: A complete MCP server supporting multiple transports (stdio, TCP, WebSocket)

Architecture

The package is designed with zero dependencies on StackQL internals, making it modular and reusable. The key components are:

  • Backend: Interface for query execution and schema retrieval
  • Config: Configuration structures with validation
  • MCPServer: Main server implementation supporting MCP protocol
  • ExampleBackend: Sample implementation for testing and demonstration

Usage

Basic Usage
package main

import (
    "context"
    "log"
    
    "github.com/stackql/stackql/pkg/mcp_server"
)

func main() {
    // Create server with default configuration and example backend
    server, err := mcp_server.NewMCPServerWithExampleBackend(nil)
    if err != nil {
        log.Fatal(err)
    }
    
    // Start the server
    ctx := context.Background()
    if err := server.Start(ctx); err != nil {
        log.Fatal(err)
    }
    
    // Server will run until context is cancelled
    <-ctx.Done()
    
    // Graceful shutdown
    server.Stop(context.Background())
}
Custom Configuration
config := &mcp_server.Config{
    Server: mcp_server.ServerConfig{
        Name:                  "My StackQL MCP Server",
        Version:               "1.0.0",
        Description:           "Custom MCP server for StackQL",
        MaxConcurrentRequests: 50,
        RequestTimeout:        mcp_server.Duration(30 * time.Second),
    },
    Backend: mcp_server.BackendConfig{
        Type:              "stackql",
        ConnectionString:  "stackql://localhost:5432",
        MaxConnections:    20,
        ConnectionTimeout: mcp_server.Duration(10 * time.Second),
        QueryTimeout:      mcp_server.Duration(60 * time.Second),
    },
    Transport: mcp_server.TransportConfig{
        EnabledTransports: []string{"stdio", "tcp"},
        TCP: mcp_server.TCPTransportConfig{
            Address: "0.0.0.0",
            Port:    8080,
        },
    },
    Logging: mcp_server.LoggingConfig{
        Level:  "info",
        Format: "json",
        Output: "/var/log/mcp-server.log",
    },
}

server, err := mcp_server.NewMCPServer(config, backend, logger)
Implementing a Custom Backend
type MyBackend struct {
    // Your backend implementation
}

func (b *MyBackend) Execute(ctx context.Context, query string, params map[string]interface{}) (*mcp_server.QueryResult, error) {
    // Execute the query using your preferred method
    // Return structured results
}

func (b *MyBackend) GetSchema(ctx context.Context) (*mcp_server.Schema, error) {
    // Return schema information about available providers and resources
}

func (b *MyBackend) Ping(ctx context.Context) error {
    // Verify backend connectivity
}

func (b *MyBackend) Close() error {
    // Clean up resources
}

Configuration

JSON Configuration Example
{
  "server": {
    "name": "StackQL MCP Server",
    "version": "1.0.0",
    "description": "Model Context Protocol server for StackQL",
    "max_concurrent_requests": 100,
    "request_timeout": "30s"
  },
  "backend": {
    "type": "stackql",
    "connection_string": "stackql://localhost",
    "max_connections": 10,
    "connection_timeout": "10s",
    "query_timeout": "30s",
    "retry": {
      "enabled": true,
      "max_attempts": 3,
      "initial_delay": "100ms",
      "max_delay": "5s",
      "multiplier": 2.0
    }
  },
  "transport": {
    "enabled_transports": ["stdio", "tcp"],
    "tcp": {
      "address": "localhost",
      "port": 8080,
      "max_connections": 100,
      "read_timeout": "30s",
      "write_timeout": "30s"
    }
  },
  "logging": {
    "level": "info",
    "format": "text",
    "output": "stdout",
    "enable_request_logging": false
  }
}
YAML Configuration Example
server:
  name: "StackQL MCP Server"
  version: "1.0.0"
  description: "Model Context Protocol server for StackQL"
  max_concurrent_requests: 100
  request_timeout: "30s"

backend:
  type: "stackql"
  connection_string: "stackql://localhost"
  max_connections: 10
  connection_timeout: "10s"
  query_timeout: "30s"
  retry:
    enabled: true
    max_attempts: 3
    initial_delay: "100ms"
    max_delay: "5s"
    multiplier: 2.0

transport:
  enabled_transports: ["stdio", "tcp"]
  tcp:
    address: "localhost"
    port: 8080
    max_connections: 100
    read_timeout: "30s"
    write_timeout: "30s"

logging:
  level: "info"
  format: "text"
  output: "stdout"
  enable_request_logging: false

MCP Protocol Support

The server implements the Model Context Protocol specification and supports:

  • Initialization: Capability negotiation with MCP clients
  • Resources: Listing and reading StackQL resources (providers, services, resources)
  • Tools: Query execution tool for running StackQL queries
  • Multiple Transports: stdio, TCP, and WebSocket (WebSocket implementation is placeholder)
Supported MCP Methods
  • initialize: Server initialization and capability negotiation
  • resources/list: List available StackQL resources
  • resources/read: Read specific resource data
  • tools/list: List available tools (StackQL query execution)
  • tools/call: Execute StackQL queries

Transport Support

Stdio Transport
  • Primary transport for command-line integration
  • JSON-RPC over stdin/stdout
  • Ideal for shell integrations and CLI tools
TCP Transport
  • HTTP-based JSON-RPC
  • Suitable for network-based integrations
  • Configurable address, port, and connection limits
WebSocket Transport (Placeholder)
  • Real-time bidirectional communication
  • Suitable for web applications
  • Currently implemented as placeholder

Development

Testing

The package includes an example backend for testing:

go test ./pkg/mcp_server/...
Integration with StackQL

To integrate with actual StackQL:

  1. Implement the Backend interface using StackQL's query execution engine
  2. Map StackQL's schema information to the Schema structure
  3. Handle StackQL-specific error types and convert them to BackendError

Dependencies

The package uses minimal external dependencies:

  • github.com/gorilla/mux: HTTP routing (already available in StackQL)
  • golang.org/x/sync: Concurrency utilities (already available in StackQL)
  • gopkg.in/yaml.v2: YAML configuration support (already available in StackQL)

No MCP SDK dependency is required as the package implements the MCP protocol directly.

Future Enhancements

  1. Full WebSocket Implementation: Complete WebSocket transport support
  2. Stdio Transport: Complete stdio JSON-RPC implementation
  3. Authentication: Add authentication and authorization support
  4. Streaming: Support for streaming large query results
  5. Caching: Query result caching for improved performance
  6. Metrics: Prometheus metrics for monitoring and observability

Documentation

Index

Constants

View Source
const (
	MCPClientTypeHTTP  = "http"
	MCPClientTypeSTDIO = "stdio"
)
View Source
const (
	ExplainerForeignKeyStackql         = "At present, foreign keys are not meaningfully supported in stackql."
	ExplainerFindRelationships         = "At present, relationship finding is not meaningfully supported in stackql."
	ExplainerPromptWriteSafeSelectTool = `` /* 257-byte string literal not displayed */

)
View Source
const (
	DefaultHTTPServerAddress = "127.0.0.1:9876"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend

type Backend interface {

	// Ping verifies the backend connection is active.
	Ping(ctx context.Context) error

	// Close gracefully shuts down the backend connection.
	Close() error
	// Server and environment info
	ServerInfo(ctx context.Context, args any) (dto.ServerInfoOutput, error)

	// Current DB identity details
	DBIdentity(ctx context.Context, args any) (map[string]any, error)

	Greet(ctx context.Context, args dto.GreetInput) (string, error)

	// Execute a SQL query with typed input (preferred)
	RunQuery(ctx context.Context, args dto.QueryInput) (string, error)

	// Execute a SQL query that does not return rows
	ExecQuery(ctx context.Context, query string) (map[string]any, error)

	// Execute a SQL query that does not return rows
	ValidateQuery(ctx context.Context, query string) ([]map[string]any, error)

	// Execute a SQL query and return JSON rows with typed input (preferred)
	RunQueryJSON(ctx context.Context, input dto.QueryJSONInput) ([]map[string]interface{}, error)

	// Prompt: guidelines for writing safe SELECT queries
	PromptWriteSafeSelectTool(ctx context.Context, args dto.HierarchyInput) (string, error)

	// List tables in a schema with optional filters and return JSON rows
	ListTablesJSON(ctx context.Context, input dto.ListTablesInput) ([]map[string]interface{}, error)

	// List tables with pagination and filters
	ListTablesJSONPage(ctx context.Context, input dto.ListTablesPageInput) (map[string]interface{}, error)

	// List all schemas in the database
	ListProviders(ctx context.Context) ([]map[string]any, error)

	ListServices(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

	ListResources(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)
	ListMethods(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

	// Get detailed information about a table
	DescribeTable(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

	// Get foreign key information for a table
	GetForeignKeys(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

	// Find both explicit and implied relationships for a table
	FindRelationships(ctx context.Context, hI dto.HierarchyInput) (string, error)
}

func NewExampleBackend

func NewExampleBackend(connectionString string) Backend

NewExampleBackend creates a new example backend instance.

type BackendConfig

type BackendConfig struct {
	// Type specifies the backend type ("tcp", "memory").
	Type string `json:"type" yaml:"type"`

	// AppName is an optional application name describing the backend.
	// In the first instance, this is stackql.
	// **Possible** future use case for the backing db (e.g., "postgres", "mysql", etc).
	AppName string `json:"app_name" yaml:"app_name"`

	// ConnectionString contains the connection details for the backend.
	// Format depends on the backend type.
	ConnectionString string `json:"dsn" yaml:"dsn"`

	// MaxConnections limits the number of backend connections.
	MaxConnections int `json:"max_connections" yaml:"max_connections"`

	// ConnectionTimeout specifies the timeout for backend connections.
	ConnectionTimeout Duration `json:"connection_timeout" yaml:"connection_timeout"`

	// QueryTimeout specifies the timeout for individual queries.
	QueryTimeout Duration `json:"query_timeout" yaml:"query_timeout"`
}

BackendConfig contains configuration for the backend connection.

type BackendError

type BackendError struct {
	// Code is a machine-readable error code.
	Code string `json:"code"`

	// Message is a human-readable error message.
	Message string `json:"message"`

	// Details contains additional context about the error.
	Details map[string]interface{} `json:"details,omitempty"`
}

BackendError represents an error that occurred in the backend.

func (*BackendError) Error

func (e *BackendError) Error() string

func (*BackendError) Value

func (e *BackendError) Value() (driver.Value, error)

Ensure BackendError implements the driver.Valuer interface for database compatibility.

type ColumnInfo

type ColumnInfo interface {
	// GetName returns the column name as returned by the query.
	GetName() string

	// GetType returns the data type of the column (e.g., "string", "int64", "float64").
	GetType() string

	// IsNullable indicates whether the column can contain null values.
	IsNullable() bool
}

ColumnInfo provides metadata about a result column.

func NewColumnInfo

func NewColumnInfo(name, colType string, nullable bool) ColumnInfo

NewColumnInfo creates a new ColumnInfo instance.

type Config

type Config struct {
	// Server contains server-specific configuration.
	Server ServerConfig `json:"server" yaml:"server"`

	// Backend contains backend-specific configuration.
	Backend BackendConfig `json:"backend" yaml:"backend"`
}

Config represents the complete configuration for the MCP server.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a configuration with sensible defaults.

func DefaultHTTPConfig

func DefaultHTTPConfig() *Config

func DefaultSSEConfig

func DefaultSSEConfig() *Config

func LoadFromJSON

func LoadFromJSON(data []byte) (*Config, error)

LoadFromJSON loads configuration from JSON data.

func LoadFromYAML

func LoadFromYAML(data []byte) (*Config, error)

LoadFromYAML loads configuration from YAML data.

func (*Config) GetBackendConnectionString

func (c *Config) GetBackendConnectionString() string

func (*Config) GetServerAddress

func (c *Config) GetServerAddress() string

func (*Config) GetServerTransport

func (c *Config) GetServerTransport() string

func (*Config) IsTcpBackend

func (c *Config) IsTcpBackend() bool

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration and returns an error if invalid.

type Duration

type Duration time.Duration

Duration is a wrapper around time.Duration that can be marshaled to/from JSON and YAML.

func (Duration) MarshalJSON

func (d Duration) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (Duration) MarshalYAML

func (d Duration) MarshalYAML() (interface{}, error)

MarshalYAML implements yaml.Marshaler.

func (*Duration) UnmarshalJSON

func (d *Duration) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

func (*Duration) UnmarshalYAML

func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error

UnmarshalYAML implements yaml.Unmarshaler.

type ExampleBackend

type ExampleBackend struct {
	// contains filtered or unexported fields
}

ExampleBackend is a simple implementation of the Backend interface for demonstration purposes. This shows how to implement the Backend interface without depending on StackQL internals.

func (*ExampleBackend) Close

func (b *ExampleBackend) Close() error

Close implements the Backend interface.

func (*ExampleBackend) DBIdentity

func (b *ExampleBackend) DBIdentity(ctx context.Context, _ any) (map[string]any, error)

Please adjust all below to sensible signatures in keeping with what is above. Do it now!

func (*ExampleBackend) DescribeTable

func (b *ExampleBackend) DescribeTable(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

func (*ExampleBackend) ExecQuery added in v0.9.266

func (b *ExampleBackend) ExecQuery(ctx context.Context, query string) (map[string]any, error)

func (*ExampleBackend) FindRelationships

func (b *ExampleBackend) FindRelationships(ctx context.Context, hI dto.HierarchyInput) (string, error)

func (*ExampleBackend) GetForeignKeys

func (b *ExampleBackend) GetForeignKeys(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

func (*ExampleBackend) Greet

func (b *ExampleBackend) Greet(ctx context.Context, args dto.GreetInput) (string, error)

func (*ExampleBackend) ListMethods

func (b *ExampleBackend) ListMethods(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

func (*ExampleBackend) ListProviders

func (b *ExampleBackend) ListProviders(ctx context.Context) ([]map[string]any, error)

func (*ExampleBackend) ListResources

func (b *ExampleBackend) ListResources(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

func (*ExampleBackend) ListServices

func (b *ExampleBackend) ListServices(ctx context.Context, hI dto.HierarchyInput) ([]map[string]any, error)

func (*ExampleBackend) ListTables

func (b *ExampleBackend) ListTables(ctx context.Context, hI dto.HierarchyInput) ([]map[string]interface{}, error)

func (*ExampleBackend) ListTablesJSON

func (b *ExampleBackend) ListTablesJSON(ctx context.Context, input dto.ListTablesInput) ([]map[string]interface{}, error)

func (*ExampleBackend) ListTablesJSONPage

func (b *ExampleBackend) ListTablesJSONPage(ctx context.Context, input dto.ListTablesPageInput) (map[string]interface{}, error)

func (*ExampleBackend) Ping

func (b *ExampleBackend) Ping(ctx context.Context) error

Ping implements the Backend interface.

func (*ExampleBackend) PromptWriteSafeSelectTool

func (b *ExampleBackend) PromptWriteSafeSelectTool(ctx context.Context, args dto.HierarchyInput) (string, error)

func (*ExampleBackend) ReadTableResource

func (b *ExampleBackend) ReadTableResource(ctx context.Context, hI dto.HierarchyInput) ([]map[string]interface{}, error)

func (*ExampleBackend) RunQuery

func (b *ExampleBackend) RunQuery(ctx context.Context, args dto.QueryInput) (string, error)

func (*ExampleBackend) RunQueryJSON

func (b *ExampleBackend) RunQueryJSON(ctx context.Context, input dto.QueryJSONInput) ([]map[string]interface{}, error)

func (*ExampleBackend) ServerInfo

func (b *ExampleBackend) ServerInfo(ctx context.Context, _ any) (dto.ServerInfoOutput, error)

func (*ExampleBackend) ValidateQuery added in v0.9.266

func (b *ExampleBackend) ValidateQuery(ctx context.Context, query string) ([]map[string]any, error)

type Field

type Field interface {
	// GetName returns the field identifier.
	GetName() string

	// GetType returns the field data type.
	GetType() string

	// IsRequired indicates if this field is mandatory for certain operations.
	IsRequired() bool

	// GetDescription returns human-readable documentation for the field.
	GetDescription() string
}

Field represents a field within a resource.

func NewField

func NewField(name, fieldType string, required bool, description string) Field

NewField creates a new Field instance.

type MCPClient

type MCPClient interface {
	InspectTools() ([]map[string]any, error)
	CallToolText(toolName string, args map[string]any) (string, error)
}

func NewMCPClient

func NewMCPClient(clientType string, baseURL string, clientCfgMap map[string]any, logger *logrus.Logger) (MCPClient, error)

type MCPServer

type MCPServer interface {
	Start(context.Context) error
	Stop() error
}

func NewAgnosticBackendServer

func NewAgnosticBackendServer(backend Backend, config *Config, logger *logrus.Logger) (MCPServer, error)

func NewExampleBackendServer

func NewExampleBackendServer(config *Config, logger *logrus.Logger) (MCPServer, error)

func NewMCPServerWithExampleBackend

func NewMCPServerWithExampleBackend(config *Config) (MCPServer, error)

NewMCPServerWithExampleBackend creates a new MCP server with an example backend. This is a convenience function for testing and demonstration purposes.

type Provider

type Provider interface {
	// GetName returns the provider identifier (e.g., "aws", "google").
	GetName() string

	// GetVersion returns the provider version.
	GetVersion() string

	// GetServices returns all services available in this provider.
	GetServices() []Service
}

Provider represents a StackQL provider with its services and resources.

func NewProvider

func NewProvider(name, version string, services []Service) Provider

NewProvider creates a new Provider instance.

type QueryResult

type QueryResult interface {
	// GetColumns returns metadata about each column in the result set.
	GetColumns() []ColumnInfo

	// GetRows returns the actual data returned by the query.
	GetRows() [][]interface{}

	// GetRowsAffected returns the number of rows affected by DML operations.
	GetRowsAffected() int64

	// GetExecutionTime returns the time taken to execute the query in milliseconds.
	GetExecutionTime() int64
}

QueryResult represents the result of a query execution.

func NewQueryResult

func NewQueryResult(columns []ColumnInfo, rows [][]interface{}, rowsAffected, executionTime int64) QueryResult

NewQueryResult creates a new QueryResult instance.

type Resource

type Resource interface {
	// GetName returns the resource identifier (e.g., "instances", "buckets").
	GetName() string

	// GetMethods returns the available operations for this resource.
	GetMethods() []string

	// GetFields returns the available fields in this resource.
	GetFields() []Field
}

Resource represents a queryable resource.

func NewResource

func NewResource(name string, methods []string, fields []Field) Resource

NewResource creates a new Resource instance.

type SchemaProvider

type SchemaProvider interface {
	// GetProviders returns all available providers (e.g., aws, google, azure).
	GetProviders() []Provider
}

SchemaProvider represents the metadata structure of available resources.

func NewSchemaProvider

func NewSchemaProvider(providers []Provider) SchemaProvider

NewSchemaProvider creates a new SchemaProvider instance.

type ServerConfig

type ServerConfig struct {
	// Name is the server name advertised to clients.
	Name string `json:"name" yaml:"name"`

	// Transport specifies the transport configuration for the server.
	Transport string `json:"transport" yaml:"transport"`

	// Address is the server Address advertised to clients.
	Address string `json:"address" yaml:"address"`

	// Scheme is the protocol scheme used by the server.
	Scheme string `json:"scheme" yaml:"scheme"`

	// Version is the server version advertised to clients.
	Version string `json:"version" yaml:"version"`

	TLSCertFile string `json:"tls_cert_file,omitempty" yaml:"tls_cert_file,omitempty"`
	TLSKeyFile  string `json:"tls_key_file,omitempty" yaml:"tls_key_file,omitempty"`

	TransportCfg map[string]any `json:"transport_cfg,omitempty" yaml:"transport_cfg,omitempty"`

	// Description is a human-readable description of the server.
	Description string `json:"description" yaml:"description"`

	// MaxConcurrentRequests limits the number of concurrent client requests.
	MaxConcurrentRequests int `json:"max_concurrent_requests" yaml:"max_concurrent_requests"`

	// RequestTimeout specifies the timeout for individual requests.
	RequestTimeout Duration `json:"request_timeout" yaml:"request_timeout"`

	IsReadOnly *bool `json:"read_only,omitempty" yaml:"read_only,omitempty"`
}

ServerConfig contains configuration for the MCP server itself.

type Service

type Service interface {
	// GetName returns the service identifier (e.g., "ec2", "compute").
	GetName() string

	// GetResources returns all resources available in this service.
	GetResources() []Resource
}

Service represents a service within a provider.

func NewService

func NewService(name string, resources []Resource) Service

NewService creates a new Service instance.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL