Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 6 additions & 3 deletions src/assets/templates/mcp-python-fastmcp/main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{{#if needsOs}}
import os
{{/if}}
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("{{ name }}", host="0.0.0.0", stateless_http=True)
mcp = FastMCP(
"{{ name }}",
host="0.0.0.0",
port=int(os.environ.get("FASTMCP_PORT", "8000")),
stateless_http=True,
)

{{#if needsOs}}
_MOUNT_PATHS = [
Expand Down
8 changes: 5 additions & 3 deletions src/assets/templates/runtime-docs/python/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ in more detail.
- Accept the platform-provided `Mcp-Session-Id` header. Stay stateless unless
the user needs elicitation or sampling with MCP protocol version 2025-11-25
or earlier, which requires stateful mode.
- Add `mcp` to the dependencies. Do not hardcode a port other than 8000;
`agentcore dev` sets `FASTMCP_PORT`.
- Add `mcp` to the dependencies. Pass
`port=int(os.environ.get("FASTMCP_PORT", "8000"))` to `FastMCP`, so
`agentcore dev` can move the server when port 8000 is busy.
{{/if}}
{{#if (eq protocol "A2A")}}
- Serve A2A on `0.0.0.0` port 9000: JSON-RPC 2.0 at `POST /` (for example
`message/send`), the agent card at `GET /.well-known/agent-card.json`, and
`GET /ping`. Use `serve_a2a(executor)` from `bedrock_agentcore.runtime`
under `if __name__ == "__main__":`; it implements all three.
under `if __name__ == "__main__":`; it implements all three and reads the
`A2A_PORT` override that `agentcore dev` sets for local development.
- Add `bedrock-agentcore[a2a] ~= 1.24.0` and `a2a-sdk` to the dependencies.
{{/if}}
{{#if (eq protocol "AGUI")}}
Expand Down
14 changes: 11 additions & 3 deletions src/assets/templates/runtime-docs/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,15 @@ with MCP protocol version 2025-11-25 and earlier; from 2026-07-28 those use
multi-round-trip requests, which work in stateless mode.

```python
import os
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("{{name}}", host="0.0.0.0", stateless_http=True)
mcp = FastMCP(
"{{name}}",
host="0.0.0.0",
port=int(os.environ.get("FASTMCP_PORT", "8000")),
stateless_http=True,
)


@mcp.tool()
Expand All @@ -125,8 +131,8 @@ if __name__ == "__main__":
mcp.run(transport="streamable-http")
```

Add `mcp` to your dependencies. `agentcore dev` sets `FASTMCP_PORT`, so
don't hardcode a different port.
Add `mcp` to your dependencies. Read `FASTMCP_PORT` as above so
`agentcore dev` can move the server when port 8000 is busy.

Full contract: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp-protocol-contract.html
{{/if}}
Expand All @@ -146,6 +152,8 @@ if __name__ == "__main__":

Add `bedrock-agentcore[a2a] ~= 1.24.0` (the version line with `serve_a2a`) and
`a2a-sdk` to your dependencies, as in the `pyproject.toml` example below.
`agentcore dev` sets `A2A_PORT` when it needs a local port other than the
deployed service-contract default of 9000; `serve_a2a` reads it automatically.

Full contract: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-a2a-protocol-contract.html
{{/if}}
Expand Down
10 changes: 5 additions & 5 deletions src/assets/templates/shared/env.local.template
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Environment variables for local development.
# `agentcore dev` loads this file into your agent's process. Values here
# override injected values except PORT, FASTMCP_PORT, and LOCAL_DEV, which the
# CLI owns. While trace collection is on (the default), the CLI also owns the
# OTEL_* and AGENT_OBSERVABILITY_ENABLED variables so traces reach its local
# collector — pass --no-traces (or set instrumentation.enableOtel to false in
# agentcore.json) to disable collection and set your own.
# override injected values except PORT, FASTMCP_PORT, A2A_PORT, and LOCAL_DEV,
# which the CLI owns. While trace collection is on (the default), the CLI also
# owns the OTEL_* and AGENT_OBSERVABILITY_ENABLED variables so traces reach its
# local collector — pass --no-traces (or set instrumentation.enableOtel to
# false in agentcore.json) to disable collection and set your own.
# This file is gitignored — keep secrets out of version control.
#
# Example:
Expand Down
1 change: 1 addition & 0 deletions src/core/dev/codezip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ describe("CodeZipDevRunner", () => {

expect(calls[0]?.command).toEqual(["uv", "run", "python", "main.py"]);
expect(calls[0]?.options.env?.FASTMCP_PORT).toBe(protocol === "MCP" ? "9000" : undefined);
expect(calls[0]?.options.env?.A2A_PORT).toBe(protocol === "A2A" ? "9000" : undefined);
},
);

Expand Down
3 changes: 3 additions & 0 deletions src/core/dev/codezip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ function commandForRuntime(
if (input.runtime.protocol === "MCP") {
env.FASTMCP_PORT = String(input.port);
}
if (input.runtime.protocol === "A2A") {
env.A2A_PORT = String(input.port);
}

if (!entrypoint.endsWith(".py")) {
return {
Expand Down
2 changes: 2 additions & 0 deletions src/handlers/project/dev/environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ SHARED="local value"
AWS_REGION=local-region
PORT=enc:v1:ignored
FASTMCP_PORT=enc:v1:ignored
A2A_PORT=enc:v1:ignored
LOCAL_DEV=enc:v1:ignored
MULTILINE="first
second"
Expand All @@ -45,6 +46,7 @@ second"
{ name: "SHARED", value: "runtime" },
{ name: "RUNTIME_ONLY", value: "yes" },
{ name: "PORT", value: "1234" },
{ name: "A2A_PORT", value: "9000" },
]),
),
).resolves.toEqual({
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/project/dev/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { join } from "node:path";
import type { ProjectRuntime } from "../../../projectSchemas/runtime";
import { readEnvFile } from "../../../io/envFile";

const RESERVED_ENV_KEYS = ["PORT", "FASTMCP_PORT", "LOCAL_DEV"] as const;
const RESERVED_ENV_KEYS = ["PORT", "FASTMCP_PORT", "A2A_PORT", "LOCAL_DEV"] as const;

export type DevEnvironmentInput = {
projectRoot: string;
Expand Down
1 change: 1 addition & 0 deletions src/handlers/project/project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ describe("project create", () => {
const runtimeRoot = join(projectRoot, "app", "agent");
const mainPy = await Bun.file(join(runtimeRoot, "main.py")).text();
expect(mainPy).toContain("FastMCP");
expect(mainPy).toContain('port=int(os.environ.get("FASTMCP_PORT", "8000"))');
expect(mainPy).toContain('mcp.run(transport="streamable-http")');
expect(await Bun.file(join(runtimeRoot, "Dockerfile")).exists()).toBe(false);
expect(spec.memories ?? []).toEqual([]);
Expand Down
Loading