f92e54e3ed
CI / test (push) Successful in 10m10s
Thin, stateless stdio MCP server (official Go SDK) that exposes a gadfly-reports store to an MCP client (e.g. Claude). Tools: list_findings, record_finding_grade, scoreboard (grader forced to claude). Launch via 'go run ...@latest' — nothing to install. Core logic tested against httptest, no daemon required. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
51 lines
2.3 KiB
Markdown
51 lines
2.3 KiB
Markdown
# gadfly-mcp — Developer Guide
|
|
|
|
A stdio [MCP](https://modelcontextprotocol.io) server exposing the
|
|
[gadfly-reports](https://gitea.stevedudenhoeffer.com/steve/gadfly-reports) findings store to an MCP
|
|
client (e.g. Claude). It is a **thin, stateless HTTP client** to the store — it never opens SQLite
|
|
and never imports the store's package.
|
|
|
|
> This is a public, **vibe-coded** project (built largely by an AI agent). Keep that honest in the
|
|
> README; it's homelab-grade.
|
|
|
|
## Shape
|
|
|
|
- Single `main.go` (`package main`) at the repo root, so the launch path is just
|
|
`go run gitea.stevedudenhoeffer.com/steve/gadfly-mcp@latest` — no `cmd/` subpath. This is the
|
|
whole point: the client compiles + caches it on demand; nothing to install or manage.
|
|
- Uses the official Go MCP SDK (`github.com/modelcontextprotocol/go-sdk`): `mcp.NewServer` →
|
|
`mcp.AddTool[In,Out]` (input schemas inferred from struct + `jsonschema` tags) → `server.Run(ctx,
|
|
&mcp.StdioTransport{})`.
|
|
- Config: `--store` flag (default `$GADFLY_REPORTS_URL`, else `http://localhost:8090`); bearer token
|
|
from `$GADFLY_REPORTS_TOKEN`, sent on every request when set.
|
|
|
|
## Contract with gadfly-reports
|
|
|
|
The store's HTTP/JSON API is the contract — its README is the **source of truth**. This client
|
|
mirrors only the subset it needs with small local structs (`exportRow`, `modelStat`, `gradeReq`,
|
|
…). If you change a field here, check it against gadfly-reports' `server.go`/`store.go`. Endpoints
|
|
used: `GET /export`, `POST /findings/{id}/grade`, `GET /scoreboard`.
|
|
|
|
Three tools: `list_findings`, `record_finding_grade`, `scoreboard`. The grader is always forced to
|
|
`"claude"`. The store holds **no points**; ranking by points/value-per-minute is a client concern —
|
|
say so in the `scoreboard` tool description.
|
|
|
|
## Tests
|
|
|
|
The core logic (`groupFindings` / `listFindings` / `recordGrade` / `scoreboard`) is factored free of
|
|
MCP types and tested against an `httptest.Server`, so tests need no real daemon. Keep it that way —
|
|
add a test when you add a tool or change the grouping/filtering.
|
|
|
|
```sh
|
|
go build ./...
|
|
go vet ./...
|
|
gofmt -l . # must be empty
|
|
go test -race ./...
|
|
```
|
|
|
|
## When making changes
|
|
|
|
- Keep this a thin client: no SQLite, no business logic the store should own.
|
|
- Keep the launch path a root `package main` (don't move it under `cmd/`), so `go run …@latest`
|
|
stays the one-liner the README documents.
|