MCP server: Cloudflare Workers vs AWS Bedrock AgentCore — chọn cái nào

So sánh MCP server Cloudflare (Workers + R2/D1/KV, OAuth) với AWS Bedrock AgentCore (IAM, dài-hạn). Latency, cost, auth, kịch bản dùng — và tôi chọn cái nào.

· 8 phút đọc

TL;DR

  • MCP (Model Context Protocol) là chuẩn Anthropic mở 2024 cho phép Claude (và LLM khác) gọi tool từ server tự host. 2025 trở thành de facto cho agent tooling — Claude Desktop, Cursor, Continue đều support.
  • cloudflare/mcp-server-cloudflare chạy trên Workers, expose tool cho R2, D1, KV, Workers, Analytics. Latency edge ~10-30ms từ client tới tool. OAuth Cloudflare Access.
  • AWS Bedrock AgentCore (GA 2025) là wrapper để expose AWS API làm MCP tool cho Bedrock model. IAM Identity Center auth. Latency 100-300ms vì tool phải qua AWS region.
  • Workers thắng cho: latency-sensitive, multi-user OAuth, public tool expose. AgentCore thắng cho: AWS resource access (IAM-scoped), long-running stateful tool, compliance HIPAA/PCI cần audit CloudTrail.
  • Cost: Workers free tier 100k req/day + $5/M req sau. AgentCore tính theo token Bedrock + Lambda invocation. Cho 1M tool call/tháng: Workers ~$5-10 vs AgentCore ~$30-80 (chưa kể Bedrock token).
  • Đừng chọn dựa trên “ecosystem hiện tại” — chọn dựa trên nơi tool data sống. Tool R2/D1 → Workers. Tool DynamoDB/S3/RDS → AgentCore.

Vì sao 2025 phải nghĩ về MCP server

Trước MCP, mỗi agent platform có cơ chế tool riêng: OpenAI Functions, Anthropic Tools, LangChain Tools, etc. Tool viết cho framework này không reuse được cho framework khác. MCP đổi luật chơi: spec đơn giản, server expose tool qua JSON-RPC 2.0 over stdio/HTTP/SSE, client (Claude Desktop, Cursor, Cline, Continue) gọi tool standard cách nhau.

Khi bạn build một bộ tool “list R2 bucket”, “query D1 table”, “deploy Worker” — viết một lần với MCP, dùng cho mọi client. Đó là lý do 2025 thấy MCP server cho Postgres, GitHub, Slack, Linear, Notion, AWS, Cloudflare bùng nổ.

Câu hỏi production: host MCP server ở đâu? Đây là so sánh sau 6 tháng deploy cả hai pattern cho team Platform của tôi (~50 dev dùng Claude Desktop daily).

Cloudflare MCP server — Workers + Cloudflare API

cloudflare/mcp-server-cloudflare là MCP server chính chủ Cloudflare, expose phần lớn Cloudflare API làm tool:

  • R2: list bucket, list object, get object, put object, delete
  • D1: list database, run query, schema introspect
  • KV: list namespace, get/put/delete key
  • Workers: list, deploy, view logs, view metrics
  • Analytics: query Analytics Engine
  • Email Routing: list rule, send email
  • Hyperdrive: list connection

Server chạy trên Workers tự host (mã nguồn mở). Auth qua Cloudflare OAuth — client Claude Desktop redirect tới Cloudflare login, lấy access token, gọi MCP tool. Mỗi tool call chạy với scope OAuth của user, không phải global API key.

Deploy:

git clone https://github.com/cloudflare/mcp-server-cloudflare
cd mcp-server-cloudflare/apps/sandbox-container
npm install
wrangler deploy

Config Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "cloudflare": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://mcp.example.workers.dev/sse"
      ]
    }
  }
}

mcp-remote là bridge stdio-to-HTTP. Claude Desktop chỉ support stdio MCP server local, nên cần bridge cho remote. Cloudflare cũng release workers-oauth-provider để add OAuth vào Worker.

