Skip to content

Commit 1dfe9f2

Browse files
authored
feat: rename app.resource to app.retrieve (#82)
1 parent cadbeea commit 1dfe9f2

File tree

23 files changed

+114
-90
lines changed

23 files changed

+114
-90
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.4.2] - 2025-06-19
11+
12+
### Changed
13+
- Renamed `app.resource` decorator to `app.retrieve`. `app.resource` remains
14+
as a deprecated alias.
15+
16+
### Added
17+
- Support for marking fields as mutable with `mutable=True` and CRUD example
18+
- BigInteger column type handling for SQLAlchemy integration
19+
- Example smoke tests and improved OpenAI chat example
20+
- Optional cleanup for SQLAlchemy lifespans
21+
- Detailed ROBOTS guide and CI improvements
22+
1023
## [0.4.1] - 2025-06-15
1124

1225
### Fixed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class Order(EnrichModel):
113113
customer: Customer = Relationship(description="Customer who placed this order")
114114

115115
# Define how to fetch data
116-
@app.resource
116+
@app.retrieve
117117
async def get_customer(customer_id: int) -> Customer:
118118
"""Fetch customer from CRM API."""
119119
response = await http.get(f"/api/customers/{customer_id}")
@@ -165,7 +165,7 @@ class Segment(EnrichModel):
165165
users: list[User] = Relationship(description="Users in this segment")
166166

