1. ローカルに WebSearch 環境を構築

Windows 11 環境において、LM Studio で動作する AI Agent(ローカルLLM)に外部インター ネット検索機能を持たせ、ソース(参考リンク)を出力させるには、大きく分けて2つの アプローチがありる。

  1. LM Studio 標準の「MCP (Model Context Protocol)」機能を利用する(単体完結)

  2. 「AnythingLLM」などの外部フロントエンドツールと連携する(高機能・GUIが優秀)

現在は LM Studio 自体が Anthropic の提唱する MCP(Model Context Protocol)を標準 サポートしているため、LM Studio の画面内だけで完結させる方法(方法1)が最も シンプルでおすすめです。

1.1. 方法1:LM StudioのMCP(Model Context Protocol)機能を利用する

LM Studio に「Brave Search」などの外部検索 MCP サーバーを登録することで、AI が自律的に インターネットを検索し、ソース付きで回答を生成できるようになる。

1.1.1. 必要な前提環境の準備

  • Windows 11 に Node.js または Python (uvx) がインストールされている必要がある (MCP サーバーの実行に必要です)。

    • 💡 Node.js(LTS版)を公式サイト等からインストールしておくのが最も確実です。

  • 検索 API キーの取得:

    • 無料で使える AI 向け検索 API として Brave Search API が広く使われている。 「Brave Search API Dashboard」等から無料枠(Free Tier)の API キーを 取得してください。

1.1.2. LM Studioでの設定手順

  1. Tool使用(Function Calling)対応モデルの用意:

    • LM Studio 内で、ツール利用に対応したモデル(例: Gemma 3, Llama 3.1 / 3.2 Instruct, Qwen 2.5 Instruct など)をダウンロードする。

    • モデル名の横にハンマー(かなづち)のアイコンがついているものが対応モデルです。

  2. mcp.json の編集:

    • LM Studio の右側パネル、または設定(Settings)から 「Edit mcp.json」 を開く。

    • 以下のように、Brave Search MCPサーバーの設定を記述する(Node.jsの npx を利用する例です)。

{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-brave-search"
      ],
      "env": {
        "BRAVE_API_KEY": "YOUR_BRAVE_API_KEY_HERE"
      }
    }
  }
}

3.MCP の有効化とチャットでの利用:

  • 設定を保存すると、LM Studio のチャット画面の右側(Integrations / Tools)に brave-search が表示される。

  • トグルを ON にし、ピン留め(Pin)する。

  • チャットで「最新の日本のニュースは?」など、ローカルの知識にない質問を投げると、 AI Agent が自動的に外部検索を実行して情報を補完し、参考リンク付きで回答を出力する。

1.2. 方法2:AnythingLLM(フロントエンド)と連携する

