@aws/nx-plugin-mcp 1.0.0-rc.7 → 1.0.0-rc.71
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 +12317 -10933
- package/docs/get_started/building-with-ai.mdx +116 -0
- package/docs/get_started/concepts.mdx +67 -0
- package/docs/get_started/existing-project.mdx +180 -0
- package/docs/get_started/graph-builder.mdx +39 -0
- package/docs/get_started/quick-start.mdx +277 -0
- package/docs/get_started/tutorials/contribute-generator.mdx +408 -0
- package/docs/get_started/tutorials/dungeon-game/1.mdx +1301 -0
- package/docs/get_started/tutorials/dungeon-game/2.mdx +237 -0
- package/docs/get_started/tutorials/dungeon-game/3.mdx +76 -0
- package/docs/get_started/tutorials/dungeon-game/4.mdx +164 -0
- package/docs/get_started/tutorials/dungeon-game/overview.mdx +145 -0
- package/docs/get_started/tutorials/dungeon-game/wrap-up.mdx +41 -0
- package/docs/get_started/tutorials/existing-project.mdx +4 -0
- package/docs/get_started/upgrading.mdx +147 -0
- package/docs/guides/agentcore-gateway.mdx +490 -0
- package/docs/guides/agentcore-harness.mdx +275 -0
- package/docs/guides/astro-docs.mdx +8 -0
- package/docs/guides/connection/agentcore-gateway-agent.mdx +222 -0
- package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
- package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
- package/docs/guides/connection/py-agent-a2a.mdx +48 -16
- package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
- package/docs/guides/connection/py-agent-gateway.mdx +178 -0
- package/docs/guides/connection/py-agent-mcp.mdx +43 -14
- package/docs/guides/connection/py-agent-rdb.mdx +178 -0
- package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
- package/docs/guides/connection/py-fast-api-rdb.mdx +184 -0
- package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
- package/docs/guides/connection/py-mcp-server-rdb.mdx +187 -0
- package/docs/guides/connection/react-agentcore-gateway.mdx +112 -0
- package/docs/guides/connection/react-agui.mdx +13 -13
- package/docs/guides/connection/react-fastapi.mdx +38 -2
- package/docs/guides/connection/react-py-agent.mdx +9 -15
- package/docs/guides/connection/react-smithy.mdx +3 -3
- package/docs/guides/connection/react-trpc.mdx +1 -1
- package/docs/guides/connection/react-ts-agent.mdx +8 -8
- package/docs/guides/connection/smithy-dynamodb.mdx +5 -5
- package/docs/guides/connection/smithy-rdb.mdx +9 -9
- package/docs/guides/connection/trpc-dynamodb.mdx +5 -5
- package/docs/guides/connection/trpc-rdb.mdx +6 -6
- package/docs/guides/connection/ts-agent-a2a.mdx +14 -11
- package/docs/guides/connection/ts-agent-dynamodb.mdx +5 -5
- package/docs/guides/connection/ts-agent-gateway.mdx +143 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +12 -9
- package/docs/guides/connection/ts-agent-rdb.mdx +70 -25
- package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +5 -5
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +68 -18
- package/docs/guides/connection.mdx +122 -5
- package/docs/guides/docker-bundling.mdx +69 -12
- package/docs/guides/fastapi.mdx +249 -9
- package/docs/guides/local-development.mdx +87 -0
- package/docs/guides/nx-generator.mdx +4 -3
- package/docs/guides/nx-migration.mdx +165 -0
- package/docs/guides/py-agent.mdx +264 -49
- package/docs/guides/py-dynamodb.mdx +476 -0
- package/docs/guides/py-mcp-server.mdx +61 -2
- package/docs/guides/py-rdb.mdx +265 -0
- package/docs/guides/python-lambda-function.mdx +1 -1
- package/docs/guides/react-website-auth.mdx +65 -4
- package/docs/guides/react-website.mdx +149 -30
- package/docs/guides/runtime-config.mdx +1 -1
- package/docs/guides/security.mdx +75 -0
- package/docs/guides/smithy-project.mdx +167 -0
- package/docs/guides/terraform-project.mdx +2 -2
- package/docs/guides/trpc.mdx +53 -16
- package/docs/guides/ts-agent.mdx +183 -10
- package/docs/guides/ts-dcr-proxy.mdx +569 -0
- package/docs/guides/ts-dynamodb.mdx +66 -242
- package/docs/guides/ts-lambda-function.mdx +1 -1
- package/docs/guides/ts-mcp-server.mdx +109 -29
- package/docs/guides/ts-nx-plugin.mdx +3 -3
- package/docs/guides/ts-rdb.mdx +113 -467
- package/docs/guides/ts-smithy-api.mdx +258 -18
- package/docs/guides/typescript-infrastructure.mdx +46 -24
- package/docs/guides/typescript-project.mdx +134 -27
- package/docs/guides/workspace.mdx +10 -3
- package/docs/snippets/agent/architecture.mdx +1 -1
- package/docs/snippets/agent/bedrock-deployment.mdx +9 -5
- package/docs/snippets/agent/runtime-arn.mdx +23 -2
- package/docs/snippets/agent/securing-your-agent.mdx +39 -0
- package/docs/snippets/api/access-logging.mdx +33 -0
- package/docs/snippets/api/cors-configuration-cdk-note.mdx +1 -1
- package/docs/snippets/api/cors-configuration-terraform-note.mdx +1 -1
- package/docs/snippets/api/type-safe-api-integrations.mdx +33 -2
- package/docs/snippets/api/waf-configuration.mdx +3 -3
- package/docs/snippets/connection/a2a-infrastructure.mdx +1 -1
- package/docs/snippets/connection/dynamodb-local-development.mdx +2 -2
- package/docs/snippets/connection/lambda-dynamodb-access.mdx +1 -1
- package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
- package/docs/snippets/connection/py-lambda-rdb-ssl-requirements.mdx +7 -0
- package/docs/snippets/connection/rdb-api-infrastructure.mdx +51 -19
- package/docs/snippets/dynamodb/deploying-table.mdx +166 -0
- package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
- package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
- package/docs/snippets/dynamodb/local-dev-start.mdx +13 -0
- package/docs/snippets/dynamodb/local-dev-windows.mdx +15 -0
- package/docs/snippets/lambda-function/deploying-your-function.mdx +3 -3
- package/docs/snippets/mcp/architecture.mdx +1 -1
- package/docs/snippets/mcp/bedrock-deployment.mdx +9 -5
- package/docs/snippets/mcp/config.mdx +3 -2
- package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +7 -5
- package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +29 -10
- package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +4 -4
- package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +5 -111
- package/docs/snippets/prerequisites.mdx +1 -4
- package/docs/snippets/rdb/architecture.mdx +38 -0
- package/docs/snippets/rdb/cluster-instances.mdx +31 -0
- package/docs/snippets/rdb/deletion-protection.mdx +34 -0
- package/docs/snippets/rdb/deploying.mdx +187 -0
- package/docs/snippets/rdb/encryption-key-rotation.mdx +30 -0
- package/docs/snippets/rdb/engine-version.mdx +63 -0
- package/docs/snippets/rdb/infrastructure.mdx +35 -0
- package/docs/snippets/rdb/logging-mysql.mdx +5 -0
- package/docs/snippets/rdb/logging-postgres.mdx +5 -0
- package/docs/snippets/rdb/performance-insights.mdx +34 -0
- package/docs/snippets/rdb/rds-proxy.mdx +50 -0
- package/docs/snippets/rdb/removal-policy.mdx +57 -0
- package/docs/snippets/rdb/serverless-capacity.mdx +32 -0
- package/docs/snippets/recommended-prerequisites.mdx +10 -0
- package/docs/snippets/required-prerequisites.mdx +1 -4
- package/docs/snippets/runtime-config-app-id-note.mdx +8 -0
- package/docs/snippets/shared-constructs.mdx +1 -1
- package/docs/snippets/trivy-image-scan.mdx +37 -0
- package/generators.json +152 -10
- package/package.json +1 -1
- package/src/agentcore-gateway/agent-connection/schema.json +31 -0
- package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
- package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
- package/src/agentcore-gateway/react-connection/schema.json +31 -0
- package/src/agentcore-gateway/schema.json +72 -0
- package/src/agentcore-harness/schema.json +53 -0
- package/src/connection/schema.json +5 -0
- package/src/infra/app/schema.json +5 -0
- package/src/init/schema.json +35 -0
- package/src/internal/test-matrix/schema.json +21 -0
- package/src/license/schema.json +5 -0
- package/src/preset/schema.json +16 -5
- package/src/py/agent/a2a-connection/schema.json +5 -0
- package/src/py/agent/gateway-connection/schema.json +31 -0
- package/src/py/agent/mcp-connection/schema.json +5 -0
- package/src/py/agent/react-connection/schema.json +5 -0
- package/src/py/agent/schema.json +15 -1
- package/src/py/api/schema.json +5 -0
- package/src/py/dynamodb/agent-connection/schema.json +27 -0
- package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
- package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
- package/src/py/dynamodb/schema.json +76 -0
- package/src/py/fast-api/react/schema.json +5 -0
- package/src/py/fast-api/schema.json +6 -0
- package/src/py/lambda-function/schema.json +5 -0
- package/src/py/mcp-server/schema.json +6 -0
- package/src/py/project/schema.json +5 -0
- package/src/py/rdb/agent-connection/schema.json +27 -0
- package/src/py/rdb/fast-api-connection/schema.json +23 -0
- package/src/py/rdb/mcp-server-connection/schema.json +27 -0
- package/src/py/rdb/schema.json +78 -0
- package/src/smithy/project/schema.json +28 -1
- package/src/smithy/react-connection/schema.json +5 -0
- package/src/smithy/ts/api/schema.json +6 -0
- package/src/terraform/project/schema.json +5 -0
- package/src/trpc/backend/schema.json +6 -0
- package/src/trpc/react/schema.json +5 -0
- package/src/ts/agent/a2a-connection/schema.json +5 -0
- package/src/ts/agent/gateway-connection/schema.json +31 -0
- package/src/ts/agent/mcp-connection/schema.json +5 -0
- package/src/ts/agent/react-connection/schema.json +5 -0
- package/src/ts/agent/schema.json +14 -0
- package/src/ts/api/schema.json +5 -0
- package/src/ts/astro-docs/schema.json +3 -3
- package/src/ts/dcr-proxy/schema.json +44 -0
- package/src/ts/docs/schema.json +3 -3
- package/src/ts/dynamodb/agent-connection/schema.json +5 -0
- package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
- package/src/ts/dynamodb/schema.json +26 -2
- package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
- package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
- package/src/ts/lambda-function/schema.json +5 -0
- package/src/ts/lib/schema.json +5 -0
- package/src/ts/mcp-server/schema.json +6 -0
- package/src/ts/nx-generator/schema.json +5 -0
- package/src/ts/nx-migration/schema.json +63 -0
- package/src/ts/nx-plugin/schema.json +5 -0
- package/src/ts/rdb/agent-connection/schema.json +5 -0
- package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
- package/src/ts/rdb/schema.json +7 -1
- package/src/ts/rdb/smithy-connection/schema.json +5 -0
- package/src/ts/rdb/trpc-connection/schema.json +5 -0
- package/src/ts/react-website/app/schema.json +12 -6
- package/src/ts/react-website/cognito-auth/schema.json +5 -0
- package/src/ts/react-website/runtime-config/schema.json +5 -0
- package/src/ts/website/app/schema.json +11 -6
- package/src/ts/website/auth/schema.json +5 -0
- /package/docs/snippets/connection/{lambda-rdb-ssl-requirements.mdx → ts-lambda-rdb-ssl-requirements.mdx} +0 -0
- /package/docs/snippets/connection/{mcp-server-rdb-ssl-requirements.mdx → ts-mcp-server-rdb-ssl-requirements.mdx} +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Python DynamoDB
|
|
3
|
+
description: Create a Python DynamoDB project
|
|
4
|
+
generator: py#dynamodb
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import { FileTree, CardGrid } from '@astrojs/starlight/components';
|
|
8
|
+
import Astro from '@astrojs/react';
|
|
9
|
+
import ConnectionCard from '@components/connection-card.astro';
|
|
10
|
+
import Link from '@components/link.astro';
|
|
11
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
12
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
13
|
+
import Snippet from '@components/snippet.astro';
|
|
14
|
+
|
|
15
|
+
This generator creates a new Python project backed by [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), using [PynamoDB](https://pynamodb.readthedocs.io/) for entity modelling. It generates the application code and infrastructure needed to provision and manage a DynamoDB table using AWS CDK or Terraform, with single-table design support and built-in local development via DynamoDB Local.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Generate a DynamoDB Project
|
|
20
|
+
|
|
21
|
+
<RunGenerator generator="py#dynamodb" />
|
|
22
|
+
|
|
23
|
+
### Options
|
|
24
|
+
|
|
25
|
+
<GeneratorParameters generator="py#dynamodb" />
|
|
26
|
+
|
|
27
|
+
## Generator Output
|
|
28
|
+
|
|
29
|
+
The generator creates the following project structure in the `<directory>/<name>` directory:
|
|
30
|
+
|
|
31
|
+
<FileTree>
|
|
32
|
+
- \<name>
|
|
33
|
+
- \_\_init\_\_.py Package exports
|
|
34
|
+
- client.py DynamoDB client and table name resolution
|
|
35
|
+
- entities
|
|
36
|
+
- base.py Base PynamoDB model with GSI declarations
|
|
37
|
+
- example.py Example entity definition
|
|
38
|
+
- \_\_init\_\_.py Entity exports
|
|
39
|
+
- config.json Table configuration including GSI definitions and local development settings
|
|
40
|
+
- project.json Project configuration and build targets
|
|
41
|
+
</FileTree>
|
|
42
|
+
|
|
43
|
+
The local development scripts are shared across all DynamoDB projects (both TypeScript and Python) and generated once into:
|
|
44
|
+
|
|
45
|
+
<FileTree>
|
|
46
|
+
- packages/common/scripts/src/dynamodb
|
|
47
|
+
- create-local-table.ts Creates the DynamoDB table in the local DynamoDB Local instance
|
|
48
|
+
- pull-image.ts Pulls the DynamoDB Local image
|
|
49
|
+
- start-container.ts Starts the DynamoDB Local container
|
|
50
|
+
</FileTree>
|
|
51
|
+
|
|
52
|
+
### Infrastructure
|
|
53
|
+
|
|
54
|
+
<Snippet name="dynamodb/infrastructure" />
|
|
55
|
+
|
|
56
|
+
## Local Development
|
|
57
|
+
|
|
58
|
+
### Starting Local DynamoDB
|
|
59
|
+
|
|
60
|
+
<Snippet name="dynamodb/local-dev-start" />
|
|
61
|
+
|
|
62
|
+
### Data Modelling
|
|
63
|
+
|
|
64
|
+
The generated project uses [PynamoDB](https://pynamodb.readthedocs.io/) for entity modelling. All entities **must** inherit from the generated `BaseModel` — it resolves the correct DynamoDB table name at runtime, reading from AWS AppConfig when deployed or from `config.json` when running locally via DynamoDB Local. Without this, PynamoDB will not know which table to use. `BaseModel` also uses [PynamoDB's polymorphism support](https://pynamodb.readthedocs.io/en/stable/polymorphism.html) to store multiple entity types in a single table, following [DynamoDB's single-table design](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/data-modeling-foundations.html).
|
|
65
|
+
|
|
66
|
+
Add or update entity files under `<name>/entities/`, using the generated example entity as a starting point:
|
|
67
|
+
|
|
68
|
+
```python title="packages/my_table/my_table/entities/example.py"
|
|
69
|
+
from collections.abc import Iterator
|
|
70
|
+
from datetime import UTC, datetime
|
|
71
|
+
from pynamodb.attributes import UnicodeAttribute
|
|
72
|
+
from .base import BaseModel
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ExampleModel(BaseModel, discriminator='ExampleModel'):
|
|
76
|
+
"""
|
|
77
|
+
Key design:
|
|
78
|
+
pk=EXAMPLE#<id>, sk=EXAMPLE#<id>
|
|
79
|
+
gsi1pk=CATEGORY#<cat>, gsi1sk=EXAMPLE#<id> <- list items by category
|
|
80
|
+
gsi2pk=EXAMPLE, gsi2sk=<created_at> <- list all items by date
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
name = UnicodeAttribute()
|
|
84
|
+
category = UnicodeAttribute()
|
|
85
|
+
created_at = UnicodeAttribute()
|
|
86
|
+
updated_at = UnicodeAttribute()
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def make_pk(cls, id: str) -> str:
|
|
90
|
+
return f'EXAMPLE#{id}'
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def create(cls, id: str, name: str, category: str) -> 'ExampleModel':
|
|
94
|
+
now = datetime.now(UTC).isoformat()
|
|
95
|
+
item = cls(
|
|
96
|
+
pk=cls.make_pk(id),
|
|
97
|
+
sk=cls.make_pk(id),
|
|
98
|
+
gsi1pk=f'CATEGORY#{category}',
|
|
99
|
+
gsi1sk=cls.make_pk(id),
|
|
100
|
+
gsi2pk='EXAMPLE',
|
|
101
|
+
gsi2sk=now,
|
|
102
|
+
name=name,
|
|
103
|
+
category=category,
|
|
104
|
+
created_at=now,
|
|
105
|
+
updated_at=now,
|
|
106
|
+
)
|
|
107
|
+
item.save()
|
|
108
|
+
return item
|
|
109
|
+
|
|
110
|
+
# ── Primary index ─────────────────────────────────────────────────────────
|
|
111
|
+
@classmethod
|
|
112
|
+
def get_by_id(cls, id: str) -> 'ExampleModel':
|
|
113
|
+
return cls.get(cls.make_pk(id), cls.make_pk(id))
|
|
114
|
+
|
|
115
|
+
# ── gsi1_index: partition=category, sort=id ───────────────────────────────
|
|
116
|
+
@classmethod
|
|
117
|
+
def list_by_category(cls, category: str) -> Iterator['ExampleModel']:
|
|
118
|
+
return cls.gsi1_index.query(f'CATEGORY#{category}')
|
|
119
|
+
|
|
120
|
+
# ── gsi2_index: partition=type, sort=created_at ───────────────────────────
|
|
121
|
+
@classmethod
|
|
122
|
+
def list_created_between(cls, start: datetime, end: datetime) -> Iterator['ExampleModel']:
|
|
123
|
+
return cls.gsi2_index.query(
|
|
124
|
+
'EXAMPLE',
|
|
125
|
+
range_key_condition=ExampleModel.gsi2sk.between(
|
|
126
|
+
start.isoformat(), end.isoformat(),
|
|
127
|
+
),
|
|
128
|
+
scan_index_forward=False,
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For more details, see the [PynamoDB tutorial](https://pynamodb.readthedocs.io/en/stable/tutorial.html).
|
|
133
|
+
|
|
134
|
+
#### Designing Around Access Patterns
|
|
135
|
+
|
|
136
|
+
In DynamoDB, schema design starts with your queries, not your data shape. Before writing any model, list every access pattern your application needs, then design `pk`, `sk`, and GSI key values so each pattern is answered by a single table request — no JOINs, no sequential reads.
|
|
137
|
+
|
|
138
|
+
The generated `ExampleModel` demonstrates this for three patterns:
|
|
139
|
+
|
|
140
|
+
- **Get by ID** — primary index, `pk=EXAMPLE#<id>`, `sk=EXAMPLE#<id>`
|
|
141
|
+
- **List by category** — `gsi1`, `pk=CATEGORY#<category>`
|
|
142
|
+
- **List by creation date** — `gsi2`, `pk=EXAMPLE`, sort key between ISO timestamps
|
|
143
|
+
|
|
144
|
+
The **type prefix** convention (e.g. `EXAMPLE#`, `CATEGORY#`) is deliberate: it makes items self-describing when browsing the table, prevents accidental key collisions between entity types that share an index, and allows sort key prefix filtering using `begins_with`.
|
|
145
|
+
|
|
146
|
+
Before writing a new entity, define its key patterns upfront in a docstring. The `OrderModel` in the next section follows this convention:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
class OrderModel(BaseModel, discriminator='OrderModel'):
|
|
150
|
+
"""
|
|
151
|
+
Key design:
|
|
152
|
+
pk=ORDER#<order_id>, sk=ORDER#<order_id>
|
|
153
|
+
gsi1pk=USER#<user_id>, gsi1sk=ORDER#<order_id> <- list orders for a user
|
|
154
|
+
gsi2pk=ORDER, gsi2sk=<created_at> <- list all orders by date
|
|
155
|
+
"""
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Storing Multiple Entity Types
|
|
159
|
+
|
|
160
|
+
PynamoDB's `DiscriminatorAttribute` stores a type label (`entity_type`) in every item. When querying via `BaseModel`, this label is used to instantiate each result as its correct subclass automatically — so a single query can return a mix of `UserModel`, `OrderModel`, and any other entity type registered in the same table.
|
|
161
|
+
|
|
162
|
+
:::caution[PynamoDB is not purpose-built for single-table design]
|
|
163
|
+
PynamoDB's `DiscriminatorAttribute` was designed for class hierarchy polymorphism within a single homogeneous table — not for storing structurally different entity types in one table. The pattern used here works, but keep these caveats in mind:
|
|
164
|
+
|
|
165
|
+
- **Key collision is your responsibility.** PynamoDB does not prevent two entity types from writing the same `pk`/`sk` pair. Always use unique type prefixes (e.g. `ORDER#`, `USER#`).
|
|
166
|
+
- **Cross-entity queries require `BaseModel`.** PynamoDB automatically adds a discriminator filter when querying a specific subclass, so items of other entity types at the same key will never be returned. To retrieve a mix of types from a shared GSI partition key, always query via `BaseModel`.
|
|
167
|
+
- **Shared table settings.** All entities share the `Meta` configuration (table name, region, credentials) defined in `BaseModel`.
|
|
168
|
+
:::
|
|
169
|
+
|
|
170
|
+
Below is a complete two-entity example — a `UserModel` with associated `OrderModel` records stored in the same table:
|
|
171
|
+
|
|
172
|
+
```python title="packages/my_table/my_table/entities/user.py"
|
|
173
|
+
from collections.abc import Iterator
|
|
174
|
+
from datetime import UTC, datetime
|
|
175
|
+
from pynamodb.attributes import UnicodeAttribute
|
|
176
|
+
from .base import BaseModel
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class UserModel(BaseModel, discriminator='UserModel'):
|
|
180
|
+
"""
|
|
181
|
+
Key design:
|
|
182
|
+
pk=USER#<user_id>, sk=USER#<user_id>
|
|
183
|
+
gsi2pk=USER, gsi2sk=<created_at> <- list all users by date
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
username = UnicodeAttribute()
|
|
187
|
+
email = UnicodeAttribute()
|
|
188
|
+
created_at = UnicodeAttribute()
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def make_pk(cls, user_id: str) -> str:
|
|
192
|
+
return f'USER#{user_id}'
|
|
193
|
+
|
|
194
|
+
@classmethod
|
|
195
|
+
def create(cls, user_id: str, username: str, email: str) -> 'UserModel':
|
|
196
|
+
now = datetime.now(UTC).isoformat()
|
|
197
|
+
item = cls(
|
|
198
|
+
pk=cls.make_pk(user_id),
|
|
199
|
+
sk=cls.make_pk(user_id),
|
|
200
|
+
gsi2pk='USER',
|
|
201
|
+
gsi2sk=now,
|
|
202
|
+
username=username,
|
|
203
|
+
email=email,
|
|
204
|
+
created_at=now,
|
|
205
|
+
)
|
|
206
|
+
item.save()
|
|
207
|
+
return item
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def get_by_id(cls, user_id: str) -> 'UserModel':
|
|
211
|
+
return cls.get(cls.make_pk(user_id), cls.make_pk(user_id))
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def list_recent(cls, limit: int | None = None) -> Iterator['UserModel']:
|
|
215
|
+
return cls.gsi2_index.query('USER', limit=limit, scan_index_forward=False)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```python title="packages/my_table/my_table/entities/order.py"
|
|
219
|
+
from collections.abc import Iterator
|
|
220
|
+
from datetime import UTC, datetime
|
|
221
|
+
from pynamodb.attributes import UnicodeAttribute
|
|
222
|
+
from .base import BaseModel
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class OrderModel(BaseModel, discriminator='OrderModel'):
|
|
226
|
+
"""
|
|
227
|
+
Key design:
|
|
228
|
+
pk=ORDER#<order_id>, sk=ORDER#<order_id>
|
|
229
|
+
gsi1pk=USER#<user_id>, gsi1sk=ORDER#<order_id> <- list orders by user
|
|
230
|
+
gsi2pk=ORDER, gsi2sk=<created_at> <- list all orders by date
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
user_id = UnicodeAttribute()
|
|
234
|
+
total = UnicodeAttribute()
|
|
235
|
+
created_at = UnicodeAttribute()
|
|
236
|
+
|
|
237
|
+
@classmethod
|
|
238
|
+
def make_pk(cls, order_id: str) -> str:
|
|
239
|
+
return f'ORDER#{order_id}'
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def create(cls, order_id: str, user_id: str, total: str) -> 'OrderModel':
|
|
243
|
+
now = datetime.now(UTC).isoformat()
|
|
244
|
+
item = cls(
|
|
245
|
+
pk=cls.make_pk(order_id),
|
|
246
|
+
sk=cls.make_pk(order_id),
|
|
247
|
+
gsi1pk=f'USER#{user_id}',
|
|
248
|
+
gsi1sk=cls.make_pk(order_id),
|
|
249
|
+
gsi2pk='ORDER',
|
|
250
|
+
gsi2sk=now,
|
|
251
|
+
user_id=user_id,
|
|
252
|
+
total=total,
|
|
253
|
+
created_at=now,
|
|
254
|
+
)
|
|
255
|
+
item.save()
|
|
256
|
+
return item
|
|
257
|
+
|
|
258
|
+
@classmethod
|
|
259
|
+
def get_by_id(cls, order_id: str) -> 'OrderModel':
|
|
260
|
+
return cls.get(cls.make_pk(order_id), cls.make_pk(order_id))
|
|
261
|
+
|
|
262
|
+
# ── gsi1_index: partition=user, sort=order_id ────────────────────────────
|
|
263
|
+
@classmethod
|
|
264
|
+
def list_by_user(cls, user_id: str) -> Iterator['OrderModel']:
|
|
265
|
+
return cls.gsi1_index.query(f'USER#{user_id}')
|
|
266
|
+
|
|
267
|
+
# ── gsi2_index: partition=type, sort=created_at ───────────────────────────
|
|
268
|
+
@classmethod
|
|
269
|
+
def list_recent(cls, limit: int | None = None) -> Iterator['OrderModel']:
|
|
270
|
+
return cls.gsi2_index.query('ORDER', limit=limit, scan_index_forward=False)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Export the new entities from `__init__.py`:
|
|
274
|
+
|
|
275
|
+
```python title="packages/my_table/my_table/entities/__init__.py"
|
|
276
|
+
from .user import UserModel
|
|
277
|
+
from .order import OrderModel
|
|
278
|
+
from .example import ExampleModel
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### GSI Overloading
|
|
282
|
+
|
|
283
|
+
`BaseModel` provides two shared GSIs (`gsi1_index`, `gsi2_index`). Both `UserModel` and `OrderModel` above write to `gsi2` — but with different `gsi2pk` values (`USER` vs `ORDER`). This is **GSI overloading**: reusing a single physical index to serve multiple independent access patterns without consuming extra GSI capacity.
|
|
284
|
+
|
|
285
|
+
- **`UserModel`** — `gsi2pk=USER`, `gsi2sk=<created_at>` → list all users by date
|
|
286
|
+
- **`OrderModel`** — `gsi2pk=ORDER`, `gsi2sk=<created_at>` → list all orders by date
|
|
287
|
+
|
|
288
|
+
`gsi1` can also be overloaded when multiple entity types share the same parent. If you later add a `ReviewModel` that also belongs to a user, you can assign it `gsi1pk=USER#<user_id>` with a `REVIEW#<id>` sort key — no additional GSI needed. Querying `gsi1` via `BaseModel` then returns both orders and reviews for that user in one request, with PynamoDB instantiating each item as its correct subclass:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
from .base import BaseModel
|
|
292
|
+
from .order import OrderModel
|
|
293
|
+
from .review import ReviewModel
|
|
294
|
+
|
|
295
|
+
user_id = 'user-123'
|
|
296
|
+
items = list(BaseModel.gsi1_index.query(f'USER#{user_id}'))
|
|
297
|
+
|
|
298
|
+
orders = [i for i in items if isinstance(i, OrderModel)]
|
|
299
|
+
reviews = [i for i in items if isinstance(i, ReviewModel)]
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
To retrieve only one entity type from an overloaded GSI, use a sort key prefix condition:
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
orders_only = list(BaseModel.gsi1_index.query(
|
|
306
|
+
f'USER#{user_id}',
|
|
307
|
+
range_key_condition=BaseModel.gsi1sk.startswith('ORDER#'),
|
|
308
|
+
))
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### One-to-Many Relationships
|
|
312
|
+
|
|
313
|
+
In a **one-to-many** relationship the child entity stores a reference to its parent in a GSI partition key, making the relationship traversable in both directions without duplicating data. The `UserModel` / `OrderModel` example above is exactly this pattern:
|
|
314
|
+
|
|
315
|
+
- **Get a single order by ID** — primary table: `pk=ORDER#<id>`, `sk=ORDER#<id>`
|
|
316
|
+
- **List all orders for a user** — `gsi1`: `pk=USER#<user_id>`
|
|
317
|
+
|
|
318
|
+
An alternative to GSI-based lookups is the **item collection** pattern: give child items the same `pk` as their parent and use the sort key to differentiate them. This lets you retrieve the parent and all its children in a single primary-table query, without a GSI:
|
|
319
|
+
|
|
320
|
+
```python title="packages/my_table/my_table/entities/order.py (item collection variant)"
|
|
321
|
+
class OrderModel(BaseModel, discriminator='OrderModel'):
|
|
322
|
+
"""
|
|
323
|
+
Key design (item collection):
|
|
324
|
+
pk=USER#<user_id>, sk=ORDER#<order_id> <- co-located under the parent user
|
|
325
|
+
"""
|
|
326
|
+
...
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
# Retrieve the user and all their orders in one primary-table query
|
|
331
|
+
# BaseModel dispatches each item to its correct subclass via DiscriminatorAttribute
|
|
332
|
+
items = list(BaseModel.query(f'USER#{user_id}'))
|
|
333
|
+
user = next(i for i in items if isinstance(i, UserModel))
|
|
334
|
+
orders = [i for i in items if isinstance(i, OrderModel)]
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The tradeoff: item collections place all children under a single partition key, which is optimal for most workloads but can create a hot partition at extreme write throughput. The GSI approach (used in the examples above) keeps each entity in its own partition and is generally safer to start with.
|
|
338
|
+
|
|
339
|
+
#### Many-to-Many Relationships
|
|
340
|
+
|
|
341
|
+
Many-to-many relationships require a **junction entity** using the [adjacency list pattern](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html): a dedicated item that records each link, with its GSI key inverting the direction so the relationship can be traversed both ways.
|
|
342
|
+
|
|
343
|
+
Consider `ArticleModel` and `TagModel`, where an article can have many tags and a tag can apply to many articles:
|
|
344
|
+
|
|
345
|
+
```python title="packages/my_table/my_table/entities/article_tag.py"
|
|
346
|
+
from collections.abc import Iterator
|
|
347
|
+
from pynamodb.attributes import UnicodeAttribute
|
|
348
|
+
from .base import BaseModel
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class ArticleTagModel(BaseModel, discriminator='ArticleTag'):
|
|
352
|
+
"""
|
|
353
|
+
Junction entity for the Article ↔ Tag many-to-many relationship.
|
|
354
|
+
|
|
355
|
+
Key design:
|
|
356
|
+
pk=ARTICLE#<article_id>, sk=TAG#<tag_name> <- list tags for an article
|
|
357
|
+
gsi1pk=TAG#<tag_name>, gsi1sk=ARTICLE#<article_id> <- list articles for a tag
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
article_id = UnicodeAttribute()
|
|
361
|
+
tag_name = UnicodeAttribute()
|
|
362
|
+
|
|
363
|
+
@classmethod
|
|
364
|
+
def add(cls, article_id: str, tag_name: str) -> 'ArticleTagModel':
|
|
365
|
+
item = cls(
|
|
366
|
+
pk=f'ARTICLE#{article_id}',
|
|
367
|
+
sk=f'TAG#{tag_name}',
|
|
368
|
+
gsi1pk=f'TAG#{tag_name}',
|
|
369
|
+
gsi1sk=f'ARTICLE#{article_id}',
|
|
370
|
+
article_id=article_id,
|
|
371
|
+
tag_name=tag_name,
|
|
372
|
+
)
|
|
373
|
+
item.save()
|
|
374
|
+
return item
|
|
375
|
+
|
|
376
|
+
@classmethod
|
|
377
|
+
def remove(cls, article_id: str, tag_name: str) -> None:
|
|
378
|
+
cls.get(f'ARTICLE#{article_id}', f'TAG#{tag_name}').delete()
|
|
379
|
+
|
|
380
|
+
# ── Primary index: pk=article, sk=tag ─────────────────────────────────────
|
|
381
|
+
@classmethod
|
|
382
|
+
def list_tags_for_article(cls, article_id: str) -> Iterator['ArticleTagModel']:
|
|
383
|
+
return cls.query(f'ARTICLE#{article_id}')
|
|
384
|
+
|
|
385
|
+
# ── gsi1_index: pk=tag, sk=article ────────────────────────────────────────
|
|
386
|
+
@classmethod
|
|
387
|
+
def list_articles_for_tag(cls, tag_name: str) -> Iterator['ArticleTagModel']:
|
|
388
|
+
return cls.gsi1_index.query(f'TAG#{tag_name}')
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Because `ArticleTagModel` uses `pk=ARTICLE#<article_id>` — the same partition as the article itself — you can retrieve an article and all its tags in a single primary-table query:
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
from .base import BaseModel
|
|
395
|
+
from .article import ArticleModel
|
|
396
|
+
from .article_tag import ArticleTagModel
|
|
397
|
+
|
|
398
|
+
items = list(BaseModel.query('ARTICLE#article-123'))
|
|
399
|
+
article = next(i for i in items if isinstance(i, ArticleModel))
|
|
400
|
+
tags = [i.tag_name for i in items if isinstance(i, ArticleTagModel)]
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
For further reading on DynamoDB data modelling, see the [DynamoDB data modelling guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/data-modeling.html) and [Creating a single-table design with Amazon DynamoDB](https://aws.amazon.com/blogs/compute/creating-a-single-table-design-with-amazon-dynamodb/).
|
|
404
|
+
|
|
405
|
+
### Using the DynamoDB Client
|
|
406
|
+
|
|
407
|
+
The generated `client.py` exports two key utilities:
|
|
408
|
+
|
|
409
|
+
- `is_local()` — returns `True` when `LOCAL_DEV=true`, used to switch between local and AWS behaviour.
|
|
410
|
+
- `get_table_name()` — returns the DynamoDB table name. When `LOCAL_DEV=true`, reads the table name from `localDev.tableName` in `config.json`; otherwise fetches the name from AWS AppConfig using the `RUNTIME_CONFIG_APP_ID` environment variable and caches it for subsequent calls.
|
|
411
|
+
|
|
412
|
+
`BaseModel` in `entities/base.py` uses both to configure PynamoDB automatically:
|
|
413
|
+
|
|
414
|
+
- **Connection** — `BaseModel.Meta` sets `host` from `config.json` and hardcodes `region`, `aws_access_key_id`, and `aws_secret_access_key` when `is_local()` is `True`, pointing PynamoDB at the local DynamoDB instance. In AWS, these are left unset so PynamoDB uses the default credential chain.
|
|
415
|
+
- **Table name** — `BaseModel._get_connection()` calls `get_table_name()` before each operation, so the correct table is resolved at runtime without any manual configuration.
|
|
416
|
+
|
|
417
|
+
### Stopping Local DynamoDB
|
|
418
|
+
|
|
419
|
+
<Snippet name="dynamodb/local-dev-windows" />
|
|
420
|
+
|
|
421
|
+
## Adding/Removing Global Secondary Indexes
|
|
422
|
+
|
|
423
|
+
GSIs are defined in `config.json` at the project root under the `tableConfig.globalSecondaryIndexes` key. Add an entry for each GSI, then reflect the change in `BaseModel` by adding or removing the corresponding `GlobalSecondaryIndex` class and attributes in `<name>/entities/base.py`:
|
|
424
|
+
|
|
425
|
+
<Snippet name="dynamodb/gsi-config" parentHeading="Adding/Removing Global Secondary Indexes" />
|
|
426
|
+
|
|
427
|
+
## Connecting to the Table
|
|
428
|
+
|
|
429
|
+
In any Python project, add the DynamoDB package as a workspace dependency and import entity classes directly:
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
from my_db_package.entities import ExampleModel
|
|
433
|
+
|
|
434
|
+
item = ExampleModel.get_by_id('123')
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Behind the scenes, `ExampleModel` calls `get_table_name()` to fetch the table name from AWS AppConfig at runtime.
|
|
438
|
+
|
|
439
|
+
<Snippet name="runtime-config-app-id-note" parentHeading="Connecting to the Table" />
|
|
440
|
+
|
|
441
|
+
## Deploying your Table
|
|
442
|
+
|
|
443
|
+
<Snippet name="dynamodb/deploying-table" parentHeading="Deploying your Table" />
|
|
444
|
+
|
|
445
|
+
## Connections
|
|
446
|
+
|
|
447
|
+
Use the <Link path="guides/connection">`connection`</Link> generator to integrate this project with others in your workspace. The following connections involve this project:
|
|
448
|
+
|
|
449
|
+
<CardGrid>
|
|
450
|
+
<ConnectionCard
|
|
451
|
+
title="FastAPI to Python DynamoDB"
|
|
452
|
+
description="Connect a FastAPI to a DynamoDB table"
|
|
453
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-fast-api-dynamodb`}
|
|
454
|
+
source="fastapi"
|
|
455
|
+
target="dynamodb"
|
|
456
|
+
targetBadge="python"
|
|
457
|
+
/>
|
|
458
|
+
<ConnectionCard
|
|
459
|
+
title="Python Agent to Python DynamoDB"
|
|
460
|
+
description="Connect a Python Agent to a DynamoDB table"
|
|
461
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-agent-dynamodb`}
|
|
462
|
+
source="strands"
|
|
463
|
+
sourceBadge="python"
|
|
464
|
+
target="dynamodb"
|
|
465
|
+
targetBadge="python"
|
|
466
|
+
/>
|
|
467
|
+
<ConnectionCard
|
|
468
|
+
title="Python MCP Server to Python DynamoDB"
|
|
469
|
+
description="Connect a Python MCP Server to a DynamoDB table"
|
|
470
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-mcp-server-dynamodb`}
|
|
471
|
+
source="mcp"
|
|
472
|
+
sourceBadge="python"
|
|
473
|
+
target="dynamodb"
|
|
474
|
+
targetBadge="python"
|
|
475
|
+
/>
|
|
476
|
+
</CardGrid>
|
|
@@ -4,7 +4,9 @@ description: Generate a Python Model Context Protocol (MCP) server for providing
|
|
|
4
4
|
generator: py#mcp-server
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
import { FileTree } from '@astrojs/starlight/components';
|
|
7
|
+
import { FileTree, CardGrid } from '@astrojs/starlight/components';
|
|
8
|
+
import Astro from '@astrojs/react';
|
|
9
|
+
import ConnectionCard from '@components/connection-card.astro';
|
|
8
10
|
import RunGenerator from '@components/run-generator.astro';
|
|
9
11
|
import NxCommands from '@components/nx-commands.astro';
|
|
10
12
|
import Link from '@components/link.astro';
|
|
@@ -115,14 +117,28 @@ def dynamic_resource(item_id: str) -> str:
|
|
|
115
117
|
|
|
116
118
|
## Running Your MCP Server
|
|
117
119
|
|
|
120
|
+
### Local Development
|
|
121
|
+
|
|
122
|
+
To run your MCP server (and everything connected to it, such as a local database) locally, use the project's `dev` target:
|
|
123
|
+
|
|
124
|
+
<NxCommands commands={['dev your-project']} />
|
|
125
|
+
|
|
126
|
+
If you have added multiple components to your project (MCP servers, agents, etc.), this starts them all. To run just this MCP server, target its `<your-server-name>-dev` target:
|
|
127
|
+
|
|
128
|
+
<NxCommands commands={['your-server-name-dev your-project']} />
|
|
129
|
+
|
|
118
130
|
### Inspector
|
|
119
131
|
|
|
120
|
-
The generator configures a target named `<your-server-name>-inspect`, which starts the [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
|
|
132
|
+
The generator configures a target named `<your-server-name>-inspect`, which starts your MCP server locally (via the `<your-server-name>-dev` target, including any connected dependencies such as a local database) and launches the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) pre-configured to connect to it over Streamable HTTP transport.
|
|
121
133
|
|
|
122
134
|
<NxCommands commands={['your-server-name-inspect your-project']} />
|
|
123
135
|
|
|
124
136
|
This will start the inspector at `http://localhost:6274`. Get started by clicking on the "Connect" button.
|
|
125
137
|
|
|
138
|
+
:::tip
|
|
139
|
+
To inspect the server using STDIO transport instead, use the `<your-server-name>-inspect-stdio` target, which launches the inspector against a STDIO instance of your server.
|
|
140
|
+
:::
|
|
141
|
+
|
|
126
142
|
### STDIO
|
|
127
143
|
|
|
128
144
|
The easiest way to test and use an MCP server is by using the inspector or configuring it with an AI assistant (as above).
|
|
@@ -155,7 +171,50 @@ In order to build your MCP server for Bedrock AgentCore Runtime, a `bundle` targ
|
|
|
155
171
|
|
|
156
172
|
A `docker` target specific to your MCP server is also added, which copies the `Dockerfile` and bundled artifacts into a docker context directory. This co-locates the `Dockerfile` with the built output, allowing CDK to build the Docker image directly using `AgentRuntimeArtifact.fromAsset`.
|
|
157
173
|
|
|
174
|
+
### Image Scanning
|
|
175
|
+
|
|
176
|
+
<Snippet name="trivy-image-scan" parentHeading="Image Scanning" />
|
|
177
|
+
|
|
158
178
|
### Observability
|
|
159
179
|
|
|
160
180
|
<Snippet name="mcp/observability" parentHeading="Observability" />
|
|
161
181
|
</OptionFilter>
|
|
182
|
+
|
|
183
|
+
## Connections
|
|
184
|
+
|
|
185
|
+
Use the <Link path="guides/connection">`connection`</Link> generator to integrate this project with others in your workspace. The following connections involve this project:
|
|
186
|
+
|
|
187
|
+
<CardGrid>
|
|
188
|
+
<ConnectionCard
|
|
189
|
+
title="TypeScript Agent to MCP"
|
|
190
|
+
description="Connect a TypeScript Agent to an MCP server"
|
|
191
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/ts-agent-mcp`}
|
|
192
|
+
source="strands"
|
|
193
|
+
sourceBadge="typescript"
|
|
194
|
+
target="mcp"
|
|
195
|
+
/>
|
|
196
|
+
<ConnectionCard
|
|
197
|
+
title="Python Agent to MCP"
|
|
198
|
+
description="Connect a Python Agent to an MCP server"
|
|
199
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-agent-mcp`}
|
|
200
|
+
source="strands"
|
|
201
|
+
sourceBadge="python"
|
|
202
|
+
target="mcp"
|
|
203
|
+
/>
|
|
204
|
+
<ConnectionCard
|
|
205
|
+
title="Python MCP Server to Python DynamoDB"
|
|
206
|
+
description="Connect a Python MCP Server to a DynamoDB table"
|
|
207
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-mcp-server-dynamodb`}
|
|
208
|
+
source="mcp"
|
|
209
|
+
sourceBadge="python"
|
|
210
|
+
target="dynamodb"
|
|
211
|
+
targetBadge="python"
|
|
212
|
+
/>
|
|
213
|
+
<ConnectionCard
|
|
214
|
+
title="AgentCore Gateway to MCP Server"
|
|
215
|
+
description="Aggregate an MCP server behind an AgentCore Gateway"
|
|
216
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/agentcore-gateway-mcp`}
|
|
217
|
+
source="agentcore"
|
|
218
|
+
target="mcp"
|
|
219
|
+
/>
|
|
220
|
+
</CardGrid>
|