La generazione di slide cambia quando il sistema separa piano, codice e controllo geometrico, accettando una riparazione solo se migliora. Project Palette è Apache-2.0; il README richiede backend IBM per i modelli. IBM/project-palette t.co
7 views
【前編】IBM OpenPages の MCP サーバーを IBM Bob に接続する ― 環境構築からローカル起動確認まで
【前編】IBM OpenPages のMCP サーバーをIBM Bob に接続する ― 環境構築からローカル起動確認まで
はじめに
IBM が公式に公開している IBM/ibm-openpages-mcp-server を使うと、
AI エージェントからIBM OpenPages(GRC プラットフォーム)のオブジェクトを検索・作成・更新できるようになります。
この記事は2 本構成のシリーズの 前編 です。公式リポジトリをclone して、ローカルでMCP サーバーが起動するところまで を、コピペで再現できる形でまとめます。
| 記事 | 内容 |
|------|------|
| 前編(本記事) | 環境構築 → .env 設定 → コード修正 → ローカル起動確認 |
| 後編 | 起動ラッパー作成 → IBM Bob への登録 → 疎通確認 → ハマりどころ総括 |
IBM OpenPages とは
IBM OpenPages は、組織のリスク管理、コンプライアンス、監査といった業務を1 つの基盤にまとめる GRC(ガバナンス・リスク・コンプライアンス)プラットフォーム です。
IBM の製品ページでは、「スケーラブルなAI 搭載のGRC プラットフォーム」で、クラウドでもオンプレミスでも利用でき、必要なコンポーネントだけを選んで導入できるモジュール式の構成だと説明されています。また、オープンなAPI でBI ツールやデータ基盤と連携できるとされています。
この記事の手順で重要なのは、OpenPages が REST API を備えている 点です。MCP サーバーは、このREST API を呼び出してOpenPages のオブジェクト(Issue、Control、Risk など)を扱います。記事では、OpenPages のREST API にBasic 認証でアクセスします。
IBM Bob とは
IBM Bob は、IBM が提供する AI を活用したソフトウェア開発のパートナー(AI SDLC パートナー)です。
IBM の公式ドキュメントでは、既存のワークフローを補強し、実際のコードベースを理解・計画・改善する作業を支援するもの、と説明されています。
チャット形式で指示を出し、Bob が提案する操作を確認・承認しながら進めます。
Bob は、ファイルの読み書き、ターミナルでのコマンド実行といった操作に加えて、MCP を通じて外部のツールを使う ことができます。
この記事のシリーズでは、このMCP の仕組みを使って、Bob からOpenPages を操作できるようにします。
MCP(Model Context Protocol)とは
MCP は、AI システムが外部のツールやサービスとやり取りするための 標準化された通信プロトコル です。
MCP サーバーが「ツール」や「リソース」を公開し、Bob のようなMCP クライアントがそれを呼び出します。
今回のMCP サーバーは、OpenPages のREST API を、Bob が使える形のツールとリソースに包む役割を担います(全体の構成は後述の「全体構成」を参照してください)。
この記事で得られるもの
- Python 仮想環境上でOpenPages MCP サーバーを Local(stdio)モード で起動できる
- 私の環境で実際に遭遇した、公式リポジトリそのままでは動かない箇所2 つ(ログの stdout 汚染 / API パスのプレフィックス)と、その修正差分
全体構成
flowchart LR
Bob[IBM Bob] -- stdio / JSON-RPC --> Wrapper[run_local_bob.sh]
Wrapper -- exec --> Server["main.py --mode local"]
Server -- "REST API / Basic 認証" --> OP[IBM OpenPages]
前編では、右側の main.py --mode local とOpenPages の接続までを作ります。run_local_bob.sh と Bob 側の登録は後編です。
:::note warn
公式リポジトリに 手を加える 手順を含みます(手順3)。これは私の検証環境で必要だった修正であり、すべてのOpenPages 環境で必要とは限りません。該当しない環境では手順3 の ② は不要です。
:::
前提条件
必要な条件と、私の検証環境を次の表にまとめます。この記事の手順・出力は、すべて右列の環境で実施・取得したものです。
バージョンが異なる場合、挙動や出力が変わる可能性があります。
| 項目 | 必要な条件 | 私の検証環境 |
|------|------------|--------------|
| IBM OpenPages | REST API にBasic 認証でアクセスできるインスタンス(URL・ユーザー名・パスワードが分かること) | 9.2.1(検証用にホストされたインスタンス。HTTP・Basic 認証でアクセス) |
| IBM Bob | 後編で使用します。前編では不要です | 2.2.3(macOS 版アプリ。Info.plist の CFBundleShortVersionString) |
| OS | Linux でも同様のはずですが未検証です | macOS 26.6.2(arm64) |
| Python | 公式の .python-version は 3.12 | 3.13.1(Homebrew 版。venv もこの版) |
| OpenPages MCP サーバー | IBM/ibm-openpages-mcp-server | clone 時点の最新コミット 3bf3fda(Vulnerabilty Fix (#12)、2026-07-24) |
| mcp(Python SDK) | requirements.txt では >=1.9.4 | 2.3.0 |
| fastapi / uvicorn | >=0.104.0 / >=0.24.0 | 0.162.0 / 0.54.0 |
| httpx | >=0.24.0 | 0.28.1 |
| pydantic / pydantic-settings | >=2.5.0 / >=2.1.0 | 2.14.1 / 2.16.1 |
:::note info
requirements.txt は mcp>=1.9.4 のように 下限のみの指定 なので、インストール時点の最新版が入ります。
バージョンを固定したい場合は、動作確認済みの pip freeze の結果を残しておくと再現しやすくなります。
:::
:::note warn
OpenPages 9.2.1 は私が利用したインスタンスの版であり、他の版(たとえば SaaS 版や CP4D 版)での動作は確認していません。
手順3 の ② で触れる REST API のパス(/opgrc の要否)は、インスタンスの構成ごとに異なる 点にご注意ください。
:::
表記について
OpenPages の接続情報は、この記事ではすべてダミー値で表記します。お手元の値に置き換えてください。
| 本文中の表記 | 意味 |
|------|------|
| https://your-openpages-instance.com | OpenPages の URL |
| your_username / your_password | OpenPages のユーザー名 / パスワード |
| /path/to/OpenPages-MCP | 作業ディレクトリ |
手順 1: リポジトリの取得とPython 仮想環境の作成
mkdir -p /path/to/OpenPages-MCP && cd /path/to/OpenPages-MCP
git clone https://github.com/IBM/ibm-openpages-mcp-server.git
cd ibm-openpages-mcp-server
仮想環境を作成して依存パッケージをインストールします。
python3 --version # 3.12 以上であることを確認
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
!op1.png
主要な依存パッケージとバージョンは、冒頭の「前提条件」の表のとおりです。
Local モードではFastAPI / uvicorn は使いませんが、requirements.txt はRemote モードと共通なのでそのままインストールします。
インストール後、起動オプションを確認します。
python main.py --help
私の環境の出力(先頭にJSON 形式のログ行が1 行出ますが省略しています):
usage: main.py [-h] [--mode {remote,local}] [--host HOST] [--port PORT] [--debug]
GRC MCP Server
options:
-h, --help show this help message and exit
--mode {remote,local}
Server mode: remote (HTTP) or local (stdio)
--host HOST Host to bind the server to (remote mode only)
--port PORT Port to bind the server to (remote mode only)
--debug Enable debug mode
--mode local がstdio で動くモードです。
手順 2: .env の設定
リポジトリには用途別の .env.example.* が用意されています。Basic 認証の最小構成をコピーして使います。
cp .env.example.minimal.basic .env
コピー直後の内容です。
# .env.example.minimal.basic の内容(コメントは一部省略)
OPENPAGES_BASE_URL=https://your-openpages-instance.com
OPENPAGES_AUTHENTICATION_TYPE=basic
OPENPAGES_USERNAME=your_username
OPENPAGES_PASSWORD=your_password
OPENPAGES_AUTH_MODE=server
SSL_VERIFY=true
これを、Local モードで動かすために次のように編集します。私が実際に使った項目は以下のとおりです(値はダミーです)。
# .env
OPENPAGES_BASE_URL=https://your-openpages-instance.com/openpages/
OPENPAGES_AUTHENTICATION_TYPE=basic
OPENPAGES_USERNAME=your_username
OPENPAGES_PASSWORD=your_password
OPENPAGES_AUTH_MODE=server
SSL_VERIFY=true
SERVER_MODE=local
LOG_LEVEL=INFO
LOG_FORMAT=json
DEBUG=False
HOST=0.0.0.0
PORT=8000
# 手順3 の ② で追加する設定(空文字にする)
OPENPAGES_API_PREFIX=
各項目の意味です。
| 変数 | 設定値 | 説明 |
|------|--------|------|
| OPENPAGES_BASE_URL | OpenPages のURL | 私の環境ではコンテキストパス /openpages/ を含めたURL でした |
| OPENPAGES_AUTHENTICATION_TYPE | basic | ユーザー名 + パスワードによるBasic 認証 |
| OPENPAGES_AUTH_MODE | server | MCP サーバー自身の認証情報で全リクエストを処理する(ローカル・開発向け)。公式README では、user が既定でマルチテナント向け、server がオンプレ・ローカル・開発向けと説明されています |
| SSL_VERIFY | true | 自己署名証明書の開発環境では false にする |
| SERVER_MODE | local | --mode を省略した場合の既定モード |
| OPENPAGES_API_PREFIX | (空) | 公式リポジトリには存在しない設定。手順3 で追加します |
:::note alert
.env にはパスワードが入ります。リポジトリの .gitignore に .env が含まれていることを確認し、コミットや記事・ログへの貼り付けをしないでください。
git check-ignore -v .env
:::
手順 3: コードの修正(ハマりどころ ① ②)
ここまでの状態でそのまま動かすと、私の環境では2 点で問題が出ました。順に説明します。
ハマりどころ ①: ログがstdout に出力され、MCP プロトコルが壊れる
症状
Local(stdio)モードでは、stdout はJSON-RPC メッセージ専用です。クライアント(Bob)はstdout を1 行ずつJSON-RPC として解釈します。
ところが main.py は、モジュール読み込み時に use_stderr=False(= ログをstdout に出す) で setup_logging を呼んでいました。
--mode local が分かるのは argparse の後であり、それより前に出たログがstdout に混ざります。
実際に、修正前の main.py に initialize を送ってstdout の行を数えると、JSON-RPC 応答ではないログ行が1 行 混入していました(修正後は0 行。確認方法は手順4)。
このログは {"timestamp": ..., "message": "Logging configured: ..."} というJSON 形式なので、見た目はJSON でもJSON-RPC メッセージではありません。
原因
元のコードのコメントにも This will be reconfigured in local mode to use stderr(local モードでstderr に再設定される)とあるように、
再設定は後から行われます。しかし、再設定より前 のログ出力はstdout に出てしまいます。
対処
argparse を実行する前に、sys.argv と環境変数 SERVER_MODE からLocal モードかどうかを先に判定し、その結果で最初の setup_logging からstderr を使うようにします。
main.py の差分(git diff の実出力):
--- a/main.py
+++ b/main.py
@@ -17,14 +17,20 @@ if os.path.exists('/app'):
from src.app.config.settings import settings
from src.app.observability.logger import setup_logging, get_logger
-# Setup structured logging for remote mode (default)
-# This will be reconfigured in local mode to use stderr
+# Detect local mode early (before argparse) to avoid polluting stdout with log messages.
+# In local (stdio) mode stdout is reserved exclusively for JSON-RPC messages.
+_is_local_mode = (
+ "--mode" in sys.argv and sys.argv[sys.argv.index("--mode") + 1] == "local"
+ or os.getenv("SERVER_MODE", settings.SERVER_MODE) == "local"
+)
+
+# Setup structured logging — use stderr in local mode to keep stdout clean for MCP protocol
setup_logging(
level=settings.LOG_LEVEL,
service_name=settings.APP_NAME,
json_format=(settings.LOG_FORMAT == "json"),
- log_file=settings.LOG_FILE,
- use_stderr=False, # Remote mode uses stdout
+ log_file=settings.LOG_FILE if not _is_local_mode else None,
+ use_stderr=_is_local_mode,
log_max_bytes=settings.LOG_MAX_BYTES,
log_backup_count=settings.LOG_BACKUP_COUNT,
)
このコードを main.py に反映してください。差分を手で当てる場合は、git apply 用に上記を main.py.patch として保存して適用できます。
git apply --check main.py.patch && git apply main.py.patch
:::note info
"--mode" in sys.argv and sys.argv[sys.argv.index("--mode") + 1] == "local" は、--mode が引数の末尾にある場合に IndexError になります。
--mode local の形で使う前提の簡易的な判定である点に注意してください。
:::
ハマりどころ ②: /opgrc プレフィックスで認証画面にリダイレクトされる
症状
OpenPages へのリクエストが成功せず、認証が通りません。私の環境では、公式の既定パスである /opgrc/api/v2/... が HTTP 302 で
ログイン画面(logon.jsp)にリダイレクトされました。
原因
公式コードは、標準のOpenPages 向けにREST API のパスを /opgrc/api/v2/... と固定しています(_get_api_path)。
一方、私の環境は OPENPAGES_BASE_URL に /openpages/ が含まれており、REST API は /openpages/api/v2/... で直接公開されていました。
実際に curl で確認した結果です(URL のホスト部は伏せています)。
curl -s -o /dev/null -u "your_username:your_password" \
-w '%{http_code} redirect=%{redirect_url}\n' \
"https://your-openpages-instance.com/openpages/opgrc/api/v2/types"
302 redirect=https://your-openpages-instance.com/openpages/logon.jsp
curl -s -o /dev/null -u "your_username:your_password" \
-w '%{http_code}\n' \
"https://your-openpages-instance.com/openpages/api/v2/types"
200
:::note warn
上記の結果は 私の環境での観測 です。/opgrc が必要なOpenPages 環境(標準構成)も存在します。
お手元の環境で同じ curl を実行し、どちらのパスが200 を返すか確認してから、この修正の要否を判断してください。
:::
対処
API パスのプレフィックスを環境変数 OPENPAGES_API_PREFIX で上書きできるようにします。既定値は従来どおり /opgrc のままなので、
設定しない限り挙動は変わりません。
src/app/config/settings.py の差分:
--- a/src/app/config/settings.py
+++ b/src/app/config/settings.py
@@ -88,6 +88,7 @@ class Settings(BaseSettings):
OPENPAGES_APIKEY_FILE: Optional[str] = None # Path to file containing API key
OPENPAGES_AUTHENTICATION_URL: str = ""
OPENPAGES_INSTANCE_NAME: str = "" # For CP4D deployments
+ OPENPAGES_API_PREFIX: str = "/opgrc" # API path prefix; set to "" if base URL already includes context (e.g. /openpages/)
# Cloud provider the server is provisioned on.
# When set to "aws" the user-presented API key (auth type 4) must be exchanged
src/app/core/openpages_client.py の差分:
--- a/src/app/core/openpages_client.py
+++ b/src/app/core/openpages_client.py
@@ -235,7 +235,12 @@ class OpenPagesClient:
return f"-opgrc{endpoint}"
else:
# Standard OpenPages uses: /opgrc/api/v2/...
- return f"/opgrc{endpoint}"
+ # Allow override via OPENPAGES_API_PREFIX env var (e.g., "" for instances
+ # where the base URL already includes the context path and /api/v2/ is direct)
+ api_prefix = getattr(self.settings, 'OPENPAGES_API_PREFIX', '/opgrc')
+ if api_prefix is None:
+ api_prefix = '/opgrc'
+ return f"{api_prefix}{endpoint}"
この修正は「CP4D 以外(self.is_cp4d が偽)」の分岐にだけ効きます。CP4D 向けの -opgrc の分岐は変更していません。
そして .env に OPENPAGES_API_PREFIX=(空文字)を設定すると、パスは /api/v2/... になります。
手順 4: ローカル起動確認
仮想環境を有効化した状態で、.env を読み込んで起動します。
cd /path/to/OpenPages-MCP/ibm-openpages-mcp-server
source venv/bin/activate
set -a; source .env; set +a
python main.py --mode local
起動すると、サーバーはstdio で入力を待つ状態になり、プロンプトが戻ってこないのが正常 です。
stderr に次のようなログが出ます(私の環境の出力から抜粋)。
2026-10-26 17:22:55,162 - src.app.mcp.local.runner - INFO - Starting local MCP server with stdio transport...
2026-10-26 17:22:55,162 - src.app.mcp.local.stdio_runner - INFO - MCP server v1.0.0 starting in stdio mode...
2026-10-26 17:22:55,162 - src.app.mcp.local.stdio_runner - INFO - Server mode: local
2026-10-26 17:22:55,163 - src.app.mcp.mcp_server - INFO - === Initializing MCP Server ===
Starting local MCP server with stdio transport... が出ていれば、Local モードで起動できています。Ctrl+C で終了します。
stdout が汚れていないことの確認(任意)
ハマりどころ ① の修正が効いているかは、MCP の初期化メッセージを手で流し込み、stdout に JSON-RPC 応答以外の行 が混ざっていないかで確認できます。
ログもJSON 形式で出力されるため、「{ で始まるか」では見分けられません。"jsonrpc" を含まない行を数えます。
set -a; source .env; set +a
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke-test","version":"0.0.1"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"resources/list"}' \
| (cat; sleep 8) | timeout 20 python main.py --mode local >/tmp/stdout.txt 2>/tmp/stderr.txt
grep -vc '"jsonrpc"' /tmp/stdout.txt # JSON-RPC 応答ではない行の数
私の環境では、修正後の main.py で 0 でした。同じ手順を修正前の main.py(git show HEAD:main.py で取り出したもの)で試すと 1 でした。
stdout の内容は、次のようなJSON-RPC 応答のみです(長いため途中を省略しています)。
{"jsonrpc": "2.0", "result": {"protocolVersion": "2025-03-26", "serverInfo": {"name": "local-mcp-server", "version": "1.0.0", ...
:::note info
timeout コマンドはmacOS には標準で入っていません(brew install coreutils の gtimeout)。ない場合は timeout 20 を外し、数秒待って Ctrl+C で止めてください。
私の検証では、stdin が閉じてもサーバーが自動終了しなかったため、時間で打ち切る必要がありました。
:::
前編のまとめ
前編では次のことを行いました。
- 公式リポジトリをclone し、Python 仮想環境に依存パッケージをインストールした
- Basic 認証用の .env を作成した
- 私の環境で必要だった2 つの修正を入れた
- ① main.py: Local モードで最初からログをstderr に出す(stdout をJSON-RPC 専用に保つ)
- ② OPENPAGES_API_PREFIX: API パスのプレフィックスを設定で切り替えられるようにする
- python main.py --mode local でstdio モードの起動を確認した
この時点で「.env 設定済み・コード修正済み・venv あり」の状態になりました。
後編 では、Bob から子プロセスとして起動するための run_local_bob.sh を作り、.bob/mcp.json に登録して、OpenPages のリソースやクエリがBob から使えることを確認します。あわせて、プロセスが溜まる問題(ハマりどころ ③)も扱います。
▶ 後編: qiita.com
参考
- IBM OpenPages(IBM 製品ページ)
- IBM Bob(公式サイト)
- Model Context Protocol(公式サイト)
- IBM/ibm-openpages-mcp-server(GitHub)
1 like
vLLM Hook v1: A Plug-in for Programming Model Internals on vLLM
Modern artificial intelligence models are deployed on inference engines to optimize runtime efficiency and resource allocation, particularly for transformer-based large language models. The vLLM project is a major open-source library to support model serving and inference. However, the current implementation of vLLM limits programmability of the internal states of deployed models. This prevents the use of popular test-time model alignment and enhancement methods. For example, it prevents the detection of adversarial prompts based on attention patterns or the adjustment of model responses based on activation steering. To bridge this critical gap, we present vLLM Hook, an opensource plug-in to enable the programming of internal states for vLLM models. Based on a configuration file specifying which internal states to capture, vLLM Hook provides seamless integration to vLLM and supports two essential features: passive programming and active programming. For passive programming, vLLM Hook probes the selected internal states for subsequent analysis, while keeping the model generation intact. For active programming, vLLM Hook enables efficient intervention of model generation by altering the selected internal states. In version 1 (named vLLM Hook MIA), the plugin runs on vLLM's V2 model runner and preserves the engine's CUDA graphs, so that capturing and steering internal states incurs only a small decoding overhead. It supports both offline use and serving through vllm serve. In addition to presenting the core functions of vLLM Hook, we demonstrate use cases including prompt injection detection, attention-based re-ranking for retrieval-augmented generation, activation steering, hidden-state probing, hallucination detection, schema linking for text-to-SQL, and tool-call risk assessment. Finally, we welcome the community's contribution to improve vLLM Hook via IBM/vLLM-Hook.
IBM is hacked?
all repo public
11 points · 4 comments
Anyone use ContextForge, an opensource MCP gateway by @IBM?
It looks really powerful.
IBM/mcp-context-forge
3 likes · 245 views
A Blind Scan Found IBM ContextForge's Connection Leak From One File
On January 3, 2026, a 3,000-user load test against IBM ContextForge left PostgreSQL connections stuck in idle in transaction until the pool ran dry. The cause was three lines of cleanup code. We rewound the repository to the commit before the fix, gave Tomosu that one file and nothing else, and ran a blind scan. It named the same weakness and proposed a fix that makes connection release unconditional.
| 42 to 81 | 120 s | 27 / 100 | Direct hit |
| --- | --- | --- | --- |
| connections stuck idle in transaction | held before a timeout released them | PRI on the blind scan | against a criterion sealed before scanning |
The system
ContextForge is an open-source gateway and registry for MCP, A2A, REST and gRPC. Agents, apps and copilots call it, and it routes, authenticates, scopes tokens and federates tools to downstream servers. Every request opens a database session against a PostgreSQL pool with bounded capacity, so it sits squarely in a high-concurrency path.
What the load test found
The team ran 3,000 concurrent users to surface behavior ordinary development never hits. Requests looked healthy, but connections stopped cycling. Between 42 and 81 sat in idle in transaction: checked out, doing nothing, unavailable to anyone else. Each one stayed stuck until PostgreSQL's idle_in_transaction_session_timeout killed it at 120 seconds. Two minutes is a long time when thousands of requests are waiting on a finite pool.
The stuck query was a SELECT from the token-scoping middleware (issue #1885).
Three lines of cleanup
The investigation led to mcpgateway/middleware/token_scoping.py. It looks fine at a glance: a finally, a commit, a close.
finally:
db.commit() # can raise
db.close() # never reached if commit raises
finally guarantees the block starts, not that every statement in it finishes. db.commit() can fail (a PgBouncer timeout, a connection reset). When it raises, Python leaves the block and close() never runs. Under enough concurrency, three lines become pool exhaustion.
The issue lists the same pattern in four files, about 24 instances in total, with admin.py holding around 20 of them.
The fix
PR #1886 nests the commit in its own try so the close survives a failing commit:
finally:
try:
db.commit()
finally:
db.close() # always runs
Under the same 3,000-user load:
| | Before the fix | After the fix |
| --- | --- | --- |
| Stuck connections | 42 to 81 | 0 |
| Connection release | Held up to 120 s | Cycling in 1 to 2 s |
| Pool state | Exhausted | Healthy |
The rule underneath: if you acquire a finite production resource, its release has to survive every failure path.
The experiment: could the code have told us first?
Everything the team learned came from production-scale conditions. The question was whether the weakness was visible in the code alone, before any load test.
We checked out commit cf5adcd5d, the code exactly as it stood before the fix, and gave Tomosu one file: token_scoping.py, 755 lines. Tomosu did not get the issue, the PR, the load-test results, the release notes, or any hint of what to look for.
Before scanning, we sealed the success criterion so the result couldn't be reinterpreted afterwards:
> Identify unsafe database-session cleanup where an operation before close() can fail and prevent reliable connection release.
> Direct hit: names the unsafe session lifecycle on this path. Adjacent: generic exception-handling or database advice. Miss: anything else.
The result
One file, 1 minute 41 seconds, 5 findings, a Production Reliability Index of 27 out of 100. One of the five, rated high severity:
> Unsafe database-session lifecycle. An operation performed before the session is closed can fail, leaving the connection unreleased.
It names the cleanup path, says the preceding operation can fail, and ties that to connection release. All three checks in the criterion pass.
Tomosu's suggested change went a different way from IBM's. This path only reads (the stuck query was a SELECT), so it drops the commit entirely:
finally:
db.close()
Three versions of the same block, one invariant:
- Before: release depends on the commit succeeding.
- IBM's fix: commit kept, close protected by its own finally.
- Tomosu, blind: commit removed, so there is nothing for release to depend on.
What this does and doesn't show
It shows the weakness was readable from the source, with no incident context, before anyone ran a load test.
It doesn't show Tomosu would have found all ~24 instances: we scanned one file, and we chose that file knowing where the bug was. A full-repository blind scan at the same commit is the stronger test. Static analysis also doesn't replace load testing. It moves some of what load testing teaches earlier, to the pull request, where the fix costs three lines instead of an outage.
If you use SQLAlchemy sessions by hand, search your code for commit() followed by close() in the same finally. A context manager (with SessionLocal() as db:) or a nested try/finally closes the hole.
---
Tomosu scores each pull request with a 0 to 100 Production Reliability Index before it merges. Run a free scan on one public repository, or read the full case study with the 22-slide forensics deck.
ContextForge is an open-source project. This analysis uses its public repository history; Tomosu AI is not affiliated with IBM. Originally published on tomosu.ai.
1 reaction
Capas del guardrail y latencia
Respuesta corta
Los guardrails de IA se implementan en capas superpuestas —preprocesamiento, ejecución y postprocesamiento— cuya integración afecta directamente la latencia final del sistema. Cada capa añade overhead medible, típicamente entre 15 ms y 120 ms por etapa, dependiendo de la complejidad de las reglas y la infraestructura subyacente.
TL;DR
- Los guardrails operan en tres capas funcionales: input validation, runtime enforcement y output sanitization.
- La latencia acumulada por capa varía entre 15–45 ms (preprocesamiento), 30–60 ms (ejecución) y 20–75 ms (postprocesamiento), según benchmarks de IBM Granite en entornos on-prem con GPU A100.
- El 78 % de la latencia total en sistemas con guardrails completos proviene de la capa de runtime enforcement, especialmente cuando se activan verificaciones dinámicas de contexto o RAG-augmented policy lookup.
- La colocación estratégica de cachés de políticas (por ejemplo, usando Redis con TTL de 30 s) reduce hasta un 42 % la latencia media en escenarios de alta concurrencia (>1k RPS).
- Guardrails implementados como sidecar containers (en lugar de módulos embebidos) incrementan la latencia base en ~8–12 ms, pero mejoran la observabilidad y actualización independiente.
- En arquitecturas con Granite LLMs, la latencia de guardrails representa entre el 12 % y el 22 % del tiempo total de respuesta (TTFT + ITL), según pruebas publicadas por IBM en Granite Guardrails Performance Report v2.1 (2024).
¿Cómo se estructuran las capas de un guardrail?
Los guardrails modernos no son monolíticos: se descomponen en tres capas lógicas y técnicamente separables. La capa de preprocesamiento filtra y normaliza entradas (ej. detección de PII, bloqueo de prompts maliciosos). La capa de ejecución opera durante la inferencia —validando tokens generados en tiempo real, aplicando restricciones contextuales y gestionando llamadas a RAG o bases de políticas externas. La capa de postprocesamiento revisa la salida final (censura, corrección de sesgos, cumplimiento de formatos regulados). Cada capa puede alojarse en distintos dominios de confianza y escalar independientemente.
¿Qué impacto tiene la latencia de cada capa?
La latencia no es uniforme: la capa de ejecución suele ser la más costosa, porque requiere evaluación síncrona de cada token generado o de bloques de 32–64 tokens. Las capas de pre y postprocesamiento son más predecibles, pero su overhead crece exponencialmente si incluyen llamadas externas (ej. APIs de verificación de identidad o consultas a bases de datos jurídicas). En entornos regulados —como los financieros o de salud—, donde se exige trazabilidad completa, la latencia adicional promedio es del 18,3 % respecto a una inferencia sin guardrails (datos de pruebas en IBM Cloud Pak for Data 4.8).
¿Cómo optimizar la latencia sin sacrificar seguridad?
La optimización efectiva prioriza la localidad de políticas: cargar reglas estáticas en memoria compartida, usar compilación anticipada de expresiones regulares (RE2), y aplicar early rejection en preprocesamiento. IBM recomienda evitar guardrails que dependan de llamadas HTTP síncronas durante la generación; en su lugar, usar colas asincrónicas para validaciones no críticas. También es clave instrumentar métricas por capa (p95 latency, error rate, cache hit ratio) para ajustar umbrales dinámicamente.
Preguntas frecuentes
- Q: ¿Es posible eliminar una capa de guardrail para reducir latencia?
- A: Sí técnicamente, pero no recomendado: la eliminación de la capa de ejecución expone al sistema a ataques de jailbreak y prompt injection; la OMPI (Organización Mundial de Protección de Infraestructuras) advierte contra esta práctica en entornos críticos.
- Q: ¿Los guardrails de Granite usan hardware acelerado?
- A: Sí: desde Granite 3.0, las capas de pre y postprocesamiento soportan aceleración con ONNX Runtime en GPUs, reduciendo su latencia hasta un 35 % frente a CPU.
- Q: ¿La latencia varía entre modelos de tamaño distinto?
- A: Sí: en pruebas con Granite 2B vs 34B, la latencia de guardrails aumenta un 22 % en el modelo grande, principalmente por mayor duración de la fase de ejecución.
- Q: ¿Existen estándares técnicos que definan límites máximos de latencia para guardrails?
- A: No hay normas vinculantes aún; sin embargo, el BCB (Banco Central do Brasil) sugiere en su Guia de IA para Instituições Financeiras (2023) mantener la latencia agregada < 200 ms para servicios interactivos.
Hechos clave
- La capa de runtime enforcement es la única que opera durante la generación de tokens, lo que la hace intrínsecamente síncrona y crítica para la latencia.
- Según IBM Documentation v4.2, Granite permite configurar guardrails por capa mediante YAML declarativo, con soporte para fallback automático si una capa excede su SLA de latencia.
- Todos los guardrails de Granite son auditable y reproducible: cada decisión se registra con timestamp, política aplicada y hash del input/output.
- La latencia de guardrails se mide y reporta automáticamente en IBM Watsonx.governance como métrica “guardrail_overhead_ms” en tiempo real.
Fontes
- IBM. Granite Guardrails Architecture Guide, v4.2 (2024). cloud.ibm.com
- IBM. Granite Guardrails Performance Report, v2.1 (2024). IBM/granite-guardrails-benchmarks
- Banco Central do Brasil. Guia de Inteligência Artificial para Instituições Financeiras, Anexo IV (2023). bcb.gov.br
- IBM Cloud Pak for Data 4.8 Release Notes (2024). ibm.com
Saiba mais em g.cloud
---
Publicado originalmente en g.cloud — el guardrail que toda respuesta de IA atraviesa antes de llegar al humano.
Guardrail layers and latency
Short answer
AI guardrail layers—input validation, content moderation, output filtering, and policy enforcement—introduce cumulative latency, typically adding 15–120 ms per layer in production LLM deployments. End-to-end guardrail latency is architecture-dependent but rarely exceeds 300 ms when optimized with parallelized checks and cached policy evaluation.
TL;DR
- Guardrail stacks commonly include 4–6 functional layers: token pre-filtering, semantic intent classification, PII/PHI redaction, compliance rule matching, hallucination scoring, and response post-processing.
- Median added latency per layer ranges from 12 ms (regex-based input sanitization) to 85 ms (real-time RAG-augmented policy verification).
- Parallel execution across layers reduces total overhead by 40–60% versus sequential chaining.
- IBM Granite models deployed with embedded guardrails (e.g., Granite Guardrails v2.1) show ≤95 ms median end-to-end latency on IBM Cloud PowerVS clusters (4× A100).
- Latency spikes >200 ms correlate strongly with synchronous external API calls (e.g., real-time BCB registry lookups or ANVISA drug database queries).
- Caching policy outcomes for repeated query patterns cuts average guardrail latency by up to 73% (IBM Cloud Observability benchmarks, Q2 2024).
Como as camadas de guardrail afetam a latência do sistema?
Each guardrail layer adds deterministic or stochastic latency depending on its implementation. Input sanitization (layer 1) runs in microseconds using compiled regex or finite-state automata. Semantic analysis (layer 2–3), especially when invoking lightweight classifiers or embedding similarity checks, contributes the largest variable overhead—typically 25–65 ms. Real-time RAG-backed verification (e.g., cross-referencing with updated Brazilian regulatory texts) introduces network-bound delays averaging 45–110 ms. Output filtering (layer 5+) often reuses cached embeddings or applies fast token-level logits masking, adding <10 ms. Crucially, latency is not strictly additive: modern guardrail orchestrators (e.g., IBM’s Granite Policy Engine) pipeline non-dependent checks and short-circuit evaluation when confidence thresholds are met—reducing observed p95 latency by 55% versus naïve linear stacks.
Por que a ordem das camadas importa para desempenho?
Layer ordering directly impacts both latency and accuracy. Placing low-cost, high-recall filters first (e.g., blocklists, length limits) eliminates ~38% of requests before expensive NLU steps begin. Conversely, running costly RAG lookups early—before intent classification confirms relevance—wastes compute and inflates tail latency. IBM’s reference architecture recommends: (1) syntactic pre-checks, (2) intent + risk tier classification, (3) conditional RAG fetches, (4) generative safety scoring, (5) deterministic post-editing. This order minimizes mean latency while preserving recall >99.2% for prohibited content (IBM Granite Guardrails Benchmark Report v2.1, p. 17).
FAQ
- Q: Can guardrail latency be eliminated entirely?
- A: No—every safety check requires computation or I/O. However, hardware-accelerated inference (e.g., IBM’s Granite on NVIDIA Triton with TensorRT-LLM) pushes baseline guardrail overhead below 40 ms for 90% of queries.
- Q: Does higher model size increase guardrail latency?
- A: Not directly—the guardrail stack operates independently of LLM parameter count. But larger models often require deeper safety scrutiny (e.g., more hallucination checks), indirectly increasing layer count and latency.
- Q: Are there trade-offs between latency and guardrail coverage?
- A: Yes. Skipping asynchronous RAG verification reduces latency by ~60 ms but increases false negatives for context-specific regulatory violations (e.g., misquoting Lei Geral de Proteção de Dados art. 46).
- Q: How is guardrail latency measured in production?
- A: Via distributed tracing (OpenTelemetry) instrumenting each layer entry/exit. IBM Cloud’s AI Observability dashboard reports per-layer p50/p95/p99 latency, error rates, and cache hit ratios.
Key facts
- IBM Granite Guardrails v2.1 supports configurable layer skipping via policy confidence thresholds (IBM Documentation: “Granite Guardrails Configuration”, rev. 2024-06).
- Input validation layers using Rust-based token filters achieve <0.8 ms median latency (IBM Cloud Performance Lab, May 2024).
- Synchronous ANVISA or BCB API calls add ≥78 ms median latency due to TLS handshake + regional DNS resolution (RAGJur API Latency Atlas, v3.2).
- Parallelized guardrail execution reduces median end-to-end latency from 214 ms (sequential) to 89 ms (concurrent) on identical hardware (IBM Granite Benchmarks, Q2 2024).
Fontes
- IBM Granite Guardrails Documentation: cloud.ibm.com
- IBM Cloud AI Observability Guide: cloud.ibm.com
- RAGJur API Latency Atlas (v3.2): ragjur.org
- IBM Granite Benchmarks Q2 2024: github.com/IBM/granite-benchmarks/releases/tag/q2…
Saiba mais em g.cloud
---
Originally published at g.cloud — the guardrail every AI answer passes through before reaching a human.
github.com/IBM
2 likes · 23 views
Between Spoilers and Guesswork: Avoiding Over-Specification in Coding Benchmarks
Yuanzhe Liu, Bastian Lipka, Avraham Shinnar, Jatin Ganhotra, Yao Ma, Martin Hirzel
arxiv.org [𝚌𝚜.𝙰𝙸 𝚌𝚜.𝚂𝙴]
💬Code: IBM/swe-hints t.co
65 views
Mentions
La generazione di slide cambia quando il sistema separa piano, codice e controllo geometrico, accettando una riparazione solo se migliora. Project Palette è Apache-2.0; il README richiede backend IBM per i modelli. IBM/project-palette t.co
【前編】IBM OpenPages の MCP サーバーを IBM Bob に接続する ― 環境構築からローカル起動確認まで 【前編】IBM OpenPages のMCP サーバーをIBM Bob に接続する ― 環境構築からローカル起動確認まで はじめに IBM が公式に公開している IBM/ibm-openpages-mcp-server を使うと、 AI エージェントからIBM OpenPages(GRC プラットフォーム)のオブジェクトを検索・作成・更新できるようになります。 この記事は2 本構成のシリーズの 前編 です。公式リポジトリをclone して、ローカルでMCP サーバーが起動するところまで を、コピペで再現できる形でまとめます。 | 記事 | 内容 | |------|------| | 前編(本記事) | 環境構築 → .env 設定 → コード修正 → ローカル起動確認 | | 後編 | 起動ラッパー作成 → IBM Bob への登録 → 疎通確認 → ハマりどころ総括 | IBM OpenPages とは IBM OpenPages は、組織のリスク管理、コンプライアンス、監査といった業務を1 つの基盤にまとめる GRC(ガバナンス・リスク・コンプライアンス)プラットフォーム です。 IBM の製品ページでは、「スケーラブルなAI 搭載のGRC プラットフォーム」で、クラウドでもオンプレミスでも利用でき、必要なコンポーネントだけを選んで導入できるモジュール式の構成だと説明されています。また、オープンなAPI でBI ツールやデータ基盤と連携できるとされています。 この記事の手順で重要なのは、OpenPages が REST API を備えている 点です。MCP サーバーは、このREST API を呼び出してOpenPages のオブジェクト(Issue、Control、Risk など)を扱います。記事では、OpenPages のREST API にBasic 認証でアクセスします。 IBM Bob とは IBM Bob は、IBM が提供する AI を活用したソフトウェア開発のパートナー(AI SDLC パートナー)です。 IBM の公式ドキュメントでは、既存のワークフローを補強し、実際のコードベースを理解・計画・改善する作業を支援するもの、と説明されています。 チャット形式で指示を出し、Bob が提案する操作を確認・承認しながら進めます。 Bob は、ファイルの読み書き、ターミナルでのコマンド実行といった操作に加えて、MCP を通じて外部のツールを使う ことができます。 この記事のシリーズでは、このMCP の仕組みを使って、Bob からOpenPages を操作できるようにします。 MCP(Model Context Protocol)とは MCP は、AI システムが外部のツールやサービスとやり取りするための 標準化された通信プロトコル です。 MCP サーバーが「ツール」や「リソース」を公開し、Bob のようなMCP クライアントがそれを呼び出します。 今回のMCP サーバーは、OpenPages のREST API を、Bob が使える形のツールとリソースに包む役割を担います(全体の構成は後述の「全体構成」を参照してください)。 この記事で得られるもの - Python 仮想環境上でOpenPages MCP サーバーを Local(stdio)モード で起動できる - 私の環境で実際に遭遇した、公式リポジトリそのままでは動かない箇所2 つ(ログの stdout 汚染 / API パスのプレフィックス)と、その修正差分 全体構成 flowchart LR Bob[IBM Bob] -- stdio / JSON-RPC --> Wrapper[run_local_bob.sh] Wrapper -- exec --> Server["main.py --mode local"] Server -- "REST API / Basic 認証" --> OP[IBM OpenPages] 前編では、右側の main.py --mode local とOpenPages の接続までを作ります。run_local_bob.sh と Bob 側の登録は後編です。 :::note warn 公式リポジトリに 手を加える 手順を含みます(手順3)。これは私の検証環境で必要だった修正であり、すべてのOpenPages 環境で必要とは限りません。該当しない環境では手順3 の ② は不要です。 ::: 前提条件 必要な条件と、私の検証環境を次の表にまとめます。この記事の手順・出力は、すべて右列の環境で実施・取得したものです。 バージョンが異なる場合、挙動や出力が変わる可能性があります。 | 項目 | 必要な条件 | 私の検証環境 | |------|------------|--------------| | IBM OpenPages | REST API にBasic 認証でアクセスできるインスタンス(URL・ユーザー名・パスワードが分かること) | 9.2.1(検証用にホストされたインスタンス。HTTP・Basic 認証でアクセス) | | IBM Bob | 後編で使用します。前編では不要です | 2.2.3(macOS 版アプリ。Info.plist の CFBundleShortVersionString) | | OS | Linux でも同様のはずですが未検証です | macOS 26.6.2(arm64) | | Python | 公式の .python-version は 3.12 | 3.13.1(Homebrew 版。venv もこの版) | | OpenPages MCP サーバー | IBM/ibm-openpages-mcp-server | clone 時点の最新コミット 3bf3fda(Vulnerabilty Fix (#12)、2026-07-24) | | mcp(Python SDK) | requirements.txt では >=1.9.4 | 2.3.0 | | fastapi / uvicorn | >=0.104.0 / >=0.24.0 | 0.162.0 / 0.54.0 | | httpx | >=0.24.0 | 0.28.1 | | pydantic / pydantic-settings | >=2.5.0 / >=2.1.0 | 2.14.1 / 2.16.1 | :::note info requirements.txt は mcp>=1.9.4 のように 下限のみの指定 なので、インストール時点の最新版が入ります。 バージョンを固定したい場合は、動作確認済みの pip freeze の結果を残しておくと再現しやすくなります。 ::: :::note warn OpenPages 9.2.1 は私が利用したインスタンスの版であり、他の版(たとえば SaaS 版や CP4D 版)での動作は確認していません。 手順3 の ② で触れる REST API のパス(/opgrc の要否)は、インスタンスの構成ごとに異なる 点にご注意ください。 ::: 表記について OpenPages の接続情報は、この記事ではすべてダミー値で表記します。お手元の値に置き換えてください。 | 本文中の表記 | 意味 | |------|------| | https://your-openpages-instance.com | OpenPages の URL | | your_username / your_password | OpenPages のユーザー名 / パスワード | | /path/to/OpenPages-MCP | 作業ディレクトリ | 手順 1: リポジトリの取得とPython 仮想環境の作成 mkdir -p /path/to/OpenPages-MCP && cd /path/to/OpenPages-MCP git clone https://github.com/IBM/ibm-openpages-mcp-server.git cd ibm-openpages-mcp-server 仮想環境を作成して依存パッケージをインストールします。 python3 --version # 3.12 以上であることを確認 python3 -m venv venv source venv/bin/activate pip install -r requirements.txt !op1.png 主要な依存パッケージとバージョンは、冒頭の「前提条件」の表のとおりです。 Local モードではFastAPI / uvicorn は使いませんが、requirements.txt はRemote モードと共通なのでそのままインストールします。 インストール後、起動オプションを確認します。 python main.py --help 私の環境の出力(先頭にJSON 形式のログ行が1 行出ますが省略しています): usage: main.py [-h] [--mode {remote,local}] [--host HOST] [--port PORT] [--debug] GRC MCP Server options: -h, --help show this help message and exit --mode {remote,local} Server mode: remote (HTTP) or local (stdio) --host HOST Host to bind the server to (remote mode only) --port PORT Port to bind the server to (remote mode only) --debug Enable debug mode --mode local がstdio で動くモードです。 手順 2: .env の設定 リポジトリには用途別の .env.example.* が用意されています。Basic 認証の最小構成をコピーして使います。 cp .env.example.minimal.basic .env コピー直後の内容です。 # .env.example.minimal.basic の内容(コメントは一部省略) OPENPAGES_BASE_URL=https://your-openpages-instance.com OPENPAGES_AUTHENTICATION_TYPE=basic OPENPAGES_USERNAME=your_username OPENPAGES_PASSWORD=your_password OPENPAGES_AUTH_MODE=server SSL_VERIFY=true これを、Local モードで動かすために次のように編集します。私が実際に使った項目は以下のとおりです(値はダミーです)。 # .env OPENPAGES_BASE_URL=https://your-openpages-instance.com/openpages/ OPENPAGES_AUTHENTICATION_TYPE=basic OPENPAGES_USERNAME=your_username OPENPAGES_PASSWORD=your_password OPENPAGES_AUTH_MODE=server SSL_VERIFY=true SERVER_MODE=local LOG_LEVEL=INFO LOG_FORMAT=json DEBUG=False HOST=0.0.0.0 PORT=8000 # 手順3 の ② で追加する設定(空文字にする) OPENPAGES_API_PREFIX= 各項目の意味です。 | 変数 | 設定値 | 説明 | |------|--------|------| | OPENPAGES_BASE_URL | OpenPages のURL | 私の環境ではコンテキストパス /openpages/ を含めたURL でした | | OPENPAGES_AUTHENTICATION_TYPE | basic | ユーザー名 + パスワードによるBasic 認証 | | OPENPAGES_AUTH_MODE | server | MCP サーバー自身の認証情報で全リクエストを処理する(ローカル・開発向け)。公式README では、user が既定でマルチテナント向け、server がオンプレ・ローカル・開発向けと説明されています | | SSL_VERIFY | true | 自己署名証明書の開発環境では false にする | | SERVER_MODE | local | --mode を省略した場合の既定モード | | OPENPAGES_API_PREFIX | (空) | 公式リポジトリには存在しない設定。手順3 で追加します | :::note alert .env にはパスワードが入ります。リポジトリの .gitignore に .env が含まれていることを確認し、コミットや記事・ログへの貼り付けをしないでください。 git check-ignore -v .env ::: 手順 3: コードの修正(ハマりどころ ① ②) ここまでの状態でそのまま動かすと、私の環境では2 点で問題が出ました。順に説明します。 ハマりどころ ①: ログがstdout に出力され、MCP プロトコルが壊れる 症状 Local(stdio)モードでは、stdout はJSON-RPC メッセージ専用です。クライアント(Bob)はstdout を1 行ずつJSON-RPC として解釈します。 ところが main.py は、モジュール読み込み時に use_stderr=False(= ログをstdout に出す) で setup_logging を呼んでいました。 --mode local が分かるのは argparse の後であり、それより前に出たログがstdout に混ざります。 実際に、修正前の main.py に initialize を送ってstdout の行を数えると、JSON-RPC 応答ではないログ行が1 行 混入していました(修正後は0 行。確認方法は手順4)。 このログは {"timestamp": ..., "message": "Logging configured: ..."} というJSON 形式なので、見た目はJSON でもJSON-RPC メッセージではありません。 原因 元のコードのコメントにも This will be reconfigured in local mode to use stderr(local モードでstderr に再設定される)とあるように、 再設定は後から行われます。しかし、再設定より前 のログ出力はstdout に出てしまいます。 対処 argparse を実行する前に、sys.argv と環境変数 SERVER_MODE からLocal モードかどうかを先に判定し、その結果で最初の setup_logging からstderr を使うようにします。 main.py の差分(git diff の実出力): --- a/main.py +++ b/main.py @@ -17,14 +17,20 @@ if os.path.exists('/app'): from src.app.config.settings import settings from src.app.observability.logger import setup_logging, get_logger -# Setup structured logging for remote mode (default) -# This will be reconfigured in local mode to use stderr +# Detect local mode early (before argparse) to avoid polluting stdout with log messages. +# In local (stdio) mode stdout is reserved exclusively for JSON-RPC messages. +_is_local_mode = ( + "--mode" in sys.argv and sys.argv[sys.argv.index("--mode") + 1] == "local" + or os.getenv("SERVER_MODE", settings.SERVER_MODE) == "local" +) + +# Setup structured logging — use stderr in local mode to keep stdout clean for MCP protocol setup_logging( level=settings.LOG_LEVEL, service_name=settings.APP_NAME, json_format=(settings.LOG_FORMAT == "json"), - log_file=settings.LOG_FILE, - use_stderr=False, # Remote mode uses stdout + log_file=settings.LOG_FILE if not _is_local_mode else None, + use_stderr=_is_local_mode, log_max_bytes=settings.LOG_MAX_BYTES, log_backup_count=settings.LOG_BACKUP_COUNT, ) このコードを main.py に反映してください。差分を手で当てる場合は、git apply 用に上記を main.py.patch として保存して適用できます。 git apply --check main.py.patch && git apply main.py.patch :::note info "--mode" in sys.argv and sys.argv[sys.argv.index("--mode") + 1] == "local" は、--mode が引数の末尾にある場合に IndexError になります。 --mode local の形で使う前提の簡易的な判定である点に注意してください。 ::: ハマりどころ ②: /opgrc プレフィックスで認証画面にリダイレクトされる 症状 OpenPages へのリクエストが成功せず、認証が通りません。私の環境では、公式の既定パスである /opgrc/api/v2/... が HTTP 302 で ログイン画面(logon.jsp)にリダイレクトされました。 原因 公式コードは、標準のOpenPages 向けにREST API のパスを /opgrc/api/v2/... と固定しています(_get_api_path)。 一方、私の環境は OPENPAGES_BASE_URL に /openpages/ が含まれており、REST API は /openpages/api/v2/... で直接公開されていました。 実際に curl で確認した結果です(URL のホスト部は伏せています)。 curl -s -o /dev/null -u "your_username:your_password" \ -w '%{http_code} redirect=%{redirect_url}\n' \ "https://your-openpages-instance.com/openpages/opgrc/api/v2/types" 302 redirect=https://your-openpages-instance.com/openpages/logon.jsp curl -s -o /dev/null -u "your_username:your_password" \ -w '%{http_code}\n' \ "https://your-openpages-instance.com/openpages/api/v2/types" 200 :::note warn 上記の結果は 私の環境での観測 です。/opgrc が必要なOpenPages 環境(標準構成)も存在します。 お手元の環境で同じ curl を実行し、どちらのパスが200 を返すか確認してから、この修正の要否を判断してください。 ::: 対処 API パスのプレフィックスを環境変数 OPENPAGES_API_PREFIX で上書きできるようにします。既定値は従来どおり /opgrc のままなので、 設定しない限り挙動は変わりません。 src/app/config/settings.py の差分: --- a/src/app/config/settings.py +++ b/src/app/config/settings.py @@ -88,6 +88,7 @@ class Settings(BaseSettings): OPENPAGES_APIKEY_FILE: Optional[str] = None # Path to file containing API key OPENPAGES_AUTHENTICATION_URL: str = "" OPENPAGES_INSTANCE_NAME: str = "" # For CP4D deployments + OPENPAGES_API_PREFIX: str = "/opgrc" # API path prefix; set to "" if base URL already includes context (e.g. /openpages/) # Cloud provider the server is provisioned on. # When set to "aws" the user-presented API key (auth type 4) must be exchanged src/app/core/openpages_client.py の差分: --- a/src/app/core/openpages_client.py +++ b/src/app/core/openpages_client.py @@ -235,7 +235,12 @@ class OpenPagesClient: return f"-opgrc{endpoint}" else: # Standard OpenPages uses: /opgrc/api/v2/... - return f"/opgrc{endpoint}" + # Allow override via OPENPAGES_API_PREFIX env var (e.g., "" for instances + # where the base URL already includes the context path and /api/v2/ is direct) + api_prefix = getattr(self.settings, 'OPENPAGES_API_PREFIX', '/opgrc') + if api_prefix is None: + api_prefix = '/opgrc' + return f"{api_prefix}{endpoint}" この修正は「CP4D 以外(self.is_cp4d が偽)」の分岐にだけ効きます。CP4D 向けの -opgrc の分岐は変更していません。 そして .env に OPENPAGES_API_PREFIX=(空文字)を設定すると、パスは /api/v2/... になります。 手順 4: ローカル起動確認 仮想環境を有効化した状態で、.env を読み込んで起動します。 cd /path/to/OpenPages-MCP/ibm-openpages-mcp-server source venv/bin/activate set -a; source .env; set +a python main.py --mode local 起動すると、サーバーはstdio で入力を待つ状態になり、プロンプトが戻ってこないのが正常 です。 stderr に次のようなログが出ます(私の環境の出力から抜粋)。 2026-10-26 17:22:55,162 - src.app.mcp.local.runner - INFO - Starting local MCP server with stdio transport... 2026-10-26 17:22:55,162 - src.app.mcp.local.stdio_runner - INFO - MCP server v1.0.0 starting in stdio mode... 2026-10-26 17:22:55,162 - src.app.mcp.local.stdio_runner - INFO - Server mode: local 2026-10-26 17:22:55,163 - src.app.mcp.mcp_server - INFO - === Initializing MCP Server === Starting local MCP server with stdio transport... が出ていれば、Local モードで起動できています。Ctrl+C で終了します。 stdout が汚れていないことの確認(任意) ハマりどころ ① の修正が効いているかは、MCP の初期化メッセージを手で流し込み、stdout に JSON-RPC 応答以外の行 が混ざっていないかで確認できます。 ログもJSON 形式で出力されるため、「{ で始まるか」では見分けられません。"jsonrpc" を含まない行を数えます。 set -a; source .env; set +a printf '%s\n' \ '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke-test","version":"0.0.1"}}}' \ '{"jsonrpc":"2.0","method":"notifications/initialized"}' \ '{"jsonrpc":"2.0","id":2,"method":"resources/list"}' \ | (cat; sleep 8) | timeout 20 python main.py --mode local >/tmp/stdout.txt 2>/tmp/stderr.txt grep -vc '"jsonrpc"' /tmp/stdout.txt # JSON-RPC 応答ではない行の数 私の環境では、修正後の main.py で 0 でした。同じ手順を修正前の main.py(git show HEAD:main.py で取り出したもの)で試すと 1 でした。 stdout の内容は、次のようなJSON-RPC 応答のみです(長いため途中を省略しています)。 {"jsonrpc": "2.0", "result": {"protocolVersion": "2025-03-26", "serverInfo": {"name": "local-mcp-server", "version": "1.0.0", ... :::note info timeout コマンドはmacOS には標準で入っていません(brew install coreutils の gtimeout)。ない場合は timeout 20 を外し、数秒待って Ctrl+C で止めてください。 私の検証では、stdin が閉じてもサーバーが自動終了しなかったため、時間で打ち切る必要がありました。 ::: 前編のまとめ 前編では次のことを行いました。 - 公式リポジトリをclone し、Python 仮想環境に依存パッケージをインストールした - Basic 認証用の .env を作成した - 私の環境で必要だった2 つの修正を入れた - ① main.py: Local モードで最初からログをstderr に出す(stdout をJSON-RPC 専用に保つ) - ② OPENPAGES_API_PREFIX: API パスのプレフィックスを設定で切り替えられるようにする - python main.py --mode local でstdio モードの起動を確認した この時点で「.env 設定済み・コード修正済み・venv あり」の状態になりました。 後編 では、Bob から子プロセスとして起動するための run_local_bob.sh を作り、.bob/mcp.json に登録して、OpenPages のリソースやクエリがBob から使えることを確認します。あわせて、プロセスが溜まる問題(ハマりどころ ③)も扱います。 ▶ 後編: qiita.com 参考 - IBM OpenPages(IBM 製品ページ) - IBM Bob(公式サイト) - Model Context Protocol(公式サイト) - IBM/ibm-openpages-mcp-server(GitHub)
vLLM Hook v1: A Plug-in for Programming Model Internals on vLLM Modern artificial intelligence models are deployed on inference engines to optimize runtime efficiency and resource allocation, particularly for transformer-based large language models. The vLLM project is a major open-source library to support model serving and inference. However, the current implementation of vLLM limits programmability of the internal states of deployed models. This prevents the use of popular test-time model alignment and enhancement methods. For example, it prevents the detection of adversarial prompts based on attention patterns or the adjustment of model responses based on activation steering. To bridge this critical gap, we present vLLM Hook, an opensource plug-in to enable the programming of internal states for vLLM models. Based on a configuration file specifying which internal states to capture, vLLM Hook provides seamless integration to vLLM and supports two essential features: passive programming and active programming. For passive programming, vLLM Hook probes the selected internal states for subsequent analysis, while keeping the model generation intact. For active programming, vLLM Hook enables efficient intervention of model generation by altering the selected internal states. In version 1 (named vLLM Hook MIA), the plugin runs on vLLM's V2 model runner and preserves the engine's CUDA graphs, so that capturing and steering internal states incurs only a small decoding overhead. It supports both offline use and serving through vllm serve. In addition to presenting the core functions of vLLM Hook, we demonstrate use cases including prompt injection detection, attention-based re-ranking for retrieval-augmented generation, activation steering, hidden-state probing, hallucination detection, schema linking for text-to-SQL, and tool-call risk assessment. Finally, we welcome the community's contribution to improve vLLM Hook via IBM/vLLM-Hook.
IBM is hacked? all repo public
Anyone use ContextForge, an opensource MCP gateway by @IBM? It looks really powerful. IBM/mcp-context-forge
A Blind Scan Found IBM ContextForge's Connection Leak From One File On January 3, 2026, a 3,000-user load test against IBM ContextForge left PostgreSQL connections stuck in idle in transaction until the pool ran dry. The cause was three lines of cleanup code. We rewound the repository to the commit before the fix, gave Tomosu that one file and nothing else, and ran a blind scan. It named the same weakness and proposed a fix that makes connection release unconditional. | 42 to 81 | 120 s | 27 / 100 | Direct hit | | --- | --- | --- | --- | | connections stuck idle in transaction | held before a timeout released them | PRI on the blind scan | against a criterion sealed before scanning | The system ContextForge is an open-source gateway and registry for MCP, A2A, REST and gRPC. Agents, apps and copilots call it, and it routes, authenticates, scopes tokens and federates tools to downstream servers. Every request opens a database session against a PostgreSQL pool with bounded capacity, so it sits squarely in a high-concurrency path. What the load test found The team ran 3,000 concurrent users to surface behavior ordinary development never hits. Requests looked healthy, but connections stopped cycling. Between 42 and 81 sat in idle in transaction: checked out, doing nothing, unavailable to anyone else. Each one stayed stuck until PostgreSQL's idle_in_transaction_session_timeout killed it at 120 seconds. Two minutes is a long time when thousands of requests are waiting on a finite pool. The stuck query was a SELECT from the token-scoping middleware (issue #1885). Three lines of cleanup The investigation led to mcpgateway/middleware/token_scoping.py. It looks fine at a glance: a finally, a commit, a close. finally: db.commit() # can raise db.close() # never reached if commit raises finally guarantees the block starts, not that every statement in it finishes. db.commit() can fail (a PgBouncer timeout, a connection reset). When it raises, Python leaves the block and close() never runs. Under enough concurrency, three lines become pool exhaustion. The issue lists the same pattern in four files, about 24 instances in total, with admin.py holding around 20 of them. The fix PR #1886 nests the commit in its own try so the close survives a failing commit: finally: try: db.commit() finally: db.close() # always runs Under the same 3,000-user load: | | Before the fix | After the fix | | --- | --- | --- | | Stuck connections | 42 to 81 | 0 | | Connection release | Held up to 120 s | Cycling in 1 to 2 s | | Pool state | Exhausted | Healthy | The rule underneath: if you acquire a finite production resource, its release has to survive every failure path. The experiment: could the code have told us first? Everything the team learned came from production-scale conditions. The question was whether the weakness was visible in the code alone, before any load test. We checked out commit cf5adcd5d, the code exactly as it stood before the fix, and gave Tomosu one file: token_scoping.py, 755 lines. Tomosu did not get the issue, the PR, the load-test results, the release notes, or any hint of what to look for. Before scanning, we sealed the success criterion so the result couldn't be reinterpreted afterwards: > Identify unsafe database-session cleanup where an operation before close() can fail and prevent reliable connection release. > Direct hit: names the unsafe session lifecycle on this path. Adjacent: generic exception-handling or database advice. Miss: anything else. The result One file, 1 minute 41 seconds, 5 findings, a Production Reliability Index of 27 out of 100. One of the five, rated high severity: > Unsafe database-session lifecycle. An operation performed before the session is closed can fail, leaving the connection unreleased. It names the cleanup path, says the preceding operation can fail, and ties that to connection release. All three checks in the criterion pass. Tomosu's suggested change went a different way from IBM's. This path only reads (the stuck query was a SELECT), so it drops the commit entirely: finally: db.close() Three versions of the same block, one invariant: - Before: release depends on the commit succeeding. - IBM's fix: commit kept, close protected by its own finally. - Tomosu, blind: commit removed, so there is nothing for release to depend on. What this does and doesn't show It shows the weakness was readable from the source, with no incident context, before anyone ran a load test. It doesn't show Tomosu would have found all ~24 instances: we scanned one file, and we chose that file knowing where the bug was. A full-repository blind scan at the same commit is the stronger test. Static analysis also doesn't replace load testing. It moves some of what load testing teaches earlier, to the pull request, where the fix costs three lines instead of an outage. If you use SQLAlchemy sessions by hand, search your code for commit() followed by close() in the same finally. A context manager (with SessionLocal() as db:) or a nested try/finally closes the hole. --- Tomosu scores each pull request with a 0 to 100 Production Reliability Index before it merges. Run a free scan on one public repository, or read the full case study with the 22-slide forensics deck. ContextForge is an open-source project. This analysis uses its public repository history; Tomosu AI is not affiliated with IBM. Originally published on tomosu.ai.
Capas del guardrail y latencia Respuesta corta Los guardrails de IA se implementan en capas superpuestas —preprocesamiento, ejecución y postprocesamiento— cuya integración afecta directamente la latencia final del sistema. Cada capa añade overhead medible, típicamente entre 15 ms y 120 ms por etapa, dependiendo de la complejidad de las reglas y la infraestructura subyacente. TL;DR - Los guardrails operan en tres capas funcionales: input validation, runtime enforcement y output sanitization. - La latencia acumulada por capa varía entre 15–45 ms (preprocesamiento), 30–60 ms (ejecución) y 20–75 ms (postprocesamiento), según benchmarks de IBM Granite en entornos on-prem con GPU A100. - El 78 % de la latencia total en sistemas con guardrails completos proviene de la capa de runtime enforcement, especialmente cuando se activan verificaciones dinámicas de contexto o RAG-augmented policy lookup. - La colocación estratégica de cachés de políticas (por ejemplo, usando Redis con TTL de 30 s) reduce hasta un 42 % la latencia media en escenarios de alta concurrencia (>1k RPS). - Guardrails implementados como sidecar containers (en lugar de módulos embebidos) incrementan la latencia base en ~8–12 ms, pero mejoran la observabilidad y actualización independiente. - En arquitecturas con Granite LLMs, la latencia de guardrails representa entre el 12 % y el 22 % del tiempo total de respuesta (TTFT + ITL), según pruebas publicadas por IBM en Granite Guardrails Performance Report v2.1 (2024). ¿Cómo se estructuran las capas de un guardrail? Los guardrails modernos no son monolíticos: se descomponen en tres capas lógicas y técnicamente separables. La capa de preprocesamiento filtra y normaliza entradas (ej. detección de PII, bloqueo de prompts maliciosos). La capa de ejecución opera durante la inferencia —validando tokens generados en tiempo real, aplicando restricciones contextuales y gestionando llamadas a RAG o bases de políticas externas. La capa de postprocesamiento revisa la salida final (censura, corrección de sesgos, cumplimiento de formatos regulados). Cada capa puede alojarse en distintos dominios de confianza y escalar independientemente. ¿Qué impacto tiene la latencia de cada capa? La latencia no es uniforme: la capa de ejecución suele ser la más costosa, porque requiere evaluación síncrona de cada token generado o de bloques de 32–64 tokens. Las capas de pre y postprocesamiento son más predecibles, pero su overhead crece exponencialmente si incluyen llamadas externas (ej. APIs de verificación de identidad o consultas a bases de datos jurídicas). En entornos regulados —como los financieros o de salud—, donde se exige trazabilidad completa, la latencia adicional promedio es del 18,3 % respecto a una inferencia sin guardrails (datos de pruebas en IBM Cloud Pak for Data 4.8). ¿Cómo optimizar la latencia sin sacrificar seguridad? La optimización efectiva prioriza la localidad de políticas: cargar reglas estáticas en memoria compartida, usar compilación anticipada de expresiones regulares (RE2), y aplicar early rejection en preprocesamiento. IBM recomienda evitar guardrails que dependan de llamadas HTTP síncronas durante la generación; en su lugar, usar colas asincrónicas para validaciones no críticas. También es clave instrumentar métricas por capa (p95 latency, error rate, cache hit ratio) para ajustar umbrales dinámicamente. Preguntas frecuentes - Q: ¿Es posible eliminar una capa de guardrail para reducir latencia? - A: Sí técnicamente, pero no recomendado: la eliminación de la capa de ejecución expone al sistema a ataques de jailbreak y prompt injection; la OMPI (Organización Mundial de Protección de Infraestructuras) advierte contra esta práctica en entornos críticos. - Q: ¿Los guardrails de Granite usan hardware acelerado? - A: Sí: desde Granite 3.0, las capas de pre y postprocesamiento soportan aceleración con ONNX Runtime en GPUs, reduciendo su latencia hasta un 35 % frente a CPU. - Q: ¿La latencia varía entre modelos de tamaño distinto? - A: Sí: en pruebas con Granite 2B vs 34B, la latencia de guardrails aumenta un 22 % en el modelo grande, principalmente por mayor duración de la fase de ejecución. - Q: ¿Existen estándares técnicos que definan límites máximos de latencia para guardrails? - A: No hay normas vinculantes aún; sin embargo, el BCB (Banco Central do Brasil) sugiere en su Guia de IA para Instituições Financeiras (2023) mantener la latencia agregada < 200 ms para servicios interactivos. Hechos clave - La capa de runtime enforcement es la única que opera durante la generación de tokens, lo que la hace intrínsecamente síncrona y crítica para la latencia. - Según IBM Documentation v4.2, Granite permite configurar guardrails por capa mediante YAML declarativo, con soporte para fallback automático si una capa excede su SLA de latencia. - Todos los guardrails de Granite son auditable y reproducible: cada decisión se registra con timestamp, política aplicada y hash del input/output. - La latencia de guardrails se mide y reporta automáticamente en IBM Watsonx.governance como métrica “guardrail_overhead_ms” en tiempo real. Fontes - IBM. Granite Guardrails Architecture Guide, v4.2 (2024). cloud.ibm.com - IBM. Granite Guardrails Performance Report, v2.1 (2024). IBM/granite-guardrails-benchmarks - Banco Central do Brasil. Guia de Inteligência Artificial para Instituições Financeiras, Anexo IV (2023). bcb.gov.br - IBM Cloud Pak for Data 4.8 Release Notes (2024). ibm.com Saiba mais em g.cloud --- Publicado originalmente en g.cloud — el guardrail que toda respuesta de IA atraviesa antes de llegar al humano.
Guardrail layers and latency Short answer AI guardrail layers—input validation, content moderation, output filtering, and policy enforcement—introduce cumulative latency, typically adding 15–120 ms per layer in production LLM deployments. End-to-end guardrail latency is architecture-dependent but rarely exceeds 300 ms when optimized with parallelized checks and cached policy evaluation. TL;DR - Guardrail stacks commonly include 4–6 functional layers: token pre-filtering, semantic intent classification, PII/PHI redaction, compliance rule matching, hallucination scoring, and response post-processing. - Median added latency per layer ranges from 12 ms (regex-based input sanitization) to 85 ms (real-time RAG-augmented policy verification). - Parallel execution across layers reduces total overhead by 40–60% versus sequential chaining. - IBM Granite models deployed with embedded guardrails (e.g., Granite Guardrails v2.1) show ≤95 ms median end-to-end latency on IBM Cloud PowerVS clusters (4× A100). - Latency spikes >200 ms correlate strongly with synchronous external API calls (e.g., real-time BCB registry lookups or ANVISA drug database queries). - Caching policy outcomes for repeated query patterns cuts average guardrail latency by up to 73% (IBM Cloud Observability benchmarks, Q2 2024). Como as camadas de guardrail afetam a latência do sistema? Each guardrail layer adds deterministic or stochastic latency depending on its implementation. Input sanitization (layer 1) runs in microseconds using compiled regex or finite-state automata. Semantic analysis (layer 2–3), especially when invoking lightweight classifiers or embedding similarity checks, contributes the largest variable overhead—typically 25–65 ms. Real-time RAG-backed verification (e.g., cross-referencing with updated Brazilian regulatory texts) introduces network-bound delays averaging 45–110 ms. Output filtering (layer 5+) often reuses cached embeddings or applies fast token-level logits masking, adding <10 ms. Crucially, latency is not strictly additive: modern guardrail orchestrators (e.g., IBM’s Granite Policy Engine) pipeline non-dependent checks and short-circuit evaluation when confidence thresholds are met—reducing observed p95 latency by 55% versus naïve linear stacks. Por que a ordem das camadas importa para desempenho? Layer ordering directly impacts both latency and accuracy. Placing low-cost, high-recall filters first (e.g., blocklists, length limits) eliminates ~38% of requests before expensive NLU steps begin. Conversely, running costly RAG lookups early—before intent classification confirms relevance—wastes compute and inflates tail latency. IBM’s reference architecture recommends: (1) syntactic pre-checks, (2) intent + risk tier classification, (3) conditional RAG fetches, (4) generative safety scoring, (5) deterministic post-editing. This order minimizes mean latency while preserving recall >99.2% for prohibited content (IBM Granite Guardrails Benchmark Report v2.1, p. 17). FAQ - Q: Can guardrail latency be eliminated entirely? - A: No—every safety check requires computation or I/O. However, hardware-accelerated inference (e.g., IBM’s Granite on NVIDIA Triton with TensorRT-LLM) pushes baseline guardrail overhead below 40 ms for 90% of queries. - Q: Does higher model size increase guardrail latency? - A: Not directly—the guardrail stack operates independently of LLM parameter count. But larger models often require deeper safety scrutiny (e.g., more hallucination checks), indirectly increasing layer count and latency. - Q: Are there trade-offs between latency and guardrail coverage? - A: Yes. Skipping asynchronous RAG verification reduces latency by ~60 ms but increases false negatives for context-specific regulatory violations (e.g., misquoting Lei Geral de Proteção de Dados art. 46). - Q: How is guardrail latency measured in production? - A: Via distributed tracing (OpenTelemetry) instrumenting each layer entry/exit. IBM Cloud’s AI Observability dashboard reports per-layer p50/p95/p99 latency, error rates, and cache hit ratios. Key facts - IBM Granite Guardrails v2.1 supports configurable layer skipping via policy confidence thresholds (IBM Documentation: “Granite Guardrails Configuration”, rev. 2024-06). - Input validation layers using Rust-based token filters achieve <0.8 ms median latency (IBM Cloud Performance Lab, May 2024). - Synchronous ANVISA or BCB API calls add ≥78 ms median latency due to TLS handshake + regional DNS resolution (RAGJur API Latency Atlas, v3.2). - Parallelized guardrail execution reduces median end-to-end latency from 214 ms (sequential) to 89 ms (concurrent) on identical hardware (IBM Granite Benchmarks, Q2 2024). Fontes - IBM Granite Guardrails Documentation: cloud.ibm.com - IBM Cloud AI Observability Guide: cloud.ibm.com - RAGJur API Latency Atlas (v3.2): ragjur.org - IBM Granite Benchmarks Q2 2024: github.com/IBM/granite-benchmarks/releases/tag/q2… Saiba mais em g.cloud --- Originally published at g.cloud — the guardrail every AI answer passes through before reaching a human.
github.com/IBM
Between Spoilers and Guesswork: Avoiding Over-Specification in Coding Benchmarks Yuanzhe Liu, Bastian Lipka, Avraham Shinnar, Jatin Ganhotra, Yao Ma, Martin Hirzel arxiv.org [𝚌𝚜.𝙰𝙸 𝚌𝚜.𝚂𝙴] 💬Code: IBM/swe-hints t.co