Skip to content

Commit 47ec84e

Browse files
authored
Remove EnrichContext injection (#135)
1 parent 9b9a629 commit 47ec84e

File tree

12 files changed

+80
-64
lines changed

12 files changed

+80
-64
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ app.run()
154154
Build a complete data layer with custom logic:
155155

156156
```python
157-
from enrichmcp import EnrichMCP, EnrichModel, Relationship, EnrichContext
157+
from enrichmcp import EnrichMCP, EnrichModel, Relationship
158158
from datetime import datetime
159159
from decimal import Decimal
160160
from pydantic import Field
@@ -254,10 +254,11 @@ async def calculate_lifetime_value(user_id: int) -> Decimal:
254254

255255
# ML-powered field
256256
@User.churn_risk.resolver
257-
async def predict_churn_risk(user_id: int, context: EnrichContext) -> float:
257+
async def predict_churn_risk(user_id: int) -> float:
258258
"""Run churn prediction model."""
259+
ctx = app.get_context()
259260
features = await gather_user_features(user_id)
260-
model = context.get("ml_models")["churn"]
261+
model = ctx.get("ml_models")["churn"]
261262
return float(model.predict_proba(features)[0][1])
262263

263264
app.run()
@@ -360,9 +361,10 @@ class UserProfile(EnrichModel):
360361
bio: str | None = Field(default=None, description="Short bio")
361362

362363
@app.retrieve
363-
async def get_user_profile(user_id: int, context: EnrichContext) -> UserProfile:
364+
async def get_user_profile(user_id: int) -> UserProfile:
365+
ctx = app.get_context()
364366
# Access context provided by MCP client
365-
auth_user = context.get("authenticated_user_id")
367+
auth_user = ctx.get("authenticated_user_id")
366368
if auth_user != user_id:
367369
raise PermissionError("Can only access your own profile")
368370
return await db.get_profile(user_id)
@@ -375,7 +377,8 @@ Reduce API overhead by storing results in a per-request, per-user, or global cac
375377
```python
376378

377379
@app.retrieve
378-
async def get_customer(cid: int, ctx: EnrichContext) -> Customer:
380+
async def get_customer(cid: int) -> Customer:
381+
ctx = app.get_context()
379382
async def fetch() -> Customer:
380383
return await db.get_customer(cid)
381384

docs/api/context.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ class MyContext(EnrichContext):
5858

5959
# Use in resources
6060
@app.retrieve
61-
async def get_data(context: MyContext) -> dict:
61+
async def get_data() -> dict:
62+
ctx = app.get_context()
6263
# Use your custom context
63-
return await context.db.fetch_data()
64+
return await ctx.db.fetch_data()
6465
```
6566

66-
Note: Full context support with dependency injection is planned for future releases.
67+
Note: Dependency injection is no longer supported; always call ``app.get_context()`` to access the current request context.

docs/api/parameter.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
`EnrichParameter` attaches hints like descriptions and examples to function parameters.
44
When a parameter's default value is an instance of `EnrichParameter`, those hints
5-
are appended to the generated tool description (except for parameters typed as
6-
`EnrichContext`).
5+
are appended to the generated tool description.
76

87
```python
98
from enrichmcp import EnrichParameter

docs/concepts.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ class AppContext(EnrichContext):
195195

196196

197197
@app.retrieve
198-
async def get_customer(customer_id: int, context: AppContext) -> Customer:
198+
async def get_customer(customer_id: int) -> Customer:
199199
"""Get customer using context."""
200+
context = app.get_context()
200201
# Check cache first
201202
cached = await context.cache.get(f"customer:{customer_id}")
202203
if cached:
@@ -249,16 +250,16 @@ The `describe_model()` output will list these allowed values.
249250

250251
## Context and Lifespan Management
251252

252-
EnrichMCP extends FastMCP's context system to provide automatic injection of logging, progress reporting, and shared resources:
253+
EnrichMCP extends FastMCP's context system to provide logging, progress reporting, and shared resources.
253254

254-
### Context Injection
255+
### Accessing Context
255256

256-
Any resource or resolver can receive context by adding a parameter typed as `EnrichContext`:
257+
Call ``app.get_context()`` inside resources or resolvers to work with the current request context:
257258

258259
```python
259260
@app.retrieve
260-
async def my_resource(param: str, ctx: EnrichContext) -> Result:
261-
# Context is automatically injected
261+
async def my_resource(param: str) -> Result:
262+
ctx = app.get_context()
262263
await ctx.info("Processing request")
263264
await ctx.report_progress(50, 100)
264265
return result
@@ -300,7 +301,8 @@ Access lifespan resources through the context:
300301

301302
```python
302303
@User.orders.resolver
303-
async def get_user_orders(user_id: int, ctx: EnrichContext) -> list[Order]:
304+
async def get_user_orders(user_id: int) -> list[Order]:
305+
ctx = app.get_context()
304306
# Get database from lifespan context
305307
db = ctx.request_context.lifespan_context["db"]
306308

@@ -327,7 +329,8 @@ from enrichmcp.errors import NotFoundError, ValidationError, AuthorizationError
327329

328330

329331
@app.retrieve
330-
async def get_order(order_id: int, context: AppContext) -> Order:
332+
async def get_order(order_id: int) -> Order:
333+
context = app.get_context()
331334
order = await context.db.get_order(order_id)
332335

333336
if not order:

docs/getting-started.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,10 @@ if __name__ == "__main__":
153153

154154
## Using Context
155155

156-
EnrichMCP provides automatic context injection for accessing logging, progress reporting, and lifespan resources:
156+
Access logging, progress reporting, and lifespan resources through the application context:
157157

158158
```python
159159
from contextlib import asynccontextmanager
160-
from enrichmcp import EnrichContext
161160

162161

163162
# Set up lifespan for database connection
@@ -176,7 +175,8 @@ app = EnrichMCP("My API", "Description", lifespan=lifespan)
176175

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

@@ -189,7 +189,7 @@ async def get_user(user_id: int, ctx: EnrichContext) -> User:
189189
return await db.get_user(user_id)
190190
```
191191

192-
Context is automatically injected when you add a parameter typed as `EnrichContext`.
192+
193193

194194
## Parameter Hints
195195

docs/pagination.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ async def get_user_orders(
210210
user_id: int,
211211
page: int = 1,
212212
page_size: int = 10,
213-
ctx: EnrichContext
214213
) -> PageResult[Order]:
214+
ctx = app.get_context()
215215
"""Get user orders with pagination."""
216216
db = ctx.request_context.lifespan_context["db"]
217217

docs/server_side_llm.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ other resources.
4343

4444
```python
4545
@app.retrieve
46-
async def summarize(text: str, ctx: EnrichContext) -> str:
46+
async def summarize(text: str) -> str:
47+
ctx = app.get_context()
4748
result = await ctx.ask_llm(
4849
f"Summarize this: {text}",
4950
model_preferences=prefer_fast_model(),

examples/caching/app.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import asyncio
44
import random
55

6-
from enrichmcp import EnrichContext, EnrichMCP
6+
from enrichmcp import EnrichMCP
77

88
app = EnrichMCP("Caching API", description="Demo of request caching")
99

1010

1111
@app.retrieve
12-
async def slow_square(n: int, ctx: EnrichContext) -> int:
12+
async def slow_square(n: int) -> int:
1313
"""Return n squared using request-scoped caching."""
14+
ctx = app.get_context()
1415

1516
async def compute() -> int:
1617
await asyncio.sleep(0.1)
@@ -20,8 +21,9 @@ async def compute() -> int:
2021

2122

2223
@app.retrieve
23-
async def fibonacci(n: int, ctx: EnrichContext) -> int:
24+
async def fibonacci(n: int) -> int:
2425
"""Compute the n-th Fibonacci number with global caching."""
26+
ctx = app.get_context()
2527

2628
async def compute() -> int:
2729
await asyncio.sleep(0.1)
@@ -34,8 +36,9 @@ async def compute() -> int:
3436

3537

3638
@app.retrieve
37-
async def user_analytics(ctx: EnrichContext) -> dict:
39+
async def user_analytics() -> dict:
3840
"""Return fake analytics for the user with user-scoped caching."""
41+
ctx = app.get_context()
3942

4043
async def compute() -> dict:
4144
await asyncio.sleep(0.1)

examples/server_side_llm_travel_planner/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from pydantic import Field
77

8-
from enrichmcp import EnrichContext, EnrichMCP, EnrichModel, prefer_fast_model
8+
from enrichmcp import EnrichMCP, EnrichModel, prefer_fast_model
99

1010
app = EnrichMCP(
1111
title="Travel Planner",
@@ -60,9 +60,9 @@ def list_destinations() -> list[Destination]:
6060
@app.retrieve
6161
async def plan_trip(
6262
preferences: Annotated[str, Field(description="Your travel preferences")],
63-
ctx: EnrichContext,
6463
) -> list[Destination]:
6564
"""Return three destinations that best match the given preferences."""
65+
ctx = app.get_context()
6666

6767
bullet_list = "\n".join(f"- {d.name}: {d.summary}" for d in DESTINATIONS)
6868
prompt = (

examples/shop_api_gateway/app.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import httpx
1414
from pydantic import Field
1515

16-
from enrichmcp import EnrichContext, EnrichMCP, EnrichModel, Relationship
16+
from enrichmcp import EnrichMCP, EnrichModel, Relationship
1717

1818
BACKEND_URL = "http://localhost:8001"
1919

@@ -69,42 +69,43 @@ class Order(EnrichModel):
6969
products: list[Product] = Relationship(description="Products in the order")
7070

7171

72-
async def _client(ctx: EnrichContext) -> httpx.AsyncClient:
72+
async def _client() -> httpx.AsyncClient:
7373
"""Helper to get the shared HTTP client."""
74+
ctx = app.get_context()
7475
return ctx.request_context.lifespan_context["client"]
7576

7677

7778
@app.retrieve
78-
async def list_users(ctx: EnrichContext) -> list[User]:
79+
async def list_users() -> list[User]:
7980
"""Fetch all users from the backend service."""
80-
client = await _client(ctx)
81+
client = await _client()
8182
resp = await client.get("/users")
8283
resp.raise_for_status()
8384
return [User(**u) for u in resp.json()]
8485

8586

8687
@app.retrieve
87-
async def get_user(user_id: int, ctx: EnrichContext) -> User:
88+
async def get_user(user_id: int) -> User:
8889
"""Return a single user by ID."""
89-
client = await _client(ctx)
90+
client = await _client()
9091
resp = await client.get(f"/users/{user_id}")
9192
resp.raise_for_status()
9293
return User(**resp.json())
9394

9495

9596
@app.retrieve
96-
async def list_products(ctx: EnrichContext) -> list[Product]:
97+
async def list_products() -> list[Product]:
9798
"""Retrieve all products available for sale."""
98-
client = await _client(ctx)
99+
client = await _client()
99100
resp = await client.get("/products")
100101
resp.raise_for_status()
101102
return [Product(**p) for p in resp.json()]
102103

103104

104105
@app.retrieve
105-
async def get_product(product_id: int, ctx: EnrichContext) -> Product:
106+
async def get_product(product_id: int) -> Product:
106107
"""Get a single product by ID."""
107-
client = await _client(ctx)
108+
client = await _client()
108109
resp = await client.get(f"/products/{product_id}")
109110
resp.raise_for_status()
110111
return Product(**resp.json())
@@ -113,40 +114,37 @@ async def get_product(product_id: int, ctx: EnrichContext) -> Product:
113114
@app.retrieve
114115
async def list_orders(
115116
user_id: int | None = None,
116-
ctx: EnrichContext | None = None,
117117
) -> list[Order]:
118118
"""List orders optionally filtered by user."""
119-
if ctx is None:
120-
raise RuntimeError("Context required")
121-
client = await _client(ctx)
119+
client = await _client()
122120
params = {"user_id": user_id} if user_id is not None else None
123121
resp = await client.get("/orders", params=params)
124122
resp.raise_for_status()
125123
return [Order(**o) for o in resp.json()]
126124

127125

128126
@app.retrieve
129-
async def get_order(order_id: int, ctx: EnrichContext) -> Order:
127+
async def get_order(order_id: int) -> Order:
130128
"""Retrieve a specific order."""
131-
client = await _client(ctx)
129+
client = await _client()
132130
resp = await client.get(f"/orders/{order_id}")
133131
resp.raise_for_status()
134132
return Order(**resp.json())
135133

136134

137135
@User.orders.resolver
138-
async def get_orders_for_user(user_id: int, ctx: EnrichContext) -> list["Order"]:
139-
return await list_orders(user_id=user_id, ctx=ctx)
136+
async def get_orders_for_user(user_id: int) -> list["Order"]:
137+
return await list_orders(user_id=user_id)
140138

141139

142140
@Order.user.resolver
143-
async def get_order_user(user_id: int, ctx: EnrichContext) -> "User":
144-
return await get_user(user_id=user_id, ctx=ctx)
141+
async def get_order_user(user_id: int) -> "User":
142+
return await get_user(user_id=user_id)
145143

146144

147145
@Order.products.resolver
148-
async def get_order_products(order_id: int, ctx: EnrichContext) -> list[Product]:
149-
client = await _client(ctx)
146+
async def get_order_products(order_id: int) -> list[Product]:
147+
client = await _client()
150148
resp = await client.get(f"/orders/{order_id}")
151149
resp.raise_for_status()
152150
data = resp.json()

0 commit comments

Comments
 (0)