Install
$ agentstack add mcp-donaldmurillo-gofastr ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
GoFastr
[](https://github.com/DonaldMurillo/gofastr/actions/workflows/ci.yml) [](https://github.com/DonaldMurillo/gofastr/releases) [](go.mod) [](https://pkg.go.dev/github.com/DonaldMurillo/gofastr) [](LICENSE) [](https://www.coderabbit.ai)
> The full-stack Go framework that doesn't get in the way of you or your agents.
Docs, component gallery, and live demos → · [Quickstart](#quickstart) · A GoFastr app in production
GoFastr is a pre-v1 full-stack Go framework. The API can still change between releases, under the [deprecation policy](framework/docs/content/stability.md). Declare your domain in Go and get server-rendered screens, REST endpoints, MCP tools, an OpenAPI spec, SQL migrations, and a typed query builder. The output is plain Go you can read, edit, and own: no reflection discovers your entities, no generated code you can't open. Auth, background jobs, search, and storage are opt-in packages, and you can drop to net/http or database/sql at any point.
It is built for both the agentic web and AI-assisted development. The app you ship joins the agentic web: the agents your users bring call your data over MCP, with the same login and permissions your users have. While you build, gofastr dev hands your coding agent, Claude Code or Codex, the app's routes, config, and logs over MCP, to help build and debug it.
Start with [the quickstart](#quickstart). Or scaffold a whole app in one command: screens, API, and auth from gofastr init , or gofastr generate from a one-file declaration ([blueprint tutorial](framework/docs/content/tutorial-blueprint-app.md)).
A shoutout to CodeRabbit: it reviews every PR in this repo and keeps catching what everyone else missed, like six Major findings on #198 while the checks list showed pass. Every finding is triaged on the PR before merge.
Quickstart
Requires Go 1.27+. Install the CLI:
go install github.com/DonaldMurillo/gofastr/cmd/gofastr@latest
Three complete programs, smallest to fullest, the same three the site's homepage shows (examples/site): plain core/, one framework entity, and the full app shape. CI extracts all three from this README, compiles them, boots them, and curls them (cmd/gofastr/readme_quickstart_test.go).
Core only
core/ is stdlib-first building blocks: router, typed handlers, render, a SQL query builder, schema, migrate, mcp. Each is usable without the framework. The basic app is one screen and one API route:
package main
import (
"context"
"net/http"
"github.com/DonaldMurillo/gofastr/core/handler"
"github.com/DonaldMurillo/gofastr/core/render"
"github.com/DonaldMurillo/gofastr/core/router"
)
type Pong struct {
Status string `json:"status"`
}
func main() {
r := router.New()
// A server-rendered page.
r.Get("/", render.HTMLHandler(func(req *http.Request) render.HTML {
return render.Tag("h1", nil, render.Text("Hello from core."))
}))
// A typed JSON route: the adapter binds input and serializes output.
r.Get("/api/ping", handler.HandlerAdapter(func(ctx context.Context, _ struct{}) (Pong, error) {
return Pong{Status: "ok"}, nil
}))
http.ListenAndServe(":8080", r)
}
Framework
One framework entity is a complete server: a migrated table, REST CRUD, an OpenAPI spec, and MCP tools. Add only what you need from there.
package main
import (
"database/sql"
"log"
"github.com/DonaldMurillo/gofastr/core/schema"
"github.com/DonaldMurillo/gofastr/framework"
_ "github.com/DonaldMurillo/gofastr/sqlite/stdlib"
)
func main() {
db, _ := sql.Open("sqlite3", "app.db")
app := framework.NewApp(framework.WithDB(db), framework.WithMCP()) // WithMCP serves the tools at /mcp
// CRUD is auto-on when a DB is set (CRUD *bool: nil = auto).
app.Entity("posts", framework.EntityConfig{
Exposure: &framework.ExposureConfig{
Public: true, // anonymous read AND write; omit it and CRUD requires a session (secure by default)
MCP: true, // emit posts_list/get/create/update/delete MCP tools
},
Fields: []schema.Field{{Name: "title", Type: schema.String, Required: true}},
})
log.Fatal(app.Start(":8080")) // GET/POST /posts, /openapi.json, MCP: all live
}
That's the whole program. No config files, no codegen step, no registration boilerplate. Add entities-as-JSON, batteries, the UI runtime, or the generator when you need them. For how a flat app grows into internal// as boundaries appear, see [project structure](framework/docs/content/project-structure.md).
Donald's Way
The full app shape: server-rendered screens with SEO, an owner-scoped entity API, MCP for agents, and login + sessions, in one binary. A screen is Go too: Render returns HTML, and a small JS runtime hydrates it in place, with no React or Vue on the client:
package main
import (
"database/sql"
"log"
"github.com/DonaldMurillo/gofastr/battery/auth"
"github.com/DonaldMurillo/gofastr/core-ui/app"
"github.com/DonaldMurillo/gofastr/core-ui/html"
"github.com/DonaldMurillo/gofastr/core/render"
"github.com/DonaldMurillo/gofastr/core/schema"
"github.com/DonaldMurillo/gofastr/framework"
"github.com/DonaldMurillo/gofastr/framework/uihost"
_ "github.com/DonaldMurillo/gofastr/sqlite/stdlib"
)
// A screen is plain Go: Render returns server-rendered HTML.
type HomeScreen struct{}
func (s *HomeScreen) ScreenTitle() string { return "Notes" }
func (s *HomeScreen) Render() render.HTML {
return html.Heading(html.HeadingConfig{Level: 1}, render.Text("My notes"))
}
func main() {
db, _ := sql.Open("sqlite3", "notes.db")
// Server-rendered screens. Each also serves an auto llm.md.
ui := app.NewApp("Notes")
ui.Register("/", &HomeScreen{}, nil)
// SEO for those pages.
host := uihost.New(ui,
uihost.WithDescription("A tiny notes app."),
uihost.WithOpenGraph(uihost.OG{Title: "Notes", Type: "website"}),
uihost.WithSitemap(uihost.SitemapConfig{BaseURL: "https://notes.example"}),
)
// MCP for agents.
fwApp := framework.NewUIHostApp(host,
framework.WithDB(db),
framework.WithAPIPrefix("/api"),
framework.WithMCP(),
)
// Scope.OwnerField scopes rows per user: anonymous → 401, cross-user → 404.
fwApp.Entity("notes", framework.EntityConfig{
Scope: &framework.ScopeConfig{OwnerField: "user_id"},
Exposure: &framework.ExposureConfig{MCP: true},
Fields: []schema.Field{{Name: "title", Type: schema.String, Required: true}},
})
// Login + sessions.
authMgr := auth.New(auth.AuthConfig{
DevMode: true, // dev only: mints a per-process JWT secret; set JWTSecret in prod
UserStore: auth.NewEntityUserStore(db, "auth_users"),
SessionStore: auth.NewEntitySessionStore(db, "auth_sessions"),
})
authMgr.Use(auth.NewCorePlugin())
if err := authMgr.Init(fwApp); err != nil {
log.Fatal(err)
}
fwApp.Use(auth.SessionMiddleware(authMgr))
log.Fatal(fwApp.Start(":8080"))
}
GET / is the rendered screen. Anonymous GET /api/notes answers 401: OwnerField scopes rows per user, and auto-CRUD requires a session unless the entity is Public. /auth/register and /auth/login come from the auth battery, and the MCP tools at /mcp respect the same owner scope as the REST API.
Run it from a clone
To work on the framework itself, or run the examples:
git clone https://github.com/DonaldMurillo/gofastr.git
cd gofastr
go test ./... # SQLite; the Postgres halves skip without TEST_POSTGRES_DSN
go run ./cmd/gofastr --help # CLI overview
go run ./examples/blog # minimal blog with auto-CRUD on SQLite
Postgres setup and the race pass are under [Contributing](#contributing). Linked Git worktrees of the same app each get their own port and database path, so two coding agents can run side by side ([isolation](framework/docs/content/isolation.md)).
Updating GoFastr
The module dependency and the installed CLI are versioned independently; keep them on the same release. gofastr upgrade reads your go.mod, lists every migration note between your version and the target (breaking changes are marked in the release notes), and points at the affected lines in your code (--apply runs the steps). Manual steps and the full guide: [upgrading](framework/docs/content/upgrading.md), or gofastr docs upgrading.
The code you don't write
The framework emits routes, validation, migrations, pagination, uploads, the spec, and agent tools from one declaration (app.Entity in Go, or an entities: entry in a blueprint). Declarations are optional: core/ routes and hand-written screens run without them. A declaration grows the same way it starts, with fields, enums, relations, and soft delete:
app.Entity("posts", framework.EntityConfig{
Scope: &framework.ScopeConfig{SoftDelete: true},
Fields: []schema.Field{
{Name: "title", Type: schema.String, Required: true},
{Name: "body", Type: schema.Text},
{Name: "status", Type: schema.Enum,
Values: []string{"draft", "published"}, Default: "draft"},
{Name: "author_id", Type: schema.Relation, To: "users"},
},
Exposure: &framework.ExposureConfig{MCP: true},
})
| Output | Auto-generated | |------------------|---------------------------------------------------------------------------------| | HTTP | GET / POST /posts, GET / PUT / PATCH / DELETE /posts/{id} | | Batch endpoints | POST / PATCH / DELETE /posts/_batch: atomic; one tx for all items | | SSE stream | GET /posts/_events: entity.created/updated/deleted, scoped per tenant | | Filtering | ?status=published&views_gte=10&sort=-created_at&page=2 | | Eager loading | ?include=author.profile,comments: flat or nested, validated against the registry | | Cursor paging | ?cursor=&limit=50: keyset paging ([cursor-pagination](framework/docs/content/cursor-pagination.md)) | | Multipart upload | multipart/form-data on Image/File fields → streamed through WithFileStorage | | Validation | Required, unique, enum, min/max, regex pattern, multi-tenant scope | | Migrations | Versioned runner with drift + dirty-state guards; declarative incremental generation ([migrations](framework/docs/content/migrations.md)) | | FK constraints | BelongsTo relations emit FOREIGN KEY clauses; AutoMigrate topo-sorts tables | | Transactions | Create/Update/Delete + hooks share one tx; TxFromContext(ctx) exposes it | | OpenAPI 3 | /openapi.json plus a spec-viewer page at /api/docs/ | | MCP | posts_list, posts_get, posts_create, posts_update, posts_delete | | Soft delete | deleted_at column + automatic filter | | Multi-tenant | tenant_id column + automatic scope from request context | | Hooks | BeforeCreate, AfterUpdate, etc. for custom behaviour | | Custom routes | EntityConfig.Endpoints with optional MCP exposure | | Client SDKs | gofastr generate sdk: a Go module + JS/TS clients, with a live docs site ([sdk](framework/docs/content/sdk.md)) | | Customer CLI | gofastr generate cli: a branded terminal client for your customers, scoped API-token auth |
Try all of it against a running server: [examples/api-tour](examples/api-tour/README.md) is the curl tour, covering eager loading, cursor paging, atomic batch, SSE, uploads, and sparse updates. Hooks run inside the write's transaction ([hooks-and-transactions](framework/docs/content/hooks-and-transactions.md)).
The design bets
- Two layers. A small
core/of stdlib-first primitives sits under an opinionatedframework/. Use the framework for the common path; drop to core and write plainnet/httpwhen it's in your way. (The one external touchpoint iscore/middleware/tracing.go, which pulls in OpenTelemetry; the rest ofcore/is stdlib-only.) - Server-rendered UI, hydrated in place. Screens are Go:
Renderreturns HTML and the server sends the full page. A small JS runtime attaches to it. In-page changes like sort, paginate, or add-a-row call the server and swap one region, and cross-page navigation swaps content client-side with a route cache, so there are no hard refreshes. No React or Vue on the client, and no router code for you to write. - The interactive layer keeps no server state. Sessions are signed tokens, so any replica serves any request. Updates pull first: client signals, then RPC, then polling. SSE push is reserved for presence and collaboration ([
reactivity.md](framework/docs/content/reactivity.md)). - Security scopes live in the declaration, fail-closed.
owner_fieldmakes auto-CRUD per-user (anonymous → 401, cross-user → 404),access:gates operations behind RBAC permissions (403),multi_tenantscopes by tenant, andgofastr validateflags PII-shaped fields (email, phone, address, …) exposed without any of them. The MCP tools respect the same scopes as the REST routes. - You own the output. The generated code is normal Go you read, debug, commit, edit, and compose from your own
main. Registration is ordinary Go in the generated files; no reflection discovers your entities, and no platform sits between your binary and your server. - Batteries are separate packages. Auth, cache, email, queue, search, storage sit behind narrow interfaces; swap any one without forking.
- The framework checks whether you're still using it well.
gofastr verifyruns the 63 rules of the contract catalog (routing, permissions, security, rendering, accessibility) and measures semantic coverage: not "did this line run" but "did a request ever reach this route, did this permission ever get evaluated". Error-severity findings fail the run (--strictmakes warnings fail too), with per-line waivers and a baseline mode for existing codebases. See [contracts](framework/docs/content/contracts.md). - A blueprint scaffolds the whole app when you want a head start. One
gofastr.ymlgenerates the screens and the API in one pass; then it's plain Go you own and edit, and the running app never needs the blueprint again ([blueprint tutorial](framework/docs/content/tutorial-blueprint-app.md)).
The repo in 60 seconds
| Directory | What it is | Depend on it when… | |---|---|---| | core/ | Stdlib-only primitives: router, query, schema, render, mcp, openapi, migrate. Each usable on its own. | you want plain Go building blocks, no framework. | | framework/ | The opinionated entity layer (App, EntityConfig, CRUD, hooks, migrations). A thin facade re-exporting its focused runtime subpackages. | you want one declaration → SQL + REST + OpenAPI + MCP. | | core-ui/ | Server-driven UI runtime: html primitives, patterns, widget islands, signals, the vanilla-JS runtime. Independently usable. | you're rendering HTML from Go. | | battery/ | Opt-in infrastructure: admin, auth, cache, email, semantic, log, notify, print, queue, relay, rtc, search, setup, storage, webhook. Each behind a small interface. | you need a real subsystem; import only the ones you use. | | cmd/gofastr | The CLI: init, generate, pack (lossy app→blueprint snapshot), migrate, build, dev, verify, docs, and more. | you're scaffolding, generating, or checking code. | | kiln | Experimental agent build-mode runtime (mutate an in-memory IR over HTTP). | you're driving the app from an agent. | | examples/ | Runnable reference apps: the meridian blueprint flagship (a SaaS billing console + marketing site), the `ecomme
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: DonaldMurillo
- Source: DonaldMurillo/gofastr
- License: MIT
- Homepage: https://pkg.go.dev/github.com/DonaldMurillo/gofastr
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.