Write an MCP tool in Go
Build an MCP tool in Go with the official MCP Go SDK: the template, typed input schemas, logging, the host API, dependencies and custom builds.
Glxymesh tools are ordinary MCP servers written with the official
MCP Go SDK. The only Glxymesh-specific part is the
small host package, which provides what WebAssembly can’t provide by itself: outbound HTTP,
storage, logs, the clock and randomness.
Scaffold
Section titled “Scaffold”gxmesh new weather| File | What it is |
|---|---|
manifest.json |
The tool’s name and the hosts it’s allowed to reach |
main.go |
The MCP server |
go.mod |
The module and its pinned dependencies, for your editor and for local builds |
README.md |
Notes on publishing and egress |
The name has to be 1–64 characters of a-z, 0-9 and -. It identifies the tool within the project
and also names its KV storage. If you change the name in manifest.json, the next push publishes a
new tool alongside the old one, which you then remove with gxmesh rm.
The server
Section titled “The server”package main
import ( "context" "fmt" "log"
"github.com/modelcontextprotocol/go-sdk/mcp"
"glxymesh.com/mcp-core/host")
type args struct { City string `json:"city" jsonschema:"the city to report on"`}
func main() { server := mcp.NewServer(&mcp.Implementation{Name: "weather", Version: "0.1.0"}, nil)
mcp.AddTool(server, &mcp.Tool{Name: "weather", Description: "Current weather for a city"}, func(_ context.Context, _ *mcp.CallToolRequest, a args) (*mcp.CallToolResult, any, error) { host.Logf(host.LevelInfo, "weather for %q", a.City) return &mcp.CallToolResult{ Content: []mcp.Content{&mcp.TextContent{Text: fmt.Sprintf("It is sunny in %s", a.City)}}, }, nil, nil })
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { log.Fatal(err) }}- The SDK generates the tool’s input schema from the
argsstruct, and thejsonschematag becomes each field’s description. Clients show these descriptions to the model, so write them for the model. - The server runs over stdio. The platform handles HTTP, authorization and routing, so your code never deals with them.
- Write the tool’s
Descriptioncarefully. It’s what the model reads when deciding whether to call the tool. - One module can register several MCP tools. Every name must be unique within the project; see one endpoint per project.
The host API
Section titled “The host API”Everything in glxymesh.com/mcp-core/host:
| Call | Purpose |
|---|---|
host.HTTPClient() |
A standard *http.Client whose requests go through the platform’s egress allowlist. Vendor SDKs that accept a custom client work with it unchanged. |
host.KV.Get / Put / Delete / List |
Key/value storage that persists between calls. |
host.Log(level, msg), host.Logf(level, format, ...) |
Logs shown in the console under this tool. Levels: LevelDebug, LevelInfo, LevelWarn, LevelError. |
host.Now() |
The current time. |
host.Rand(n) |
n cryptographically random bytes. |
Secrets are read with os.Getenv; see Secrets.
Dependencies
Section titled “Dependencies”A build from gxmesh push or the console compiles offline against a pinned set of modules: the Go
standard library, github.com/modelcontextprotocol/go-sdk and glxymesh.com/mcp-core. Importing
anything else fails with no required module provides package. Your go.mod is not used for these builds;
the platform supplies its own.
The build takes every .go file in the tool’s directory and nothing in subdirectories, so keep the
tool in one main package.
Pushing a module you built yourself
Section titled “Pushing a module you built yourself”To use other modules, build the WebAssembly module yourself and push that. gxmesh push looks for a
.wasm file next to the manifest with the same base name, manifest.wasm. If it finds one, it
uploads that file instead of the source:
GOOS=wasip1 GOARCH=wasm go build -o manifest.wasm .gxmesh pushThe module must be wasip1 and must serve MCP over stdio, the same as the template. Any .go files
in the directory are sent along with it, and are used only to generate the tool’s description in the
console.
Publish and iterate
Section titled “Publish and iterate”gxmesh push # build and publish to the active projectgxmesh tools # list what the project hasgxmesh rm weather # remove itPushing a tool that already exists replaces it. The runtime picks up new versions within about 15 seconds.