Skip to main content
Glama
README.md
# AgentCore MCP 2026-07-28 sample

A minimal, reproducible sample for exercising the **MCP `2026-07-28` (stateless)**
protocol on **Amazon Bedrock AgentCore** — both a **Runtime-hosted MCP server** and a
**SigV4 probe** you can point at a Gateway or a Runtime.

MCP `2026-07-28` makes the protocol stateless: no `initialize` handshake, no
protocol-level `Mcp-Session-Id`, every request self-contained. The two artifacts here
let you see that end to end.

## Contents

| File | What it is |
|---|---|
| `server.py` | A stateless MCP server built on the `mcp` Python SDK **v2** (`MCPServer`), ready to deploy to AgentCore Runtime. |
| `requirements.txt` | Runtime dependencies (`mcp>=2.0.0`). |
| `mcp_probe.py` | A tiny SigV4-signed MCP client for probing an AgentCore Gateway `/mcp` endpoint or a Runtime `/invocations` endpoint with IAM auth. |

> Tested with `mcp==2.0.0` (`LATEST_PROTOCOL_VERSION == "2026-07-28"`),
> `bedrock-agentcore==1.19.0`, `bedrock-agentcore-starter-toolkit==0.3.11`,
> Python 3.13, in `us-east-1`. Pin your `mcp` version — a different major version
> changes the server API (see note below).

## The server

`server.py` uses the **v2** high-level API. Note that `mcp` v2 **removed `FastMCP`** —
the class is now `MCPServer` (`mcp.server.mcpserver`). It serves a stateless
streamable-HTTP app at `0.0.0.0:8000/mcp`, which is what AgentCore Runtime expects.

Key choices:
- `stateless_http=True` — the 2026-07-28 model and the recommended AgentCore default.
- `enable_dns_rebinding_protection=False` — the AgentCore front door forwards a
  non-localhost `Host` header, so the v2 default host validation must be relaxed for
  the container.

### Run locally

```bash
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
python server.py            # serves http://0.0.0.0:8000/mcp
```

Compare the two protocol shapes locally:

```bash
# old protocol -> SSE, no envelope
curl -s http://localhost:8000/mcp \
  -H 'Content-Type: application/json' -H 'Accept: application/json,text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-03-26' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# 2026-07-28 stateless -> plain JSON with resultType/cacheScope envelope
curl -s http://localhost:8000/mcp \
  -H 'Content-Type: application/json' -H 'Accept: application/json,text/event-stream' \
  -H 'MCP-Protocol-Version: 2026-07-28' -H 'Mcp-Method: tools/list' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{
        "io.modelcontextprotocol/protocolVersion":"2026-07-28",
        "io.modelcontextprotocol/clientInfo":{"name":"local","version":"1.0"},
        "io.modelcontextprotocol/clientCapabilities":{}}}}'
```

### Deploy to AgentCore Runtime

Using the starter toolkit's `direct_code_deploy` (no local container build; IAM inbound
auth is the default when you omit a JWT authorizer):

```bash
pip install bedrock-agentcore-starter-toolkit
agentcore configure -e server.py -n <agent-name> --protocol MCP \
  -r us-east-1 -rf requirements.txt --non-interactive
agentcore deploy
```

There is **no MCP-version flag** on a Runtime — the runtime declares only
`serverProtocol: MCP`. Which MCP versions the server speaks is decided entirely by the
`mcp` SDK version in your `requirements.txt`.

## The probe

`mcp_probe.py` SigV4-signs a POST (default service `bedrock-agentcore`) so you can hit
IAM-auth AgentCore endpoints with your own credentials — no Cognito/OAuth setup.

```bash
pip install boto3

# Point at a Gateway MCP endpoint or a Runtime /invocations URL:
URL="https://<gateway-id>.gateway.bedrock-agentcore.us-east-1.amazonaws.com/mcp"

# 2026-07-28 stateless tools/list
python mcp_probe.py --url "$URL" --proto 2026-07-28 --mcp-method tools/list --method tools/list \
  --meta '{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"probe","version":"1.0"},"io.modelcontextprotocol/clientCapabilities":{}}'

# tools/call
python mcp_probe.py --url "$URL" --proto 2026-07-28 --mcp-method tools/call --mcp-name add_numbers \
  --method tools/call --name add_numbers --arguments '{"a":2,"b":40}' \
  --meta '{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"probe","version":"1.0"},"io.modelcontextprotocol/clientCapabilities":{}}'
```

For a Runtime, use the data-plane URL with the URL-escaped runtime ARN:

```
https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/<URL-ESCAPED-ARN>/invocations?qualifier=DEFAULT
```

## Gotchas this sample demonstrates

- A **stateless `2026-07-28` request must carry `protocolVersion`, `clientInfo`, and
  `clientCapabilities` inside `_meta`** on every call — omit any and you get `-32602`.
  A real client SDK does this for you; hand-rolling from an abbreviated example fails.
- `mcp` v2 **dropped `FastMCP`** → use `MCPServer`. (Pin `mcp>=1.28,<2` if you must keep
  `FastMCP`.)
- v2 **DNS-rebinding protection** blocks the non-localhost `Host` behind AgentCore →
  disable it for the container.
- On the wire: old protocol responds via **SSE** with no envelope; `2026-07-28` responds
  with **plain JSON** carrying `resultType` / `cacheScope` (and `structuredContent` /
  `ttlMs` where applicable).

## Prerequisites

- Python 3.10+ (3.13 tested)
- AWS credentials in your environment with permission to deploy/invoke AgentCore
- For probing: an AgentCore Gateway or Runtime configured with **IAM (SigV4)** inbound auth

## References

- [How AgentCore Gateway supports the MCP 2026-07-28 spec](https://aws.amazon.com/blogs/machine-learning/how-agentcore-gateway-supports-the-mcp-2026-07-28-spec/)
- [Deploy MCP servers in AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp.html)
- [MCP 2026-07-28 specification & changelog](https://modelcontextprotocol.io/specification/2026-07-28/changelog)

## License

MIT-0. See [LICENSE](LICENSE).