Skip to content

Instantly share code, notes, and snippets.

@IAmSurajBobade
Created July 24, 2025 09:32
Show Gist options
  • Select an option

  • Save IAmSurajBobade/35f847132ba42c8841cc544b6231ba7f to your computer and use it in GitHub Desktop.

Select an option

Save IAmSurajBobade/35f847132ba42c8841cc544b6231ba7f to your computer and use it in GitHub Desktop.
Code gen
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)
}
{
"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