
【自作 MCP】Amazon Bedrock Guardrails の ApplyGuardrail API を MCP 経由で実行し EDR っぽく使ってみた
こんにちは!クラウド事業本部コンサルティング部のたかくに(@takakuni_)です。
MCP サーバー、非常に便利ですよね。
MCP を使いこなせられれば、さまざまな用途に応用できる可能性があります。
そこで今回は Amazon Bedrock Guardrailsの機能を活用して、MCP Server を実装してみました。
ApplyGuardrail API
Amazon Bedrock Guardrails の ApplyGuardrail API は、LLM とのやり取りで期待される入出力データを Amazon Bedrock Guardrails に渡してチェックする API です。
やり取りで期待される入出力データを受け渡しすることで、Amazon Bedrock でホストされていない LLM の入出力をチェックできます。
より詳しい内容は以下をご覧ください。
Amazon Bedrock Guardrails MCP Server
個人的な感想ですが、執筆時点では MCP の用途として、LLM のコンテキスト強化に関するものが多い印象です。
たとえば、検索 API として利用可能な Brave Search MCP であったり、AWS だと AWS Documentation MCP Server などが挙げられます。生成する系で言うと Amazon Nova Canvas MCP Server などがありますね。
MCP はあくまでプロトコルの話なので、 EDR (Endpoint Detection and Response) 的なことができないのか試してみました。
やってみた
Amazon Bedrock Guardrails の作成
ガードレールの作成を行います。プロンプトフィルターのすべての項目の強さを High に設定してみました。
作成されたガードレールの ID を控えておきます。バージョンは DRAFT
を利用します。
コード
以下のコードを作成しました。Tools を使い contents_filter
なるものを作成してみました。
はじめて自作 MCP をやってみたのですが、難しい概念がない(知らないだけかもですが)ので良きですね。
"""
Bedrock Guardrails MCP Server implementation.
"""
import logging
import os
import sys
import boto3
from typing import Optional
from pydantic import BaseModel, Field
from mcp.server.fastmcp import Context, FastMCP
# Logging
logging.basicConfig(
level=os.getenv("FASTMCP_LOG_LEVEL", "INFO"),
format="%(asctime)s %(levelname)s %(name)s %(message)s",
stream=sys.stderr,
)
logger = logging.getLogger(__name__)
# Bedrock Runtime Client
aws_region = os.environ.get("AWS_REGION", "us-east-1")
try:
if aws_profile := os.environ.get("AWS_PROFILE"):
bedrock_client = boto3.Session(
profile_name=aws_profile, region_name=aws_region
).client("bedrock-runtime")
else:
bedrock_client = boto3.Session(region_name=aws_region).client("bedrock-runtime")
except Exception as e:
logger.error(f"Error creating bedrock runtime client: {str(e)}")
raise
# MCP Response Model
class McpGuardrailFilterResponse(BaseModel):
filtered_text: str = Field(description="Guardrail適用後のテキスト")
guardrail_intervened: bool = Field(description="ガードレールが介入したかどうか")
trace: Optional[dict] = Field(default=None, description="ガードレールのトレース情報")
# FastMCPサーバー初期化
mcp = FastMCP(
"bedrock-guardrails-mcp-server",
instructions="""
# Bedrock Guardrails MCP Server
このMCPサーバーは、Amazon Bedrock Guardrailsを使ってテキストのフィルタリングを行うツールを提供します。
""",
dependencies=[
"pydantic",
"boto3",
],
)
@mcp.tool(
name="contents_filter",
description="Bedrock Guardrailsを使って入力テキストにガードレールを適用し、フィルタ済みテキストを返します"
)
async def contents_filter(
ctx: Context,
input_text: str = Field(description="フィルタ対象のテキスト"),
guardrail_id: Optional[str] = Field(default=None, description="ガードレールID(未指定時は環境変数から取得)"),
guardrail_version: Optional[str] = Field(default=None, description="ガードレールバージョン(未指定時は環境変数から取得)"),
) -> McpGuardrailFilterResponse:
"""
Bedrock Guardrailsを使って入力テキストにガードレールを適用し、フィルタ済みテキストを返します。
"""
try:
guardrail_id = guardrail_id or os.getenv("GUARDRAIL_ID")
guardrail_version = guardrail_version or os.getenv("GUARDRAIL_VERSION")
if not guardrail_id or not guardrail_version:
raise ValueError("GUARDRAIL_IDとGUARDRAIL_VERSIONは必須です(引数または環境変数で指定)")
# Guardrails適用用のmessages構築
logger.info(f"Applying guardrail: id={guardrail_id}, version={guardrail_version}")
logger.info(f"input_text type: {type(input_text)}, value: {input_text}")
response = bedrock_client.apply_guardrail(
content=[
{
"text": {
"text": str(input_text)
}
}
],
guardrailIdentifier=guardrail_id,
guardrailVersion=guardrail_version,
source="INPUT"
)
outputs = response.get("outputs", [])
filtered_text = outputs[0]["text"] if outputs and "text" in outputs[0] else input_text
guardrail_intervened = response.get("action", "") == "GUARDRAIL_INTERVENED"
return {
"filtered_text": filtered_text,
"guardrail_intervened": guardrail_intervened,
"trace": None
}
except Exception as e:
logger.error(f"Error in contents_filter: {str(e)}")
await ctx.error(f"Guardrails適用時にエラーが発生しました: {str(e)}")
raise
if __name__ == "__main__":
mcp.run(transport="stdio")
パッケージマネージャーには Quick Start を真似て uv を利用してみました。
uv init
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv add "mcp[cli]" boto3 pydantic
最後に MCP Client から MCP Server へ到達できるよう、設定ファイルを編集します。私の場合は Roo Code を利用しているため、mcp_settings.json
を修正します。
{
"mcpServers": {
"bedrock-guardrails-mcp-server": {
"command": "uv",
"args": [
"--directory",
"ファイル置き場の絶対パス/amazon-bedrock-guardrails-mcp",
"run",
"main.py"
],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR",
"GUARDRAIL_ID": "rw2shyzgmcp6",
"GUARDRAIL_VERSION": "DRAFT",
"AWS_REGION": "ap-northeast-1",
"AWS_ACCESS_KEY_ID": "ASIAAAAAAAAAAAAAAAAA",
"AWS_SECRET_ACCESS_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"disabled": false,
"autoApprove": [],
"alwaysAllow": []
}
}
}
以下のように MCP サーバーが緑になっていれば OK です。
まずは、「bedrock-guardrails-mcp-server と会話してみたいです。」と入力してみました。
強制力は強くありませんが、Roo Code のプロンプト内に「デフォルトで bedrock-guardrails-mcp-server を経由してください
」などを入れておくのも良さそうです。
Guardrails の結果が返ってきましたが、エンコードされている様子でした。
調査していると FastMCP 側で ensure_ascii
が True の状態で出力されていたため、 False に設定します。(LLM 的には日本語を認識しているため、無理に行わなくても良さそうですが)
if not isinstance(result, str):
try:
+ result = json.dumps(pydantic_core.to_jsonable_python(result), ensure_ascii=False)
- result = json.dumps(pydantic_core.to_jsonable_python(result))
サーバーを再起動して再度実行すると、デコードされた状態で返ってきました!
最後に Guardrails で検出されるようなやりとりを想定します。想定通りブロックされていますね。
まとめ
以上、「Amazon Bedrock Guardrails の ApplyGuardrail API を MCP 経由で実行し EDR っぽく使ってみた」でした。
近い将来、このようなセキュリティ製品が出てきそうだなぁと思い、触りの部分だけ実装してみました。
このブログがどなたかの参考になれば幸いです。 クラウド事業本部コンサルティング部のたかくに(@takakuni_)でした!