@aws/nx-plugin-mcp 1.2.0 → 1.3.1

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.
@@ -0,0 +1,306 @@
1
+ ---
2
+ title: Python Agent Guardrails
3
+ description: Attach an Amazon Bedrock Guardrail to a Python Strands or LangChain Agent
4
+ generator: py#agent#guardrails
5
+ ---
6
+
7
+ import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
8
+ import GeneratorParameters from '@components/generator-parameters.astro';
9
+ import Infrastructure from '@components/infrastructure.astro';
10
+ import Link from '@components/link.astro';
11
+ import NxCommands from '@components/nx-commands.astro';
12
+ import RunGenerator from '@components/run-generator.astro';
13
+
14
+ Attach an [Amazon Bedrock Guardrail](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html) to a <Link path="guides/py-agent">Python Agent</Link>. A guardrail is a set of rules that Amazon Bedrock applies to the messages your agent sends to the model and to the model's answers. Without one, a user can ask your agent about any topic, and the model can repeat personal data such as email addresses back in its answers.
15
+
16
+ The generator adds a policy file that holds your rules, the code that applies the guardrail to your agent's model, and the infrastructure that creates the guardrail in your AWS account. It supports both `py#agent` frameworks, Strands and LangChain, with every protocol.
17
+
18
+ ## How this works
19
+
20
+ - `guardrail.json` next to your `agent.py` holds the rules: the topics your agent must refuse and the types of personal data (PII, personally identifiable information) it must hide or block.
21
+ - Your CDK construct or Terraform module reads `guardrail.json` when you synthesize or plan. It creates the guardrail and a numbered version of it. A guardrail version is a read-only snapshot of the rules.
22
+ - The infrastructure writes the guardrail's ID and version number to <Link path="guides/runtime-config">runtime config</Link>, the AWS AppConfig application where your infrastructure stores the details of deployed resources. The entry is `agentcore.guardrails.<AgentClass>`, named after your agent's class, for example `agentcore.guardrails.MyAgent`. Each guarded agent has its own entry.
23
+ - `guardrail.py` defines the Bedrock model that your `agent.py` uses. Before each model call, the model reads the agent's entry from runtime config and adds that guardrail to the request.
24
+
25
+ ## Usage
26
+
27
+ ### Generate Agent Guardrails
28
+
29
+ You will need an existing Python project containing an agent created with the `py#agent` generator.
30
+
31
+ <RunGenerator generator="py#agent#guardrails" />
32
+
33
+ ### Options
34
+
35
+ <GeneratorParameters generator="py#agent#guardrails" />
36
+
37
+ ## Generator Output
38
+
39
+ The generator adds the following files next to your agent, where `<module>` is your project's Python module and `<agent>` is the snake-case name of your agent component (`agent` by default):
40
+
41
+ <FileTree>
42
+ - \<your-project>/\<module>/\<agent>/
43
+ - agent.py Your agent, now created with the guardrailed model
44
+ - guardrail.json The rules your guardrail applies
45
+ - guardrail.py Defines the Bedrock model with the guardrail applied
46
+ </FileTree>
47
+
48
+ It also adds the infrastructure for your agent's `iac` provider, where `<agent-name>` is the kebab-case name of your agent's construct or module:
49
+
50
+ <Infrastructure>
51
+ <Fragment slot="cdk">
52
+ <FileTree>
53
+ - packages/common/constructs/src/app/guardrails/\<agent-name>/
54
+ - \<agent-name>-guardrail.ts CDK construct containing the guardrail and its version
55
+ </FileTree>
56
+ </Fragment>
57
+ <Fragment slot="terraform">
58
+ <FileTree>
59
+ - packages/common/terraform/src/app/guardrails/\<agent-name>/
60
+ - \<agent-name>-guardrail.tf Terraform module containing the guardrail and its version
61
+ </FileTree>
62
+ </Fragment>
63
+ </Infrastructure>
64
+
65
+ The generator edits `agent.py` like this:
66
+
67
+ <Tabs syncKey="agent-framework">
68
+ <TabItem label="Strands">
69
+ ```diff lang="python"
70
+ +from .guardrail import get_guardrailed_model
71
+ from .session import get_session_manager
72
+
73
+ @contextmanager
74
+ def get_agent():
75
+ yield Agent(
76
+ + model=get_guardrailed_model(),
77
+ name="MyAgent",
78
+ ```
79
+
80
+ `get_guardrailed_model()` returns a `GuardrailedBedrockModel`, a subclass of the Strands `BedrockModel`. It uses the same default model as an `Agent` created without a `model`.
81
+ </TabItem>
82
+ <TabItem label="LangChain">
83
+ ```diff lang="python"
84
+ -from langchain_aws import ChatBedrockConverse
85
+ from langchain_core.tools import tool
86
+
87
+ +from .guardrail import GuardrailedChatBedrockConverse
88
+ from .session import get_checkpointer
89
+
90
+ def get_agent():
91
+ - model = ChatBedrockConverse(model=MODEL_ID, region_name=REGION)
92
+ + model = GuardrailedChatBedrockConverse(model=MODEL_ID, region_name=REGION)
93
+ ```
94
+
95
+ `GuardrailedChatBedrockConverse` is a subclass of `ChatBedrockConverse`. The generator keeps the arguments of your `ChatBedrockConverse(...)` call.
96
+ </TabItem>
97
+ </Tabs>
98
+
99
+ Running the generator again on the same agent changes no file, and it keeps your edits to `guardrail.json` and `guardrail.py`.
100
+
101
+ If your agent was generated with `infra: none`, the generator adds only the agent files and prints a warning. You then create the guardrail yourself and write its ID and version to runtime config at `agentcore.guardrails.<AgentClass>` as `{ guardrailId, guardrailVersion }`.
102
+
103
+ If a TypeScript agent in another project has the same class name and already has a guardrail, the generator stops with an error and changes no file. Both agents would share one runtime construct and one guardrail. Give one of the agents a different name.
104
+
105
+ ### An agent that already sets a model
106
+
107
+ If `agent.py` does not have the expected shape, the generator leaves it unchanged. It prints the file name and the lines to add.
108
+
109
+ <Tabs syncKey="agent-framework">
110
+ <TabItem label="Strands">
111
+ This happens when your `Agent(...)` call already sets `model`. To keep your own model options, create your model with the `GuardrailedBedrockModel` class from `guardrail.py`. It takes the same options as `BedrockModel`, for example:
112
+
113
+ ```python title="agent.py"
114
+ from .guardrail import GuardrailedBedrockModel
115
+
116
+ agent = Agent(
117
+ model=GuardrailedBedrockModel(model_id="my-model-id"),
118
+ # ...
119
+ )
120
+ ```
121
+ </TabItem>
122
+ <TabItem label="LangChain">
123
+ This happens when `agent.py` has no `ChatBedrockConverse(...)` call, for example because you create your model another way. Create your model with the `GuardrailedChatBedrockConverse` class from `guardrail.py`. It takes the same arguments as `ChatBedrockConverse`, for example:
124
+
125
+ ```python title="agent.py"
126
+ from .guardrail import GuardrailedChatBedrockConverse
127
+
128
+ model = GuardrailedChatBedrockConverse(model=MODEL_ID, region_name=REGION)
129
+ ```
130
+ </TabItem>
131
+ </Tabs>
132
+
133
+ ## What the guardrail checks
134
+
135
+ The guardrail checks two things on every model call:
136
+
137
+ - the conversation your agent sends to the model, including the user's latest message
138
+ - the model's answer, before your agent streams it back to the user
139
+
140
+ When the guardrail blocks a user's message, the model is not called. When an `ANONYMIZE` rule matches, the answer contains a placeholder such as `{EMAIL}` instead of the value. When the guardrail blocks an answer, the user gets the `blockedOutputsMessaging` text.
141
+
142
+ <Tabs syncKey="agent-framework">
143
+ <TabItem label="Strands">
144
+ When the guardrail blocks a user's message, the user gets the `blockedInputMessaging` text. Strands also replaces the blocked message in the agent's conversation history with `[User input redacted.]`.
145
+ </TabItem>
146
+ <TabItem label="LangChain">
147
+ When the guardrail blocks a user's message, the model's answer is the `blockedInputMessaging` text, and the user gets that text.
148
+
149
+ On later model calls in the same session, `guardrail.py` sends `[User input redacted.]` in place of each user message whose turn the guardrail blocked, as Strands does. The guardrail checks the whole conversation on every call, so without this the blocked message would block every later message in the session. The checkpointer still saves the original message.
150
+ </TabItem>
151
+ </Tabs>
152
+
153
+ The guardrail does not check tool definitions, the arguments the model passes to your tools, or the results your tools return. For example, if a tool returns a customer's email address from a database, the guardrail does not hide it from the model. Treat tool results as untrusted, as the <Link path="guides/py-agent">Python Agent guide</Link> describes under "Securing your Agent".
154
+
155
+ ## Editing guardrail.json
156
+
157
+ The vended policy is an example for the generated maths agent. It refuses investment advice and hides or blocks three types of personal data:
158
+
159
+ ```json title="guardrail.json"
160
+ {
161
+ "blockedInputMessaging": "Sorry, I can't help with that request.",
162
+ "blockedOutputsMessaging": "Sorry, I can't share that answer.",
163
+ "deniedTopics": [
164
+ {
165
+ "name": "Investment advice",
166
+ "definition": "Recommendations about which specific stocks, funds or other investments to buy or sell.",
167
+ "examples": ["Which stocks should I buy this year?"]
168
+ }
169
+ ],
170
+ "piiEntities": [
171
+ { "type": "EMAIL", "action": "ANONYMIZE" },
172
+ { "type": "PHONE", "action": "ANONYMIZE" },
173
+ { "type": "US_SOCIAL_SECURITY_NUMBER", "action": "BLOCK" }
174
+ ]
175
+ }
176
+ ```
177
+
178
+ The fields are:
179
+
180
+ - `blockedInputMessaging`: the reply a user gets when the guardrail blocks their message. At most 500 characters.
181
+ - `blockedOutputsMessaging`: the reply a user gets when the guardrail blocks the model's answer. At most 500 characters.
182
+ - `deniedTopics`: topics your agent must refuse. Each topic has a `name` (at most 100 letters, digits, spaces and the characters `-_!?.`), a `definition` of at most 1000 characters that describes the topic, and optional `examples` of at most 100 characters each.
183
+ - `piiEntities`: types of personal data to act on. `type` is a [sensitive information type](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-sensitive-filters.html) such as `EMAIL`, `PHONE` or `US_SOCIAL_SECURITY_NUMBER`. `action` is `ANONYMIZE` to replace the value with a placeholder, or `BLOCK` to block the whole message or answer.
184
+
185
+ Write a topic `definition` that describes the topic itself. For example, "Recommendations about which specific stocks to buy" works better than "Do not give investment advice".
186
+
187
+ ### Why the version is numbered
188
+
189
+ Each time you change `guardrail.json` and deploy, the infrastructure creates a new numbered guardrail version and writes it to runtime config. The version's description holds the SHA-256 hash of `guardrail.json`, so a change to the file changes the description, and a new version replaces the old one. With the CDK construct, the hash also covers any guardrail properties you pass.
190
+
191
+ Your running agent does not need a restart. `guardrail.py` keeps what it reads from runtime config for 5 seconds, so the agent uses the new version within 5 seconds of the AppConfig deployment. The old version is deleted after the AppConfig deployment. CloudFormation deletes it in its cleanup step, which in one measurement (2026-10-24, us-east-1) began about 7 seconds after the deployment completed. CloudFormation does not guarantee that delay. Terraform keeps the old version for about 15 seconds after the deployment module, so the 5-second cache never points at a deleted version. This works when you add the guardrail module to that module's `depends_on`, as shown in [Wiring the guardrail to your agent](#wiring-the-guardrail-to-your-agent).
192
+
193
+ Your agent never uses the `DRAFT` version. `DRAFT` always holds the latest rules, so an edit made in the AWS console would reach your running agent without a deployment. `guardrail.py` raises an error if the version in runtime config is not a version number.
194
+
195
+ ## Wiring the guardrail to your agent
196
+
197
+ The generator does not change your stack or your root Terraform module, in the same way that the `py#agent` generator leaves deploying the agent to you. When it finishes, it prints the code below with your agent's names filled in. Add it to create the guardrail, write its runtime-config entry and allow the agent to apply the guardrail:
198
+
199
+ <Infrastructure>
200
+ <Fragment slot="cdk">
201
+ ```ts title="packages/infra/src/stacks/application-stack.ts"
202
+ import { MyAgent, MyAgentGuardrail } from '@my-scope/common-constructs';
203
+
204
+ const agent = new MyAgent(this, 'MyAgent');
205
+ new MyAgentGuardrail(this, 'MyAgentGuardrail', { agent });
206
+ ```
207
+
208
+ The construct writes the guardrail's ID and version to runtime config at `agentcore.guardrails.MyAgent`, and grants the `agent` permission to apply the guardrail. The agent construct already allows the agent to read runtime config.
209
+
210
+ The construct exposes:
211
+
212
+ - `guardrail` (the `CfnGuardrail`) and `version` (the `CfnGuardrailVersion`)
213
+ - `guardrailId`, `guardrailArn` and `guardrailVersion`
214
+ - `grantApply(grantee)`, which grants `bedrock:ApplyGuardrail` on the guardrail to another principal
215
+
216
+ It also adds the `GuardrailId` and `GuardrailVersion` stack outputs. Its props are `agent` and any `CfnGuardrail` properties. The `CfnGuardrail` properties take precedence over `guardrail.json`. For example, add content filters:
217
+
218
+ ```ts
219
+ new MyAgentGuardrail(this, 'MyAgentGuardrail', {
220
+ agent,
221
+ contentPolicyConfig: {
222
+ filtersConfig: [
223
+ { type: 'HATE', inputStrength: 'HIGH', outputStrength: 'HIGH' },
224
+ ],
225
+ },
226
+ });
227
+ ```
228
+
229
+ The generator also adds `guardrail.json` to the `synth` inputs of each CDK infrastructure project, so a change to the file runs the synth again instead of using the Nx cache.
230
+ </Fragment>
231
+ <Fragment slot="terraform">
232
+ Add the `my_agent_guardrail` module as shown, in the root module where you deploy your agent. Add its `additional_iam_policy_statements` line to your existing `my_agent` module block. Add `module.my_agent_guardrail` to the `depends_on` list of your `runtime_config_appconfig_deployment` module, so the deployment includes the guardrail's runtime-config entry and Terraform deletes an old guardrail version only after the deployment. If your root module does not deploy the agent yet, add the agent's module first, as described in <Link path="guides/py-agent#infrastructure-as-code">the Python Agent guide</Link>.
233
+
234
+ ```hcl title="packages/infra/src/main.tf"
235
+ module "my_agent_guardrail" {
236
+ source = "../../common/terraform/src/app/guardrails/my-agent"
237
+ }
238
+
239
+ module "my_agent" {
240
+ source = "../../common/terraform/src/app/agents/my-agent"
241
+ # ...existing arguments...
242
+ additional_iam_policy_statements = module.my_agent_guardrail.iam_policy_statements
243
+ }
244
+
245
+ module "runtime_config_appconfig_deployment" {
246
+ # ...existing arguments...
247
+ depends_on = [
248
+ # ...existing modules...
249
+ module.my_agent_guardrail,
250
+ ]
251
+ }
252
+ ```
253
+
254
+ If your agent module already sets `additional_iam_policy_statements`, combine the lists:
255
+
256
+ ```hcl
257
+ additional_iam_policy_statements = concat(module.my_agent_guardrail.iam_policy_statements, local.my_statements)
258
+ ```
259
+
260
+ The module writes the guardrail's ID and version to runtime config at `agentcore.guardrails.MyAgent`. The `agentcore` namespace is in the default `namespaces` of the runtime-config modules, so you do not need to add it. The agent module already allows the agent to read runtime config.
261
+
262
+ The module takes a `tags` variable and outputs `guardrail_id`, `guardrail_arn`, `guardrail_version` and `iam_policy_statements`. To add other guardrail policies, such as content filters, edit the `aws_bedrock_guardrail` resource in the module.
263
+
264
+ The module sets `create_before_destroy` on the guardrail version, so Terraform creates the new version before it deletes the old one. A `time_sleep` resource from the `hashicorp/time` provider keeps the old version for about 15 seconds after the runtime-config deployment, and the runtime-config entry reads the guardrail ID and version from it. Because of this wait, `terraform destroy` also takes about 15 seconds longer.
265
+ </Fragment>
266
+ </Infrastructure>
267
+
268
+ ### A missing runtime-config entry
269
+
270
+ If you forget the wiring, runtime config has no entry for your agent. The model then raises an error before it calls Bedrock, so the agent does not run without its guardrail. For `MyAgent`, the error is:
271
+
272
+ ```
273
+ No guardrail for this agent in runtime config at agentcore.guardrails.MyAgent. Add the MyAgentGuardrail construct (CDK) or the guardrails/my-agent module (Terraform) to your infrastructure.
274
+ ```
275
+
276
+ The agent starts with every protocol (`http`, `a2a` and `ag-ui`), and each request fails with this error. If the agent cannot read runtime config at all, for example because `RUNTIME_CONFIG_APP_ID` is not set, each request fails with the error from the agent's runtime-config reader instead.
277
+
278
+ With the `http` protocol, the agent has already started streaming its response when the model raises the error. The caller then gets no answer, and the error appears only in the agent's log, for a deployed agent in its runtime log group.
279
+
280
+ ## Local development
281
+
282
+ The `<agent>-dev` target sets `LOCAL_DEV=true`. When `LOCAL_DEV` is `true` and the `RUNTIME_CONFIG_APP_ID` environment variable is not set, `guardrail.py` does not read runtime config. It logs a warning once and the agent runs without a guardrail:
283
+
284
+ <NxCommands commands={['agent-dev your-project']} />
285
+
286
+ To test your rules locally, deploy the guardrail first. Then set `RUNTIME_CONFIG_APP_ID` to the ID of your deployed runtime-config application, from the `RuntimeConfigApplicationId` stack output (CDK) or `module.runtime_config_appconfig.application_id` (Terraform). Your shell also needs AWS credentials that can read AppConfig and apply the guardrail:
287
+
288
+ <NxCommands commands={['agent-dev your-project']} env={{ RUNTIME_CONFIG_APP_ID: '<application-id>' }} />
289
+
290
+ The agent then reads only its own entry, so several guarded agents can run locally against the same application. If the agent cannot read runtime config, or the entry is missing, it logs the warning once and runs without a guardrail.
291
+
292
+ The `<agent>-serve` target does not set `LOCAL_DEV`, so it needs `RUNTIME_CONFIG_APP_ID` and the deployed entry, otherwise each request fails as described above. The `<agent>-chat` target connects to a running agent and needs no runtime config itself.
293
+
294
+ ## Cost and latency
295
+
296
+ Amazon Bedrock charges for each guardrail policy that evaluates text, on both the input and the answer. See [Amazon Bedrock pricing](https://aws.amazon.com/bedrock/pricing/).
297
+
298
+ Each model call also takes longer, because the guardrail checks the answer before your agent streams it to the user.
299
+
300
+ While requests arrive, each agent process reads runtime config at most once every 5 seconds. Each read makes two AppConfig requests.
301
+
302
+ ## Limitations
303
+
304
+ - This generator supports agents created with `py#agent`, with the Strands and LangChain frameworks. It does not support the AgentCore Harness.
305
+ - `guardrail.json` holds denied topics and PII entities only. Add other policies, such as content filters and word filters, with the construct's props (CDK) or by editing the module (Terraform).
306
+ - The guardrail does not check tool results, as described in [What the guardrail checks](#what-the-guardrail-checks).
@@ -736,22 +736,15 @@ Refer to the <Link path="/guides/connection/react-agui">`connection` generator g
736
736
 
737
737
  <Snippet name="agent/securing-your-agent" parentHeading="Securing your Agent" />
738
738
 
739
+ The <Link path="guides/py-agent-guardrails">`py#agent#guardrails` generator</Link> does this for you. It adds a `guardrail.json` policy file and the CDK construct or Terraform module that creates the guardrail, and it creates your agent with the guardrailed model:
740
+
739
741
  <Tabs syncKey="agent-framework">
740
742
  <TabItem label="Strands" _filter={{ framework: 'strands' }}>
741
743
  ```python
742
744
  # agent.py
743
- import os
744
-
745
- from strands import Agent
746
- from strands.models import BedrockModel
747
-
748
- model = BedrockModel(
749
- model_id=os.environ.get("MODEL_ID"),
750
- guardrail_id=os.environ["GUARDRAIL_ID"],
751
- guardrail_version=os.environ.get("GUARDRAIL_VERSION", "DRAFT"),
752
- )
745
+ from .guardrail import get_guardrailed_model
753
746
 
754
- agent = Agent(model=model)
747
+ agent = Agent(model=get_guardrailed_model(), ...)
755
748
  ```
756
749
 
757
750
  See the Strands [Guardrails](https://strandsagents.com/docs/user-guide/safety-security/guardrails/) guide for more detail.
@@ -759,17 +752,9 @@ See the Strands [Guardrails](https://strandsagents.com/docs/user-guide/safety-se
759
752
  <TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
760
753
  ```python
761
754
  # agent.py
762
- import os
755
+ from .guardrail import GuardrailedChatBedrockConverse
763
756
 
764
- from langchain_aws import ChatBedrockConverse
765
-
766
- model = ChatBedrockConverse(
767
- model=os.environ.get("MODEL_ID"),
768
- guardrail_config={
769
- "guardrailIdentifier": os.environ["GUARDRAIL_ID"],
770
- "guardrailVersion": os.environ.get("GUARDRAIL_VERSION", "DRAFT"),
771
- },
772
- )
757
+ model = GuardrailedChatBedrockConverse(model=MODEL_ID, region_name=REGION)
773
758
  ```
774
759
 
775
760
  See the [`ChatBedrockConverse`](https://docs.langchain.com/oss/python/integrations/chat/bedrock_converse) documentation for the `guardrail_config` fields.
@@ -19,7 +19,7 @@ Four built-in namespaces are used by generated constructs:
19
19
  - **API URLs** — registered automatically by API constructs
20
20
  - **Cognito settings** — registered automatically by the UserIdentity construct
21
21
  - **Agent runtime ARNs** — added by the connection generator when you connect a React website to an Agent
22
- - **`agentcore`** — AgentCore runtime ARNs for agents and MCP servers, and the guardrail ID and version of each agent guarded with `ts#agent#guardrails`. Registered automatically by the agent/MCP and guardrail constructs and used for server-side discovery (agent → agent via A2A, agent → MCP server).
22
+ - **`agentcore`** — AgentCore runtime ARNs for agents and MCP servers, and the guardrail ID and version of each agent guarded with `ts#agent#guardrails` or `py#agent#guardrails`. Registered automatically by the agent/MCP and guardrail constructs and used for server-side discovery (agent → agent via A2A, agent → MCP server).
23
23
  - **`dynamodb`** — table names, registered automatically by DynamoDB table constructs and read by the generated table client.
24
24
  - **`database`** — Aurora connection details, registered automatically by relational database constructs and read by the generated database client.
25
25
 
@@ -138,7 +138,7 @@ Write a topic `definition` that describes the topic itself. For example, "Recomm
138
138
 
139
139
  Each time you change `guardrail.json` and deploy, the infrastructure creates a new numbered guardrail version and writes it to runtime config. The version's description holds the SHA-256 hash of `guardrail.json`, so a change to the file changes the description, and a new version replaces the old one. With the CDK construct, the hash also covers any guardrail properties you pass.
140
140
 
141
- Your running agent does not need a restart. It caches what it reads from runtime config for 5 seconds, so it uses the new version within 5 seconds of the AppConfig deployment. The old version is deleted after the AppConfig deployment: CloudFormation deletes it in its cleanup step, and Terraform deletes it after the deployment module when you add the guardrail module to that module's `depends_on`, as shown in [Wiring the guardrail to your agent](#wiring-the-guardrail-to-your-agent).
141
+ Your running agent does not need a restart. It caches what it reads from runtime config for 5 seconds, so it uses the new version within 5 seconds of the AppConfig deployment. The old version is deleted after the AppConfig deployment. CloudFormation deletes it in its cleanup step, which in one measurement (2026-10-24, us-east-1) began about 7 seconds after the deployment completed. CloudFormation does not guarantee that delay. Terraform keeps the old version for about 15 seconds after the deployment module, so the 5-second cache never points at a deleted version. This works when you add the guardrail module to that module's `depends_on`, as shown in [Wiring the guardrail to your agent](#wiring-the-guardrail-to-your-agent).
142
142
 
143
143
  Your agent never uses the `DRAFT` version. `DRAFT` always holds the latest rules, so an edit made in the AWS console would reach your running agent without a deployment. `guardrail.ts` throws an error if the version in runtime config is not a version number.
144
144
 
@@ -209,7 +209,7 @@ The module writes the guardrail's ID and version to runtime config at `agentcore
209
209
 
210
210
  The module takes a `tags` variable and outputs `guardrail_id`, `guardrail_arn`, `guardrail_version` and `iam_policy_statements`. To add other guardrail policies, such as content filters, edit the `aws_bedrock_guardrail` resource in the module.
211
211
 
212
- The module sets `create_before_destroy` on the guardrail version, so Terraform creates the new version before it deletes the old one.
212
+ The module sets `create_before_destroy` on the guardrail version, so Terraform creates the new version before it deletes the old one. A `time_sleep` resource from the `hashicorp/time` provider keeps the old version for about 15 seconds after the runtime-config deployment, and the runtime-config entry reads the guardrail ID and version from it. Because of this wait, `terraform destroy` also takes about 15 seconds longer.
213
213
  </Fragment>
214
214
  </Infrastructure>
215
215
 
package/generators.json CHANGED
@@ -204,6 +204,14 @@
204
204
  "metric": "g25",
205
205
  "guidePages": ["py-agent"]
206
206
  },
207
+ "py#agent#guardrails": {
208
+ "factory": "./src/py/agent/guardrails/generator",
209
+ "schema": "./src/py/agent/guardrails/schema.json",
210
+ "description": "Add an Amazon Bedrock Guardrail to a Python Agent",
211
+ "metric": "g77",
212
+ "guidePages": ["py-agent-guardrails"],
213
+ "experimental": true
214
+ },
207
215
  "py#agent#mcp-connection": {
208
216
  "factory": "./src/py/agent/mcp-connection/generator",
209
217
  "schema": "./src/py/agent/mcp-connection/schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "py#agent#guardrails",
4
+ "title": "py#agent#guardrails",
5
+ "x-label": "Agent Guardrails",
6
+ "description": "Add an Amazon Bedrock Guardrail to a Python Agent",
7
+ "type": "object",
8
+ "properties": {
9
+ "project": {
10
+ "type": "string",
11
+ "description": "The project containing the Python Agent",
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
16
+ "x-prompt": "Select the project containing the Python Agent to guard",
17
+ "x-dropdown": "projects"
18
+ },
19
+ "agent": {
20
+ "type": "string",
21
+ "description": "The name of the Agent component to guard. Required when the project contains more than one Python Agent."
22
+ }
23
+ },
24
+ "required": ["project"]
25
+ }