From f2d24cb7d437ad099291262d7c1b021809cd66ae Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Sun, 13 Sep 2026 13:35:03 +0900 Subject: feat(multimedia): MCP画像・音声artifactの安全な表示経路を追加 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCP Tool結果をテキストと型付きartifactへ分離し、画像・音声のbase64をMIME、サイズ、件数のallowlistで検証する。annotations.audienceを反映し、ユーザー向けartifactだけをセッションへ保存してSSEにはメタデータのみを公開する。 画像はvision capabilityが明示されたモデルだけへ渡し、非対応時は既存の多言語プロンプト機構による固定通知へ置き換える。MCP生成音声とユーザー添付音声はOllamaへ送らず、誤デコードしたテキストやbase64がモデル入力へ混入しないポリシーに統一する。 保存メディア用の認証済み同一オリジン配信ルートを追加し、セッションスコープ、MIME allowlist、nosniff、private/no-store、Rangeリクエストを適用する。UIはMCP由来HTMLを使わずDOM APIでimgとaudio controlsを生成し、CSPへmedia-src selfを追加する。 web_searchは文字列メタデータだけを返す既存仕様を維持する。scrape_urlとsearch_and_fetchは画像・音声・動画レスポンスを拒否し、search_and_fetchの対象拡張子を明示的allowlistへ変更して標準Webツールをテキスト専用の契約に揃える。 責務境界と導入しない過剰対策をdocs/multimedia.mdへ記録し、README、ツール仕様、CHANGELOGを更新する。MCP artifact変換・永続化、vision分岐、音声非送信、認証、Range配信、MIME偽装拒否をテストで追加確認した。 Validation: 148 tests passed; ruff check passed; mypy src passed; node --check src/ollama_web/static/app.js passed. --- CHANGELOG.md | 13 +++ README.md | 4 + README_ja.md | 4 + docs/multimedia.md | 55 +++++++++ docs/tools-schema.md | 5 +- src/ollama_web/app.py | 6 + src/ollama_web/i18n/__init__.py | 2 +- src/ollama_web/i18n/messages/en.json | 3 +- src/ollama_web/i18n/messages/ja.json | 3 +- src/ollama_web/llm.py | 101 +++++++++------- src/ollama_web/mcp.py | 220 +++++++++++++++++++++++++++-------- src/ollama_web/middleware.py | 1 + src/ollama_web/prompts/__init__.py | 2 +- src/ollama_web/prompts/en.json | 4 + src/ollama_web/prompts/ja.json | 4 + src/ollama_web/routes/chat.py | 124 +++++++++++++++----- src/ollama_web/routes/sessions.py | 44 ++++++- src/ollama_web/sessions.py | 33 +++++- src/ollama_web/static/app.js | 56 +++++++++ src/ollama_web/static/style.css | 26 +++++ src/ollama_web/tools/fetch.py | 23 ++-- src/ollama_web/tools/registry.py | 56 ++++++++- src/ollama_web/tools/scrape.py | 4 + tests/test_llm.py | 177 ++++++++++++++++++++++++++-- tests/test_mcp.py | 156 ++++++++++++++++++++++++- tests/test_security.py | 92 +++++++++++++++ tests/test_tools.py | 74 ++++++++---- 27 files changed, 1110 insertions(+), 182 deletions(-) create mode 100644 docs/multimedia.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f91e32..9fb3f92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ ## [Unreleased] +### Added + +- MCP の画像・音声結果をセッションへ保存し、認証済みの同一オリジン URL からチャット上で表示・再生できるようにしました。 + +### Changed + +- 画像は vision 対応モデルだけへ渡し、非対応時は多言語の固定通知へ置き換えるようにしました。MCP 音声データはモデル capability にかかわらず Ollama へ渡しません。 +- `web_search`、`scrape_url`、`search_and_fetch` をテキスト専用の契約に統一し、後二者は画像・音声・動画レスポンスを拒否するようにしました。 + +### Security + +- MCP の base64 メディアをテキスト結果から分離し、MIME type・件数・サイズを制限しました。メディア配信は認証、セッションスコープ、MIME allowlist、`media-src 'self'` を適用します。 + ## [0.5.2] - 2026-08-26 ### Changed diff --git a/README.md b/README.md index 24271bd..cb7a62b 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,10 @@ Server names and tool names may only contain alphanumeric characters, `_`, and ` In GET responses from the MCP settings API, secret-like values in `env` / `headers` are masked as `***`. Tool execution results and errors are also quarantined as untrusted data before being passed to the LLM. +When an MCP tool returns an image or audio item, its base64 payload is separated from the text result, checked against size and MIME allowlists, and stored in the session. Images are sent only to models that explicitly advertise vision support; other models receive a fixed localized notice. Audio bytes are never sent to Ollama, regardless of model capabilities, and are played in the chat through a same-origin URL and an `