---
title: Go
description: The Go SDK.
---

[`subako-function-sdk-go`](https://github.com/subako-ai/subako-function-sdk-go) runs an MCP server written with the [official MCP Go SDK](https://github.com/modelcontextprotocol/go-sdk) as a Subako function package. Each tool you add becomes a function an agent can call. It needs Go 1.25 or newer.

## Start a package

```bash
go run golang.org/x/tools/cmd/gonew@latest \
  github.com/subako-ai/subako-function-template-go example.com/orders
```

Or add the SDK to a module of your own:

```bash
go get github.com/modelcontextprotocol/go-sdk github.com/subako-ai/subako-function-sdk-go
```

## Tools

```go main.go
package main

import (
	"context"
	"fmt"

	"github.com/modelcontextprotocol/go-sdk/mcp"
	subakofn "github.com/subako-ai/subako-function-sdk-go"
)

type LookupInput struct {
	Order int `json:"order" jsonschema:"the order's number, such as 1042"`
}

type Order struct {
	Status     string `json:"status"`
	TotalCents int    `json:"total_cents"`
}

func lookup(ctx context.Context, req *mcp.CallToolRequest, in LookupInput) (*mcp.CallToolResult, Order, error) {
	if in.Order <= 0 {
		return nil, Order{}, fmt.Errorf("order numbers start at 1")
	}
	return nil, Order{Status: "shipped", TotalCents: 12900}, nil
}

func main() {
	server := mcp.NewServer(&mcp.Implementation{Name: "orders", Version: "0.1.0"}, nil)
	mcp.AddTool(server, &mcp.Tool{Name: "lookup", Description: "Look an order up by its number."}, lookup)
	subakofn.Serve(server)
}
```

- One `mcp.AddTool` per tool. The schemas are inferred from the input and output structs, and a field's `jsonschema` tag is its description.
- A returned `error` is a failed call the model reads.
- `subakofn.Serve(server)` takes the place of `server.Run(ctx, &mcp.StdioTransport{})`, which stalls under WASI.

The package's name and description live in `subako-package.json` beside `main.go`:

```json subako-package.json
{ "abi": 1, "name": "orders", "description": "Looks orders up." }
```

## Files

Use `os` on the [volume and assets](/functions/runtime#the-filesystem): `os.ReadFile("/volume/tmp/export.csv")`, `os.WriteFile("/volume/data/q3.md", data, 0o644)`.

## HTTP

Under `wasip1` the SDK replaces `http.DefaultTransport`, so `net/http` sends requests through Subako, under the grant's network and credentials:

```go
resp, err := http.Get("https://api.example.com/orders/1042")
```

`net/http` carries text bodies. For a volume file as the body, or a response saved to the volume, use `subakofn.Do`:

```go
res, err := subakofn.Do(subakofn.Request{
	URL:    "https://api.example.com/exports/q3",
	Output: subakofn.ToFile("/volume/tmp/q3.csv"),
})
```

`subakofn.TextBody`, `subakofn.JSONBody`, and `subakofn.FileBody` build request bodies, and `subakofn.Get(url)` is the short form of a GET. A failure is an `*subakofn.HTTPError` with a `Kind` and a `Message`.

## Images

`subakofn.ImageResult` shows the model images from the volume beside the value:

```go
res, err := subakofn.ImageResult(plot, plot.Path)
return res, plot, err
```

## Build and test

```bash
go test ./...                                         # tools run as plain Go
GOOS=wasip1 GOARCH=wasm go build -trimpath -o dist/module.wasm .
cp subako-package.json dist/
subako function create dist
```

The template's `package.sh` builds and packs `dist/<name>.tar.gz`, adding `assets/` when there is one. Run it with `bash package.sh`.
