@@ -2,7 +2,7 @@ package mcp_server
22
33import (
44 "context"
5- "database/sql/driver"
5+ "database/sql/driver" //nolint:unused
66)
77
88// Backend defines the interface for executing queries from MCP clients.
@@ -11,11 +11,11 @@ import (
1111type Backend interface {
1212 // Execute runs a query and returns the results.
1313 // The query string and parameters are provided by the MCP client.
14- Execute (ctx context.Context , query string , params map [string ]interface {}) (* QueryResult , error )
14+ Execute (ctx context.Context , query string , params map [string ]interface {}) (QueryResult , error )
1515
1616 // GetSchema returns metadata about available resources and their structure.
1717 // This is used by MCP clients to understand what data is available.
18- GetSchema (ctx context.Context ) (* Schema , error )
18+ GetSchema (ctx context.Context ) (SchemaProvider , error )
1919
2020 // Ping verifies the backend connection is active.
2121 Ping (ctx context.Context ) error
@@ -25,84 +25,84 @@ type Backend interface {
2525}
2626
2727// QueryResult represents the result of a query execution.
28- type QueryResult struct {
29- // Columns contains metadata about each column in the result set.
30- Columns []ColumnInfo `json:"columns"`
28+ type QueryResult interface {
29+ // GetColumns returns metadata about each column in the result set.
30+ GetColumns () []ColumnInfo
3131
32- // Rows contains the actual data returned by the query.
33- Rows [][]interface {} `json:"rows"`
32+ // GetRows returns the actual data returned by the query.
33+ GetRows () [][]interface {}
3434
35- // RowsAffected indicates the number of rows affected by DML operations.
36- RowsAffected int64 `json:"rows_affected"`
35+ // GetRowsAffected returns the number of rows affected by DML operations.
36+ GetRowsAffected () int64
3737
38- // ExecutionTime is the time taken to execute the query in milliseconds.
39- ExecutionTime int64 `json:"execution_time_ms"`
38+ // GetExecutionTime returns the time taken to execute the query in milliseconds.
39+ GetExecutionTime () int64
4040}
4141
4242// ColumnInfo provides metadata about a result column.
43- type ColumnInfo struct {
44- // Name is the column name as returned by the query.
45- Name string `json:"name"`
43+ type ColumnInfo interface {
44+ // GetName returns the column name as returned by the query.
45+ GetName () string
4646
47- // Type is the data type of the column (e.g., "string", "int64", "float64").
48- Type string `json:"type"`
47+ // GetType returns the data type of the column (e.g., "string", "int64", "float64").
48+ GetType () string
4949
50- // Nullable indicates whether the column can contain null values.
51- Nullable bool `json:"nullable"`
50+ // IsNullable indicates whether the column can contain null values.
51+ IsNullable () bool
5252}
5353
54- // Schema represents the metadata structure of available resources.
55- type Schema struct {
56- // Providers lists all available providers (e.g., aws, google, azure).
57- Providers []Provider `json:"providers"`
54+ // SchemaProvider represents the metadata structure of available resources.
55+ type SchemaProvider interface {
56+ // GetProviders returns all available providers (e.g., aws, google, azure).
57+ GetProviders () []Provider
5858}
5959
6060// Provider represents a StackQL provider with its services and resources.
61- type Provider struct {
62- // Name is the provider identifier (e.g., "aws", "google").
63- Name string `json:"name"`
61+ type Provider interface {
62+ // GetName returns the provider identifier (e.g., "aws", "google").
63+ GetName () string
6464
65- // Version is the provider version.
66- Version string `json:"version"`
65+ // GetVersion returns the provider version.
66+ GetVersion () string
6767
68- // Services lists all services available in this provider.
69- Services []Service `json:"services"`
68+ // GetServices returns all services available in this provider.
69+ GetServices () []Service
7070}
7171
7272// Service represents a service within a provider.
73- type Service struct {
74- // Name is the service identifier (e.g., "ec2", "compute").
75- Name string `json:"name"`
73+ type Service interface {
74+ // GetName returns the service identifier (e.g., "ec2", "compute").
75+ GetName () string
7676
77- // Resources lists all resources available in this service.
78- Resources []Resource `json:"resources"`
77+ // GetResources returns all resources available in this service.
78+ GetResources () []Resource
7979}
8080
8181// Resource represents a queryable resource.
82- type Resource struct {
83- // Name is the resource identifier (e.g., "instances", "buckets").
84- Name string `json:"name"`
82+ type Resource interface {
83+ // GetName returns the resource identifier (e.g., "instances", "buckets").
84+ GetName () string
8585
86- // Methods lists the available operations for this resource.
87- Methods []string `json:"methods"`
86+ // GetMethods returns the available operations for this resource.
87+ GetMethods () []string
8888
89- // Fields describes the available fields in this resource.
90- Fields []Field `json:"fields"`
89+ // GetFields returns the available fields in this resource.
90+ GetFields () []Field
9191}
9292
9393// Field represents a field within a resource.
94- type Field struct {
95- // Name is the field identifier.
96- Name string `json:"name"`
94+ type Field interface {
95+ // GetName returns the field identifier.
96+ GetName () string
9797
98- // Type is the field data type.
99- Type string `json:"type"`
98+ // GetType returns the field data type.
99+ GetType () string
100100
101- // Required indicates if this field is mandatory for certain operations.
102- Required bool `json:"required"`
101+ // IsRequired indicates if this field is mandatory for certain operations.
102+ IsRequired () bool
103103
104- // Description provides human-readable documentation for the field.
105- Description string `json:"description,omitempty"`
104+ // GetDescription returns human-readable documentation for the field.
105+ GetDescription () string
106106}
107107
108108// BackendError represents an error that occurred in the backend.
@@ -122,6 +122,140 @@ func (e *BackendError) Error() string {
122122}
123123
124124// Ensure BackendError implements the driver.Valuer interface for database compatibility
125- func (e * BackendError ) Value () (driver.Value , error ) {
125+ func (e * BackendError ) Value () (driver.Value , error ) { //nolint:unused
126126 return e .Message , nil
127+ }
128+
129+ // Private implementations of interfaces
130+
131+ type queryResult struct {
132+ Columns []ColumnInfo `json:"columns"`
133+ Rows [][]interface {} `json:"rows"`
134+ RowsAffected int64 `json:"rows_affected"`
135+ ExecutionTime int64 `json:"execution_time_ms"`
136+ }
137+
138+ func (qr * queryResult ) GetColumns () []ColumnInfo { return qr .Columns }
139+ func (qr * queryResult ) GetRows () [][]interface {} { return qr .Rows }
140+ func (qr * queryResult ) GetRowsAffected () int64 { return qr .RowsAffected }
141+ func (qr * queryResult ) GetExecutionTime () int64 { return qr .ExecutionTime }
142+
143+ type columnInfo struct {
144+ Name string `json:"name"`
145+ Type string `json:"type"`
146+ Nullable bool `json:"nullable"`
147+ }
148+
149+ func (ci * columnInfo ) GetName () string { return ci .Name }
150+ func (ci * columnInfo ) GetType () string { return ci .Type }
151+ func (ci * columnInfo ) IsNullable () bool { return ci .Nullable }
152+
153+ type schemaProvider struct {
154+ Providers []Provider `json:"providers"`
155+ }
156+
157+ func (sp * schemaProvider ) GetProviders () []Provider { return sp .Providers }
158+
159+ type provider struct {
160+ Name string `json:"name"`
161+ Version string `json:"version"`
162+ Services []Service `json:"services"`
163+ }
164+
165+ func (p * provider ) GetName () string { return p .Name }
166+ func (p * provider ) GetVersion () string { return p .Version }
167+ func (p * provider ) GetServices () []Service { return p .Services }
168+
169+ type service struct {
170+ Name string `json:"name"`
171+ Resources []Resource `json:"resources"`
172+ }
173+
174+ func (s * service ) GetName () string { return s .Name }
175+ func (s * service ) GetResources () []Resource { return s .Resources }
176+
177+ type resource struct {
178+ Name string `json:"name"`
179+ Methods []string `json:"methods"`
180+ Fields []Field `json:"fields"`
181+ }
182+
183+ func (r * resource ) GetName () string { return r .Name }
184+ func (r * resource ) GetMethods () []string { return r .Methods }
185+ func (r * resource ) GetFields () []Field { return r .Fields }
186+
187+ type field struct {
188+ Name string `json:"name"`
189+ Type string `json:"type"`
190+ Required bool `json:"required"`
191+ Description string `json:"description,omitempty"`
192+ }
193+
194+ func (f * field ) GetName () string { return f .Name }
195+ func (f * field ) GetType () string { return f .Type }
196+ func (f * field ) IsRequired () bool { return f .Required }
197+ func (f * field ) GetDescription () string { return f .Description }
198+
199+ // Factory functions
200+
201+ // NewQueryResult creates a new QueryResult instance.
202+ func NewQueryResult (columns []ColumnInfo , rows [][]interface {}, rowsAffected , executionTime int64 ) QueryResult {
203+ return & queryResult {
204+ Columns : columns ,
205+ Rows : rows ,
206+ RowsAffected : rowsAffected ,
207+ ExecutionTime : executionTime ,
208+ }
209+ }
210+
211+ // NewColumnInfo creates a new ColumnInfo instance.
212+ func NewColumnInfo (name , colType string , nullable bool ) ColumnInfo {
213+ return & columnInfo {
214+ Name : name ,
215+ Type : colType ,
216+ Nullable : nullable ,
217+ }
218+ }
219+
220+ // NewSchemaProvider creates a new SchemaProvider instance.
221+ func NewSchemaProvider (providers []Provider ) SchemaProvider {
222+ return & schemaProvider {
223+ Providers : providers ,
224+ }
225+ }
226+
227+ // NewProvider creates a new Provider instance.
228+ func NewProvider (name , version string , services []Service ) Provider {
229+ return & provider {
230+ Name : name ,
231+ Version : version ,
232+ Services : services ,
233+ }
234+ }
235+
236+ // NewService creates a new Service instance.
237+ func NewService (name string , resources []Resource ) Service {
238+ return & service {
239+ Name : name ,
240+ Resources : resources ,
241+ }
242+ }
243+
244+ // NewResource creates a new Resource instance.
245+ func NewResource (name string , methods []string , fields []Field ) Resource {
246+ return & resource {
247+ Name : name ,
248+ Methods : methods ,
249+ Fields : fields ,
250+ }
251+ }
252+
253+ // NewField creates a new Field instance.
254+ func NewField (name , fieldType string , required bool , description string ) Field {
255+ return & field {
256+ Name : name ,
257+ Type : fieldType ,
258+ Required : required ,
259+ Description : description ,
260+ }
127261}
0 commit comments