Run your application
Reboot applications are defined using an instance of Application, and launched from the file
configured as your --application in .rbtrc.
Application
Your entrypoint will construct an Application and then run it:
- Python
- TypeScript
async def main():
await Application(
servicers=[ChatRoomServicer],
initialize=initialize,
).run()
if __name__ == '__main__':
asyncio.run(main())
new Application({
servicers: [ChatRoomServicer],
initialize,
}).run();
initialize functions
The optional initialize argument to the Application constructor is a function that
runs every time your application starts up.
Initializers can be used to create any initial state that your application needs. In particular, they are usually where any singleton instances used by your application are created.
- Python
- TypeScript
async def initialize(context: InitializeContext):
chat_room = ChatRoom.ref(EXAMPLE_STATE_MACHINE_ID)
# Implicitly construct state machine upon first write.
await chat_room.send(
context,
message="Hello, World!",
)
const initialize = async (context) => {
const chatRoom = ChatRoom.ref("chat-room-nodejs");
await chatRoom.send(context, { message: "Hello, World!" });
};
If you have declared an initialize function, then you can additionally pass an
initialize_bearer_token (initializeBearerToken in TypeScript). That token is used
to construct the context passed to initialize, so that the calls initialize makes
are authenticated to your application.
Signing users in
Pass an OAuth to have Reboot run an OAuth server for
your application — the sign-in flow for browsers, native apps, and AI
MCP clients alike, plus
User auto-construction:
from reboot.aio.auth.oauth import OAuth
from reboot.aio.auth.oauth_providers import (
Development,
Google,
OAuthProviderByEnvironment,
)
application = Application(
servicers=[UserServicer, CounterServicer],
oauth=OAuth(
provider=OAuthProviderByEnvironment(
dev=Development(),
prod=Google(...),
),
allowed_origins=["https://app.example.com"],
),
)
await application.run()
An application whose API declares a User type must configure this;
starting without it is an error rather than a silent fallback. To
verify tokens minted somewhere else instead, see
Bearer tokens.
Presenting your app
Three optional arguments describe your application to the clients that connect to it — most visibly MCP clients and the setup wizard your app serves at its root URL:
| Argument | Description |
|---|---|
title | A human-readable name. Defaults to the application name. |
description | What the application does, in a sentence. |
example_prompts | ExamplePrompts that give a first-time visitor something to try. |
The MCP endpoint
Application mounts an MCP endpoint at /mcp, so any
MCP client can connect. Methods declared with
mcp=Tool() appear there as tools, and
UI methods as tools plus resources. No extra
configuration is needed in your main.py.
HTTP custom routes
Using a Reboot Application you can not only run your Reboot
servicers but you can also
provide custom HTTP route handlers for circumstances where you can't
just call one of your data type's methods.
For Python, this is implemented using FastAPI. For TypeScript, this is implemented with Express.js.
Limitations of custom HTTP routes
-
Currently only
GETandPOSTmethods are supported. -
The
/route is currently used by Reboot itself to show a helpful page explaining that this is a Reboot application.
Reach out at [email protected] if you run into use cases for fixing these!
Here is an example of implementing a handler for an HTTP GET:
- Python
- TypeScript
@application.http.get("/hello_world")
def hello_world():
return {"message": "Hello, world!"}
const application = new Application({ servicers: [GreeterServicer] });
application.http.get("/hello_world", async (context, req, res) => {
res.json({ message: `Hello, world!` });
});
To simplify calling directly into your Reboot application from your
application.http.get and application.http.post handlers, Reboot
provides a context of type
ExternalContext, because
you are still "external" to your application from an authorization
perspective.
This context includes any bearer token from
Authorization: Bearer <token> so that any calls into your Reboot application
will be properly authorized. In TypeScript, the context is injected into
every handler. In Python, Reboot follows the FastAPI dependency
injection strategy: if you want the context, you must explicitly add
it to your handler's arguments as shown in the following example:
- Python
- TypeScript
@application.http.post("/hello_greeter")
async def hello_greeter(
request: Request,
context: ExternalContext = InjectExternalContext,
):
body = await request.json()
greeter, _ = await Greeter.create(
context,
title=body['title'],
name=body['name'],
adjective=body['adjective'],
)
response = await greeter.greet(context, name="You")
return {"message": response.message}
const application = new Application({ servicers: [GreeterServicer] });
application.http.post("/hello_greeter", async (context, req, res) => {
const { title, name, adjective } = req.body as {
title: string;
name: string;
adjective: string;
};
const [greeter] = await Greeter.create(context, {
title,
name,
adjective,
});
const { message } = await greeter.greet(context, { name: "You" });
res.json({ message });
});