@aws/agentcore 0.3.0-preview.2.1 → 0.3.0-preview.3.0
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/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +415 -58
- package/dist/assets/cdk/README.md +19 -7
- package/dist/assets/cdk/bin/cdk.ts +37 -2
- package/dist/assets/cdk/lib/cdk-stack.ts +25 -2
- package/dist/assets/cdk/package.json +1 -1
- package/dist/assets/cdk/test/cdk.test.ts +18 -14
- package/dist/assets/cdk/tsconfig.json +4 -4
- package/dist/assets/container/python/Dockerfile +7 -1
- package/dist/assets/python/googleadk/base/main.py +10 -1
- package/dist/assets/python/googleadk/base/mcp_client/client.py +54 -3
- package/dist/assets/python/googleadk/base/pyproject.toml +2 -0
- package/dist/assets/python/langchain_langgraph/base/main.py +11 -1
- package/dist/assets/python/langchain_langgraph/base/mcp_client/client.py +52 -3
- package/dist/assets/python/langchain_langgraph/base/pyproject.toml +2 -1
- package/dist/assets/python/openaiagents/base/main.py +43 -3
- package/dist/assets/python/openaiagents/base/mcp_client/client.py +54 -3
- package/dist/assets/python/openaiagents/base/pyproject.toml +2 -0
- package/dist/assets/python/strands/base/README.md +1 -1
- package/dist/assets/python/strands/base/main.py +16 -3
- package/dist/assets/python/strands/base/mcp_client/client.py +56 -4
- package/dist/assets/python/strands/base/pyproject.toml +2 -0
- package/dist/cli/index.mjs +290 -286
- package/dist/lib/packaging/build-args.d.ts +6 -0
- package/dist/lib/packaging/build-args.d.ts.map +1 -0
- package/dist/lib/packaging/build-args.js +18 -0
- package/dist/lib/packaging/build-args.js.map +1 -0
- package/dist/lib/packaging/container.d.ts.map +1 -1
- package/dist/lib/packaging/container.js +2 -1
- package/dist/lib/packaging/container.js.map +1 -1
- package/dist/lib/schemas/io/cli-config.d.ts +10 -0
- package/dist/lib/schemas/io/cli-config.d.ts.map +1 -0
- package/dist/lib/schemas/io/cli-config.js +27 -0
- package/dist/lib/schemas/io/cli-config.js.map +1 -0
- package/dist/lib/schemas/io/index.d.ts +1 -0
- package/dist/lib/schemas/io/index.d.ts.map +1 -1
- package/dist/lib/schemas/io/index.js +3 -1
- package/dist/lib/schemas/io/index.js.map +1 -1
- package/dist/lib/utils/subprocess.d.ts.map +1 -1
- package/dist/lib/utils/subprocess.js +32 -10
- package/dist/lib/utils/subprocess.js.map +1 -1
- package/dist/schema/constants.d.ts.map +1 -1
- package/dist/schema/constants.js +0 -1
- package/dist/schema/constants.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +48 -5
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +19 -4
- package/dist/schema/schemas/agentcore-project.js.map +1 -1
- package/dist/schema/schemas/aws-targets.js +1 -1
- package/dist/schema/schemas/aws-targets.js.map +1 -1
- package/dist/schema/schemas/deployed-state.d.ts +32 -0
- package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
- package/dist/schema/schemas/deployed-state.js +11 -1
- package/dist/schema/schemas/deployed-state.js.map +1 -1
- package/dist/schema/schemas/mcp-defs.d.ts +1 -1
- package/dist/schema/schemas/mcp-defs.js +1 -1
- package/dist/schema/schemas/mcp.d.ts +146 -6
- package/dist/schema/schemas/mcp.d.ts.map +1 -1
- package/dist/schema/schemas/mcp.js +49 -4
- package/dist/schema/schemas/mcp.js.map +1 -1
- package/package.json +12 -6
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AgentCore CDK Project
|
|
2
2
|
|
|
3
|
-
This is
|
|
3
|
+
This CDK project is managed by the AgentCore CLI. It deploys your agent infrastructure into AWS using the `@aws/agentcore-cdk` L3 constructs.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `bin/cdk.ts` — Entry point. Reads project configuration from `agentcore/` and creates a stack per deployment target.
|
|
8
|
+
- `lib/cdk-stack.ts` — Defines `AgentCoreStack`, which wraps the `AgentCoreApplication` L3 construct.
|
|
9
|
+
- `test/cdk.test.ts` — Unit tests for stack synthesis.
|
|
6
10
|
|
|
7
11
|
## Useful commands
|
|
8
12
|
|
|
9
|
-
- `npm run build` compile
|
|
10
|
-
- `npm run
|
|
11
|
-
- `
|
|
13
|
+
- `npm run build` compile TypeScript to JavaScript
|
|
14
|
+
- `npm run test` run unit tests
|
|
15
|
+
- `npx cdk synth` emit the synthesized CloudFormation template
|
|
12
16
|
- `npx cdk deploy` deploy this stack to your default AWS account/region
|
|
13
17
|
- `npx cdk diff` compare deployed stack with current state
|
|
14
|
-
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
You typically don't need to interact with this directory directly. The AgentCore CLI handles synthesis and deployment:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
agentcore deploy # synthesizes and deploys via CDK
|
|
25
|
+
agentcore status # checks deployment status
|
|
26
|
+
```
|
|
@@ -3,6 +3,7 @@ import { AgentCoreStack } from '../lib/cdk-stack';
|
|
|
3
3
|
import { ConfigIO, type AwsDeploymentTarget } from '@aws/agentcore-cdk';
|
|
4
4
|
import { App, type Environment } from 'aws-cdk-lib';
|
|
5
5
|
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
6
7
|
|
|
7
8
|
function toEnvironment(target: AwsDeploymentTarget): Environment {
|
|
8
9
|
return {
|
|
@@ -11,8 +12,12 @@ function toEnvironment(target: AwsDeploymentTarget): Environment {
|
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
function sanitize(name: string): string {
|
|
16
|
+
return name.replace(/_/g, '-');
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
function toStackName(projectName: string, targetName: string): string {
|
|
15
|
-
return `AgentCore-${projectName}-${targetName}`;
|
|
20
|
+
return `AgentCore-${sanitize(projectName)}-${sanitize(targetName)}`;
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
async function main() {
|
|
@@ -23,6 +28,22 @@ async function main() {
|
|
|
23
28
|
const spec = await configIO.readProjectSpec();
|
|
24
29
|
const targets = await configIO.readAWSDeploymentTargets();
|
|
25
30
|
|
|
31
|
+
// Read MCP configuration if it exists
|
|
32
|
+
let mcpSpec;
|
|
33
|
+
try {
|
|
34
|
+
mcpSpec = await configIO.readMcpSpec();
|
|
35
|
+
} catch {
|
|
36
|
+
// MCP config is optional
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Read deployed state for credential ARNs (populated by pre-deploy identity setup)
|
|
40
|
+
let deployedState: Record<string, unknown> | undefined;
|
|
41
|
+
try {
|
|
42
|
+
deployedState = JSON.parse(fs.readFileSync(path.join(configRoot, '.cli', 'deployed-state.json'), 'utf8'));
|
|
43
|
+
} catch {
|
|
44
|
+
// Deployed state may not exist on first deploy
|
|
45
|
+
}
|
|
46
|
+
|
|
26
47
|
if (targets.length === 0) {
|
|
27
48
|
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
|
|
28
49
|
}
|
|
@@ -33,8 +54,19 @@ async function main() {
|
|
|
33
54
|
const env = toEnvironment(target);
|
|
34
55
|
const stackName = toStackName(spec.name, target.name);
|
|
35
56
|
|
|
57
|
+
// Extract credentials from deployed state for this target
|
|
58
|
+
const targetState = (deployedState as Record<string, unknown>)?.targets as
|
|
59
|
+
| Record<string, Record<string, unknown>>
|
|
60
|
+
| undefined;
|
|
61
|
+
const targetResources = targetState?.[target.name]?.resources as Record<string, unknown> | undefined;
|
|
62
|
+
const credentials = targetResources?.credentials as
|
|
63
|
+
| Record<string, { credentialProviderArn: string; clientSecretArn?: string }>
|
|
64
|
+
| undefined;
|
|
65
|
+
|
|
36
66
|
new AgentCoreStack(app, stackName, {
|
|
37
67
|
spec,
|
|
68
|
+
mcpSpec,
|
|
69
|
+
credentials,
|
|
38
70
|
env,
|
|
39
71
|
description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`,
|
|
40
72
|
tags: {
|
|
@@ -47,4 +79,7 @@ async function main() {
|
|
|
47
79
|
app.synth();
|
|
48
80
|
}
|
|
49
81
|
|
|
50
|
-
main()
|
|
82
|
+
main().catch((error: unknown) => {
|
|
83
|
+
console.error('AgentCore CDK synthesis failed:', error instanceof Error ? error.message : error);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
});
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AgentCoreApplication,
|
|
3
|
+
AgentCoreMcp,
|
|
4
|
+
type AgentCoreProjectSpec,
|
|
5
|
+
type AgentCoreMcpSpec,
|
|
6
|
+
} from '@aws/agentcore-cdk';
|
|
2
7
|
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
|
|
3
8
|
import { Construct } from 'constructs';
|
|
4
9
|
|
|
@@ -7,6 +12,14 @@ export interface AgentCoreStackProps extends StackProps {
|
|
|
7
12
|
* The AgentCore project specification containing agents, memories, and credentials.
|
|
8
13
|
*/
|
|
9
14
|
spec: AgentCoreProjectSpec;
|
|
15
|
+
/**
|
|
16
|
+
* The MCP specification containing gateways and servers.
|
|
17
|
+
*/
|
|
18
|
+
mcpSpec?: AgentCoreMcpSpec;
|
|
19
|
+
/**
|
|
20
|
+
* Credential provider ARNs from deployed state, keyed by credential name.
|
|
21
|
+
*/
|
|
22
|
+
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
|
|
10
23
|
}
|
|
11
24
|
|
|
12
25
|
/**
|
|
@@ -22,13 +35,23 @@ export class AgentCoreStack extends Stack {
|
|
|
22
35
|
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
|
|
23
36
|
super(scope, id, props);
|
|
24
37
|
|
|
25
|
-
const { spec } = props;
|
|
38
|
+
const { spec, mcpSpec, credentials } = props;
|
|
26
39
|
|
|
27
40
|
// Create AgentCoreApplication with all agents
|
|
28
41
|
this.application = new AgentCoreApplication(this, 'Application', {
|
|
29
42
|
spec,
|
|
30
43
|
});
|
|
31
44
|
|
|
45
|
+
// Create AgentCoreMcp if there are gateways configured
|
|
46
|
+
if (mcpSpec?.agentCoreGateways && mcpSpec.agentCoreGateways.length > 0) {
|
|
47
|
+
new AgentCoreMcp(this, 'Mcp', {
|
|
48
|
+
projectName: spec.name,
|
|
49
|
+
mcpSpec,
|
|
50
|
+
agentCoreApplication: this.application,
|
|
51
|
+
credentials,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
// Stack-level output
|
|
33
56
|
new CfnOutput(this, 'StackNameOutput', {
|
|
34
57
|
description: 'Name of the CloudFormation Stack',
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import { Template } from 'aws-cdk-lib/assertions';
|
|
3
|
+
import { AgentCoreStack } from '../lib/cdk-stack';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
test('AgentCoreStack synthesizes with empty spec', () => {
|
|
6
|
+
const app = new cdk.App();
|
|
7
|
+
const stack = new AgentCoreStack(app, 'TestStack', {
|
|
8
|
+
spec: {
|
|
9
|
+
name: 'testproject',
|
|
10
|
+
version: 1,
|
|
11
|
+
agents: [],
|
|
12
|
+
memories: [],
|
|
13
|
+
credentials: [],
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const template = Template.fromStack(stack);
|
|
17
|
+
template.hasOutput('StackNameOutput', {
|
|
18
|
+
Description: 'Name of the CloudFormation Stack',
|
|
19
|
+
});
|
|
16
20
|
});
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"strictNullChecks": true,
|
|
11
11
|
"noImplicitThis": true,
|
|
12
12
|
"alwaysStrict": true,
|
|
13
|
-
"noUnusedLocals":
|
|
14
|
-
"noUnusedParameters":
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
15
|
"noImplicitReturns": true,
|
|
16
|
-
"noFallthroughCasesInSwitch":
|
|
16
|
+
"noFallthroughCasesInSwitch": true,
|
|
17
17
|
"inlineSourceMap": true,
|
|
18
18
|
"inlineSources": true,
|
|
19
19
|
"experimentalDecorators": true,
|
|
20
|
-
"strictPropertyInitialization":
|
|
20
|
+
"strictPropertyInitialization": true,
|
|
21
21
|
"skipLibCheck": true,
|
|
22
22
|
"typeRoots": ["./node_modules/@types"],
|
|
23
23
|
"rootDir": ".",
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
|
2
2
|
|
|
3
|
+
ARG UV_DEFAULT_INDEX
|
|
4
|
+
ARG UV_INDEX
|
|
5
|
+
|
|
3
6
|
WORKDIR /app
|
|
4
7
|
|
|
5
8
|
ENV UV_SYSTEM_PYTHON=1 \
|
|
6
9
|
UV_COMPILE_BYTECODE=1 \
|
|
7
10
|
UV_NO_PROGRESS=1 \
|
|
8
11
|
PYTHONUNBUFFERED=1 \
|
|
9
|
-
DOCKER_CONTAINER=1
|
|
12
|
+
DOCKER_CONTAINER=1 \
|
|
13
|
+
UV_DEFAULT_INDEX=${UV_DEFAULT_INDEX} \
|
|
14
|
+
UV_INDEX=${UV_INDEX} \
|
|
15
|
+
PATH="/app/.venv/bin:$PATH"
|
|
10
16
|
|
|
11
17
|
RUN useradd -m -u 1000 bedrock_agentcore
|
|
12
18
|
|
|
@@ -5,7 +5,11 @@ from google.adk.sessions import InMemorySessionService
|
|
|
5
5
|
from google.genai import types
|
|
6
6
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
7
7
|
from model.load import load_model
|
|
8
|
+
{{#if hasGateway}}
|
|
9
|
+
from mcp_client.client import get_all_gateway_mcp_toolsets
|
|
10
|
+
{{else}}
|
|
8
11
|
from mcp_client.client import get_streamable_http_mcp_client
|
|
12
|
+
{{/if}}
|
|
9
13
|
|
|
10
14
|
app = BedrockAgentCoreApp()
|
|
11
15
|
log = app.logger
|
|
@@ -23,7 +27,12 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
# Get MCP Toolset
|
|
26
|
-
|
|
30
|
+
{{#if hasGateway}}
|
|
31
|
+
mcp_toolset = get_all_gateway_mcp_toolsets()
|
|
32
|
+
{{else}}
|
|
33
|
+
mcp_client = get_streamable_http_mcp_client()
|
|
34
|
+
mcp_toolset = [mcp_client] if mcp_client else []
|
|
35
|
+
{{/if}}
|
|
27
36
|
|
|
28
37
|
_credentials_loaded = False
|
|
29
38
|
|
|
@@ -1,15 +1,66 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
1
3
|
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
|
|
2
4
|
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
|
|
3
5
|
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
{{#if hasGateway}}
|
|
9
|
+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
|
|
10
|
+
import httpx
|
|
11
|
+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if (includes gatewayAuthTypes "CUSTOM_JWT")}}
|
|
14
|
+
from bedrock_agentcore.identity import requires_access_token
|
|
15
|
+
{{/if}}
|
|
16
|
+
|
|
17
|
+
{{#each gatewayProviders}}
|
|
18
|
+
{{#if (eq authType "CUSTOM_JWT")}}
|
|
19
|
+
@requires_access_token(
|
|
20
|
+
provider_name="{{credentialProviderName}}",
|
|
21
|
+
scopes=[{{#if scopes}}"{{scopes}}"{{/if}}],
|
|
22
|
+
auth_flow="M2M",
|
|
23
|
+
)
|
|
24
|
+
def _get_bearer_token_{{snakeCase name}}(*, access_token: str):
|
|
25
|
+
"""Obtain OAuth access token via AgentCore Identity for {{name}}."""
|
|
26
|
+
return access_token
|
|
27
|
+
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{/each}}
|
|
30
|
+
|
|
31
|
+
def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
|
|
32
|
+
"""Returns MCP Toolsets for all configured gateways."""
|
|
33
|
+
toolsets = []
|
|
34
|
+
{{#each gatewayProviders}}
|
|
35
|
+
url = os.environ.get("{{envVarName}}")
|
|
36
|
+
if url:
|
|
37
|
+
{{#if (eq authType "AWS_IAM")}}
|
|
38
|
+
session = create_aws_session()
|
|
39
|
+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
|
|
40
|
+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(
|
|
41
|
+
url=url,
|
|
42
|
+
httpx_client_factory=lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)
|
|
43
|
+
)))
|
|
44
|
+
{{else if (eq authType "CUSTOM_JWT")}}
|
|
45
|
+
token = _get_bearer_token_{{snakeCase name}}()
|
|
46
|
+
headers = {"Authorization": f"Bearer {token}"} if token else None
|
|
47
|
+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
|
|
48
|
+
{{else}}
|
|
49
|
+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
|
|
50
|
+
{{/if}}
|
|
51
|
+
else:
|
|
52
|
+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
|
|
53
|
+
{{/each}}
|
|
54
|
+
return toolsets
|
|
55
|
+
{{else}}
|
|
4
56
|
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
|
|
5
57
|
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
|
|
6
58
|
|
|
7
59
|
|
|
8
60
|
def get_streamable_http_mcp_client() -> MCPToolset:
|
|
9
|
-
"""
|
|
10
|
-
Returns an MCP Toolset compatible with Google ADK.
|
|
11
|
-
"""
|
|
61
|
+
"""Returns an MCP Toolset compatible with Google ADK."""
|
|
12
62
|
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
|
|
13
63
|
return MCPToolset(
|
|
14
64
|
connection_params=StreamableHTTPConnectionParams(url=EXAMPLE_MCP_ENDPOINT)
|
|
15
65
|
)
|
|
66
|
+
{{/if}}
|
|
@@ -14,6 +14,8 @@ dependencies = [
|
|
|
14
14
|
"google-adk >= 1.17.0",
|
|
15
15
|
"bedrock-agentcore >= 1.0.3",
|
|
16
16
|
"botocore[crt] >= 1.35.0",
|
|
17
|
+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
|
|
18
|
+
{{/if}}{{/if}}
|
|
17
19
|
]
|
|
18
20
|
|
|
19
21
|
[tool.hatch.build.targets.wheel]
|
|
@@ -4,7 +4,11 @@ from langgraph.prebuilt import create_react_agent
|
|
|
4
4
|
from langchain.tools import tool
|
|
5
5
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
6
6
|
from model.load import load_model
|
|
7
|
+
{{#if hasGateway}}
|
|
8
|
+
from mcp_client.client import get_all_gateway_mcp_client
|
|
9
|
+
{{else}}
|
|
7
10
|
from mcp_client.client import get_streamable_http_mcp_client
|
|
11
|
+
{{/if}}
|
|
8
12
|
|
|
9
13
|
app = BedrockAgentCoreApp()
|
|
10
14
|
log = app.logger
|
|
@@ -34,10 +38,16 @@ async def invoke(payload, context):
|
|
|
34
38
|
log.info("Invoking Agent.....")
|
|
35
39
|
|
|
36
40
|
# Get MCP Client
|
|
41
|
+
{{#if hasGateway}}
|
|
42
|
+
mcp_client = get_all_gateway_mcp_client()
|
|
43
|
+
{{else}}
|
|
37
44
|
mcp_client = get_streamable_http_mcp_client()
|
|
45
|
+
{{/if}}
|
|
38
46
|
|
|
39
47
|
# Load MCP Tools
|
|
40
|
-
mcp_tools =
|
|
48
|
+
mcp_tools = []
|
|
49
|
+
if mcp_client:
|
|
50
|
+
mcp_tools = await mcp_client.get_tools()
|
|
41
51
|
|
|
42
52
|
# Define the agent using create_react_agent
|
|
43
53
|
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
|
|
@@ -1,13 +1,61 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
1
3
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
2
4
|
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
{{#if hasGateway}}
|
|
8
|
+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
|
|
9
|
+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
|
|
10
|
+
{{/if}}
|
|
11
|
+
{{#if (includes gatewayAuthTypes "CUSTOM_JWT")}}
|
|
12
|
+
from bedrock_agentcore.identity import requires_access_token
|
|
13
|
+
{{/if}}
|
|
14
|
+
|
|
15
|
+
{{#each gatewayProviders}}
|
|
16
|
+
{{#if (eq authType "CUSTOM_JWT")}}
|
|
17
|
+
@requires_access_token(
|
|
18
|
+
provider_name="{{credentialProviderName}}",
|
|
19
|
+
scopes=[{{#if scopes}}"{{scopes}}"{{/if}}],
|
|
20
|
+
auth_flow="M2M",
|
|
21
|
+
)
|
|
22
|
+
def _get_bearer_token_{{snakeCase name}}(*, access_token: str):
|
|
23
|
+
"""Obtain OAuth access token via AgentCore Identity for {{name}}."""
|
|
24
|
+
return access_token
|
|
25
|
+
|
|
26
|
+
{{/if}}
|
|
27
|
+
{{/each}}
|
|
28
|
+
|
|
29
|
+
def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
|
|
30
|
+
"""Returns an MCP Client connected to all configured gateways."""
|
|
31
|
+
servers = {}
|
|
32
|
+
{{#each gatewayProviders}}
|
|
33
|
+
url = os.environ.get("{{envVarName}}")
|
|
34
|
+
if url:
|
|
35
|
+
{{#if (eq authType "AWS_IAM")}}
|
|
36
|
+
session = create_aws_session()
|
|
37
|
+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
|
|
38
|
+
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
|
|
39
|
+
{{else if (eq authType "CUSTOM_JWT")}}
|
|
40
|
+
token = _get_bearer_token_{{snakeCase name}}()
|
|
41
|
+
headers = {"Authorization": f"Bearer {token}"} if token else None
|
|
42
|
+
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
|
|
43
|
+
{{else}}
|
|
44
|
+
servers["{{name}}"] = {"transport": "streamable_http", "url": url}
|
|
45
|
+
{{/if}}
|
|
46
|
+
else:
|
|
47
|
+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
|
|
48
|
+
{{/each}}
|
|
49
|
+
if not servers:
|
|
50
|
+
return None
|
|
51
|
+
return MultiServerMCPClient(servers)
|
|
52
|
+
{{else}}
|
|
3
53
|
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
|
|
4
54
|
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
|
|
5
55
|
|
|
6
56
|
|
|
7
57
|
def get_streamable_http_mcp_client() -> MultiServerMCPClient:
|
|
8
|
-
"""
|
|
9
|
-
Returns an MCP Client compatible with LangChain/LangGraph.
|
|
10
|
-
"""
|
|
58
|
+
"""Returns an MCP Client compatible with LangChain/LangGraph."""
|
|
11
59
|
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
|
|
12
60
|
return MultiServerMCPClient(
|
|
13
61
|
{
|
|
@@ -17,3 +65,4 @@ def get_streamable_http_mcp_client() -> MultiServerMCPClient:
|
|
|
17
65
|
}
|
|
18
66
|
}
|
|
19
67
|
)
|
|
68
|
+
{{/if}}
|
|
@@ -15,7 +15,6 @@ dependencies = [
|
|
|
15
15
|
"mcp >= 1.19.0",
|
|
16
16
|
"langchain-mcp-adapters >= 0.1.11",
|
|
17
17
|
"langchain >= 1.0.3",
|
|
18
|
-
"tiktoken == 0.11.0",
|
|
19
18
|
"bedrock-agentcore >= 1.0.3",
|
|
20
19
|
"botocore[crt] >= 1.35.0",
|
|
21
20
|
{{#if (eq modelProvider "Bedrock")}}
|
|
@@ -30,6 +29,8 @@ dependencies = [
|
|
|
30
29
|
{{#if (eq modelProvider "Gemini")}}
|
|
31
30
|
"langchain-google-genai >= 3.0.3",
|
|
32
31
|
{{/if}}
|
|
32
|
+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
|
|
33
|
+
{{/if}}{{/if}}
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[tool.hatch.build.targets.wheel]
|
|
@@ -2,13 +2,22 @@ import os
|
|
|
2
2
|
from agents import Agent, Runner, function_tool
|
|
3
3
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
4
4
|
from model.load import load_model
|
|
5
|
+
{{#if hasGateway}}
|
|
6
|
+
from mcp_client.client import get_all_gateway_mcp_servers
|
|
7
|
+
{{else}}
|
|
5
8
|
from mcp_client.client import get_streamable_http_mcp_client
|
|
9
|
+
{{/if}}
|
|
6
10
|
|
|
7
11
|
app = BedrockAgentCoreApp()
|
|
8
12
|
log = app.logger
|
|
9
13
|
|
|
10
14
|
# Get MCP Server
|
|
15
|
+
{{#if hasGateway}}
|
|
16
|
+
mcp_servers = get_all_gateway_mcp_servers()
|
|
17
|
+
{{else}}
|
|
11
18
|
mcp_server = get_streamable_http_mcp_client()
|
|
19
|
+
mcp_servers = [mcp_server] if mcp_server else []
|
|
20
|
+
{{/if}}
|
|
12
21
|
|
|
13
22
|
_credentials_loaded = False
|
|
14
23
|
|
|
@@ -30,16 +39,47 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
30
39
|
async def main(query):
|
|
31
40
|
ensure_credentials_loaded()
|
|
32
41
|
try:
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
{{#if hasGateway}}
|
|
43
|
+
if mcp_servers:
|
|
35
44
|
agent = Agent(
|
|
36
45
|
name="{{ name }}",
|
|
37
46
|
model="gpt-4.1",
|
|
38
|
-
mcp_servers=
|
|
47
|
+
mcp_servers=mcp_servers,
|
|
39
48
|
tools=[add_numbers]
|
|
40
49
|
)
|
|
41
50
|
result = await Runner.run(agent, query)
|
|
42
51
|
return result
|
|
52
|
+
else:
|
|
53
|
+
agent = Agent(
|
|
54
|
+
name="{{ name }}",
|
|
55
|
+
model="gpt-4.1",
|
|
56
|
+
mcp_servers=[],
|
|
57
|
+
tools=[add_numbers]
|
|
58
|
+
)
|
|
59
|
+
result = await Runner.run(agent, query)
|
|
60
|
+
return result
|
|
61
|
+
{{else}}
|
|
62
|
+
if mcp_servers:
|
|
63
|
+
async with mcp_servers[0] as server:
|
|
64
|
+
active_servers = [server]
|
|
65
|
+
agent = Agent(
|
|
66
|
+
name="{{ name }}",
|
|
67
|
+
model="gpt-4.1",
|
|
68
|
+
mcp_servers=active_servers,
|
|
69
|
+
tools=[add_numbers]
|
|
70
|
+
)
|
|
71
|
+
result = await Runner.run(agent, query)
|
|
72
|
+
return result
|
|
73
|
+
else:
|
|
74
|
+
agent = Agent(
|
|
75
|
+
name="{{ name }}",
|
|
76
|
+
model="gpt-4.1",
|
|
77
|
+
mcp_servers=[],
|
|
78
|
+
tools=[add_numbers]
|
|
79
|
+
)
|
|
80
|
+
result = await Runner.run(agent, query)
|
|
81
|
+
return result
|
|
82
|
+
{{/if}}
|
|
43
83
|
except Exception as e:
|
|
44
84
|
log.error(f"Error during agent execution: {e}", exc_info=True)
|
|
45
85
|
raise e
|
|
@@ -1,14 +1,65 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
1
3
|
from agents.mcp import MCPServerStreamableHttp
|
|
2
4
|
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
{{#if hasGateway}}
|
|
8
|
+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
|
|
9
|
+
import httpx
|
|
10
|
+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if (includes gatewayAuthTypes "CUSTOM_JWT")}}
|
|
13
|
+
from bedrock_agentcore.identity import requires_access_token
|
|
14
|
+
{{/if}}
|
|
15
|
+
|
|
16
|
+
{{#each gatewayProviders}}
|
|
17
|
+
{{#if (eq authType "CUSTOM_JWT")}}
|
|
18
|
+
@requires_access_token(
|
|
19
|
+
provider_name="{{credentialProviderName}}",
|
|
20
|
+
scopes=[{{#if scopes}}"{{scopes}}"{{/if}}],
|
|
21
|
+
auth_flow="M2M",
|
|
22
|
+
)
|
|
23
|
+
def _get_bearer_token_{{snakeCase name}}(*, access_token: str):
|
|
24
|
+
"""Obtain OAuth access token via AgentCore Identity for {{name}}."""
|
|
25
|
+
return access_token
|
|
26
|
+
|
|
27
|
+
{{/if}}
|
|
28
|
+
{{/each}}
|
|
29
|
+
|
|
30
|
+
def get_all_gateway_mcp_servers() -> list[MCPServerStreamableHttp]:
|
|
31
|
+
"""Returns MCP servers for all configured gateways."""
|
|
32
|
+
servers = []
|
|
33
|
+
{{#each gatewayProviders}}
|
|
34
|
+
url = os.environ.get("{{envVarName}}")
|
|
35
|
+
if url:
|
|
36
|
+
{{#if (eq authType "AWS_IAM")}}
|
|
37
|
+
session = create_aws_session()
|
|
38
|
+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
|
|
39
|
+
servers.append(MCPServerStreamableHttp(
|
|
40
|
+
name="{{name}}",
|
|
41
|
+
params={"url": url, "httpx_client_factory": lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)}
|
|
42
|
+
))
|
|
43
|
+
{{else if (eq authType "CUSTOM_JWT")}}
|
|
44
|
+
token = _get_bearer_token_{{snakeCase name}}()
|
|
45
|
+
headers = {"Authorization": f"Bearer {token}"} if token else {}
|
|
46
|
+
servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url, "headers": headers}))
|
|
47
|
+
{{else}}
|
|
48
|
+
servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url}))
|
|
49
|
+
{{/if}}
|
|
50
|
+
else:
|
|
51
|
+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
|
|
52
|
+
{{/each}}
|
|
53
|
+
return servers
|
|
54
|
+
{{else}}
|
|
3
55
|
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
|
|
4
56
|
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
|
|
5
57
|
|
|
6
58
|
|
|
7
59
|
def get_streamable_http_mcp_client() -> MCPServerStreamableHttp:
|
|
8
|
-
"""
|
|
9
|
-
Returns an MCP Client compatible with OpenAI Agents SDK.
|
|
10
|
-
"""
|
|
60
|
+
"""Returns an MCP Client compatible with OpenAI Agents SDK."""
|
|
11
61
|
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
|
|
12
62
|
return MCPServerStreamableHttp(
|
|
13
63
|
name="AgentCore Gateway MCP", params={"url": EXAMPLE_MCP_ENDPOINT}
|
|
14
64
|
)
|
|
65
|
+
{{/if}}
|
|
@@ -13,6 +13,8 @@ dependencies = [
|
|
|
13
13
|
"openai-agents >= 0.4.2",
|
|
14
14
|
"bedrock-agentcore >= 1.0.3",
|
|
15
15
|
"botocore[crt] >= 1.35.0",
|
|
16
|
+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
|
|
17
|
+
{{/if}}{{/if}}
|
|
16
18
|
]
|
|
17
19
|
|
|
18
20
|
[tool.hatch.build.targets.wheel]
|