167167
# Complex resource with business logic
168-
@app.resource
168+
@app.retrieve
169169
async def find_high_value_at_risk_users(
170170
lifetime_value_min: Decimal = 1000,
171171
churn_risk_min: float = 0.7,
@@ -269,7 +269,7 @@ Handle large datasets elegantly:
269269
```python
270270
from enrichmcp import PageResult
271271

272-
@app.resource
272+
@app.retrieve
273273
async def list_orders(
274274
page: int = 1,
275275
page_size: int = 50
@@ -290,7 +290,7 @@ See the [Pagination Guide](https://featureform.github.io/enrichmcp/pagination) f
290290
Pass auth, database connections, or any context:
291291

292292
```python
293-
@app.resource
293+
@app.retrieve
294294
async def get_user_profile(user_id: int, context: EnrichContext) -> UserProfile:
295295
# Access context provided by MCP client
296296
auth_user = context.get("authenticated_user_id")

docs/api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ async def get_user_orders(user_id: int) -> list["Order"]:
7272
Resources are the entry points for AI agents:
7373

7474
```python
75-
@app.resource
75+
@app.retrieve
7676
async def list_users() -> list[User]:
7777
"""List all users in the system."""
7878
return fetch_all_users()

docs/api/app.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ class User(EnrichModel):
4646
name: str = Field(description="Username")
4747
```
4848

49-
### `resource(func=None, *, name=None, description=None)`
49+
### `retrieve(func=None, *, name=None, description=None)`
5050

51-
Decorator to register a function as an MCP resource.
51+
Register a function as an MCP resource.
52+
`app.resource` is deprecated and forwards to this method.
5253

5354
**Parameters:**
5455
- `func`: The function (when used without parentheses)
@@ -57,15 +58,15 @@ Decorator to register a function as an MCP resource.
5758

5859
**Example:**
5960
```python
60-
@app.resource
61+
@app.retrieve
6162
async def list_users() -> list[User]:
6263
"""List all users in the system."""
6364
return await fetch_all_users()
6465
```
6566

6667
### `create(func=None, *, name=None, description=None)`
6768

68-
Register an entity creation operation. Works like `@app.resource` but
69+
Register an entity creation operation. Works like `@app.retrieve` but
6970
indicates a create action.
7071

7172
```python
@@ -214,7 +215,7 @@ async def get_book_author(book_id: int) -> Author:
214215

215216

216217
# Define resources
217-
@app.resource
218+
@app.retrieve
218219
async def list_authors() -> list[Author]:
219220
"""List all authors."""
220221
# Implementation here

docs/api/context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class MyContext(EnrichContext):
4545

4646

4747
# Use in resources
48-
@app.resource
48+
@app.retrieve
4949
async def get_data(context: MyContext) -> dict:
5050
# Use your custom context
5151
return await context.db.fetch_data()

docs/api/errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ except ValidationError as e:
3333
Use Python's standard exceptions:
3434

3535
```python
36-
@app.resource
36+
@app.retrieve
3737
async def get_user(user_id: int) -> User:
3838
user = find_user(user_id)
3939
if not user:

docs/concepts.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ async def get_orders(customer_id: int, limit: int = 10, offset: int = 0) -> list
149149
Resources are the entry points for AI agents:
150150

151151
```python
152-
@app.resource
152+
@app.retrieve
153153
async def get_customer(customer_id: int) -> Customer:
154154
"""Retrieve a customer by ID.
155155
@@ -162,7 +162,7 @@ async def get_customer(customer_id: int) -> Customer:
162162
return customer
163163

164164

165-
@app.resource
165+
@app.retrieve
166166
async def search_customers(query: str, status: str | None = None) -> list[Customer]:
167167
"""Search for customers by name or email.
168168
@@ -194,7 +194,7 @@ class AppContext(EnrichContext):
194194
user: User | None = None
195195

196196

197-
@app.resource
197+
@app.retrieve
198198
async def get_customer(customer_id: int, context: AppContext) -> Customer:
199199
"""Get customer using context."""
200200
# Check cache first
@@ -236,7 +236,7 @@ enrichmcp leverages Pydantic for comprehensive validation:
236236

237237
```python
238238
# This automatically validates inputs
239-
@app.resource
239+
@app.retrieve
240240
async def create_customer(
241241
email: EmailStr, # Validates email format
242242
age: int = Field(ge=18, le=150), # Range validation
@@ -255,7 +255,7 @@ EnrichMCP extends FastMCP's context system to provide automatic injection of log
255255
Any resource or resolver can receive context by adding a parameter typed as `EnrichContext`:
256256

257257
```python
258-
@app.resource
258+
@app.retrieve
259259
async def my_resource(param: str, ctx: EnrichContext) -> Result:
260260
# Context is automatically injected
261261
await ctx.info("Processing request")
@@ -325,7 +325,7 @@ Use semantic errors that AI agents understand:
325325
from enrichmcp.errors import NotFoundError, ValidationError, AuthorizationError
326326

327327

328-
@app.resource
328+
@app.retrieve
329329
async def get_order(order_id: int, context: AppContext) -> Order:
330330
order = await context.db.get_order(order_id)
331331

docs/examples.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ async def get_book_author(book_id: int) -> "Author":
110110

111111

112112
# Define root resources
113-
@app.resource
113+
@app.retrieve
114114
async def list_authors() -> list[Author]:
115115
"""List all authors in the catalog."""
116116
return [Author(**author_data) for author_data in AUTHORS]
117117

118118

119-
@app.resource
119+
@app.retrieve
120120
async def get_author(author_id: int) -> Author:
121121
"""Get a specific author by ID."""
122122
author_data = next((a for a in AUTHORS if a["id"] == author_id), None)
@@ -126,13 +126,13 @@ async def get_author(author_id: int) -> Author:
126126
return Author(id=-1, name="Not Found", bio="Author not found", birth_date=date(1900, 1, 1))
127127

128128

129-
@app.resource
129+
@app.retrieve
130130
async def list_books() -> list[Book]:
131131
"""List all books in the catalog."""
132132
return [Book(**book_data) for book_data in BOOKS]
133133

134134

135-
@app.resource
135+
@app.retrieve
136136
async def search_books(title_contains: str) -> list[Book]:
137137
"""Search for books by title."""
138138
matching_books = [book for book in BOOKS if title_contains.lower() in book["title"].lower()]
@@ -283,13 +283,13 @@ async def get_task_project(task_id: int) -> "Project":
283283

284284

285285
# Resources
286-
@app.resource
286+
@app.retrieve
287287
async def list_projects() -> list[Project]:
288288
"""List all projects."""
289289
return [Project(**project_data) for project_data in PROJECTS]
290290

291291

292-
@app.resource
292+
@app.retrieve
293293
async def list_tasks(status: Status | None = None, priority: Priority | None = None) -> list[Task]:
294294
"""List tasks with optional filtering."""
295295
filtered_tasks = TASKS
@@ -303,7 +303,7 @@ async def list_tasks(status: Status | None = None, priority: Priority | None = N
303303
return [Task(**task_data) for task_data in filtered_tasks]
304304

305305

306-
@app.resource
306+
@app.retrieve
307307
async def get_project_summary(project_id: int) -> dict:
308308
"""Get summary statistics for a project."""
309309
project_tasks = [t for t in TASKS if t["project_id"] == project_id]
@@ -421,13 +421,13 @@ async def get_ingredient_recipes(ingredient_id: int) -> list["Recipe"]:
421421

422422

423423
# Resources
424-
@app.resource
424+
@app.retrieve
425425
async def list_recipes() -> list[Recipe]:
426426
"""List all recipes."""
427427
return [Recipe(**recipe_data) for recipe_data in RECIPES]
428428

429429

430-
@app.resource
430+
@app.retrieve
431431
async def search_recipes_by_ingredient(ingredient_name: str) -> list[Recipe]:
432432
"""Find recipes containing a specific ingredient."""
433433
# Find ingredient
@@ -442,7 +442,7 @@ async def search_recipes_by_ingredient(ingredient_name: str) -> list[Recipe]:
442442
return await get_ingredient_recipes(ingredient["id"])
443443

444444

445-
@app.resource
445+
@app.retrieve
446446
async def get_quick_recipes(max_time: int = 30) -> list[Recipe]:
447447
"""Get recipes that can be made quickly."""
448448
quick_recipes = [
@@ -459,7 +459,7 @@ These examples demonstrate:
459459
- Basic entity definition with `@app.entity`
460460
- Relationship definition with `Relationship()`
461461
- Resolver implementation with `@Entity.field.resolver`
462-
- Resource creation with `@app.resource`
462+
- Resource creation with `@app.retrieve`
463463
- Simple in-memory data storage
464464
- Filtering and searching patterns
465465

@@ -472,4 +472,4 @@ can generate entities and resolvers directly from SQLAlchemy models. It works
472472
with any async database backend supported by SQLAlchemy (for example
473473
PostgreSQL with `asyncpg`).
474474

475-
The `examples/shop_api_gateway` project shows how EnrichMCP can act as a simple API gateway in front of another FastAPI service.
475+
The `examples/shop_api_gateway` project shows how EnrichMCP can act as a simple API gateway in front of another FastAPI service.

docs/getting-started.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ async def get_book_author(book_id: int) -> Author:
126126

127127

128128
# Define root resources
129-
@app.resource
129+
@app.retrieve
130130
async def list_books() -> list[Book]:
131131
"""List all books in the catalog."""
132132
return [
@@ -140,7 +140,7 @@ async def list_books() -> list[Book]:
140140
]
141141

142142

143-
@app.resource
143+
@app.retrieve
144144
async def get_author(author_id: int) -> Author:
145145
"""Get a specific author by ID."""
146146
return Author(id=author_id, name="Jane Doe", bio="Bestselling author")
@@ -175,7 +175,7 @@ app = EnrichMCP("My API", "Description", lifespan=lifespan)
175175

176176

177177
# Use context in resources and resolvers
178-
@app.resource
178+
@app.retrieve
179179
async def get_user(user_id: int, ctx: EnrichContext) -> User:
180180
# Logging
181181
await ctx.info(f"Fetching user {user_id}")

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ async def get_customer_orders(customer_id: int) -> list[Order]:
4545

4646

4747
# Create entry points for AI
48-
@app.resource
48+
@app.retrieve
4949
async def get_customer(customer_id: int) -> Customer:
5050
"""Get a customer by ID."""
5151
return await db.get_customer(customer_id)

0 commit comments

Comments
 (0)