AWS Bedrock AgentCore — IAM-scoped tool cho Bedrock

AWS phản ứng với MCP wave bằng Bedrock AgentCore (GA 2025). AgentCore là framework để build và host MCP server expose AWS API làm tool. Khác Cloudflare ở:

  • IAM Identity Center auth thay vì OAuth: user login qua AWS SSO, MCP server assume role với scope IAM.
  • Tool chạy trong AWS region, không phải edge. Nếu tool gọi DynamoDB us-east-1, MCP server cũng ở us-east-1.
  • CloudTrail logging tự động cho mọi AWS API call mà tool thực hiện.
  • Tích hợp với Bedrock model — Claude 3.7 Sonnet, Claude Opus 4.7 trên Bedrock dùng AgentCore tool natively.

Sample reference: aws-samples/sample-OpenClaw-on-AWS-with-Bedrock là pattern OpenClaw (open-source Claude-compatible agent) chạy trên AWS với AgentCore. Phức tạp hơn Workers nhưng có audit/compliance built-in.

Deploy AgentCore tool đơn giản (Python):

# agentcore_tool.py
from aws_bedrock_agentcore import tool, MCPServer
import boto3

@tool(
    name="list_dynamodb_tables",
    description="List DynamoDB tables in current account/region",
    input_schema={"type": "object", "properties": {}},
)
def list_tables() -> list[str]:
    ddb = boto3.client("dynamodb")
    return ddb.list_tables()["TableNames"]


@tool(
    name="query_table",
    description="Run a PartiQL query against DynamoDB",
    input_schema={
        "type": "object",
        "properties": {
            "table": {"type": "string"},
            "statement": {"type": "string"},
        },
        "required": ["table", "statement"],
    },
)
def query_table(table: str, statement: str) -> list[dict]:
    ddb = boto3.client("dynamodb")
    resp = ddb.execute_statement(Statement=statement)
    return resp.get("Items", [])


server = MCPServer(
    name="aws-resource-tools",
    tools=[list_tables, query_table],
    auth="iam-identity-center",
    role_arn="arn:aws:iam::123456789012:role/MCPToolRole",
)

if __name__ == "__main__":
    server.run()

Deploy qua AWS SAM/CDK lên Lambda + API Gateway, hoặc Fargate cho long-running. AgentCore CLI handle endpoint registration với Bedrock.

Latency benchmark — đo thực tế

Test setup: client Claude Desktop ở Hà Nội, tool “list 100 object trong bucket”. Cả 2 server chứa cùng 100 object metadata.

HopCloudflare Workers MCPAWS AgentCore (us-east-1)
Client → MCP server8-12ms (edge HAN)180-220ms (qua Singapore)
Server → storage3-5ms (R2 cùng region)5-10ms (DynamoDB local)
Server → client8-12ms180-220ms
Total roundtrip20-30ms400-500ms

Sự khác biệt 15-20× này quan trọng khi tool được gọi nhiều lần trong một LLM turn. Agent tool-loop điển hình gọi 5-10 tool/turn. 5 tool × 20ms = 100ms vs 5 tool × 400ms = 2000ms. Khác biệt giữa “instant” và “user cảm thấy lag”.

Caveat: nếu user ở us-east-1 native (vd dev ở Virginia), AgentCore latency xuống còn 30-60ms — không chênh nhiều Workers. Nhưng global team thì Workers thắng vì PoP gần user.

Cost — 1M tool call/tháng

KhoảnCloudflare Workers MCPAWS AgentCore
Compute$5 base + ~$3 (1M req × $0.02/M = $20 nhưng trong free tier)$1 Lambda + $3.50 API Gateway/M
Storage tool data$0.015/GB (R2)$0.25/GB (DynamoDB on-demand)
Egress$0 (R2 zero egress)$0.09/GB (S3 egress nếu cần)
AuthCloudflare Access free tier 50 userIAM Identity Center free
Bedrock model tokenN/A (LLM ở client)$3/M input, $15/M output Claude 4.7
Tổng cho 1M tool call~$5-10~$30-80 + token Bedrock

