app
Spider-Gazelle Application Template
Clone this repository to start building your own spider-gazelle based application. This is a template and as such, Do What the Fuck You Want To
Documentation
Detailed documentation and guides available: https://spider-gazelle.net/
- Action Controller base class for building Controllers
- Active Model base class for building ORMs
- Habitat configuration and settings for Crystal projects
- lucky_router base request handling and routing
- HTTP::Server built-in Crystal Lang HTTP server
- Request
- Response
- Cookies
- Headers
- Params etc
Spider-Gazelle builds on the amazing performance of lucky_router. :rocket:
OpenAPI
Routes defined with annotations are described in an OpenAPI document, generated from the code:
- Routes and parameters come from the route annotations and method signatures.
- Descriptions come from the doc comments directly above controllers and methods.
- Parameter details come from
@[AC::Param::Info(description: "...", example: "...")]. - Request and response schemas come from the argument and return types.
# Returns the example number provided as the result
@[AC::Route::GET("/api/:example")]
def api(
@[AC::Param::Info(description: "provide an example number to have it returned as the result", example: "3")]
example : Int32,
) : NamedTuple(result: Int32)
{result: example}
end
Comments are extracted with crystal docs, so the document is generated where the
source code is available:
./app --docs # print the document
./app --docs --file=openapi.yml # save it
The Dockerfile generates openapi.yml during the build and copies it into the image.
The template serves it at GET /openapi.
MCP Server
The application is also an MCP server, so LLM
clients (Claude Code, Claude Desktop, VS Code, Cursor, ...) can use your API. It's
served at /mcp over the Streamable HTTP transport.
claude mcp add --transport http my-app http://localhost:3000/mcp
- Tools: every annotated route is a tool, described by the same comments and
annotations as the OpenAPI docs. Controllers are grouped into toolboxes, and a
session starts with
list_toolboxes,open_toolboxandclose_toolbox, so the model only loads the tools it needs. - Prompts: reusable message templates users can pick in their client. Mark a
method with
@[AC::MCP(prompt: true)]. It returns aString, or anArray(AC::PromptMessage)for a conversation. Prompts aren't HTTP routes, but their arguments are parsed and your filters run exactly as for routes. SeeWelcome#number_factfor an example. - Visibility:
@[AC::MCP(hide: true)]excludes a route or controller (seeWelcome#openapi).@[AC::MCP(root: true)]makes a tool or prompt available without opening its toolbox.
- Descriptions: like the OpenAPI docs, these need the source code, so the
Dockerfile generates
mcp.yml(./app --mcp=mcp.yml) and ships it with the binary. Without it, the server still works but descriptions are missing. - Authentication: optional, and off by default. Your routes' own authentication
applies to every tool call (
Authorization,CookieandX-API-Keyheaders are forwarded). To have MCP clients sign users in with OAuth, uncommentauth_probeandresource_metadatainsrc/config.cr.
Configuration lives in src/config.cr. The environment variables are:
| Variable | Default | Purpose |
|----------|---------|---------|
| SG_MCP_PATH | /mcp | Endpoint path, an empty string disables the MCP server |
| SG_MCP_DESCRIPTION | mcp.yml | Location of the generated tool descriptions |
See the action-controller README for the full reference.
Testing
crystal spec
- to run in development mode
crystal ./src/app.cr
Compiling
crystal build ./src/app.cr
Deploying
Once compiled you are left with a binary ./app
- for help
./app --help - viewing routes
./app --routes - run on a different port or host
./app -b 0.0.0.0 -p 80 - generate the OpenAPI docs
./app --docs --file=openapi.yml - generate the MCP tool descriptions
./app --mcp=mcp.yml