@aws/nx-plugin-mcp 1.0.0-rc.95 → 1.0.0-rc.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aws-nx-mcp.js +61 -14
- package/docs/get_started/existing-project.mdx +6 -3
- package/docs/get_started/quick-start.mdx +8 -0
- package/docs/get_started/tutorials/dungeon-game/1.mdx +12 -14
- package/docs/get_started/tutorials/dungeon-game/2.mdx +10 -2
- package/docs/get_started/tutorials/dungeon-game/3.mdx +4 -0
- package/docs/get_started/tutorials/dungeon-game/4.mdx +2 -2
- package/docs/guides/agentcore-gateway.mdx +4 -2
- package/docs/guides/agentcore-harness.mdx +2 -1
- package/docs/guides/astro-docs.mdx +25 -7
- package/docs/guides/connection/py-agent-a2a.mdx +2 -0
- package/docs/guides/connection/py-agent-dynamodb.mdx +1 -1
- package/docs/guides/connection/py-agent-gateway.mdx +3 -0
- package/docs/guides/connection/py-agent-mcp.mdx +18 -4
- package/docs/guides/connection/py-agent-rdb.mdx +5 -4
- package/docs/guides/connection/py-fast-api-dynamodb.mdx +1 -1
- package/docs/guides/connection/py-fast-api-rdb.mdx +7 -2
- package/docs/guides/connection/py-mcp-server-dynamodb.mdx +1 -1
- package/docs/guides/connection/py-mcp-server-rdb.mdx +6 -6
- package/docs/guides/connection/react-agui.mdx +34 -25
- package/docs/guides/connection/react-fastapi.mdx +114 -116
- package/docs/guides/connection/react-py-agent.mdx +4 -0
- package/docs/guides/connection/react-smithy.mdx +152 -98
- package/docs/guides/connection/react-trpc.mdx +13 -6
- package/docs/guides/connection/smithy-dynamodb.mdx +2 -8
- package/docs/guides/connection/smithy-rdb.mdx +3 -6
- package/docs/guides/connection/trpc-rdb.mdx +6 -6
- package/docs/guides/connection/ts-agent-a2a.mdx +4 -4
- package/docs/guides/connection/ts-agent-dynamodb.mdx +13 -11
- package/docs/guides/connection/ts-agent-gateway.mdx +2 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +19 -7
- package/docs/guides/connection/ts-agent-rdb.mdx +2 -2
- package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +11 -7
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +4 -3
- package/docs/guides/docker-bundling.mdx +23 -3
- package/docs/guides/fastapi.mdx +16 -5
- package/docs/guides/py-agent.mdx +129 -54
- package/docs/guides/py-mcp-server.mdx +3 -1
- package/docs/guides/py-rdb.mdx +13 -4
- package/docs/guides/python-lambda-function.mdx +8 -8
- package/docs/guides/python-project.mdx +28 -25
- package/docs/guides/react-website-auth.mdx +8 -8
- package/docs/guides/react-website.mdx +46 -27
- package/docs/guides/runtime-config.mdx +24 -4
- package/docs/guides/security.mdx +1 -1
- package/docs/guides/terraform-project.mdx +8 -2
- package/docs/guides/trpc.mdx +96 -12
- package/docs/guides/ts-agent.mdx +17 -3
- package/docs/guides/ts-dcr-proxy.mdx +24 -6
- package/docs/guides/ts-lambda-function.mdx +7 -1
- package/docs/guides/ts-mcp-server.mdx +45 -15
- package/docs/guides/ts-rdb.mdx +9 -2
- package/docs/guides/ts-smithy-api.mdx +76 -7
- package/docs/guides/typescript-infrastructure.mdx +24 -10
- package/docs/guides/typescript-project.mdx +12 -5
- package/docs/guides/workspace.mdx +21 -9
- package/docs/snippets/api/type-safe-api-integrations.mdx +2 -0
- package/docs/snippets/connection/a2a-infrastructure.mdx +3 -0
- package/docs/snippets/connection/infra-project-prerequisite.mdx +8 -0
- package/docs/snippets/connection/strands-agent-rdb-ssl-requirements.mdx +1 -1
- package/docs/snippets/connection/ts-lambda-rdb-ssl-requirements.mdx +1 -1
- package/docs/snippets/connection/ts-mcp-server-rdb-ssl-requirements.mdx +1 -1
- package/docs/snippets/required-prerequisites.mdx +1 -1
- package/package.json +1 -1
- package/src/init/schema.json +5 -0
- package/src/py/project/schema.json +3 -1
package/docs/guides/py-agent.mdx
CHANGED
|
@@ -163,15 +163,25 @@ You can edit `agent.py` to add tools, configure the model and customize the syst
|
|
|
163
163
|
|
|
164
164
|
Tools are functions that the AI agent can call to perform actions. Both frameworks use a decorator-based approach for defining tools, derive the tool name and description from the function name and docstring, and generate the input schema from your type hints.
|
|
165
165
|
|
|
166
|
+
Define the tool, then add it to the `tools` list inside `get_agent()`:
|
|
167
|
+
|
|
166
168
|
<Tabs syncKey="agent-framework">
|
|
167
169
|
<TabItem label="Strands" _filter={{ framework: 'strands' }}>
|
|
168
|
-
```python
|
|
170
|
+
```python title="packages/my-project/my_module/agent/agent.py" {16-20,32}
|
|
171
|
+
from contextlib import contextmanager
|
|
172
|
+
|
|
169
173
|
from strands import Agent, tool
|
|
174
|
+
from strands.hooks import HookCallback, HookProvider
|
|
175
|
+
from strands_tools import current_time
|
|
176
|
+
from my_scope_agent_connection import log_model_errors, log_tool_errors
|
|
177
|
+
|
|
178
|
+
from .session import get_session_manager
|
|
179
|
+
|
|
170
180
|
|
|
171
181
|
@tool
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
def subtract(a: int, b: int) -> int:
|
|
183
|
+
return a - b
|
|
184
|
+
|
|
175
185
|
|
|
176
186
|
@tool
|
|
177
187
|
def get_weather(city: str) -> str:
|
|
@@ -179,23 +189,41 @@ def get_weather(city: str) -> str:
|
|
|
179
189
|
# Your weather API integration here
|
|
180
190
|
return f"Weather in {city}: Sunny, 25°C"
|
|
181
191
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
|
|
193
|
+
AGENT_HOOKS: list[HookProvider | HookCallback] = [log_model_errors, log_tool_errors]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@contextmanager
|
|
197
|
+
def get_agent():
|
|
198
|
+
yield Agent(
|
|
199
|
+
name="MyAgent",
|
|
200
|
+
description="MyAgent Strands Agent",
|
|
201
|
+
system_prompt="You are a helpful assistant with access to various tools.",
|
|
202
|
+
tools=[subtract, current_time, get_weather],
|
|
203
|
+
hooks=AGENT_HOOKS,
|
|
204
|
+
session_manager=get_session_manager(),
|
|
205
|
+
)
|
|
187
206
|
```
|
|
188
207
|
</TabItem>
|
|
189
208
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
190
|
-
```python
|
|
209
|
+
```python title="packages/my-project/my_module/agent/agent.py" {19-23,30}
|
|
210
|
+
import os
|
|
211
|
+
|
|
191
212
|
from langchain.agents import create_agent
|
|
192
213
|
from langchain_aws import ChatBedrockConverse
|
|
193
214
|
from langchain_core.tools import tool
|
|
194
215
|
|
|
216
|
+
from .session import get_checkpointer
|
|
217
|
+
|
|
218
|
+
REGION = os.environ.get("AWS_REGION", "us-east-1")
|
|
219
|
+
MODEL_ID = os.environ.get("MODEL_ID", "global.anthropic.claude-haiku-4-5-20251001-v1:0")
|
|
220
|
+
|
|
221
|
+
|
|
195
222
|
@tool
|
|
196
|
-
def
|
|
197
|
-
"""
|
|
198
|
-
return
|
|
223
|
+
def subtract(a: int, b: int) -> int:
|
|
224
|
+
"""Subtract b from a."""
|
|
225
|
+
return a - b
|
|
226
|
+
|
|
199
227
|
|
|
200
228
|
@tool
|
|
201
229
|
def get_weather(city: str) -> str:
|
|
@@ -203,12 +231,15 @@ def get_weather(city: str) -> str:
|
|
|
203
231
|
# Your weather API integration here
|
|
204
232
|
return f"Weather in {city}: Sunny, 25°C"
|
|
205
233
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
model=ChatBedrockConverse(model=MODEL_ID, region_name=REGION)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
234
|
+
|
|
235
|
+
def get_agent():
|
|
236
|
+
model = ChatBedrockConverse(model=MODEL_ID, region_name=REGION)
|
|
237
|
+
return create_agent(
|
|
238
|
+
model=model,
|
|
239
|
+
tools=[subtract, get_weather],
|
|
240
|
+
system_prompt="You are a helpful assistant with access to various tools.",
|
|
241
|
+
checkpointer=get_checkpointer(),
|
|
242
|
+
)
|
|
212
243
|
```
|
|
213
244
|
</TabItem>
|
|
214
245
|
</Tabs>
|
|
@@ -217,28 +248,45 @@ agent = create_agent(
|
|
|
217
248
|
|
|
218
249
|
<Tabs syncKey="agent-framework">
|
|
219
250
|
<TabItem label="Strands" _filter={{ framework: 'strands' }}>
|
|
220
|
-
Strands provides a collection of pre-built tools through the `strands-tools` package
|
|
221
|
-
|
|
222
|
-
```python
|
|
223
|
-
from strands_tools import current_time,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
)
|
|
251
|
+
Strands provides a collection of pre-built tools through the `strands-agents-tools` package, which the generator already adds to your project's `pyproject.toml`. Import the tools you want and add them to `get_agent()`:
|
|
252
|
+
|
|
253
|
+
```python title="packages/my-project/my_module/agent/agent.py" {1,11}
|
|
254
|
+
from strands_tools import current_time, file_read, http_request
|
|
255
|
+
|
|
256
|
+
# ...
|
|
257
|
+
|
|
258
|
+
@contextmanager
|
|
259
|
+
def get_agent():
|
|
260
|
+
yield Agent(
|
|
261
|
+
name="MyAgent",
|
|
262
|
+
description="MyAgent Strands Agent",
|
|
263
|
+
system_prompt="You are a helpful assistant.",
|
|
264
|
+
tools=[current_time, file_read, http_request],
|
|
265
|
+
hooks=AGENT_HOOKS,
|
|
266
|
+
session_manager=get_session_manager(),
|
|
267
|
+
)
|
|
229
268
|
```
|
|
230
269
|
</TabItem>
|
|
231
270
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
232
|
-
LangChain provides a large ecosystem of [tools and integrations](https://docs.langchain.com/oss/python/integrations/tools).
|
|
271
|
+
LangChain provides a large ecosystem of [tools and integrations](https://docs.langchain.com/oss/python/integrations/tools), each distributed in its own package. The generator does not add these, so install the one you need first — for example `langchain-community`, which the search tool below comes from:
|
|
233
272
|
|
|
234
|
-
|
|
273
|
+
<NxCommands commands={['run <project-name>:add langchain-community']} />
|
|
274
|
+
|
|
275
|
+
Then import the tools and add them to `get_agent()`:
|
|
276
|
+
|
|
277
|
+
```python title="packages/my-project/my_module/agent/agent.py" {1,9}
|
|
235
278
|
from langchain_community.tools import DuckDuckGoSearchRun
|
|
236
279
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
280
|
+
# ...
|
|
281
|
+
|
|
282
|
+
def get_agent():
|
|
283
|
+
model = ChatBedrockConverse(model=MODEL_ID, region_name=REGION)
|
|
284
|
+
return create_agent(
|
|
285
|
+
model=model,
|
|
286
|
+
tools=[DuckDuckGoSearchRun()],
|
|
287
|
+
system_prompt="You are a helpful assistant.",
|
|
288
|
+
checkpointer=get_checkpointer(),
|
|
289
|
+
)
|
|
242
290
|
```
|
|
243
291
|
</TabItem>
|
|
244
292
|
</Tabs>
|
|
@@ -247,33 +295,50 @@ agent = create_agent(
|
|
|
247
295
|
|
|
248
296
|
<Tabs syncKey="agent-framework">
|
|
249
297
|
<TabItem label="Strands" _filter={{ framework: 'strands' }}>
|
|
250
|
-
|
|
298
|
+
The generated agent uses the default Strands model on Amazon Bedrock. To configure it, pass a `model` to the `Agent`. See the [Strands documentation on model providers](https://strandsagents.com/docs/user-guide/concepts/model-providers/) for the available providers and their options:
|
|
251
299
|
|
|
252
|
-
```python
|
|
253
|
-
from strands import Agent
|
|
300
|
+
```python title="packages/my-project/my_module/agent/agent.py" {1,5-9,14}
|
|
254
301
|
from strands.models import BedrockModel
|
|
255
302
|
|
|
256
|
-
#
|
|
257
|
-
|
|
303
|
+
# ...
|
|
304
|
+
|
|
305
|
+
MODEL = BedrockModel(
|
|
258
306
|
model_id="anthropic.claude-sonnet-4-20250514-v1:0",
|
|
259
307
|
region_name="us-west-2",
|
|
260
308
|
temperature=0.3,
|
|
261
309
|
)
|
|
262
310
|
|
|
263
|
-
|
|
311
|
+
@contextmanager
|
|
312
|
+
def get_agent():
|
|
313
|
+
yield Agent(
|
|
314
|
+
model=MODEL,
|
|
315
|
+
name="MyAgent",
|
|
316
|
+
description="MyAgent Strands Agent",
|
|
317
|
+
system_prompt="You are a helpful assistant.",
|
|
318
|
+
tools=[subtract, current_time],
|
|
319
|
+
hooks=AGENT_HOOKS,
|
|
320
|
+
session_manager=get_session_manager(),
|
|
321
|
+
)
|
|
264
322
|
```
|
|
265
323
|
</TabItem>
|
|
266
324
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
267
|
-
LangChain agents use a [`ChatBedrockConverse`](https://docs.langchain.com/oss/python/integrations/chat/bedrock_converse) model. The generated agent reads the model id and region from the `MODEL_ID` and `AWS_REGION` environment variables,
|
|
268
|
-
|
|
269
|
-
```python
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
model=
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
325
|
+
LangChain agents use a [`ChatBedrockConverse`](https://docs.langchain.com/oss/python/integrations/chat/bedrock_converse) model. The generated agent reads the model id and region from the `MODEL_ID` and `AWS_REGION` environment variables, which the infrastructure sets for the deployed agent. To configure the model further, add arguments where it is constructed in `get_agent()`:
|
|
326
|
+
|
|
327
|
+
```python title="packages/my-project/my_module/agent/agent.py" {4-8}
|
|
328
|
+
# ...
|
|
329
|
+
|
|
330
|
+
def get_agent():
|
|
331
|
+
model = ChatBedrockConverse(
|
|
332
|
+
model=MODEL_ID,
|
|
333
|
+
region_name=REGION,
|
|
334
|
+
temperature=0.3,
|
|
335
|
+
)
|
|
336
|
+
return create_agent(
|
|
337
|
+
model=model,
|
|
338
|
+
tools=[subtract],
|
|
339
|
+
system_prompt="You are a helpful assistant.",
|
|
340
|
+
checkpointer=get_checkpointer(),
|
|
341
|
+
)
|
|
277
342
|
```
|
|
278
343
|
</TabItem>
|
|
279
344
|
</Tabs>
|
|
@@ -425,6 +490,10 @@ If you have added multiple components to your project (agents, MCP servers, etc.
|
|
|
425
490
|
|
|
426
491
|
This uses `uv run` to execute your Agent using the [Bedrock AgentCore Python SDK](https://github.com/aws/bedrock-agentcore-sdk-python).
|
|
427
492
|
|
|
493
|
+
The agent listens on a port assigned from the workspace pool when it was generated. Read it from `metadata.ports` in the project's `project.json`, or from the `--port` flag in the `<your-agent-name>-dev` target's command. The examples below use `8081`, the port a first HTTP agent is assigned in a fresh workspace.
|
|
494
|
+
|
|
495
|
+
A `<your-agent-name>-serve` target is also generated, which runs the agent against your deployed infrastructure and therefore requires `RUNTIME_CONFIG_APP_ID` to be set. See the <Link path="guides/local-development">Local Development</Link> guide for the difference between `dev` and `serve`.
|
|
496
|
+
|
|
428
497
|
### Chat with Your Agent
|
|
429
498
|
|
|
430
499
|
The generator configures a `<your-agent-name>-chat` Nx target that drops you into an interactive terminal chat with your agent.
|
|
@@ -439,11 +508,13 @@ Then, in another terminal, start the chat:
|
|
|
439
508
|
|
|
440
509
|
The generator emits a `scripts/<your-agent-name>/chat.ts` for every protocol. It connects to the local agent by default, or to your deployed agent when `RUNTIME_CONFIG_APP_ID` is set (see [Chat with your deployed agent](#chat-with-your-deployed-agent) below).
|
|
441
510
|
|
|
442
|
-
|
|
511
|
+
<OptionFilter when={{ protocol: 'http' }} description="OpenAPI client generation for the chat script">
|
|
512
|
+
For HTTP agents, the chat script uses a type-safe TypeScript client generated from the agent's OpenAPI spec. The generator also emits:
|
|
443
513
|
|
|
444
|
-
- `scripts/<
|
|
514
|
+
- `scripts/<your_agent_name>_openapi.py` — a small script that exports the agent's OpenAPI spec (named with your agent's name in `snake_case`)
|
|
445
515
|
- An `<your-agent-name>-openapi` Nx target that runs it
|
|
446
516
|
- An `<your-agent-name>-generate-client` Nx target that produces a type-safe TypeScript client under `scripts/<your-agent-name>/generated/`
|
|
517
|
+
</OptionFilter>
|
|
447
518
|
|
|
448
519
|
When you customize the agent's input shape (e.g. add new fields to `InvokeInput`), update `chat.ts` to pass the new fields when invoking the agent and the rest works automatically.
|
|
449
520
|
|
|
@@ -567,7 +638,11 @@ When running locally (`LOCAL_DEV=true`, set automatically by the `-dev` target),
|
|
|
567
638
|
<OptionFilter when={{ protocol: 'http' }} description="FastAPI HTTP invocation details">
|
|
568
639
|
### Invoke the Local Server
|
|
569
640
|
|
|
570
|
-
|
|
641
|
+
Start your agent with the `<your-agent-name>-dev` target:
|
|
642
|
+
|
|
643
|
+
<NxCommands commands={['agent-dev your-project']} />
|
|
644
|
+
|
|
645
|
+
Then send a POST request to `/invocations` on the port your local agent is running on. Substitute the port assigned to your agent — read it from `metadata.ports` in the project's `project.json`, or from the `--port` flag in the `<your-agent-name>-dev` target's command. A first HTTP agent in a fresh workspace is assigned `8081`:
|
|
571
646
|
|
|
572
647
|
```bash
|
|
573
648
|
curl -N -X POST http://localhost:8081/invocations \
|
|
@@ -157,7 +157,9 @@ If you would like to run your MCP server locally using [Streamable HTTP transpor
|
|
|
157
157
|
|
|
158
158
|
<NxCommands commands={['your-server-name-serve your-project']} />
|
|
159
159
|
|
|
160
|
-
This command uses `uv run uvicorn --reload` to run your MCP server with HTTP transport
|
|
160
|
+
This command uses `uv run uvicorn --reload` to run your MCP server with HTTP transport, and automatically restarts when files change.
|
|
161
|
+
|
|
162
|
+
Each MCP server is assigned its own port, starting at `8000`, so several servers can run side by side in the same workspace. Read the port your server listens on from its `<your-server-name>-serve` target in `project.json`.
|
|
161
163
|
|
|
162
164
|
<OptionFilter when={{ infra: ['agentcore', 'agentcore-ecr'] }} description="Bedrock AgentCore Runtime deployment details">
|
|
163
165
|
## Deploying Your MCP Server to Bedrock AgentCore Runtime
|
package/docs/guides/py-rdb.mdx
CHANGED
|
@@ -33,22 +33,31 @@ The generator creates the following project structure in the `<directory>/<name>
|
|
|
33
33
|
|
|
34
34
|
<FileTree>
|
|
35
35
|
- \<name>
|
|
36
|
-
- \_\_init\_\_.py Package exports
|
|
36
|
+
- \_\_init\_\_.py Package exports
|
|
37
37
|
- connection.py Database engine and session factory with IAM authentication
|
|
38
38
|
- utils.py Runtime config and local development helpers
|
|
39
39
|
- migration_handler.py Lambda handler that runs Alembic migrations during deployment
|
|
40
40
|
- create_db_user_handler.py Lambda handler that creates the application database user during deployment
|
|
41
41
|
- models
|
|
42
|
+
- \_\_init\_\_.py Model exports, imported by Alembic to discover your tables
|
|
42
43
|
- example.py Example SQLModel table definition
|
|
43
44
|
- migrations
|
|
44
45
|
- versions Alembic-generated migration scripts
|
|
45
46
|
- env.py Alembic environment (connects to the database)
|
|
46
47
|
- script.py.mako Alembic migration script template
|
|
48
|
+
- tests
|
|
49
|
+
- \_\_init\_\_.py Module initialisation
|
|
50
|
+
- conftest.py Test configuration
|
|
51
|
+
- test_noop.py Placeholder test
|
|
47
52
|
- alembic.ini Alembic configuration
|
|
48
53
|
- config.json Local development connection details and runtime config key
|
|
49
54
|
- Dockerfile.migration Container image for the migration handler
|
|
50
55
|
- Dockerfile.create-db-user Container image for the create-db-user handler
|
|
51
56
|
- project.json Project configuration and build targets
|
|
57
|
+
- pyproject.toml Packaging configuration file used by UV
|
|
58
|
+
- README.md Project README
|
|
59
|
+
- .python-version Contains the project's Python version
|
|
60
|
+
- .gitignore Files excluded from version control
|
|
52
61
|
</FileTree>
|
|
53
62
|
|
|
54
63
|
Local development scripts are shared across all database projects and generated into `packages/common/scripts/`:
|
|
@@ -137,12 +146,12 @@ Import `session_context` from your database package and use it as an async conte
|
|
|
137
146
|
```python
|
|
138
147
|
from sqlmodel import select
|
|
139
148
|
|
|
140
|
-
from
|
|
141
|
-
from
|
|
149
|
+
from my_scope_my_db import session_context
|
|
150
|
+
from my_scope_my_db.models.example import ExampleModel
|
|
142
151
|
|
|
143
152
|
async def example():
|
|
144
153
|
async with session_context() as session:
|
|
145
|
-
results = (await session.execute(select(ExampleModel))).all()
|
|
154
|
+
results = (await session.execute(select(ExampleModel))).scalars().all()
|
|
146
155
|
```
|
|
147
156
|
|
|
148
157
|
The database client automatically:
|
|
@@ -90,7 +90,8 @@ metrics: Metrics = Metrics()
|
|
|
90
90
|
tracer: Tracer = Tracer()
|
|
91
91
|
|
|
92
92
|
@tracer.capture_lambda_handler
|
|
93
|
-
@
|
|
93
|
+
@logger.inject_lambda_context
|
|
94
|
+
@metrics.log_metrics(capture_cold_start_metric=True)
|
|
94
95
|
@event_parser(model=EventBridgeModel)
|
|
95
96
|
def lambda_handler(event: EventBridgeModel, context: LambdaContext):
|
|
96
97
|
logger.info("Received event", extra={"event": event.model_dump() })
|
|
@@ -127,11 +128,10 @@ def lambda_handler(event: EventBridgeModel, context: LambdaContext):
|
|
|
127
128
|
It is recommended to set the correlation id for all unique requests for easier debugging and monitoring. Please refer to the [aws powertools logger](https://docs.powertools.aws.dev/lambda/python/2.22.0/core/logger/#setting-a-correlation-id) documentation for correlation id best practices.
|
|
128
129
|
:::
|
|
129
130
|
|
|
130
|
-
The logger
|
|
131
|
+
The handler is decorated with [`@logger.inject_lambda_context`](https://docs.powertools.aws.dev/lambda/python/latest/core/logger/#inject-lambda-context), so every log record it emits also carries:
|
|
131
132
|
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
- Cold start indicators
|
|
133
|
+
- `function_name`, `function_memory_size`, `function_arn` and `function_request_id` from the Lambda context
|
|
134
|
+
- `cold_start`, indicating whether the invocation initialised a new execution environment
|
|
135
135
|
|
|
136
136
|
#### Tracing
|
|
137
137
|
|
|
@@ -157,9 +157,9 @@ def lambda_handler(event: EventBridgeModel, context: LambdaContext):
|
|
|
157
157
|
|
|
158
158
|
Default metrics include:
|
|
159
159
|
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
160
|
+
- `InvocationCount`, added on every invocation
|
|
161
|
+
- `SuccessCount` and `ErrorCount`, added by the handler's `try`/`except`
|
|
162
|
+
- `ColdStart`, emitted by [`@metrics.log_metrics(capture_cold_start_metric=True)`](https://docs.powertools.aws.dev/lambda/python/latest/core/metrics/#capturing-cold-start-metric) when the invocation initialises a new execution environment
|
|
163
163
|
|
|
164
164
|
### Type Safety
|
|
165
165
|
|
|
@@ -3,11 +3,35 @@ title: Python Projects
|
|
|
3
3
|
description: Reference documentation for Python Projects
|
|
4
4
|
generator: py#project
|
|
5
5
|
---
|
|
6
|
-
import { FileTree } from '@astrojs/starlight/components';
|
|
6
|
+
import { Code, FileTree } from '@astrojs/starlight/components';
|
|
7
|
+
import Link from '@components/link.astro';
|
|
7
8
|
import RunGenerator from '@components/run-generator.astro';
|
|
8
9
|
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
9
10
|
import NxCommands from '@components/nx-commands.astro';
|
|
10
11
|
import PackageManagerShortCommand from '@components/package-manager-short-command.astro';
|
|
12
|
+
import { LAMBDA_RUNTIME_VERSIONS } from '../../../../../../packages/nx-plugin/src/utils/versions';
|
|
13
|
+
|
|
14
|
+
export const bundleTarget = `{
|
|
15
|
+
"targets": {
|
|
16
|
+
"bundle": {
|
|
17
|
+
"dependsOn": ["bundle-x86"]
|
|
18
|
+
},
|
|
19
|
+
"bundle-x86": {
|
|
20
|
+
"cache": true,
|
|
21
|
+
"inputs": ["production", "^production"],
|
|
22
|
+
"executor": "nx:run-commands",
|
|
23
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle-x86"],
|
|
24
|
+
"options": {
|
|
25
|
+
"commands": [
|
|
26
|
+
"uv export --frozen --no-dev --no-editable --project {projectRoot} --package my_scope.my_library -o dist/{projectRoot}/bundle-x86/requirements.txt",
|
|
27
|
+
"uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --python-platform x86_64-manylinux_2_28 --python-version ${LAMBDA_RUNTIME_VERSIONS.python} --target dist/{projectRoot}/bundle-x86 -r dist/{projectRoot}/bundle-x86/requirements.txt"
|
|
28
|
+
],
|
|
29
|
+
"parallel": false
|
|
30
|
+
},
|
|
31
|
+
"dependsOn": ["compile"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}`;
|
|
11
35
|
|
|
12
36
|
The Python project generator can be used to create a modern [Python](https://www.python.org/) library or application configured with best practices, managed with [UV](https://docs.astral.sh/uv/), a single lockfile and virtual environment in an [UV workspace](https://docs.astral.sh/uv/concepts/projects/workspaces/), [pytest](https://docs.pytest.org/en/stable/) for running tests, [Ruff](https://docs.astral.sh/ruff/) for static analysis, and [ty](https://docs.astral.sh/ty/) for type checking.
|
|
13
37
|
|
|
@@ -87,30 +111,9 @@ This will add the dependency to your project's `pyproject.toml` file, and update
|
|
|
87
111
|
|
|
88
112
|
#### Runtime Code
|
|
89
113
|
|
|
90
|
-
When you use your Python project as runtime code (for example as the handler for an AWS lambda function), you will need to create a bundle of the source code and all its dependencies.
|
|
114
|
+
When you use your Python project as runtime code (for example as the handler for an AWS lambda function), you will need to create a bundle of the source code and all its dependencies. The <Link path="guides/python-lambda-function">`py#lambda-function`</Link>, <Link path="guides/fastapi">`py#api`</Link> and <Link path="guides/py-mcp-server">`py#mcp-server`</Link> generators add this for you. To add one by hand, add targets such as the following to your `project.json` file, matching the shape those generators vend:
|
|
91
115
|
|
|
92
|
-
|
|
93
|
-
{
|
|
94
|
-
...
|
|
95
|
-
"targets": {
|
|
96
|
-
...
|
|
97
|
-
"bundle": {
|
|
98
|
-
"cache": true,
|
|
99
|
-
"inputs": ["production", "^production"],
|
|
100
|
-
"executor": "nx:run-commands",
|
|
101
|
-
"outputs": ["{workspaceRoot}/dist/packages/my_library/bundle"],
|
|
102
|
-
"options": {
|
|
103
|
-
"commands": [
|
|
104
|
-
"uv export --frozen --no-dev --no-editable --project packages/my_library --package my_scope.my_library -o dist/packages/my_library/bundle/requirements.txt",
|
|
105
|
-
"uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --python-platform x86_64-manylinux_2_28 --python `uv python pin` --target dist/packages/my_library/bundle -r dist/packages/my_library/bundle/requirements.txt"
|
|
106
|
-
],
|
|
107
|
-
"parallel": false
|
|
108
|
-
},
|
|
109
|
-
"dependsOn": ["compile"]
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
}
|
|
113
|
-
```
|
|
116
|
+
<Code lang="json" title="project.json" code={bundleTarget} />
|
|
114
117
|
|
|
115
118
|
### Installing
|
|
116
119
|
|
|
@@ -158,7 +161,7 @@ The deploy targets depend on `assemble`, so deploying builds only what it is abo
|
|
|
158
161
|
|
|
159
162
|
### Writing Tests
|
|
160
163
|
|
|
161
|
-
Tests should be written in the `
|
|
164
|
+
Tests should be written in the `tests` directory within your project, in python files prefixed with `test_`, for example:
|
|
162
165
|
|
|
163
166
|
<FileTree>
|
|
164
167
|
- my_library
|
|
@@ -106,9 +106,9 @@ browser -> backend: IAM/Cognito
|
|
|
106
106
|
|
|
107
107
|
#### Threat protection
|
|
108
108
|
|
|
109
|
-
The User Pool is created on the Cognito [Plus feature plan](https://docs.aws.amazon.com/cognito/latest/developerguide/feature-plans-features-plus.html) with [threat protection](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-threat-protection.html)
|
|
109
|
+
The User Pool is created on the Cognito [Plus feature plan](https://docs.aws.amazon.com/cognito/latest/developerguide/feature-plans-features-plus.html) with [threat protection](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-threat-protection.html) in **audit-only** enforcement for standard authentication. In audit-only, Cognito assigns a risk level to each sign-in and records the assessment without blocking users.
|
|
110
110
|
|
|
111
|
-
Once you have observed the risk assessments for your users, you can switch to full-function enforcement to automatically respond to risky activity (for example requiring MFA or blocking sign-in):
|
|
111
|
+
Once you have observed the risk assessments for your users, you can switch to full-function enforcement to automatically respond to risky activity (for example requiring MFA or blocking sign-in), then configure the response per risk level via [adaptive authentication](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-adaptive-authentication.html):
|
|
112
112
|
|
|
113
113
|
<Infrastructure>
|
|
114
114
|
<Fragment slot="cdk">
|
|
@@ -187,13 +187,13 @@ This rule flags loopback addresses in query arguments as [SSRF](https://docs.aws
|
|
|
187
187
|
You will need to add the user identity infrastructure to your stack, declaring it _before_ the website:
|
|
188
188
|
|
|
189
189
|
```ts title="packages/infra/src/stacks/application-stack.ts" {3,9}
|
|
190
|
-
import { Stack } from 'aws-cdk-lib';
|
|
190
|
+
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
191
191
|
import { Construct } from 'constructs';
|
|
192
192
|
import { MyWebsite, UserIdentity } from '@my-scope/common-constructs';
|
|
193
193
|
|
|
194
194
|
export class ApplicationStack extends Stack {
|
|
195
|
-
constructor(scope: Construct, id: string) {
|
|
196
|
-
super(scope, id);
|
|
195
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
196
|
+
super(scope, id, props);
|
|
197
197
|
|
|
198
198
|
new UserIdentity(this, 'Identity');
|
|
199
199
|
|
|
@@ -256,13 +256,13 @@ In order to grant authenticated users access to perform certain actions, such as
|
|
|
256
256
|
<Infrastructure>
|
|
257
257
|
<Fragment slot="cdk">
|
|
258
258
|
```ts title="packages/infra/src/stacks/application-stack.ts" {12}
|
|
259
|
-
import { Stack } from 'aws-cdk-lib';
|
|
259
|
+
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
260
260
|
import { Construct } from 'constructs';
|
|
261
261
|
import { MyWebsite, UserIdentity, MyApi } from '@my-scope/common-constructs';
|
|
262
262
|
|
|
263
263
|
export class ApplicationStack extends Stack {
|
|
264
|
-
constructor(scope: Construct, id: string) {
|
|
265
|
-
super(scope, id);
|
|
264
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
265
|
+
super(scope, id, props);
|
|
266
266
|
|
|
267
267
|
const identity = new UserIdentity(this, 'Identity');
|
|
268
268
|
const api = new MyApi(this, 'MyApi', {
|