Bedrock token cost không strictly cho MCP server — nhưng nếu agent chạy trên Bedrock, token là phần lớn cost. Workers MCP “free” vì LLM ở client (Claude Desktop dùng API key của user, không qua Worker).

Quy tắc tôi dùng:

  • Tool stateless, expose API public/auth user → Workers, cheaper + faster
  • Tool cần AWS API access với IAM → AgentCore, native auth
  • Mixed: Workers cho frontend tool (search, query), AgentCore cho backend admin tool (deploy, IAM change)

Authentication — OAuth vs IAM Identity Center

Cloudflare OAuth flow:

// workers-oauth-provider snippet
import { OAuthProvider } from "@cloudflare/workers-oauth-provider";

export default new OAuthProvider({
  apiRoute: "/mcp/sse",
  apiHandler: MCPHandler,
  defaultHandler: AuthPagesHandler,
  authorizeEndpoint: "/authorize",
  tokenEndpoint: "/token",
  clientRegistrationEndpoint: "/register",
});

User flow: Claude Desktop → mcp-remote bridge → /authorize → Cloudflare login (Google/GitHub SSO) → token issue → tool call kèm Authorization: Bearer ....

Token scope: bạn define trong MCP server (vd scope: "r2:read d1:write"). Per-user token tách biệt — user A không thấy bucket của user B nếu policy đúng.

AWS AgentCore IAM flow:

# CloudFormation snippet
Resources:
  MCPToolRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Federated: !Sub "arn:aws:iam::${AWS::AccountId}:oidc-provider/identity-center"
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                "identity-center:aud": "mcp-tools"
      Policies:
        - PolicyName: MCPToolAccess
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:Query
                  - dynamodb:GetItem
                Resource: "arn:aws:dynamodb:*:*:table/PublicData*"

User login Identity Center → assume MCPToolRole → MCP server execute tool dưới quyền role. CloudTrail log mọi API call.

Lợi thế Identity Center: nếu org dùng AWS SSO sẵn, không cần OAuth provider riêng. Lợi thế OAuth: external user không cần AWS account.

Stateful tool — AgentCore mạnh hơn

Workers MCP server stateless mặc định. State persist phải qua D1/KV/DO. Cho tool đơn giản (search, query) không vấn đề. Nhưng tool dài-hạn như “deploy CDK stack, theo dõi tới hết”, “train SageMaker job, return result khi xong” — AgentCore + Step Functions là native.

AgentCore hỗ trợ “long-running tool” pattern:

@tool(
    name="train_model",
    description="Start SageMaker training job, poll till complete",
    long_running=True,  # Tool returns job ID immediately, agent polls
)
def train_model(dataset_s3: str, model_type: str) -> dict:
    sm = boto3.client("sagemaker")
    job = sm.create_training_job(
        TrainingJobName=f"job-{uuid.uuid4()}",
        AlgorithmSpecification={...},
        InputDataConfig=[{"DataSource": {"S3DataSource": {"S3Uri": dataset_s3}}}],
    )
    return {"job_id": job["TrainingJobArn"], "status": "started"}


@tool(name="poll_training_job")
def poll_job(job_id: str) -> dict:
    sm = boto3.client("sagemaker")
    job = sm.describe_training_job(TrainingJobName=job_id.split("/")[-1])
    return {"status": job["TrainingJobStatus"], "metrics": job.get("FinalMetricDataList", [])}

Workers tương đương cần dùng Durable Object + Alarm để poll. Có thể làm được, nhưng AgentCore native hơn vì AWS infrastructure đã có Step Functions/EventBridge.

Khi nào dùng cái nào — decision tree

1. Tool gọi AWS API (DynamoDB, S3, Lambda, EC2)?
   → AgentCore. IAM auth native, CloudTrail audit free.

2. Tool gọi Cloudflare API (R2, D1, KV, Workers)?
   → cloudflare/mcp-server-cloudflare. Edge latency.

