@aws/nx-plugin-mcp 1.0.0-rc.33 → 1.0.0-rc.34
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 +27 -0
- package/docs/guides/connection/py-agent-rdb.mdx +162 -0
- package/docs/guides/connection/py-fast-api-rdb.mdx +170 -0
- package/docs/guides/connection/py-mcp-server-rdb.mdx +171 -0
- package/docs/guides/connection/smithy-rdb.mdx +1 -1
- package/docs/guides/connection/trpc-rdb.mdx +1 -1
- package/docs/guides/connection/ts-agent-rdb.mdx +45 -16
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +45 -11
- package/docs/guides/connection.mdx +28 -1
- package/docs/guides/py-rdb.mdx +250 -0
- package/docs/guides/ts-rdb.mdx +48 -483
- package/docs/snippets/connection/py-lambda-rdb-ssl-requirements.mdx +7 -0
- package/docs/snippets/connection/rdb-api-infrastructure.mdx +36 -15
- 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 +107 -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.mdx +32 -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/generators.json +27 -0
- package/package.json +1 -1
- 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 +77 -0
- package/src/ts/rdb/schema.json +1 -1
- /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
package/bin/aws-nx-mcp.js
CHANGED
|
@@ -20204,6 +20204,33 @@ var generators$1 = {
|
|
|
20204
20204
|
"description": "Connect a py#mcp-server to a py#dynamodb project",
|
|
20205
20205
|
"metric": "g55",
|
|
20206
20206
|
"hidden": true
|
|
20207
|
+
},
|
|
20208
|
+
"py#rdb": {
|
|
20209
|
+
"factory": "./src/py/rdb/generator",
|
|
20210
|
+
"schema": "./src/py/rdb/schema.json",
|
|
20211
|
+
"description": "Create a Python relational database project",
|
|
20212
|
+
"metric": "g56"
|
|
20213
|
+
},
|
|
20214
|
+
"py#rdb#fast-api-connection": {
|
|
20215
|
+
"factory": "./src/py/rdb/fast-api-connection/generator",
|
|
20216
|
+
"schema": "./src/py/rdb/fast-api-connection/schema.json",
|
|
20217
|
+
"description": "Connect a py#fast-api project to a py#rdb project",
|
|
20218
|
+
"metric": "g57",
|
|
20219
|
+
"hidden": true
|
|
20220
|
+
},
|
|
20221
|
+
"py#rdb#agent-connection": {
|
|
20222
|
+
"factory": "./src/py/rdb/agent-connection/generator",
|
|
20223
|
+
"schema": "./src/py/rdb/agent-connection/schema.json",
|
|
20224
|
+
"description": "Connect a py#agent to a py#rdb project",
|
|
20225
|
+
"metric": "g58",
|
|
20226
|
+
"hidden": true
|
|
20227
|
+
},
|
|
20228
|
+
"py#rdb#mcp-server-connection": {
|
|
20229
|
+
"factory": "./src/py/rdb/mcp-server-connection/generator",
|
|
20230
|
+
"schema": "./src/py/rdb/mcp-server-connection/schema.json",
|
|
20231
|
+
"description": "Connect a py#mcp-server to a py#rdb project",
|
|
20232
|
+
"metric": "g59",
|
|
20233
|
+
"hidden": true
|
|
20207
20234
|
}
|
|
20208
20235
|
};
|
|
20209
20236
|
//#endregion
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Python Agent to Relational Database
|
|
3
|
+
description: Connect a Python Agent to a Relational Database
|
|
4
|
+
when:
|
|
5
|
+
sourceType: py#agent
|
|
6
|
+
targetType: py#rdb
|
|
7
|
+
---
|
|
8
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
9
|
+
import Link from '@components/link.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
12
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
13
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
14
|
+
|
|
15
|
+
The `connection` generator wires a <Link path="guides/py-agent">Python Agent</Link> to a <Link path="guides/py-rdb">Python Relational Database</Link> project, making the database session available inside your agent tools.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
Before using this generator, ensure you have:
|
|
20
|
+
|
|
21
|
+
1. A <Link path="guides/py-agent">`py#agent`</Link> project
|
|
22
|
+
2. A <Link path="guides/py-rdb">`py#rdb`</Link> project
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Run the Generator
|
|
27
|
+
|
|
28
|
+
<RunGenerator generator="connection" />
|
|
29
|
+
|
|
30
|
+
Select your Agent project as the source and your relational database project as the target. If the project contains multiple agent components, specify `sourceComponent` to disambiguate.
|
|
31
|
+
|
|
32
|
+
### Options
|
|
33
|
+
|
|
34
|
+
<GeneratorParameters generator="connection" />
|
|
35
|
+
|
|
36
|
+
## Generator Output
|
|
37
|
+
|
|
38
|
+
<FileTree>
|
|
39
|
+
|
|
40
|
+
- packages/my\_service
|
|
41
|
+
- project.json Adds a dependency from `my_agent-dev` on the database's `dev` target
|
|
42
|
+
- pyproject.toml Adds the database package as a workspace dependency
|
|
43
|
+
- my\_service
|
|
44
|
+
- my\_agent
|
|
45
|
+
- Dockerfile Adds the RDS CA bundle used for direct Aurora connections
|
|
46
|
+
|
|
47
|
+
</FileTree>
|
|
48
|
+
|
|
49
|
+
## Using the Database in Agent Tools
|
|
50
|
+
|
|
51
|
+
Import `session_context` from your database package and use it inside your agent tools:
|
|
52
|
+
|
|
53
|
+
```python title="packages/my_service/my_service/my_agent/agent.py"
|
|
54
|
+
from sqlmodel import select
|
|
55
|
+
from my_scope.my_db import session_context
|
|
56
|
+
from my_scope.my_db.models.example import ExampleModel
|
|
57
|
+
from strands import tool
|
|
58
|
+
|
|
59
|
+
@tool
|
|
60
|
+
async def list_examples() -> list:
|
|
61
|
+
"""List all example records."""
|
|
62
|
+
async with session_context() as session:
|
|
63
|
+
return [item.model_dump() for item in (await session.execute(select(ExampleModel))).all()]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Infrastructure
|
|
67
|
+
|
|
68
|
+
The generated agent construct implements `IGrantable` and `IConnectable`, so you can grant network and IAM access to the database directly on the construct.
|
|
69
|
+
|
|
70
|
+
<Infrastructure>
|
|
71
|
+
<Fragment slot="cdk">
|
|
72
|
+
|
|
73
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
74
|
+
import { RuntimeNetworkConfiguration } from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
75
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
76
|
+
|
|
77
|
+
const db = new MyDatabase(this, 'Db', { vpc, ... });
|
|
78
|
+
|
|
79
|
+
const myAgent = new MyAgent(this, 'MyAgent', {
|
|
80
|
+
networkConfiguration: RuntimeNetworkConfiguration.usingVpc(this, {
|
|
81
|
+
vpc,
|
|
82
|
+
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
db.allowDefaultPortFrom(myAgent);
|
|
87
|
+
db.grantConnect(myAgent);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`allowDefaultPortFrom` opens the security group rule so the agent runtime can reach the database port. `grantConnect` grants IAM `rds-db:connect` permission to the agent's execution role.
|
|
91
|
+
|
|
92
|
+
</Fragment>
|
|
93
|
+
<Fragment slot="terraform">
|
|
94
|
+
|
|
95
|
+
Run the agent inside the same VPC as the database, grant it `rds-db:connect` via `additional_iam_policy_statements`, and open the network path with a pair of security group rules:
|
|
96
|
+
|
|
97
|
+
```hcl title="packages/infra/src/main.tf"
|
|
98
|
+
module "my_database" {
|
|
99
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
100
|
+
vpc_id = module.vpc.vpc_id
|
|
101
|
+
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
102
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module "my_agent" {
|
|
106
|
+
source = "../../common/terraform/src/app/agents/my-agent"
|
|
107
|
+
enable_vpc = true
|
|
108
|
+
vpc_id = module.vpc.vpc_id
|
|
109
|
+
subnet_ids = module.vpc.private_subnet_ids
|
|
110
|
+
|
|
111
|
+
appconfig_application_id = module.runtime_config_appconfig.application_id
|
|
112
|
+
appconfig_application_arn = module.runtime_config_appconfig.application_arn
|
|
113
|
+
|
|
114
|
+
additional_iam_policy_statements = [
|
|
115
|
+
{
|
|
116
|
+
Effect = "Allow"
|
|
117
|
+
Action = ["rds-db:connect"]
|
|
118
|
+
Resource = [
|
|
119
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}"
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
resource "aws_vpc_security_group_ingress_rule" "agent_to_database" {
|
|
126
|
+
security_group_id = module.my_database.security_group_id
|
|
127
|
+
referenced_security_group_id = module.my_agent.security_group_id
|
|
128
|
+
from_port = module.my_database.cluster_port
|
|
129
|
+
to_port = module.my_database.cluster_port
|
|
130
|
+
ip_protocol = "tcp"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
resource "aws_vpc_security_group_egress_rule" "agent_to_database" {
|
|
134
|
+
security_group_id = module.my_agent.security_group_id
|
|
135
|
+
referenced_security_group_id = module.my_database.security_group_id
|
|
136
|
+
from_port = module.my_database.cluster_port
|
|
137
|
+
to_port = module.my_database.cluster_port
|
|
138
|
+
ip_protocol = "tcp"
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`appconfig_application_id`/`appconfig_application_arn` come from the shared <Link path="guides/runtime-config">runtime configuration</Link> AppConfig application declared once in your root module, not from the database module.
|
|
143
|
+
|
|
144
|
+
</Fragment>
|
|
145
|
+
</Infrastructure>
|
|
146
|
+
|
|
147
|
+
### SSL Requirements When Connecting Without RDS Proxy
|
|
148
|
+
|
|
149
|
+
When the agent connects directly to the Aurora cluster (without RDS Proxy), the connection generator updates the generated agent Dockerfile to install the Amazon RDS CA bundle into the system trust store:
|
|
150
|
+
|
|
151
|
+
```dockerfile
|
|
152
|
+
ADD https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem /usr/local/share/ca-certificates/rds-global-bundle.crt
|
|
153
|
+
RUN update-ca-certificates
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
When using RDS Proxy, you do not need to configure the RDS CA bundle in the agent runtime.
|
|
157
|
+
|
|
158
|
+
## Local Development
|
|
159
|
+
|
|
160
|
+
<NxCommands commands={["<agent-name>-dev <project-name>"]} />
|
|
161
|
+
|
|
162
|
+
This starts the agent and all connected databases. The `LOCAL_DEV=true` environment variable causes the database client to connect to its local Docker database instead of Aurora.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: FastAPI to Relational Database
|
|
3
|
+
description: Connect a FastAPI to a Python Relational Database
|
|
4
|
+
when:
|
|
5
|
+
sourceType: py#fast-api
|
|
6
|
+
targetType: py#rdb
|
|
7
|
+
---
|
|
8
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
9
|
+
import Link from '@components/link.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
12
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
13
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
14
|
+
|
|
15
|
+
The `connection` generator wires a <Link path="guides/fastapi">FastAPI</Link> to a <Link path="guides/py-rdb">Python Relational Database</Link> project, injecting a typed SQLModel session into your route handlers via a FastAPI dependency.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
Before using this generator, ensure you have:
|
|
20
|
+
|
|
21
|
+
1. A <Link path="guides/fastapi">`py#fast-api`</Link> project
|
|
22
|
+
2. A <Link path="guides/py-rdb">`py#rdb`</Link> project
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Run the Generator
|
|
27
|
+
|
|
28
|
+
<RunGenerator generator="connection" />
|
|
29
|
+
|
|
30
|
+
Select your FastAPI project as the source and your relational database project as the target.
|
|
31
|
+
|
|
32
|
+
### Options
|
|
33
|
+
|
|
34
|
+
<GeneratorParameters generator="connection" />
|
|
35
|
+
|
|
36
|
+
## Generator Output
|
|
37
|
+
|
|
38
|
+
The generator modifies your FastAPI project:
|
|
39
|
+
|
|
40
|
+
<FileTree>
|
|
41
|
+
|
|
42
|
+
- packages/my_api
|
|
43
|
+
- project.json Adds a dependency from `dev` on the database's `dev` target
|
|
44
|
+
- pyproject.toml Adds the database package as a workspace dependency
|
|
45
|
+
- my_api
|
|
46
|
+
- dependencies
|
|
47
|
+
- my_db.py FastAPI `MyDbSession` dependency for the database session
|
|
48
|
+
|
|
49
|
+
</FileTree>
|
|
50
|
+
|
|
51
|
+
## Using the Database in Route Handlers
|
|
52
|
+
|
|
53
|
+
This generator configures an injectable [FastAPI Dependency](https://fastapi.tiangolo.com/tutorial/dependencies/) which you can use in your route handlers:
|
|
54
|
+
|
|
55
|
+
```python title="packages/my_api/my_api/api.py" {2,6,10}
|
|
56
|
+
from sqlmodel import select
|
|
57
|
+
from my_api.dependencies.my_db import MyDbSession
|
|
58
|
+
from my_scope.my_db.models.example import ExampleModel
|
|
59
|
+
|
|
60
|
+
@app.get("/examples")
|
|
61
|
+
async def list_examples(my_db: MyDbSession):
|
|
62
|
+
return (await my_db.execute(select(ExampleModel))).all()
|
|
63
|
+
|
|
64
|
+
@app.post("/examples")
|
|
65
|
+
async def create_example(name: str, my_db: MyDbSession):
|
|
66
|
+
item = ExampleModel(name=name)
|
|
67
|
+
my_db.add(item)
|
|
68
|
+
await my_db.commit()
|
|
69
|
+
await my_db.refresh(item)
|
|
70
|
+
return item
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
FastAPI automatically opens a new session per request and closes it when the handler returns.
|
|
74
|
+
|
|
75
|
+
## Infrastructure
|
|
76
|
+
|
|
77
|
+
To allow the FastAPI Lambda function to connect to the database at runtime, it must be deployed into the same VPC as the database and granted network and IAM access.
|
|
78
|
+
|
|
79
|
+
<Infrastructure>
|
|
80
|
+
<Fragment slot="cdk">
|
|
81
|
+
|
|
82
|
+
In your application stack, deploy the API into the same VPC as the database, then call `allowDefaultPortFrom` and `grantConnect` to open the network path and grant IAM `rds-db:connect` permission to the Lambda handler:
|
|
83
|
+
|
|
84
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
85
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
86
|
+
|
|
87
|
+
const db = new MyDatabase(this, 'Db', { vpc, ... });
|
|
88
|
+
|
|
89
|
+
const api = new MyApi(this, 'Api', {
|
|
90
|
+
integrations: MyApi.defaultIntegrations(this)
|
|
91
|
+
.withDefaultOptions({
|
|
92
|
+
vpc,
|
|
93
|
+
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
|
|
94
|
+
})
|
|
95
|
+
.build(),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
Object.entries(api.integrations).forEach(([operation, integration]) => {
|
|
99
|
+
db.allowDefaultPortFrom(integration.handler, `Allow ${operation} to connect to the database`);
|
|
100
|
+
db.grantConnect(integration.handler);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Deploy the API Lambda functions into a **private subnet with egress**, not a private isolated subnet. At runtime, `session_context()` retrieves database configuration from AWS AppConfig, which is a public AWS service endpoint that requires outbound internet access.
|
|
105
|
+
|
|
106
|
+
:::note
|
|
107
|
+
This example grants every handler in your API access, but if only some handlers need access it's better to configure individually.
|
|
108
|
+
:::
|
|
109
|
+
|
|
110
|
+
</Fragment>
|
|
111
|
+
<Fragment slot="terraform">
|
|
112
|
+
|
|
113
|
+
Deploy the API into the same VPC as the database, grant it `rds-db:connect` via `additional_iam_policy_statements`, and open the network path with a pair of security group rules:
|
|
114
|
+
|
|
115
|
+
```hcl title="packages/infra/src/main.tf"
|
|
116
|
+
module "my_database" {
|
|
117
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
118
|
+
vpc_id = module.vpc.vpc_id
|
|
119
|
+
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
120
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module "api" {
|
|
124
|
+
source = "..."
|
|
125
|
+
enable_vpc = true
|
|
126
|
+
vpc_id = module.vpc.vpc_id
|
|
127
|
+
subnet_ids = module.vpc.private_subnet_ids
|
|
128
|
+
|
|
129
|
+
additional_iam_policy_statements = [
|
|
130
|
+
{
|
|
131
|
+
Effect = "Allow"
|
|
132
|
+
Action = ["rds-db:connect"]
|
|
133
|
+
Resource = [
|
|
134
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
env = {
|
|
140
|
+
RUNTIME_CONFIG_APP_ID = module.runtime_config_appconfig.application_id
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
resource "aws_vpc_security_group_ingress_rule" "api_to_database" {
|
|
145
|
+
security_group_id = module.my_database.security_group_id
|
|
146
|
+
referenced_security_group_id = module.api.security_group_id
|
|
147
|
+
from_port = module.my_database.cluster_port
|
|
148
|
+
to_port = module.my_database.cluster_port
|
|
149
|
+
ip_protocol = "tcp"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
resource "aws_vpc_security_group_egress_rule" "api_to_database" {
|
|
153
|
+
security_group_id = module.api.security_group_id
|
|
154
|
+
referenced_security_group_id = module.my_database.security_group_id
|
|
155
|
+
from_port = module.my_database.cluster_port
|
|
156
|
+
to_port = module.my_database.cluster_port
|
|
157
|
+
ip_protocol = "tcp"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Deploy the API Lambda functions into **private subnets with egress**, not private isolated subnets. `RUNTIME_CONFIG_APP_ID` should point at the shared <Link path="guides/runtime-config">runtime configuration</Link> AppConfig application, not an output of the database module.
|
|
162
|
+
|
|
163
|
+
</Fragment>
|
|
164
|
+
</Infrastructure>
|
|
165
|
+
|
|
166
|
+
## Local Development
|
|
167
|
+
|
|
168
|
+
<NxCommands commands={["dev <project-name>"]} />
|
|
169
|
+
|
|
170
|
+
This starts the FastAPI and all connected databases. The `LOCAL_DEV=true` environment variable causes the database client to connect to its local Docker database instead of Aurora.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Python MCP Server to Relational Database
|
|
3
|
+
description: Connect a Python MCP Server to a Relational Database
|
|
4
|
+
when:
|
|
5
|
+
sourceType: py#mcp-server
|
|
6
|
+
targetType: py#rdb
|
|
7
|
+
---
|
|
8
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
9
|
+
import Link from '@components/link.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
12
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
13
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
14
|
+
|
|
15
|
+
The `connection` generator wires a <Link path="guides/py-mcp-server">Python MCP Server</Link> to a <Link path="guides/py-rdb">Python Relational Database</Link> project, making the database session available to all tools registered in the server.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
Before using this generator, ensure you have:
|
|
20
|
+
|
|
21
|
+
1. A <Link path="guides/py-mcp-server">`py#mcp-server`</Link> project
|
|
22
|
+
2. A <Link path="guides/py-rdb">`py#rdb`</Link> project
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Run the Generator
|
|
27
|
+
|
|
28
|
+
<RunGenerator generator="connection" />
|
|
29
|
+
|
|
30
|
+
Select your MCP server project as the source and your relational database project as the target. If the project contains multiple MCP server components, specify `sourceComponent` to disambiguate.
|
|
31
|
+
|
|
32
|
+
### Options
|
|
33
|
+
|
|
34
|
+
<GeneratorParameters generator="connection" />
|
|
35
|
+
|
|
36
|
+
## Generator Output
|
|
37
|
+
|
|
38
|
+
<FileTree>
|
|
39
|
+
|
|
40
|
+
- packages/my\_service
|
|
41
|
+
- project.json Adds a dependency from `my_mcp_server-dev` on the database's `dev` target
|
|
42
|
+
- pyproject.toml Adds the database package as a workspace dependency
|
|
43
|
+
- my\_service
|
|
44
|
+
- my\_mcp\_server
|
|
45
|
+
- Dockerfile Adds the RDS CA bundle used for direct Aurora connections
|
|
46
|
+
|
|
47
|
+
</FileTree>
|
|
48
|
+
|
|
49
|
+
## Using the Database in MCP Tools
|
|
50
|
+
|
|
51
|
+
Import `session_context` from your database package and use it inside your MCP server tools:
|
|
52
|
+
|
|
53
|
+
```python title="packages/my_service/my_service/my_mcp_server/server.py"
|
|
54
|
+
from sqlmodel import select
|
|
55
|
+
from my_scope.my_db import session_context
|
|
56
|
+
from my_scope.my_db.models.example import ExampleModel
|
|
57
|
+
|
|
58
|
+
@mcp.tool()
|
|
59
|
+
async def list_examples() -> str:
|
|
60
|
+
"""List all example records."""
|
|
61
|
+
async with session_context() as session:
|
|
62
|
+
items = (await session.execute(select(ExampleModel))).all()
|
|
63
|
+
return str([item.model_dump() for item in items])
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Multiple Databases
|
|
67
|
+
|
|
68
|
+
Running the generator again with a different target adds the second database alongside the first. Both session contexts are available to all tools:
|
|
69
|
+
|
|
70
|
+
```python title="packages/my_service/my_service/my_mcp_server/server.py"
|
|
71
|
+
from my_scope.my_db import session_context as my_db_session_context
|
|
72
|
+
from my_scope.other_db import session_context as other_db_session_context
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Infrastructure
|
|
76
|
+
|
|
77
|
+
The generated MCP server construct implements `IGrantable` and `IConnectable`, so you can grant network and IAM access to the database directly on the construct.
|
|
78
|
+
|
|
79
|
+
<Infrastructure>
|
|
80
|
+
<Fragment slot="cdk">
|
|
81
|
+
|
|
82
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
83
|
+
import { RuntimeNetworkConfiguration } from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
84
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
85
|
+
|
|
86
|
+
const db = new MyDatabase(this, 'Db', { vpc, ... });
|
|
87
|
+
|
|
88
|
+
const myMcpServer = new MyMcpServer(this, 'MyMcpServer', {
|
|
89
|
+
networkConfiguration: RuntimeNetworkConfiguration.usingVpc(this, {
|
|
90
|
+
vpc,
|
|
91
|
+
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
db.allowDefaultPortFrom(myMcpServer);
|
|
96
|
+
db.grantConnect(myMcpServer);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`allowDefaultPortFrom` opens the security group rule so the MCP server runtime can reach the database port. `grantConnect` grants IAM `rds-db:connect` permission to the server's execution role.
|
|
100
|
+
|
|
101
|
+
</Fragment>
|
|
102
|
+
<Fragment slot="terraform">
|
|
103
|
+
|
|
104
|
+
Run the MCP server inside the same VPC as the database, grant it `rds-db:connect` via `additional_iam_policy_statements`, and open the network path with a pair of security group rules:
|
|
105
|
+
|
|
106
|
+
```hcl title="packages/infra/src/main.tf"
|
|
107
|
+
module "my_database" {
|
|
108
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
109
|
+
vpc_id = module.vpc.vpc_id
|
|
110
|
+
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
111
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module "my_mcp_server" {
|
|
115
|
+
source = "../../common/terraform/src/app/mcp-servers/my-mcp-server"
|
|
116
|
+
enable_vpc = true
|
|
117
|
+
vpc_id = module.vpc.vpc_id
|
|
118
|
+
subnet_ids = module.vpc.private_subnet_ids
|
|
119
|
+
|
|
120
|
+
appconfig_application_id = module.runtime_config_appconfig.application_id
|
|
121
|
+
appconfig_application_arn = module.runtime_config_appconfig.application_arn
|
|
122
|
+
|
|
123
|
+
additional_iam_policy_statements = [
|
|
124
|
+
{
|
|
125
|
+
Effect = "Allow"
|
|
126
|
+
Action = ["rds-db:connect"]
|
|
127
|
+
Resource = [
|
|
128
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}"
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
resource "aws_vpc_security_group_ingress_rule" "mcp_server_to_database" {
|
|
135
|
+
security_group_id = module.my_database.security_group_id
|
|
136
|
+
referenced_security_group_id = module.my_mcp_server.security_group_id
|
|
137
|
+
from_port = module.my_database.cluster_port
|
|
138
|
+
to_port = module.my_database.cluster_port
|
|
139
|
+
ip_protocol = "tcp"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
resource "aws_vpc_security_group_egress_rule" "mcp_server_to_database" {
|
|
143
|
+
security_group_id = module.my_mcp_server.security_group_id
|
|
144
|
+
referenced_security_group_id = module.my_database.security_group_id
|
|
145
|
+
from_port = module.my_database.cluster_port
|
|
146
|
+
to_port = module.my_database.cluster_port
|
|
147
|
+
ip_protocol = "tcp"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`appconfig_application_id`/`appconfig_application_arn` come from the shared <Link path="guides/runtime-config">runtime configuration</Link> AppConfig application declared once in your root module, not from the database module.
|
|
152
|
+
|
|
153
|
+
</Fragment>
|
|
154
|
+
</Infrastructure>
|
|
155
|
+
|
|
156
|
+
### SSL Requirements When Connecting Without RDS Proxy
|
|
157
|
+
|
|
158
|
+
When the MCP server connects directly to the Aurora cluster (without RDS Proxy), the connection generator updates the generated MCP server Dockerfile to install the Amazon RDS CA bundle into the system trust store:
|
|
159
|
+
|
|
160
|
+
```dockerfile
|
|
161
|
+
ADD https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem /usr/local/share/ca-certificates/rds-global-bundle.crt
|
|
162
|
+
RUN update-ca-certificates
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
When using RDS Proxy, you do not need to configure the RDS CA bundle in the MCP server runtime.
|
|
166
|
+
|
|
167
|
+
## Local Development
|
|
168
|
+
|
|
169
|
+
<NxCommands commands={["<mcp-server-name>-dev <project-name>"]} />
|
|
170
|
+
|
|
171
|
+
This starts the MCP server and all connected databases. The `LOCAL_DEV=true` environment variable causes the database client to connect to its local Docker database instead of Aurora.
|
|
@@ -134,7 +134,7 @@ const httpResponse = await serviceHandler.handle(httpRequest, {
|
|
|
134
134
|
|
|
135
135
|
### SSL Requirements When Connecting Without RDS Proxy
|
|
136
136
|
|
|
137
|
-
<Snippet name="connection/lambda-rdb-ssl-requirements" parentHeading="SSL Requirements When Connecting Without RDS Proxy" />
|
|
137
|
+
<Snippet name="connection/ts-lambda-rdb-ssl-requirements" parentHeading="SSL Requirements When Connecting Without RDS Proxy" />
|
|
138
138
|
|
|
139
139
|
## Local Development
|
|
140
140
|
|
|
@@ -116,7 +116,7 @@ export const dbProcedure = t.procedure
|
|
|
116
116
|
|
|
117
117
|
### SSL Requirements When Connecting Without RDS Proxy
|
|
118
118
|
|
|
119
|
-
<Snippet name="connection/lambda-rdb-ssl-requirements" parentHeading="SSL Requirements When Connecting Without RDS Proxy" />
|
|
119
|
+
<Snippet name="connection/ts-lambda-rdb-ssl-requirements" parentHeading="SSL Requirements When Connecting Without RDS Proxy" />
|
|
120
120
|
|
|
121
121
|
## Local Development
|
|
122
122
|
|
|
@@ -48,13 +48,9 @@ The generator modifies two files in your agent's source directory:
|
|
|
48
48
|
|
|
49
49
|
Additionally, the agent's `<agent-name>-dev` target is updated to depend on the database's `dev` target.
|
|
50
50
|
|
|
51
|
-
##
|
|
51
|
+
## Using the Database in Agent Tools
|
|
52
52
|
|
|
53
|
-
The Prisma client is instantiated inside `getAgent()`. Since the `ts#agent` generator configures a single Agent per session, the client is also reused for the lifetime of the session
|
|
54
|
-
|
|
55
|
-
### Agent Definition
|
|
56
|
-
|
|
57
|
-
`getAgent` is updated to import and call the Prisma getter at the top of its body:
|
|
53
|
+
The Prisma client is instantiated inside `getAgent()`. Since the `ts#agent` generator configures a single Agent per session, the client is also reused for the lifetime of the session:
|
|
58
54
|
|
|
59
55
|
```ts title="packages/my-service/src/my-agent/agent.ts" {1,4}
|
|
60
56
|
import { getPrisma as getMyDb } from ':my-scope/my-db';
|
|
@@ -66,7 +62,6 @@ export const getAgent = async () => {
|
|
|
66
62
|
};
|
|
67
63
|
```
|
|
68
64
|
|
|
69
|
-
|
|
70
65
|
## Multiple Databases
|
|
71
66
|
|
|
72
67
|
Running the generator again with a different target adds the second database alongside the first:
|
|
@@ -91,10 +86,17 @@ The generated agent construct implements `IGrantable` and `IConnectable`, so you
|
|
|
91
86
|
<Fragment slot="cdk">
|
|
92
87
|
|
|
93
88
|
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
89
|
+
import { RuntimeNetworkConfiguration } from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
94
90
|
import { MyDatabase } from ':my-scope/common-constructs';
|
|
95
91
|
|
|
96
92
|
const db = new MyDatabase(this, 'Db', { vpc, ... });
|
|
97
|
-
|
|
93
|
+
|
|
94
|
+
const myAgent = new MyAgent(this, 'MyAgent', {
|
|
95
|
+
networkConfiguration: RuntimeNetworkConfiguration.usingVpc(this, {
|
|
96
|
+
vpc,
|
|
97
|
+
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
98
100
|
|
|
99
101
|
db.allowDefaultPortFrom(myAgent);
|
|
100
102
|
db.grantConnect(myAgent);
|
|
@@ -105,27 +107,54 @@ db.grantConnect(myAgent);
|
|
|
105
107
|
</Fragment>
|
|
106
108
|
<Fragment slot="terraform">
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
Run the agent inside the same VPC as the database, grant it `rds-db:connect` via `additional_iam_policy_statements`, and open the network path with a pair of security group rules:
|
|
109
111
|
|
|
110
112
|
```hcl title="packages/infra/src/main.tf"
|
|
111
113
|
module "my_database" {
|
|
112
114
|
source = "../../common/terraform/src/app/dbs/my-database"
|
|
113
115
|
vpc_id = module.vpc.vpc_id
|
|
114
116
|
database_subnet_ids = module.vpc.private_isolated_subnet_ids
|
|
117
|
+
lambda_subnet_ids = module.vpc.private_subnet_ids
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
module "my_agent" {
|
|
118
|
-
source
|
|
121
|
+
source = "../../common/terraform/src/app/agents/my-agent"
|
|
122
|
+
enable_vpc = true
|
|
123
|
+
vpc_id = module.vpc.vpc_id
|
|
124
|
+
subnet_ids = module.vpc.private_subnet_ids
|
|
125
|
+
|
|
126
|
+
appconfig_application_id = module.runtime_config_appconfig.application_id
|
|
127
|
+
appconfig_application_arn = module.runtime_config_appconfig.application_arn
|
|
128
|
+
|
|
129
|
+
additional_iam_policy_statements = [
|
|
130
|
+
{
|
|
131
|
+
Effect = "Allow"
|
|
132
|
+
Action = ["rds-db:connect"]
|
|
133
|
+
Resource = [
|
|
134
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
resource "aws_vpc_security_group_ingress_rule" "agent_to_database" {
|
|
141
|
+
security_group_id = module.my_database.security_group_id
|
|
142
|
+
referenced_security_group_id = module.my_agent.security_group_id
|
|
143
|
+
from_port = module.my_database.cluster_port
|
|
144
|
+
to_port = module.my_database.cluster_port
|
|
145
|
+
ip_protocol = "tcp"
|
|
146
|
+
}
|
|
119
147
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
148
|
+
resource "aws_vpc_security_group_egress_rule" "agent_to_database" {
|
|
149
|
+
security_group_id = module.my_agent.security_group_id
|
|
150
|
+
referenced_security_group_id = module.my_database.security_group_id
|
|
151
|
+
from_port = module.my_database.cluster_port
|
|
152
|
+
to_port = module.my_database.cluster_port
|
|
153
|
+
ip_protocol = "tcp"
|
|
125
154
|
}
|
|
126
155
|
```
|
|
127
156
|
|
|
128
|
-
|
|
157
|
+
`appconfig_application_id`/`appconfig_application_arn` come from the shared <Link path="guides/runtime-config">runtime configuration</Link> AppConfig application declared once in your root module, not from the database module.
|
|
129
158
|
|
|
130
159
|
</Fragment>
|
|
131
160
|
</Infrastructure>
|