チャットの UI や参考リンクの表示の見やすさ、引用元へのアクセスのしやすさを重視する 場合、LM Studio をバックエンド(API サーバー)として扱い、フロントエンドに AnythingLLM (デスクトップ版)を組み合わせる構成が非常に強力です。

  1. LM Studio側の設定(APIサーバー化)

    1. LM Studioの左側メニューから「Local Server」(開発者向けタブ)を開く。

    2. 上部のドロップダウンで、Tool利用に対応したモデルを選択してロードする。

    3. 「Start Server」 をクリックして、OpenAI互換のローカルAPIサーバーを起動する (デフォルトでは http://localhost:1234/v1 で起動)。

  2. AnythingLLM側の設定

    1. AnythingLLMのインストール: 公式サイトからWindows版をダウンロードしてインストールする。

    2. LLMの接続設定:

      • 初期設定、または設定画面の「LLM Provider」で 「LM Studio」 を選択する。

      • Base URLに http://localhost:1234/v1 を指定し、LM Studio側でロードしたモデルを選択する。

    3. Agentスキルの設定(Web Searchの有効化):

      • ワークスペースの設定、または「Agent Skills」メニューを開く。

      • 「Web Search」 を ON にする。

      • 検索プロバイダー(Search Provider)を選択する。

        • Google Programmable Search、Brave Search、あるいは完全無料でローカル構築可能な SearXNG(Dockerが必要)などが選ぶ。APIキー等を入力して保存する。

      • ついでに 「Scrape websites」 もONにしておくと、検索で見つかったURLの中身をAIが読み込めるようになる。

  3. 利用方法

    • AnythingLLMのチャット画面で、プロンプト入力欄の近くにある「Agent Mode」(あるいは @agent を入力)を指定して質問する。

    • AI Agentが自動的に検索エンジン経由で情報を補完し、回答の末尾や途中にクリック可能な参考リンク(ソース)を綺麗に明示してくれる。

      💡 構築成功のための重要なポイント
      • モデルの選定: 外部検索(Tool呼び出し)を正確に行うには、パラメータ数が少なすぎるモデル(1B〜3Bクラス)だと指示を無視したり、検索クエリの組み立てに失敗することがある。PCのスペック(VRAM容量)が許す限り、8B(80億パラメータ)クラス以上の「Instruct」モデルを使用することをお勧めする。

どちらの手法も、一度環境を作ってしまえば「機密性の高い処理は完全にローカル」「最新情報の検索時のみ外部APIを使用」というハイブリッドで安全なAI Agent環境が実現可能です。

2. WebSearch の自作(制限なし)

Windows 11 + LM Studioの環境で、「完全無料・無制限」の検索MCPサーバーをRustで構築 する場合、最大の鍵は「APIキーが不要な検索手段をどう確保するか」です。Brave SearchやSerperなどのAPIは無料枠に制限がある。

完全無料・無制限を実現するには、「SearXNG(プライベートインスタンス)」をローカルで立ち上げてそれを叩くか、「DuckDuckGoなどのスクレイピング(あるいはDDGのLite版やhtml版のパース)」を利用するのが現実的です。ここでは、最もシンプルかつ規制されにくい「DuckDuckGoのHTML/JSONエンドポイントを内部的に利用する形」、または「SearXNG連携」を想定し、ホワイトリスト/ブラックリスト機能を組み込んだRust製MCPサーバーの具体的な実装方法を解説する。

2.1. 🛠️ 開発環境と構成

  • OS: Windows 11

  • ランタイム: LM Studio (MCPクライアント)

  • 言語: Rust

  • 主要クレート:

    • tokio: 非同期処理

    • reqwest: 検索クエリの送信・HTML取得

    • scraper: HTMLパース用(スクレイピングの場合)

    • serde / serde_json: 設定ファイル(リスト)やMCPプロトコルの処理

    • url: ドメインの抽出とフィルタリング

2.2. 📂 プロジェクトの作成と依存関係

まず、Cargoプロジェクトを作成し、Cargo.toml に必要なライブラリを設定します。

[package]
name = "mcp-free-search"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.0", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
scraper = "0.19" # スクレイピング用
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
url = "2.5"

2.3. 💻 具体的な実装コード (main.rs)

MCP は標準入力(stdin)と標準出力(stdout)を使ってJSON-RPCで通信します。 以下は、ホワイトリスト/ブラックリストの読み込み機能と、検索機能を備えた MCP サーバーの骨子です。

use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fs::File;
use std::io::{self, BufRead, Write};
use url::Url;

// --- データ構造定義 ---

#[derive(Deserialize, Debug)]
struct FilterLists {
    whitelist: HashSet<String>,
    blacklist: HashSet<String>,
}

#[derive(Deserialize)]
struct McpRequest {
    jsonrpc: String,
    method: String,
    params: Option<serde_json::Value>,
    id: Option<serde_json::Value>,
}

#[derive(Serialize)]
struct McpResponse {
    jsonrpc: String,
    result: serde_json::Value,
    id: Option<serde_json::Value>,
}

// --- フィルタリングロジック ---

fn is_allowed(url_str: &str, lists: &FilterLists) -> bool {
    let parsed_url = match Url::parse(url_str) {
        Ok(u) => u,
        Err(_) => return false,
    };

    let domain = parsed_url.host_str().unwrap_or("").to_string();

    // 1. ブラックリストチェック (マッチしたら除外)
    if !lists.blacklist.is_empty() && lists.blacklist.iter().any(|d| domain.contains(d)) {
        return false;
    }

    // 2. ホワイトリストチェック (リストが空でなければ、マッチしたものだけ許可)
    if !lists.whitelist.is_empty() {
        return lists.whitelist.iter().any(|d| domain.contains(d));
    }

    true
}

// --- 検索エンジン連携 (例: DuckDuckGo HTMLパース) ---
// ※注意: 大量リクエスト時は一時的にブロックされる可能性があるため、
// 本格運用の場合はローカルに「SearXNG」をDocker等で立てて、そのAPIを叩く形が最も安定します。
async fn search_internet(query: &str, lists: &FilterLists) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let client = reqwest::Client::builder()
        .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
        .build()?;

    // DuckDuckGoのHTML版を利用する例
    let url = format!("https://html.duckduckgo.com/html/?q={}", urlencoding::encode(query));
    let res = client.get(&url).send().await?.text().await?;

    let document = scraper::Html::parse_document(&res);
    let selector = scraper::Selector::parse(".result__url").unwrap();

    let mut results = Vec::new();

    for element in document.select(&selector) {
        if let Some(raw_url) = element.text().next() {
            let clean_url = raw_url.trim();
            // フィルタリングの適用
            if is_allowed(clean_url, lists) {
                results.push(clean_url.to_string());
            }
        }
    }

    Ok(results)
}

