# Gofastr

> The framework that doesn't get in the way of you or your agents.

- **Type:** MCP server
- **Install:** `agentstack add mcp-donaldmurillo-gofastr`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [DonaldMurillo](https://agentstack.voostack.com/s/donaldmurillo)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [DonaldMurillo](https://github.com/DonaldMurillo)
- **Source:** https://github.com/DonaldMurillo/gofastr
- **Website:** https://pkg.go.dev/github.com/DonaldMurillo/gofastr

## Install

```sh
agentstack add mcp-donaldmurillo-gofastr
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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 →](https://donaldmurillo.github.io/gofastr/)**
&nbsp;·&nbsp; [Quickstart](#quickstart)
&nbsp;·&nbsp; [A GoFastr app in production](https://barcode.donaldmurillo.com/)

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](https://www.coderabbit.ai):** it reviews every
PR in this repo and keeps catching what everyone else missed, like six Major
findings on [#198](https://github.com/DonaldMurillo/gofastr/pull/198) while
the checks list showed `pass`. Every finding is triaged on the PR before merge.

## Quickstart

Requires Go 1.27+. Install the CLI:

```bash
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:

```go
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.

```go
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:

```go
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:

```bash
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](https://github.com/DonaldMurillo/gofastr/releases)),
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:

```go
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 opinionated `framework/`. Use the framework for the common path; drop to core and write plain `net/http` when it's in your way. (The one external touchpoint is `core/middleware/tracing.go`, which pulls in OpenTelemetry; the rest of `core/` is stdlib-only.)
- **Server-rendered UI, hydrated in place.** Screens are Go: `Render` returns 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_field` makes auto-CRUD per-user (anonymous → 401, cross-user → 404), `access:` gates operations behind RBAC permissions (403), `multi_tenant` scopes by tenant, and `gofastr validate` flags 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 verify` runs 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 (`--strict` makes 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.yml` generates 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](https://github.com/DonaldMurillo)
- **Source:** [DonaldMurillo/gofastr](https://github.com/DonaldMurillo/gofastr)
- **License:** MIT
- **Homepage:** https://pkg.go.dev/github.com/DonaldMurillo/gofastr

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-donaldmurillo-gofastr
- Seller: https://agentstack.voostack.com/s/donaldmurillo
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
