Developers · Go

Get a meeting transcript in Go with net/http

A Go program that fetches every line so far, with what it printed when it was run.

Ran on 10 November 2026Language GoJob Get the transcript

What it does

Standard library only: build the JSON-RPC body, POST it to /mcp with the key as a bearer token, and decode the transcript out of the tool's text answer.

It needs a key and a meeting code in MEETFUL_KEY and MEETING. Two curl requests make both. MEETFUL_URL is optional and defaults to https://meetful.com.

Go 1.22 or later. The socket programs use github.com/coder/websocket (go get github.com/coder/websocket@v1.8.12); the transcript program uses only the standard library.

The code

// Get the whole transcript of a Meetful meeting from Go, with the standard library only.
// MEETFUL_KEY=tmk_… MEETING=abc-defg-hij go run .
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
)

type transcript struct {
	Meeting    string
	Lines      int
	Transcript []struct {
		At      int64
		Speaker string
		Text    string
	}
}

func main() {
	base := os.Getenv("MEETFUL_URL")
	if base == "" {
		base = "https://meetful.com"
	}
	body, _ := json.Marshal(map[string]any{
		"jsonrpc": "2.0", "id": 1, "method": "tools/call",
		"params": map[string]any{"name": "get_transcript", "arguments": map[string]string{"meeting": os.Getenv("MEETING")}},
	})
	req, _ := http.NewRequest("POST", base+"/mcp", bytes.NewReader(body))
	req.Header.Set("authorization", "Bearer "+os.Getenv("MEETFUL_KEY"))
	req.Header.Set("content-type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	var reply struct {
		Error  *struct{ Message string }
		Result struct {
			IsError bool
			Content []struct{ Text string }
		}
	}
	if err := json.NewDecoder(res.Body).Decode(&reply); err != nil {
		log.Fatal(err)
	}
	if reply.Error != nil {
		log.Fatal(reply.Error.Message)
	}
	if reply.Result.IsError {
		log.Fatal(reply.Result.Content[0].Text)
	}
	var t transcript
	if err := json.Unmarshal([]byte(reply.Result.Content[0].Text), &t); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%d lines in %s\n", t.Lines, t.Meeting)
	for _, l := range t.Transcript {
		fmt.Printf("%s  %s: %s\n", time.UnixMilli(l.At).UTC().Format("15:04:05"), l.Speaker, l.Text)
	}
}

Run it

MEETFUL_KEY=tmk_… MEETING=abc-defg-hij go run .

What it printed

4 lines in gik-fhvv-dcu
14:17:16  Dana: Can we move the launch to the third of March?
14:17:17  Sam: Yes, if the docs are ready by the twentieth.
14:17:17  Dana: Then Sam owns the docs.
14:17:25  🤖 go bot: Noted: the launch moves to the third of March, and Sam owns the docs.

Run on 10 November 2026 against a Meetful server built from the same code as meetful.com, with two people — Dana and Sam — in the meeting saying three lines. Nothing above was edited.

How it works

The tool answer nests JSON inside JSON: result.content[0].text is itself a JSON document, decoded a second time into the transcript struct.

Error *struct{ Message string } is a pointer so the program can tell "no error" from "an empty error". IsError is a plain bool, and the text beside it says what went wrong.

What can go wrong

this key was replaced or switched off — sign in again, or make a new one at /agents

The MCP endpoint's answer to a key it does not know.

That did not work: no meeting abc-defg-hij — it was never started, or it has ended

The MCP answer for a meeting that does not exist. It comes back as a result marked isError, not as an HTTP error, so check isError as well as the status.

Next

In Go: join a meeting · live transcript · speak

The same in Node.js · Python · curl

The whole API · Every socket message and webhook · All guides

Try Meetful

Meetings that take their own notes

Free video meetings in the browser: every line of the transcript under the name of who said it, and the summary and action items when you hang up. Nothing to install — guests just open the link.