// --- メインループ (LM Studioとの標準入出力通信) ---

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 外部定義のリストを読み込み (config.json)
    let file = File::open("config.json").into_iter().next()
        .ok_or("config.json が見つかりません。")?;
    let lists: FilterLists = serde_json::from_reader(file)
        .unwrap_or(FilterLists { whitelist: HashSet::new(), blacklist: HashSet::new() });

    let stdin = io::stdin();
    let mut handle = stdin.lock();
    let mut buffer = String::new();

    // LM Studioからのリクエストを一行ずつ処理
    while handle.read_line(&mut buffer)? > 0 {
        let req: McpRequest = match serde_json::from_str(&buffer) {
            Ok(r) => r,
            Err(_) => {
                buffer.clear();
                continue;
            }
        };

        // MCPのメソッド判定
        if req.method == "tools/call" {
            // 例として、LLMから渡されたクエリを取得
            if let Some(params) = req.params {
                if let Some(query) = params.get("arguments").and_then(|a| a.get("query")).and_then(|q| q.as_str()) {

                    // 検索の実行
                    if let Ok(search_results) = search_internet(query, &lists).await {
                        let response = McpResponse {
                            jsonrpc: "2.0".to_string(),
                            result: serde_json::json!({
                                "content": [{
                                    "type": "text",
                                    "text": format!("検索結果: {:?}", search_results)
                                }]
                            }),
                            id: req.id,
                        };
                        println!("{}", serde_json::to_string(&response)?);
                        io::stdout().flush()?;
                    }
                }
            }
        }

        buffer.clear();
    }

    Ok(())
}

2.4. 📂 設定ファイルの準備 (config.json)

実行バイナリと同じディレクトリに、以下のような config.json を配置します。ドメインの部分一致で判定します。

{
  "whitelist": [],
  "blacklist": [
    "wikipedia.org",
    "w3schools.com"
  ]
}

注意: whitelist にドメインを記述すると、そこに書かれたドメインしか検索結果に表示されなくなります。基本は blacklist 運用がおすすめです。

2.5. 🛠️ LM Studio への登録方法

1.Rustプロジェクトをビルドします。

