Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2cebb4c
feat: protocol-aware dev and invoke for MCP and A2A agents
tejaskash Mar 17, 2026
a46d976
fix: MCP session ID plumbing, tool list in header, A2A venv setup
tejaskash Mar 17, 2026
32db045
fix: break circular dependency between invoke and invoke-a2a
tejaskash Mar 17, 2026
75e4e53
fix: move isMcp declaration before its first use in DevScreen
tejaskash Mar 17, 2026
cb39bf4
fix: always run uv sync for non-HTTP protocols on dev start
tejaskash Mar 17, 2026
effe395
fix: cap MCP tool list to 5 in header, add input placeholder
tejaskash Mar 17, 2026
f76af3d
fix: show clear error when only MCP/A2A agents exist in deployed invoke
tejaskash Mar 17, 2026
6f39faf
fix: remove deployed invoke guards for MCP/A2A agents
tejaskash Mar 17, 2026
705115c
feat: protocol-aware invoke and A2A agent card display
tejaskash Mar 17, 2026
4d6325c
fix: A2A dev uses fixed port 9000, add messageId to A2A requests
tejaskash Mar 17, 2026
7630605
fix: proper A2A streaming via message/stream, fix response parsing
tejaskash Mar 17, 2026
907b377
fix: skip status-update text to prevent doubled A2A responses
tejaskash Mar 17, 2026
d59a82d
feat: show A2A task status updates (working, input-required, etc.)
tejaskash Mar 17, 2026
bff1e90
fix: stream A2A responses incrementally from status-update events
tejaskash Mar 17, 2026
d34393a
fix: show MCP tool list and usage hint in conversation on startup
tejaskash Mar 17, 2026
5b5831c
fix: guard deployed invoke against unsupported MCP/A2A protocols
tejaskash Mar 17, 2026
2b474d8
fix: enable deployed invoke for MCP and A2A agents
tejaskash Mar 17, 2026
bf41a6a
fix: add MCP hint and placeholder in deployed invoke screen
tejaskash Mar 17, 2026
eff67b5
feat: MCP tool listing and tool calls in deployed invoke
tejaskash Mar 17, 2026
cd08837
fix: retry MCP calls on cold-start initialization timeouts
tejaskash Mar 17, 2026
655a173
fix: MCP deployment and invoke compatibility
tejaskash Mar 18, 2026
757eb4d
style: format useInvokeFlow after rebase
tejaskash Mar 18, 2026
6595a4a
fix: protocol backward compat, fixed ports for A2A/MCP in CLI paths
tejaskash Mar 18, 2026
cdf0b2e
feat: A2A deployed invoke via JSON-RPC message/send
tejaskash Mar 18, 2026
4a88466
fix: address code review findings for protocol dev/invoke PR
tejaskash Mar 18, 2026
d14dd44
fix: remove bedrock-agentcore-starter-toolkit from MCP template deps
tejaskash Mar 18, 2026
0e7cbca
fix: address Aidan's review comments on protocol dev/invoke PR
tejaskash Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aws/agentcore",
"version": "0.3.0-preview.5.1",
"version": "0.3.0-preview.6.0",
"description": "CLI for Amazon Bedrock AgentCore",
"license": "Apache-2.0",
"repository": {
Expand Down
29 changes: 14 additions & 15 deletions src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1645,7 +1645,8 @@ readme = "README.md"
requires-python = ">=3.10"
dependencies = [
{{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0",
{{/if}}"aws-opentelemetry-distro",
{{/if}}"a2a-sdk[all] >= 0.2.0",
"aws-opentelemetry-distro",
"bedrock-agentcore[a2a] >= 1.0.3",
"botocore[crt] >= 1.35.0",
{{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
Expand Down Expand Up @@ -4076,29 +4077,30 @@ Thumbs.db

exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/main.py should match snapshot 1`] = `
"from mcp.server.fastmcp import FastMCP
import uvicorn

mcp = FastMCP("{{ name }}")
mcp = FastMCP("{{ name }}", host="0.0.0.0", stateless_http=True)


@mcp.tool()
def add_numbers(a: int, b: int) -> int:
"""Return the sum of two numbers."""
"""Add two numbers together"""
return a + b


@mcp.tool()
def greet(name: str) -> str:
"""Return a greeting for the given name."""
return f"Hello, {name}!"
def multiply_numbers(a: int, b: int) -> int:
"""Multiply two numbers together"""
return a * b


@mcp.tool()
def greet_user(name: str) -> str:
"""Greet a user by name"""
return f"Hello, {name}! Nice to meet you."


if __name__ == "__main__":
uvicorn.run(
mcp.streamable_http_app(),
host="0.0.0.0",
port=8000,
)
mcp.run(transport="streamable-http")
"
`;

Expand All @@ -4114,10 +4116,7 @@ description = "AgentCore MCP Server"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"aws-opentelemetry-distro",
"bedrock-agentcore >= 1.0.3",
"mcp >= 1.19.0",
"uvicorn >= 0.30.0",
]

[tool.hatch.build.targets.wheel]
Expand Down
3 changes: 2 additions & 1 deletion src/assets/python/a2a/strands/base/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ readme = "README.md"
requires-python = ">=3.10"
dependencies = [
{{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0",
{{/if}}"aws-opentelemetry-distro",
{{/if}}"a2a-sdk[all] >= 0.2.0",
"aws-opentelemetry-distro",
"bedrock-agentcore[a2a] >= 1.0.3",
"botocore[crt] >= 1.35.0",
{{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
Expand Down
23 changes: 12 additions & 11 deletions src/assets/python/mcp/standalone/base/main.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
from mcp.server.fastmcp import FastMCP
import uvicorn

mcp = FastMCP("{{ name }}")
mcp = FastMCP("{{ name }}", host="0.0.0.0", stateless_http=True)


@mcp.tool()
def add_numbers(a: int, b: int) -> int:
"""Return the sum of two numbers."""
"""Add two numbers together"""
return a + b


@mcp.tool()
def greet(name: str) -> str:
"""Return a greeting for the given name."""
return f"Hello, {name}!"
def multiply_numbers(a: int, b: int) -> int:
"""Multiply two numbers together"""
return a * b


@mcp.tool()
def greet_user(name: str) -> str:
"""Greet a user by name"""
return f"Hello, {name}! Nice to meet you."


if __name__ == "__main__":
uvicorn.run(
mcp.streamable_http_app(),
host="0.0.0.0",
port=8000,
)
mcp.run(transport="streamable-http")
3 changes: 0 additions & 3 deletions src/assets/python/mcp/standalone/base/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ description = "AgentCore MCP Server"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"aws-opentelemetry-distro",
"bedrock-agentcore >= 1.0.3",
"mcp >= 1.19.0",
"uvicorn >= 0.30.0",
]

[tool.hatch.build.targets.wheel]
Expand Down
81 changes: 80 additions & 1 deletion src/cli/aws/__tests__/agentcore.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { extractResult, parseSSE, parseSSELine } from '../agentcore.js';
import { extractResult, parseA2AResponse, parseSSE, parseSSELine } from '../agentcore.js';
import { describe, expect, it } from 'vitest';

describe('parseSSELine', () => {
Expand Down Expand Up @@ -97,3 +97,82 @@ describe('extractResult', () => {
expect(extractResult('')).toBe('');
});
});

describe('parseA2AResponse', () => {
it('extracts text from artifacts with kind:text parts', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
result: {
artifacts: [{ parts: [{ kind: 'text', text: 'Hello from A2A' }] }],
},
});
expect(parseA2AResponse(response)).toBe('Hello from A2A');
});

it('extracts text from artifacts with type:text parts (backward compat)', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
result: {
artifacts: [{ parts: [{ type: 'text', text: 'Hello' }] }],
},
});
expect(parseA2AResponse(response)).toBe('Hello');
});

it('concatenates text from multiple parts', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
result: {
artifacts: [
{
parts: [
{ kind: 'text', text: 'part1' },
{ kind: 'text', text: 'part2' },
],
},
],
},
});
expect(parseA2AResponse(response)).toBe('part1part2');
});

it('returns error message for JSON-RPC error', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
error: { code: -32600, message: 'Bad request' },
});
expect(parseA2AResponse(response)).toBe('Error: Bad request');
});

it('falls back to history for agent messages', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
result: {
history: [
{ role: 'user', parts: [{ kind: 'text', text: 'hi' }] },
{ role: 'agent', parts: [{ kind: 'text', text: 'Hello!' }] },
],
},
});
expect(parseA2AResponse(response)).toBe('Hello!');
});

it('returns stringified result when no text parts found', () => {
const response = JSON.stringify({
jsonrpc: '2.0',
id: 1,
result: { id: 'task-1', status: { state: 'completed' } },
});
const parsed = parseA2AResponse(response);
expect(parsed).toContain('task-1');
});

it('returns raw text for non-JSON input', () => {
expect(parseA2AResponse('not json')).toBe('not json');
});
});
Loading
Loading