mcp_feast
mcp_feast
Feast フィーチャーストア上の MCP サーバーで、カードスワイプ不正検知モデル向けです。完全にローカルで動作します: Parquet オフラインストア、SQLite オンラインストア、クラウドなし、ブローカーなし。
システム設計
4つのレイヤー
flowchart TB
subgraph H["HOST — decides which tools to call"]
direction LR
H1["host.py<br/><i>local LLM, qwen2.5:7b</i>"]
H2["Claude Code<br/><i>.mcp.json</i>"]
H3["mcp_cli.py<br/><i>manual, for testing</i>"]
end
subgraph M["MCP SERVER — no Feast import, no credentials"]
M1["12 read tools<br/>+ 2 gated write tools"]
end
subgraph A["FEATURE API — holds the Feast SDK"]
A1["catalog"]
A2["lineage"]
A3["health"]
A4["values"]
end
subgraph S["STORAGE"]
direction LR
S1[("registry.db<br/><i>metadata</i>")]
S2[("online_store.db<br/><i>SQLite, serving</i>")]
S3[("data/*.parquet<br/><i>offline</i>")]
end
H1 -->|"stdio"| M1
H2 -->|"stdio"| M1
H3 -->|"stdio"| M1
M1 ==>|"HTTP / JSON"| A1
A1 -->|"Feast SDK"| S1
A2 --> S1
A3 --> S3
A4 --> S2その太い矢印が設計全体です。 Feast 固有のものはすべてその下にあります。その上の MCP サーバーには Feast のインストールも、ストアドライバも、ウェアハウスの認証情報も不要です。HTTP クライアントにすぎません。
これにより3つのことが得られます。SQLite を Redis に置き換えることは feature_store.yaml の変更で済み、MCP レイヤーはそれを見ることはありません。MCP サーバーを実行するラップトップは、本番 Redis へのネットワークルートではなく、到達可能な URL が1つあればよいのです。また、同じ API は2番目のコンシューマー、つまりここでは構築されなかったが MCP レイヤーとまったく同じように POST /features/online を呼び出すであろうモデルサーバーにもサービスを提供できます。
Related MCP server: tecton-mcp
実際に実行されるもの
プロセス | 起動元 | 保持するもの | ポート |
Feature API |
|
| 8000 |
MCP サーバー | ホスト (stdio 経由) |
| — |
Ollama |
| qwen2.5:7b | 11434 |
ホスト |
| 会話ループ | — |
Feast をインポートするのは API だけです。確認:
python3 -c "import mcp_server.server, sys; print('feast' in sys.modules)" # False1リクエストのエンドツーエンド
"カード C-4471 がフラグされたのはなぜか" という質問は、すべてのレイヤーを2回横断します:
sequenceDiagram
autonumber
participant L as Model
participant M as MCP server
participant A as Feature API
participant F as Feast SDK
participant D as SQLite
L->>M: resolve_card("C-4471")
M->>A: GET /cards/C-4471
A-->>M: CU-8842
M-->>L: C-4471 is owned by CU-8842
Note over L: the model spans two entities,<br/>so both join keys are needed
L->>M: explain_features_for_entity(card + customer)
M->>A: POST /features/explain
A->>F: get_online_features(fraud_model_v2)
F->>D: read 7 values
A->>F: provider.online_read(...)
F->>D: read per-entity event_ts
Note over A: joins values against TTL<br/>to classify each feature
A-->>M: values + age + is_stale + reasons
M-->>L: FRESH 6 / STALE 0 / MISSING 1その2番目の SDK 呼び出しは、Feast が無料で提供しない部分です。以下を参照してください。
データがオンラインストアに到達する方法
flowchart LR
P[("data/*.parquet<br/>offline store")]
O[("online_store.db<br/>online store")]
W["live swipe"]
R["serving<br/><i>milliseconds</i>"]
T["training set"]
P -->|"feast materialize — batch, scheduled"| O
W -->|"feast push — real time, no broker"| O
O -->|"get_online_features"| R
P -.->|"get_historical_features — not exposed"| T点線のパスはフィーチャーストアのトレーニング側です。意図的に省略されています: 数百万行を返す数分間のクエリを実行するため、チャットツールには不適切な形です。そのため、ジェネレーターは不正ラベルを書き込みません。
API がパススルーでない理由
get_online_features() は値だけを返し、それ以外は返しません。裸の null は、4つの状況のどれにいるかを教えてくれません。そして Feast は期限切れの値を文句なしに提供します:
flowchart LR
B["get_online_features<br/><b>txn_count_1h: null</b>"]
B --> C1["<b>ENTITY_NOT_FOUND</b><br/>no row for this card"]
B --> C2["<b>NULL_IN_SOURCE</b><br/>feature genuinely absent"]
B --> C3["<b>STALE</b><br/>6h58m old, TTL is 2h"]
B --> C4["<b>a real zero</b><br/>the card had no swipes"]POST /features/explain は、プロバイダーの online_read を通じてエンティティごとの event_timestamp を回復し、それをビューの TTL と結合することで、それらを分離します。これは get_online_features が内部的に行うのと同じ呼び出しですが、タイムスタンプを表面化するものです。
生の SDK が提供しない3つの事実:
エンドポイント | 導出するもの |
| フィーチャーごとの鮮度と欠損値の理由 |
| ソース → ビュー → 利用サービス |
| 変更前の影響範囲 |
これが回避するように設計された罠
鮮度はビュー単位ではなくエンティティ単位です。どちらも異なる答えを持つ現実の質問であり、それらを混同することはここで可能な最も危険な間違いです:
flowchart TB
V["<b>card_velocity</b><br/>materialized 52 seconds ago<br/>check_feature_freshness reports OK"]
V -->|"source had a row from 58m ago"| E1["<b>C-4471</b><br/>age 58m<br/>FRESH"]
V -->|"source's newest row is 6h58m old"| E2["<b>C-7788</b><br/>age 6h58m<br/>STALE"]
style E1 stroke:#2a9d4a,stroke-width:2px
style E2 stroke:#d1443c,stroke-width:3pxマテリアライゼーションはソースが保持するものを書き込みます。最近の行がないカードの場合、それは古い値です。したがって、エンティティは数秒前にマテリアライズされたビュー内で数時間古くなることがあります。ビューを更新しても修正できません。プッシュだけが可能です。
質問 | ツール | スコープ |
"パイプラインは死んでいるか?" |
| 全エンティティ |
"このカードは最新か?" |
| 1エンティティ |
小さなモデルはこれらを確実に混同します。それを修正したのはシステムプロンプトではなく、check_feature_freshness の出力に警告を追加したことでした。ツールの説明をスキップするモデルでも、自分が操作した結果は読み取ります。
ツールはエンドポイントに1対1で対応
flowchart LR
T1["list_feature_views<br/>describe_feature_view<br/>list_feature_services<br/>search_features<br/>list_entities<br/>resolve_card"] --> E1["/entities · /data-sources<br/>/feature-views · /feature-services<br/>/features/search · /cards"]
T2["get_feature_lineage<br/>get_feature_consumers"] --> E2["/features/../lineage<br/>/feature-views/../consumers"]
T3["check_feature_freshness"] --> E3["/health/materialization"]
T4["get_online_features<br/>explain_features_for_entity"] --> E4["/features/online<br/>/features/explain"]
T5["push_swipe<br/>trigger_materialization"] -.->|"only when FEAST_MCP_READONLY=false"| E5["/features/push<br/>/feature-views/../materialize"]api/routers/ と mcp_server/tools/ はファイルごとに互いを反映しています — カタログ、リネージ、ヘルス、バリュー — そのためナビゲーションは明白です。
設計を支えた2つのアイデア
エラーは指示として書かれます。 404 は Available: [...] を返し、不正なエンティティ行は必要な結合キーを指定します。繰り返し観察されたこと: 7B モデルは間違え、エラーを読み、次のステップで推測を繰り返すのではなく自分を修正します。
ガイダンスは説明だけでなく出力にも乗ります。 ツールの説明はスキップされますが、結果はスキップされません。鮮度スコープの警告と trigger_materialization の "check_feature_freshness を呼び出して確認" の両方が返されたテキストにあり、プロンプトの文言だけでは失敗したときに両方がモデルの動作を変えました。
クイックスタート
Python 3.11。Feast は >=3.10 を宣言していますが、3.10 のみを分類しており、その推移的なスタックは新しいインタープリターで問題の一般的な原因です。
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
./setup.sh # preflight + data + apply + materialize
./run_api.sh # API on :8000, docs at /docs両方のスクリプトは、依存関係が他の場所にある場合に PYTHON オーバーライドを尊重します:
PYTHON=/opt/miniconda3/envs/myenv/bin/python3 ./setup.shMCP サーバーはホストによって .mcp.json を介して起動され、トラブルシューティングの理由で絶対インタープリターパスを固定します。./run_mcp.sh はデバッグ用に手動で実行します。
トラブルシューティング: 間違ったインタープリター
2つの症状、1つの原因 — 依存関係を保持している Python とは異なる Python:
ModuleNotFoundError: No module named 'feast'
ImportError: cannot import name 'MCPServer' from 'mcp.server'2番目はより巧妙です: mcp 1.x は正常にインポートされますが、このプロジェクトが使用する 2.x の mcp.server.MCPServer ではなく mcp.server.fastmcp.FastMCP を公開します。アクティブな conda 環境を示すシェルプロンプトは証拠ではありません — PATH を確認してください:
which python3 && python3 -V
echo $PATH | tr ":" "\n" | head -3フレームワークまたはシステム Python が環境の前にあれば、プロンプトが何を言おうと、すべての python3 呼び出しは環境から逃げます。適切に診断するには:
python3 preflight.pyこれは、コードの各部分が必要とする正確なシンボルをインポートします — モジュールだけでなく — そのため、メジャーバージョンが間違った依存関係は名前で捕捉され、PATH 上の uvicorn または feast が別の環境に属している場合に警告します。
すべてのエントリポイントは PYTHON オーバーライドを受け取るため、PATH と戦う必要はありません:
PYTHON=/opt/miniconda3/envs/myenv/bin/python3 ./setup.sh
PYTHON=/opt/miniconda3/envs/myenv/bin/python3 ./run_api.sh
PYTHON=/opt/miniconda3/envs/myenv/bin/python3 python3 mcp_cli.py toolsこれを完全に回避する2つのルール:
API は
./run_api.shまたはpython3 -m uvicorn api.main:appで起動します。裸のuvicorn api.main:appは決して使わないでください — それは PATH から uvicorn を解決し、Feast を保持している Python とは異なる Python に属する可能性があり、失敗はインポートチェーンの40フレーム深くで表面化します。.mcp.jsonのcommandは絶対インタープリターパスに保ちます。そこでの"python3"は、ホストプロセスがたまたま持っていた PATH に対して解決されます。
レジストリにあるもの
エンティティ — card (card_id)、customer (customer_id)
フィーチャービュー
ビュー | エンティティ | 種類 | フィーチャー | TTL |
| card | push |
| 2h |
| customer | batch |
| 7d |
フィーチャーサービス — fraud_model_v2、全7フィーチャーをバインド。
2h / 7d の TTL 分割は意図的です: 鮮度ツールが恒久的なオールグリーンではなく実際の答えを生成するようにします。
モックデータ
data_gen/generate_swipes.py は 15,000 件の顧客スナップショット (500 顧客 × 30 日) と 14,394 行の速度データ (600 カード × 24 時間、ただし古いケースを作るために6行削除) を書き込みます。すべて実行時間に固定されているため、再生成すると常にクリーンにマテリアライズされるデータが生成されます。
デモが決定的になるように6つのペルソナが固定されています:
カード / 顧客 | セットアップ | デモンストレーション |
| 7 スワイプ/時、$2,140 対 平均 $58.20、チャージバック null | 不正ケース、および null フィーチャー |
| すべて中央値 | コントロール |
| 最新の速度行が6時間前 | 2h TTL を超えた古さ |
| 生成されていない | 未知のエンティティ |
| プロフィールはあるがカードなし | 部分的なカバレッジ |
| チャージバック4件、通常の速度 | 速度ではないリスク |
API
グループ | エンドポイント |
カタログ |
|
リネージ |
|
ヘルス |
|
バリュー |
|
対話型ドキュメントは http://localhost:8000/docs にあります。
API はパススルーではありません。生の SDK が行わない3つのことを行います: レジストリメタデータをオンラインストアのタイムスタンプと結合して鮮度を計算し、ソース → ビュー → サービスを辿ってリネージを計算し、Feast の proto 形状をプレーンな名前付きオブジェクトにフラット化します。
MCP ツール
読み取り専用ツール12個、さらに書き込みが有効な場合にのみ登録される書き込みツール2個。
list_feature_views · describe_feature_view · list_feature_services ·
describe_feature_service · search_features · list_entities · resolve_card ·
get_feature_lineage · get_feature_consumers · check_feature_freshness ·
get_online_features · explain_features_for_entity ·
push_swipe ⚠ · trigger_materialization ⚠
2種類の鮮度
これらは異なる質問に答えます。混同することはここで可能な最も危険な間違いです:
ツール | 答える質問 | スコープ |
| "パイプラインは死んでいるか?" | 全エンティティ、ビューレベル |
| "このカードのデータは最新か?" | 1エンティティ |
個々のエンティティは、数秒前にマテリアライズされたビュー内で6時間古くなることがあります。マテリアライゼーションはソースが保持するものを書き込み、最近の行がないカードの場合、それは古い値です。したがって、ビューが OK を示しても、特定のカードについては何も証明されません。
小さなモデルは2つを確実に混同し、ビューレベルのメタデータから "信頼するのに十分最新" と答えます。3つのレイヤーがそれを防ぎます: サーバーの INSTRUCTIONS、check_feature_freshness ツールの説明、そしてそのツールの出力に追加されたメモ — 最後のものが実際に機能したもので、説明をスキップしたモデルでも自分が操作した結果は読み取るからです。
explain_features_for_entity が存在する理由
get_online_features は裸の値を返します。裸の null は4つの異なる状況を区別できず、Feast は期限切れの値を文句なしに提供します:
本当のゼロ
マテリアライズされたことがないビュー
存在しないエンティティ
TTL を過ぎた値
explain_features_for_entity は、オンラインストアから回復したエンティティごとの event_ts を使用してそれらを分離します。それが推奨される取得ツールである理由です。
FEAST_MCP_READONLY
両方のプロセスから読み取られます。true(デフォルト)の場合、MCPサーバーはpush_swipeやtrigger_materializationを一切登録しません。モデルが見えないツールは試そうとしないからです。また、APIはそれらのルートに対して独立して403を返すため、直接curlしても拒否されます。
ローカルLLMホスト
host.pyは、ローカルのオープンソースモデルによって駆動される実際のMCPホストです。APIキーも、ホストされたものもありません。モデルがどのツールを呼び出すかを決定し、mcp_cli.pyはあなたが指定したツールのみを呼び出します。
ollama/qwen2.5:7b -> host.py -> MCP server -> Feature API -> Feast -> SQLiteollama serve & # if not already running
ollama pull qwen2.5:7b # any tool-calling model works
python3 host.py "Why would card C-4471 be flagged?"
python3 host.py --trace --quiet "Is anything stale?"
python3 host.py # interactiveシステムプロンプトはhost.pyには書かれていません。これはMCPサーバー自身のinstructionsから来ており、initialize()の間に返されます。サーバーはモデルにツールの使い方を伝え、ホストはそれをそのまま渡します。mcp_server/server.pyのINSTRUCTIONSを変更すると、ホストを編集することなくモデルの動作が変わります。
モデルの選択は重要です。ツール呼び出しのサポートが必要です。qwen2.5:7bは動作します。GemmaはOllamaにツールテンプレートがないため動作しません。
ホストのガードレール
7Bモデルは信頼できないプランナーであるため、ループは実際に示す3つの失敗に対して防御します:
失敗 | ガードレール |
すでに行った呼び出しを繰り返し、時にはステップ制限に達するまで繰り返す | 結果は(tool, args)でキャッシュされ、繰り返しは2回目のラウンドトリップの代わりに「これはすでに実行済みです」というメモ付きでキャッシュから提供される |
次の呼び出しを散文で語る( | 検出され、説明する代わりに呼び出しを発行するよう1回促される(最大2回) |
回答なしでステップ予算を超えてさまよう | 最後のステップで、または3回の繰り返しの後に、ツールが撤回されるため、収集した情報から回答せざるを得なくなる |
それぞれがHOST |行を出力するため、ループが介入しているのを確認できます。
それでも、オープンエンドのプロンプトではさまようことが予想されます。ツールセットを制限することが現実的な修正策です:
python3 host.py --tools resolve_card,explain_features_for_entity,check_feature_freshness \
"Why would card C-4471 be flagged?"MCPがAPIを呼び出すのを監視する
mcp_cli.pyはホストと同じstdioプロトコルを話すため、MCP → APIチェーンをシェルから観察できます:
python3 mcp_cli.py tools # what is registered
python3 mcp_cli.py --trace demo # 11-step walkthrough, with HTTP calls
python3 mcp_cli.py --trace call resolve_card '{"card_id": "C-4471"}'--traceは各ツールがヒットするエンドポイントを出力します:
http | HTTP Request: GET http://localhost:8000/cards/C-4471 "HTTP/1.1 200 OK"
C-4471 is owned by CU-8842試してみる
拒否のデバッグ
「カードC-4471が拒否されたのはなぜ?」
list_feature_services → resolve_card → explain_features_for_entity。
過去1時間の7回のスワイプ、合計$2,140(平均$58.20)を返し、チャージバック履歴はゼロと仮定されるのではなく、明示的に利用不可として返されます。
停止したパイプラインを検出
「カードC-7788で古くなっているものはありますか?」
explain_features_for_entityはcard_velocityが2時間のTTLに対して6時間46分古いことをフラグします。値は依然として返されます。読み取りをブロックするものはありません。これはまさにフラグが必要な理由です。
プッシュのラウンドトリップ(書き込み有効化が必要)
「C-7788のスワイプを記録して、もう一度確認してください。」
push_swipe → 同じカードが新しい状態で読み取られます。card_velocityのtrigger_materializationは6時間前のバッチ行にリセットするため、デモは繰り返し可能です。
レイアウト
requirements.txt pinned, verified working set
preflight.py interpreter + dependency check, run by both scripts
setup.sh data + apply + materialize
run_api.sh starts the API on the right interpreter
run_mcp.sh starts the MCP server by hand (debugging)
mcp_cli.py drives the MCP server from a shell, with --trace
host.py local-LLM MCP host -- the model picks the tools
feature_repo/ Feast definitions + feature_store.yaml (the only Feast config)
data_gen/ mock data generator
api/ FastAPI + the Feast SDK <- the API boundary
routers/ catalog | lineage | health | values
mcp_server/ MCP tools, HTTP client only <- no Feast import
tools/ catalog | lineage | health | values | adminapi/routers/とmcp_server/tools/は1対1で対応しています。
メモ
chargebacks_lifetimeはInt64ではなくFloat64です。 このフィーチャーは実際にnull許容であり、nullの整数はParquet → pandas → Feastパスで表現できません。セットアップには
materialize-incrementalではなくfeast materializeを使用してください。 インクリメンタルはビューのTTLを開始境界として使用するため、2時間のTTLでは、古いペルソナを機能させる6時間前の行をスキップしてしまいます。レジストリキャッシュ。
feature_store.yamlのcache_ttl_seconds: 30は、別のシェルでのfeast applyが30秒以内に反映されることを意味します。POST /admin/reloadは即座に強制し、オンラインストアも再オープンします。これは単純なレジストリリフレッシュでは行われません。モックデータは時間に固定されています。
card_velocityには2時間のTTLがあるため、./setup.shの実行から数時間以上経過すると、すべてのカードが古い状態で読み取られ、ペルソナを区別できなくなります。./setup.shを再実行してください。SQLiteの並行性。 uvicornが読み取っている間に
feast materializeが書き込むと、ロック競合が発生する可能性があります。ローカルでは問題ありません。本番のオンラインストアではありません。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI models to interact with local CSV and Parquet data through MCP tools, providing summarization and analysis capabilities.1
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Tecton clusters through MCP, allowing management of feature stores, execution of Tecton CLI commands, and retrieval of feature store configurations via natural language.
- AlicenseAqualityDmaintenanceExposes Azure AI Foundry agents, workflows, and AI Search vector-database capabilities as MCP tools, enabling natural language interaction with agents, semantic search, and index management.102MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to manage local project files and Git operations through MCP tools, including file CRUD, search, Git status, recent commits, and project summaries.
Related MCP Connectors
Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.
Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sidbu546/mcp_feast_dev'
If you have feedback or need assistance with the MCP directory API, please join our Discord server