cargo build --release

2.生成された target/release/mcp-free-search.exe の絶対パスをコピーします。 3.LM Studio の MCP 設定画面(または ~/.lmstudio/mcp-config.json)に以下のように登録します。

{
  "mcpServers": {
    "free-search-server": {
      "command": "C:/path/to/your/project/target/release/mcp-free-search.exe",
      "args": [],
      "env": {}
    }
  }
}

2.6. 💡 より安定して「無制限」に運用するためのワンポイント

上記コードで紹介したDuckDuckGoなどの直接スクレイピングは、LM Studioから短時間に大量の検索をかけると、一時的にロボット判定(403 Forbiddenやセッションブロック)を受けるリスクがあります。

これを完全に回避し、文字通り「無制限・無料」で安定運用したい場合の最強の構成は「SearXNG」のローカルローテーションです。

  1. Windows 11にDocker Desktopを入れ、オープンソースのメタ検索エンジンSearXNGをローカル(localhost:8080)で起動する。

  2. SearXNGは内部でGoogle、Bing、DuckDuckGoなどの結果を自動で束ねてJSONで返してくれるため、Rust側からは単に http://localhost:8080/search?q=…​&format=json を叩くだけで良くなります(APIキー不要)。

  3. Rustの search_internet 関数内を、SearXNGのローカルAPIを叩く処理に書き換える。

この構成にすれば、スクレイピングのパースコードが相手のサイトデザイン変更で壊れる心配もなくなり、非常に堅牢なプライベート検索MCPサーバーが完成します。

3. 検索でDB参照

3.1. 共通の環境設定手順

3.1.1. ステップ1: 事前準備(Windows環境の整備)

MCPサーバーの多くは Node.js (npx) や .NET CorePython をベースに動作します。まずはWindows 11に以下のランタイムをインストールしておきます。

  • Node.js (LTS推奨):パッケージマネージャー(npm/npx)を使用するために必須です。

  • .NET 8.0 SDK / Runtime:Microsoft製のSQL MCP Serverを動かす場合に必要です。

3.1.2. ステップ2: LM StudioのMCP設定ファイルを開く

LM Studioは、アプリ内の設定、または以下のローカルパスにある mcp.json(または mcp-config.json)でMCPサーバーを管理します。

設定ファイルの標準的なパス

C:/Users/<ユーザー名>/.lmstudio/mcp.json
(※LM Studioの画面左側、あるいは設定(歯車マーク)の「MCP」項目からも直接エディタで編集・追加が可能です)

3.1.3. ステップ3: mcp.json へのサーバー登録

複数のRDBMS(SQL Server, PostgreSQL, MySQL)を1つでカバーできるMicrosoft公式の SQL MCP Server (Data API builder) を登録する例です。
mcp.jsonmcpServers オブジェクト内に以下のように記述します。

{
  "mcpServers": {
    "sql-mcp-server": {
      "command": "dotnet",
      "args": [
        "tool",
        "run",
        "dab",
        "start"
      ],
      "env": {
        "DAB_ENVIRONMENT": "Development"
      }
    }
  }
}

(※あらかじめ dotnet tool install --global Microsoft.DataAPIBuilder でDABをインストールしておくか、各DB専用のNode.js製MCPサーバーを個別指定する方法もあります。個別指定の記述は後述の「DB毎のアプローチ」を参照してください)

3.2. AI Agentでの利用手順・プロンプト例

環境設定が完了し、LM Studio側でMCPサーバーが「Green(接続済み)」になったら、AI Agent(Tool Use / Function Callingに対応したモデル、例: qwen2.5-coder-14b や Llama-3 系など)を起動します。

AI Agentは自動的にDBのスキーマを解読するツール(list_tables や describe_table、execute_query など)を認識します。

データの検索(プロンプト例)

「usersテーブルから、先月登録されたアクティブなユーザーを最大10件検索して、名前とメールアドレスの一覧を出力してください。」

