Mwen santi ke nou se nan yon pwen kote Pwotokòl Konteks Modèl (MCP) sanble prèske sinonim ak enjenyè GenAI. Anthropic te prezante MCP nan mwa Novanm 2024, revolisyonye enjenyè GenAI. Li te pote nou nan pwen sa a kote, kòm enjenyè, nou ka implemante zouti divès kalite ki baze sou ka itilize nou an, ak dirije LLM a nan chwa nou an pou sèvi ak zouti sa yo soti nan konfort la nan IDEs pi renmen nou yo oswa kliyan desktopik tankou Claude. Soti nan aparans li, gen anpil serveurs MCP devlope pa enjenyè enteresan. Sa a te posib akòz devlopman rapid nan SDK MCP nan diferan lang, ki gen ladan nan Men, nan dènye a, Mwen te wè , epi mwen te konnen mwen ta dwe pran li pou yon spin! Python nan tipografik Gòlf sa a ofisyèl pwopozisyon pou yon Golang SDK Ki sa ki nan MCP, ou mande? Kòmanse ak yon rapid intro nan MCP, ki se kout pou . Anvan dènyèman, enjenyè AI te mande pou yon evalyasyon atansyon nan kapasite yo nan LLM divès kalite yo chwazi youn ki dwat. Avèk MCP, ou ka chwazi LLM nan chwa ou, ak ogmante kapasite li yo pa implemantasyon zouti Custom ak konekte nan sous done ekstèn tèt ou! Konstriksyon prensipal yo nan pwotokòl la yo: Model Context Protocol Kliyan MCP MCP sèvè Kapasite (Tools, Resous, Prompts) LLM nan Yon sèvè MCP gen kapasite sèten ki detèmine pa: Zouti - fonksyon ki li ka fè, tankou lis tout imel soti nan yon voye, gade yon PR sou Github Resous - sous done ekstèn, tankou yon lis nan dokiman ou vle LLM referans nan Prompts - Yon seri modèl ki ede itilizatè jwenn repons yo vle byen vit Gen anpil sèvè MCP deja disponib ke ou ka kòmanse sèvi ak pou aplikasyon ou yo. Ou ka referans nan kompilasyon sa a nan gwo sèvè MCP: https://github.com/punkpeye/awesome-mcp-servers BYOM (Bring Your Own MCP Servers) se yon pwopriyete. Nan pòs sa a, mwen vle ale sou ki jan nou ka devlope pwòp nou an MCP sèvè lè l sèvi avèk Golang. Yon kèk jou de sa, pou nenpòt ki rezon,n mwen te vle ale sou tout depo nan . Kouvèti nan GitHub Koulye a, mwen te kapab itilize ofisyèl la GitHub MCP sèvè, men pandan ke li ofri yon gwo zouti pou depo ak òganizasyon, li pa gen yon zouti dirèk pou lis tout depo nan yon òganizasyon. Se poutèt sa sa sa sa a te parèt kòm yon bon opòtinite yo aprann ki jan yo devlope yon sèvè MCP pou zouti espesifik mwen te bezwen pandan y ap sèvi ak Golang. Devlope yon serveur MCP nan Golang Isit la se Golang MCP SDK ofisyèl la: README ak egzanp / dosye yo gen bon egzanp sou devlope yon serveur MCP ak kliyan. https://github.com/modelcontextprotocol/go-sdk Apre egzanp sa yo, mwen te planifye yo kreye yon serveur MCP tankou sa a: server := mcp.NewServer(&mcp.Implementation{ Name: "demo-github-mcp", Title: "A demo github mcp server", Version: "0.0.1", }, nil) Etap la pwochen te bay sèvè a ak kapasite nan lis tout depo nan yon org GitHub. Sa a ka fè pa implemantasyon yon zouti nan kalite ToolHandler tankou bay pa SDK la type ToolHandlerFor[In, Out any] func(context.Context, *ServerSession, *CallToolParamsFor[In]) (*CallToolResultFor[Out], error) Apre sa, mwen te kreye yon zouti, ki aksepte argiman sa yo ki gen rapò ak Github org kòm entwodiksyon: ListRepositories // User can pass in either the name of the org (example: kubernetes), or its URL (example: https://github.com/kubernetes) type GithubOrgArgs struct { Name string URL string } func ListRepositories(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[GithubOrgArgs]) (*mcp.CallToolResultFor[struct{}], error) { Now let's go over the body of ListRepositories step-by-step: Verifikasyon entwodiksyon pou asire ke nou aksepte sèlman arguments valab if params == nil { return nil, fmt.Errorf("empty params") } args := params.Arguments if args.Name == "" && args.URL == "" { return nil, fmt.Errorf("empty args") } Formation nan GitHub API URL soti nan entwodiksyon ki baze sou GitHub API dok var apiURL string var organization string if args.URL != "" { // If URL is provided, extract org name and build API URL url := strings.TrimPrefix(args.URL, "https://") url = strings.TrimPrefix(url, "http://") url = strings.TrimPrefix(url, "github.com/") url = strings.TrimSuffix(url, "/") orgName := strings.Split(url, "/")[0] apiURL = fmt.Sprintf("https://api.github.com/orgs/%s/repos", orgName) organization = orgName } else { // Use the provided organization name apiURL = fmt.Sprintf("https://api.github.com/orgs/%s/repos", args.Name) organization = args.Name } apiURL = apiURL + "?per_page=100" Enskri demann an ak resevwa yon repons client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequestWithContext(ctx, "GET", apiURL, nil) if err != nil { return nil, err } req.Header.Add("Accept", "application/vnd.github.v3+json") resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, string(body)) } Parse repons la soti nan GitHub API type repository struct { Name string `json:"name"` FullName string `json:"full_name"` HTMLURL string `json:"html_url"` Private bool `json:"private"` } // Parse the JSON response var repositories []repository if err := json.NewDecoder(resp.Body).Decode(&repositories); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } Retire repons la kòm yon konteks tèks var result strings.Builder result.WriteString(fmt.Sprintf("Repositories for organization %s:", organization)) for _, repo := range repositories { result.WriteString(fmt.Sprintf("Name: %s, URL: %s", repo.Name, repo.HTMLURL)) } return &mcp.CallToolResultFor[struct{}]{ Content: []mcp.Content{ &mcp.TextContent{Text: result.String()}, }, }, nil Apre definisyon zouti a, etap la pwochen se enskri l 'nan sèvè a MCP: mcp.AddTool(server, &mcp.Tool{ Name: "list-repositories", Description: "A tool to list all repositories in a Github org", InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "name": { Type: "string", Description: "GitHub organization name (e.g., kubernetes)", }, "url": { Type: "string", Description: "GitHub organization URL (e.g., https://github.com/kubernetes)", }, }, }, }, ListRepositories) Lè sa a, li se tan yo kòmanse sèvè a! Pou sèvè a MCP demo sa a, mwen se lè l sèvi avèk stdio transport, ki pèmèt sèvè a kominike atravè STDIN ak STDOUT. Sa a se metòd la estanda pou entegre lokal MCP ak kliyan tankou Claude Desktop oswa VSCode. t := mcp.NewLoggingTransport(mcp.NewStdioTransport(), os.Stderr) log.Println("🚀 MCP server starting up...") if err := server.Run(context.Background(), t); err != nil { log.Printf("Server failed: %v", err) } log.Println("🚀 MCP server shutting down...") Isit la se ki jan kòd la sanble ak tout bagay mete ansanm: func main() { server := mcp.NewServer(&mcp.Implementation{ Name: "demo-github-mcp", Title: "A demo github mcp server", Version: "0.0.1", }, nil) mcp.AddTool(server, &mcp.Tool{ Name: "list-repositories", Description: "A tool to list all repositories in a Github org", InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "name": { Type: "string", Description: "GitHub organization name (e.g., kubernetes)", }, "url": { Type: "string", Description: "GitHub organization URL (e.g., https://github.com/kubernetes)", }, }, }, }, ListRepositories) t := mcp.NewLoggingTransport(mcp.NewStdioTransport(), os.Stderr) log.Println("🚀 MCP server starting up...") if err := server.Run(context.Background(), t); err != nil { log.Printf("Server failed: %v", err) } log.Println("🚀 MCP server shutting down...") } type GithubOrgArgs struct { Name string URL string } func ListRepositories(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[GithubOrgArgs]) (*mcp.CallToolResultFor[struct{}], error) { if params == nil { return nil, fmt.Errorf("empty params") } args := params.Arguments if args.Name == "" && args.URL == "" { return nil, fmt.Errorf("empty args") } var apiURL string var organization string if args.URL != "" { // If URL is provided, extract org name and build API URL url := strings.TrimPrefix(args.URL, "https://") url = strings.TrimPrefix(url, "http://") url = strings.TrimPrefix(url, "github.com/") url = strings.TrimSuffix(url, "/") orgName := strings.Split(url, "/")[0] apiURL = fmt.Sprintf("https://api.github.com/orgs/%s/repos", orgName) organization = orgName } else { // Use the provided organization name apiURL = fmt.Sprintf("https://api.github.com/orgs/%s/repos", args.Name) organization = args.Name } apiURL = apiURL + "?per_page=100" client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequestWithContext(ctx, "GET", apiURL, nil) if err != nil { return nil, err } req.Header.Add("Accept", "application/vnd.github.v3+json") resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, string(body)) } type repository struct { Name string `json:"name"` FullName string `json:"full_name"` HTMLURL string `json:"html_url"` Private bool `json:"private"` } // Parse the JSON response var repositories []repository if err := json.NewDecoder(resp.Body).Decode(&repositories); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } var result strings.Builder result.WriteString(fmt.Sprintf("Repositories for organization %s:", organization)) for _, repo := range repositories { result.WriteString(fmt.Sprintf("Name: %s, URL: %s", repo.Name, repo.HTMLURL)) } return &mcp.CallToolResultFor[struct{}]{ Content: []mcp.Content{ &mcp.TextContent{Text: result.String()}, }, }, nil } Koulye a, etap final la se kompile sa a ak kreye ekzekitif la ak: go build Sèvi ak MCP sèvè a ak yon kliyan tankou Claude Jwenn yon gade nan ki jan yo ajoute sèvè sa a nan Desktop Claude a. Louvri aplikasyon an Claude Desktop, epi ale nan Claude -> Konfigirasyon -> Devlopè. Isit la ou pral wè yon seksyon rele Local MCP Servers. Klike sou bouton la anba a rele Edit Config. Sa a pral louvri dosye a Claude config. Edit dosye a pou ajoute serveur la MCP kòm sa a: { "mcpServers": { "demo-github-mcp": { "command": "/path/to/executable/generated/from/go build", "args": [] } } } Retounen aplikasyon Claude (Pou sa a, sa a se sèlman fason yo refize serveurs MCP nan Claude) Epi se kounye a tan yo tès sa a! Sa a se pwomèt la mwen te bay: List all repositories in the Kubernetes github org Claude rekonèt sèvè a demo-github-mcp ki kouri lokalman ak te mande si li ka sèvi ak sa a! Yon fwa mwen te apwouve li, Claude lis depo yo nan org yo ak menm montre zouti a itilize (list-repositories) nan kòmansman an nan repons la: Epi nou ale! Nou te wè ki jan nou ka devlope yon serveur MCP senp lè l sèvi avèk Golang, epi sèvi ak li nan kliyan MCP tankou Claude! Momant la nan “aha” Kòm mwen te devlope sèvè sa a, mwen te kontinye mande tèt mwen: "Si mwen ekri kòd la pou lis depo, sa ki pral fè LLM la?" ak Lè sa a, sote li klike - LLM a pèmèt kominikasyon nan sèvè sa a atravè lang natirèl! Lè Claude Sonnet 4 li pwopozisyon mwen - "Liste tout depo nan Kubernetes GitHub org" - ak sou tèt li rekonèt ke sèvè a MCP ki kouri lokalman ap travay pi bon pou pwopozisyon an, tèt mwen te blese soti 😀 Nan moman sa a, mwen pa te gen yo bay li ak nenpòt enfòmasyon sou non nan zouti a oswa paramèt yo li aksepte. Mwen te mande kesyon mwen an nan yon sentans senp, epi li te aprann ki zouti yo sèvi ak, ki jan yo rele zouti a, ak te travay la fè! Konsèy pou pwodiksyon Malgre ke sèvè a MCP nou an travay gwo pou rezon demo, gen kèk karakteristik enpòtan manke pou itilize pwodiksyon: Kòmanse Pagination: API a nan GitHub retire rezilta paginated, default la se 30 enskripsyon pou chak paj. Nan kòd la pi wo a, mwen te ogmante sa a nan 100 ak paramèt la nan kesyon per_page. Pou kòd pwodiksyon, ou pral pwosesis tèt la repons Lyen pou jwenn enfòmasyon sou paj la pwochen ak kantite paj total. (Refere a sa a) Limite pri: Kòd la pi wo a pa konsidere limite pri API GitHub Authentication: Authenticated requests gen yon limite pi wo pase non-authenticated requests. Authentication se tou nesesè pou requests nan GitHub repo prive / enterprise GitHub. Ki sa ki pwochen? Demo sa a GitHub MCP sèvè te yon bon kòmansman. Men, rezon prensipal mwen ekri sa a se yo demontre ki jan fasil li ka Customize zouti GenAI pi renmen ou nan renmen ou! Li se tou surprenantman senp yo kòmanse ak yon sèvè MCP nan Golang pou pwojè pwòp ou! Mwen pa t 'kapab yo wè sèvis pouvwa a kreye soti nan konbinezon an nan fleksibilite a nan MCP ak natirite segondè-performance nan Golang!