3. Tool tự build (third-party API, internal API)?
   → Workers nếu cần low latency + global user
   → AgentCore nếu đã ở AWS ecosystem + compliance heavy

4. Compliance HIPAA/PCI/FedRAMP với CloudTrail audit?
   → AgentCore. Cloudflare có audit nhưng AWS-side compliance dễ hơn.

5. Public tool, multi-tenant OAuth?
   → Workers. workers-oauth-provider được build cho use case này.

6. Long-running tool (> 30s)?
   → AgentCore + Step Functions, hoặc
   → Workers DO Alarm (phức tạp hơn)

Pitfall thường gặp

1. Tool quá hạt mịn. Đừng expose 50 tool nhỏ. LLM context window hữu hạn — mỗi tool description ăn token. Gom 5 tool DynamoDB thành 1 tool dynamodb_query với arg dispatch.

2. Auth không scope per-user. Workers dùng global service token = mọi user thấy data nhau. Phải dùng OAuth flow per-user.

3. Đăng ký MCP server không qua TLS. Claude Desktop không cảnh báo. Tool call qua HTTP = credential leak.

4. Workers MCP server timeout 30s (Workers Paid 5 phút). Tool gọi RDS query 60s sẽ fail. Phải refactor sang long-running pattern.

5. AgentCore tool throw IAM AccessDenied. Audit IAM policy của role assume — mọi action tool gọi phải có Allow.

6. CORS với Claude Desktop. MCP server phải allow origin claude://. Nhiều dev quên config.

Multi-MCP setup — chạy cả hai

Production thực tế của tôi: chạy cả Workers MCP cho Cloudflare resource + AgentCore cho AWS resource. Claude Desktop config 2 server:

{
  "mcpServers": {
    "cloudflare": {
      "command": "npx",
      "args": ["mcp-remote", "https://mcp-cf.example.com/sse"]
    },
    "aws": {
      "command": "npx",
      "args": ["mcp-remote", "https://mcp-aws.example.com/mcp"]
    }
  }
}

LLM thấy tool từ cả 2 server. Prompt engineering nhẹ để route:

“Khi user hỏi về R2/D1/Cloudflare resource, dùng tool prefix cloudflare_*. Khi hỏi về AWS resource, dùng aws_*.”

Không có conflict tool name vì server name prepend tự động.

Vận hành — checklist 6 tháng

  • MCP server có rate limit per-user (Workers: RateLimit binding, AWS: API Gateway throttle)
  • OAuth refresh token rotation (Workers: 30 ngày, AgentCore: STS 1h)
  • Tool schema versioning — đổi tool input schema không break client
  • Audit log mọi tool call vào D1/CloudWatch — debug khi LLM gọi sai
  • CORS chỉ allow claude://, cursor://, continue:// (không wildcard)
  • Tool description < 200 token mỗi cái — tiết kiệm context
  • Test với Claude Desktop, Cursor, Continue — không assume chỉ 1 client
  • Monitoring: tool call rate, latency p99, error rate
  • Secret management: Workers wrangler secret, AWS Secrets Manager
  • DR: MCP server downtime = mọi agent stuck. Cần health endpoint + alert

Bottom line

MCP là chuẩn thắng cuộc 2025 — không tranh cãi. Câu hỏi không phải “có dùng MCP không” mà “host ở đâu”. Cloudflare Workers MCP rẻ hơn, nhanh hơn, OAuth multi-tenant native — chọn cho tool R2/D1/KV và public-facing tool. AWS Bedrock AgentCore mạnh hơn cho AWS resource access, IAM-scoped, audit CloudTrail — chọn cho admin tool nội bộ và compliance use case. Cả hai cùng tồn tại trong stack production của tôi (50 dev) và team không phải chọn one-or-other — chạy cả hai, mỗi cái cho data domain của nó. Nếu phải chọn một, cho 80% use case Workers thắng vì latency edge và cost thấp. AgentCore là 20% còn lại nhưng critical (deploy CDK, audit IAM, training pipeline).

Tham chiếu