データの集計(プロンプト例)

「ordersテーブルとproductsテーブルを結合し、商品カテゴリごとの売上合計金額を計算して、売上が高い順にランキング形式で教えてください。」

Agentの内部挙動
  1. AIが指示を理解し、適切なSQLクエリ(SELECT …​ GROUP BY …​)をバックグラウンドで自動生成。

  2. MCPサーバー経由で対象のDBにクエリを発行。

  3. 返ってきたJSON形式の集計データを、AIが自然な日本語の文章や表に整形してユーザーに回答。

3.3. DB毎のアプローチと接続文字列・個別設定

Microsoft製のSQL MCP Serverで対応しきれない場合や、よりシンプルな軽量プラグイン(Node.js/npx)を用いて個別に接続する場合の、DBごとのアプローチと設定方法です。

  • ① PostgreSQL / MySQL / MariaDB
    これらは最も標準的なMCPサーバーが用意されています。個別に立ち上げる場合は npx を利用するのが最も手軽です。

    • PostgreSQL用の設定例(mcp.json):

"postgres-mcp": {
  "command": "npx",
  "args": [
    "-y",
    "@modelcontextprotocol/server-postgres",
    "postgresql://username:password@localhost:5432/mydb"
  ]
}
  • MySQL / MariaDB用の設定例:
    公式またはサードパーティ製の mcp-server-mysql 等を利用し、接続URL(mysql://user:pass@host:port/db)を引数に渡します。

    • ② SQL Server (オンプレミス / Azure SQL)
      MicrosoftのSQL MCP Server(Data API builder)を使用する場合、カレントディレクトリに dab-config.json という接続設定ファイルを配置します。

  • 接続文字列の例:
    Server=tcp:localhost,1433;Initial Catalog=mydb;User Id=sa;Password=YourPassword;TrustServerCertificate=True;

  • Windowsの統合認証(Windows認証)を使用する場合は、LM Studioを実行しているユーザー権限でDBにアクセスできるよう、接続文字列に Integrated Security=True; を指定します。

    • ③ SQLite (ローカルファイルベース)
      サーバーを常時起動していない軽量なSQLiteの場合、ローカルの .db ファイルの絶対パスをMCPサーバーに教える必要があります。

  • SQLite用の設定例(mcp.json):

"sqlite-mcp": {
  "command": "npx",
  "args": [
    "-y",
    "@modelcontextprotocol/server-sqlite",
    "C:\\path\\to\\your\\database.db"
  ]
}

※Windows環境ではパスの区切り文字(\)を \\ とエスケープすることを忘れないでください。

  • ④ Oracle Database Oracleは独自のクライアント(Instant Client)や太いドライバ層が必要になることが多いため、汎用のNode.js製MCPよりも、Pythonベース、または専用にラップされたMCPサーバー(LobeHub等で公開されている samscarrow-mcp-servers-lmstudio のOracle版など)を利用するのが確実です。

    • アプローチ: Dockerで中継コンテナを立てるか、Pythonの oracledb ライブラリを使用した自作の軽量MCPスクリプトを "command": "python" で呼び出す方式が、Windows環境では最も接続エラー(環境変数の競合など)を起こしにくく安定します。

3.4. ⚠️ Win11環境における注意点(セキュリティと権限)

  1. 読み取り専用(Read-Only)の徹底: AI Agentに直接クエリを発行させる場合、プロンプトインジェクション等によって意図しないデータ削除(DROP や DELETE)が実行されるリスクがあります。MCP経由で接続するDBユーザーには、必ず参照権限(SELECT)のみを付与した専用アカウントを設定してください。

  2. 文字コード(UTF-8): Windows環境のRDBMSで日本語データを扱う場合、Agentに渡却されるデータが文字化けしないよう、DB側のエンコーディングがUTF-8になっているか、または接続文字列のオプションで適切な文字コードを指定してください。