Created
July 24, 2025 09:32
-
-
Save IAmSurajBobade/35f847132ba42c8841cc544b6231ba7f to your computer and use it in GitHub Desktop.
Code gen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "io/ioutil" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| "text/template" | |
| ) | |
| // Header represents a fixed header in the JSON input | |
| type Header struct { | |
| Name string `json:"name"` | |
| Value string `json:"value"` | |
| } | |
| // Parameter represents a parameter in the JSON input | |
| type Parameter struct { | |
| Name string `json:"name"` | |
| Type string `json:"type"` | |
| Description string `json:"description"` | |
| Required bool `json:"required"` | |
| In string `json:"in"` // query, body, or header | |
| } | |
| // Endpoint represents the JSON structure for an API endpoint | |
| type Endpoint struct { | |
| Name string `json:"name"` | |
| Method string `json:"method"` | |
| Path string `json:"path"` | |
| Description string `json:"description"` | |
| Parameters []Parameter `json:"parameters"` | |
| FixedHeaders []Header `json:"fixed_headers"` | |
| } | |
| // TemplateData holds data for generating main.go | |
| type TemplateData struct { | |
| Endpoints []Endpoint | |
| } | |
| func main() { | |
| if len(os.Args) != 2 { | |
| fmt.Println("Usage: go run generator.go <folder_path>") | |
| os.Exit(1) | |
| } | |
| folderPath := os.Args[1] | |
| endpoints, err := readEndpoints(folderPath) | |
| if err != nil { | |
| fmt.Printf("Error reading endpoints: %v\n", err) | |
| os.Exit(1) | |
| } | |
| if err := generateMainFile(endpoints); err != nil { | |
| fmt.Printf("Error generating main.go: %v\n", err) | |
| os.Exit(1) | |
| } | |
| fmt.Println("Generated main.go successfully") | |
| } | |
| // readEndpoints reads and parses all JSON files in the specified folder | |
| func readEndpoints(folderPath string) ([]Endpoint, error) { | |
| files, err := filepath.Glob(filepath.Join(folderPath, "*.json")) | |
| if err != nil { | |
| return nil, err | |
| } | |
| var endpoints []Endpoint | |
| for _, file := range files { | |
| data, err := ioutil.ReadFile(file) | |
| if err != nil { | |
| return nil, fmt.Errorf("error reading %s: %v", file, err) | |
| } | |
| var endpoint Endpoint | |
| if err := json.Unmarshal(data, &endpoint); err != nil { | |
| return nil, fmt.Errorf("error parsing %s: %v", file, err) | |
| } | |
| // Validate endpoint | |
| if endpoint.Name == "" || endpoint.Method == "" || endpoint.Path == "" { | |
| return nil, fmt.Errorf("invalid endpoint in %s: name, method, and path are required", file) | |
| } | |
| endpoints = append(endpoints, endpoint) | |
| } | |
| return endpoints, nil | |
| } | |
| // generateMainFile generates the main.go file with MCP tools and handlers | |
| func generateMainFile(endpoints []Endpoint) error { | |
| const tmpl = `package main | |
| import ( | |
| "bytes" | |
| "context" | |
| "encoding/json" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "net/url" | |
| "os" | |
| "github.com/mark3labs/mcp-go/mcp" | |
| "github.com/mark3labs/mcp-go/server" | |
| ) | |
| func main() { | |
| s := server.NewMCPServer("My API Tools", "1.0.0") | |
| {{range .Endpoints}} | |
| s.AddTool({{.ToolDefinition}}) | |
| {{end}} | |
| if err := s.ServeStdio(); err != nil { | |
| fmt.Fprintf(os.Stderr, "Error running server: %v\n", err) | |
| os.Exit(1) | |
| } | |
| } | |
| {{range .Endpoints}} | |
| func handler{{.Name | Title}}(ctx context.Context, request mcp.ToolRequest) (mcp.ToolResult, error) { | |
| baseURL := os.Getenv("API_BASE_URL") | |
| if baseURL == "" { | |
| return nil, fmt.Errorf("API_BASE_URL environment variable is not set") | |
| } | |
| u, err := url.Parse(baseURL) | |
| if err != nil { | |
| return nil, fmt.Errorf("invalid API_BASE_URL: %v", err) | |
| } | |
| u = u.ResolveReference(&url.URL{Path: "{{.Path}}"}) | |
| query := u.Query() | |
| body := make(map[string]interface{}) | |
| {{range .Parameters}} | |
| {{if eq .In "query"}} | |
| {{if .Required}} | |
| if val, err := request.Require{{.Type | Title}}("{{.Name}}"); err != nil { | |
| return nil, err | |
| } else { | |
| query.Set("{{.Name}}", fmt.Sprintf("%v", val)) | |
| } | |
| {{else}} | |
| if val, ok := request.Get{{.Type | Title}}("{{.Name}}"); ok { | |
| query.Set("{{.Name}}", fmt.Sprintf("%v", val)) | |
| } | |
| {{end}} | |
| {{else if eq .In "body"}} | |
| {{if .Required}} | |
| if val, err := request.Require{{.Type | Title}}("{{.Name}}"); err != nil { | |
| return nil, err | |
| } else { | |
| body["{{.Name}}"] = val | |
| } | |
| {{else}} | |
| if val, ok := request.Get{{.Type | Title}}("{{.Name}}"); ok { | |
| body["{{.Name}}"] = val | |
| } | |
| {{end}} | |
| {{end}} | |
| {{end}} | |
| u.RawQuery = query.Encode() | |
| var reqBody io.Reader | |
| if len(body) > 0 { | |
| bodyBytes, err := json.Marshal(body) | |
| if err != nil { | |
| return nil, fmt.Errorf("error marshaling request body: %v", err) | |
| } | |
| reqBody = bytes.NewReader(bodyBytes) | |
| } | |
| req, err := http.NewRequest("{{.Method}}", u.String(), reqBody) | |
| if err != nil { | |
| return nil, fmt.Errorf("error creating request: %v", err) | |
| } | |
| {{range .FixedHeaders}} | |
| req.Header.Set("{{.Name}}", "{{.Value}}") | |
| {{end}} | |
| {{range .Parameters}} | |
| {{if eq .In "header"}} | |
| {{if .Required}} | |
| if val, err := request.Require{{.Type | Title}}("{{.Name}}"); err != nil { | |
| return nil, err | |
| } else { | |
| req.Header.Set("{{.Name}}", fmt.Sprintf("%v", val)) | |
| } | |
| {{else}} | |
| if val, ok := request.Get{{.Type | Title}}("{{.Name}}"); ok { | |
| req.Header.Set("{{.Name}}", fmt.Sprintf("%v", val)) | |
| } | |
| {{end}} | |
| {{end}} | |
| {{end}} | |
| client := &http.Client{} | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return nil, fmt.Errorf("error sending request: %v", err) | |
| } | |
| defer resp.Body.Close() | |
| respBody, err := io.ReadAll(resp.Body) | |
| if err != nil { | |
| return nil, fmt.Errorf("error reading response: %v", err) | |
| } | |
| if resp.StatusCode >= 200 && resp.StatusCode < 300 { | |
| var result interface{} | |
| if err := json.Unmarshal(respBody, &result); err != nil { | |
| return nil, fmt.Errorf("error parsing response as JSON: %v", err) | |
| } | |
| return mcp.NewToolResultJSON(result), nil | |
| } | |
| return mcp.NewToolResultError(resp.StatusCode, string(respBody)), nil | |
| } | |
| {{end}} | |
| ` | |
| t, err := template.New("main").Funcs(template.FuncMap{ | |
| "Title": strings.Title, | |
| "ToolDefinition": func(e Endpoint) string { | |
| params := []string{} | |
| for _, p := range e.Parameters { | |
| var param string | |
| switch p.Type { | |
| case "string": | |
| param = fmt.Sprintf(`mcp.WithString("%s", mcp.Description("%s"))`, p.Name, p.Description) | |
| case "int": | |
| param = fmt.Sprintf(`mcp.WithInt("%s", mcp.Description("%s"))`, p.Name, p.Description) | |
| case "bool": | |
| param = fmt.Sprintf(`mcp.WithBool("%s", mcp.Description("%s"))`, p.Name, p.Description) | |
| default: | |
| continue // Skip unsupported types | |
| } | |
| if p.Required { | |
| param = fmt.Sprintf("%s, mcp.Required()", param) | |
| } | |
| params = append(params, param) | |
| } | |
| paramsStr := strings.Join(params, ", ") | |
| return fmt.Sprintf(`mcp.NewTool("%s", "%s", handler%s, %s)`, e.Name, e.Description, strings.Title(e.Name), paramsStr) | |
| }, | |
| }).Parse(tmpl) | |
| if err != nil { | |
| return fmt.Errorf("error parsing template: %v", err) | |
| } | |
| f, err := os.Create("main.go") | |
| if err != nil { | |
| return fmt.Errorf("error creating main.go: %v", err) | |
| } | |
| defer f.Close() | |
| data := TemplateData{Endpoints: endpoints} | |
| return t.Execute(f, data) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "get_users", | |
| "method": "GET", | |
| "path": "/api/users", | |
| "description": "Get list of users", | |
| "parameters": [ | |
| {"name": "limit", "type": "int", "description": "Number of users", "required": false, "in": "query"}, | |
| {"name": "Authorization", "type": "string", "description": "Bearer token", "required": true, "in": "header"} | |
| ], | |
| "fixed_headers": [{"name": "Content-Type", "value": "application/json"}] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment