Believe you can

If you can dream it, you can do it.

MCPで"自分だけの相場AI"を作ってみた

ZOZO Advent Calendar 2025 カレンダー Vol.12 の 20 日目の記事です。
恒例になりつつある黒トイプー琥珀の3歳の誕生日にアドベントカレンダーを書かせてもらいます。

Happy Birthday!!

犬のヌイグルミの上で日向ぼっこ

アドベントカレンダーしか記事を公開しないブログとなりつつありますね、、
毎年言っていますが来年は初心に帰ってインプット(主に勉強会の参加など)を増やしてアウトプット(感想記事)を行っていければと思っています。

古着の相場ってむずかしくない?

先日、僕が入会している某アーティストのファンクラブ配信で、アーティストの私物ブランド品のフリマ販売が行われました。
サンローランのブルゾンが30,000円、GUCCIのブーツも30,000円、ルイヴィトンのジャケットが10,000円と破格の値段でしたが残念ながら抽選にはずれてしまい、購入することはできませんでした。。。
そのような超格安販売を見ていてふと、「これ、いま買ったら後で値上がりするの?それとも下がるの?」みたいな疑問が頭をよぎりました(転売は絶対しません)。
特に最近は、

  • ブランドのリバイバル
  • コラボによる一時的な高騰
  • モデルチェンジによる相場落ち

など、アイテムごとに動き方がけっこう違います。
ただ、僕が実際にやっているのは、メルカリを数ページ検索してなんとなくの相場感をつかんで「たぶんこのへんの値段かな?」と判断するという、わりと属人的で肌感に頼る感じです。

もちろんそれでも問題ないですが、最近のAIブームの中で、ふとこんなことを考えました。
相場の「傾向」だけでもAIに補助してもらえないか?
細かい統計モデルやMLをやるほど大げさにしたいわけではなくて、もっとざっくりした判断をAIに持たせたい。

たとえば、

  • COMME des GARÇONS のベーシックTは年式が多少古くても需要が落ちない
  • ACG のアウターは2010年代前半の値動きが独特
  • スニーカーはリリース年とカラーで上下の差が激しい
  • GUCCI のバッグは年式が古いと一気に相場が落ちることがある

こういうジャンルごとの傾向はAI とデータがセットになるとかなり得意領域になります。
そこで今回試してみたのが、「古着・ブランド価格リスク判定MCP」 という仕組みです。

MCP(Model Context Protocol)を使うことで、自分で作ったミニDB(SQLite)をAIの“外部ツール”として扱い、ブランド×アイテム×年式の入力から、「いま買うと価値が上がりそうか/下がりそうか」を返せるようにしていきます。
投資ではなく、あくまで“相場の傾向をデータとして扱うための実験”という位置づけです。

これを作ってみると、思った以上に手軽に「AIの相場アシスト」が実現できたので、この記事ではその作り方を順番に紹介していきます。

まずはミニ相場DBを作る:SQLiteでブランド × アイテム × モデル名 × 色 × サイズを管理

「相場をAIに判断させる」と聞くと難しく感じますが、最初は 手元のミニDB(SQLite だけあれば十分です。
古着やスニーカー市場は、同じブランド・同じアイテムでも “モデル名・カラー・サイズ” で価値が激変する世界です。

そのため今回のミニDBでは、以下の7つの軸で管理することにしました。

  • ブランド(brand)
  • アイテムタイプ(item_type)
  • 商品名・モデル名(model_name)
  • 色(color)
  • サイズ(size)
  • 年式(year)
  • 平均相場(avg_price)

これだけでも、それっぽい相場感が出せます。

SQLite を作る

まずDB本体を作ります。

sqlite3 items.db

SQLite のプロンプトが開いたら、以下のテーブル作成SQLを流します。

テーブル構造(色・サイズ・モデル名まで含む)

CREATE TABLE items (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  brand TEXT NOT NULL,
  item_type TEXT NOT NULL,
  model_name TEXT,
  color TEXT,
  size TEXT,
  year INTEGER,
  avg_price REAL,
  currency TEXT
);
  • model_name
    • “Dunk Low Retro Panda” / “Box Logo Tee” / “Classic Leather” などの商品名
  • color
    • 黒 / 白 / Red / “Black/White” など
  • size
    • Tシャツ:M / L
    • スニーカー:27.5 / 28
    • バッグ:Small / Medium etc.

扱うジャンルによって揺れがあるので、TEXT型で柔軟にしておくのがポイント。

とりあえず数件だけでも十分

まずは、動かすためのダミーデータです。
※実在の相場ではありません(例示用)。

INSERT INTO items (brand, item_type, model_name, color, size, year, avg_price, currency)
VALUES
  ('Supreme', 'T-shirt', 'Box Logo Tee', 'White', 'L', 2021, 21000, 'JPY'),
  ('Supreme', 'T-shirt', 'Box Logo Tee', 'Black', 'L', 2020, 24000, 'JPY'),
  
  ('Nike', 'Sneakers', 'Dunk Low Retro "Panda"', 'Black/White', '27.5', 2020, 28000, 'JPY'),
  ('Nike', 'Sneakers', 'Dunk Low Retro "Panda"', 'Black/White', '28.0', 2021, 32000, 'JPY'),

  ('GUCCI', 'Bag', 'GG Marmont Matelassé Small', 'Black', NULL, 2019, 120000, 'JPY'),
  ('GUCCI', 'Bag', 'GG Marmont Matelassé Small', 'Beige', NULL, 2018, 110000, 'JPY'),

  ('COMME des GARÇONS', 'T-shirt', 'Heart Logo Tee', 'White', 'M', 2022, 9000, 'JPY'),
  ('COMME des GARÇONS', 'T-shirt', 'Heart Logo Tee', 'Black', 'L', 2020, 12000, 'JPY');

これだけでも、「ブランドの傾向 + モデルの人気 + カラー人気 + サイズ人気」が相場にどう効いているかがなんとなく見えるデータになります。

中身を確認

SELECT brand, item_type, model_name, color, size, year, avg_price
FROM items;

数行入っていればOKです。

どう使うのか?

次章で作る MCPサーバー は、ユーザーから受け取った情報(例:ブランド=Nike、アイテム=スニーカー…)を元に、

  1. SQLite から近いレコードを検索
  2. モデル名・カラー・サイズを加味して相場の傾向を評価
  3. 「上がりそう / 下がりそう」をスコア化
  4. JSONで返す

という流れで動きます。
つまりこの items.db が、AIが“相場のクセ”を学習するためのミニ辞書の役割を果たします。

"古着・ブランド価格リスク判定MCP" を最小構成で作る

ここからは、いよいよ MCPサーバー本体 を作っていきます。
やることはシンプルで、

  1. Node.js で MCP サーバーを立ち上げる
  2. さきほど作った items.dbSQLite)を読み込む
  3. ブランド / アイテム / 年式 などの条件で検索
  4. 「上がりそう/下がりそう」のざっくり評価を返すツールを作る

という流れです。
ここでは あくまで"最小構成のサンプル"に絞ります。

プロジェクトの準備

まずは適当なディレクトリを作ります。

mkdir vintage-risk-mcp
cd vintage-risk-mcp

npm init して最低限の設定をします。

npm init -y

次に、必要なライブラリを入れます。

npm install sql.js
npm install @modelcontextprotocol/sdk

TypeScript にしたい場合は typescript / ts-node なども入れればよいですが、ここでは シンプルに Node.js(CommonJS or ES Modules)で動く前提のサンプルにしておきます。

Note: better-sqlite3 はネイティブモジュールのため、Node.js のバージョンによってはビルドエラーが発生することがあります。sql.js は Pure JavaScript 実装なので、環境を選ばず動作します。

ファイル構成(最小)

とりあえずこんなイメージです。

vintage-risk-mcp/
  ├─ items.db          # 作ったSQLiteファイルをここにコピー
  ├─ package.json
  └─ server.mjs        # MCPサーバー本体(ES Modules形式)

package.json の例

必要に応じて "type": "module" をつけておきます。

{
  "name": "vintage-risk-mcp",
  "version": "0.1.0",
  "type": "module",
  "main": "server.mjs",
  "scripts": {
    "start": "node server.mjs"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "sql.js": "^1.10.0"
  }
}

バージョンは実際のSDKや環境に合わせて調整してください。

リスク判定の考え方(ゆるいロジック)

ここではあくまで「相場の“傾き”をざっくり見るだけ」のロジックにします。
入力として受け取るのは、だいたいこのあたり:

  • brand(ブランド名)
  • item_type(T-shirt, Sneakers, Bag …)
  • year(買おうとしているアイテムの年式)
  • あれば:model_name, color, size

これをもとに、SQLiteから近いレコードを取ってきて、以下のような判定をします。

ざっくりアルゴリズム例:

  1. 同じブランド & アイテムタイプのデータを取得(必要に応じて model_name・color・size を絞る)
  2. year が小さい順にソートして、価格推移をざっと見る
  3. 直近数年の平均価格の変化率を見る
  4. 変化率に応じて:
  5. 上昇傾向 → trend: "up", risk: "low"
  6. 横ばい → trend: "flat", risk: "medium"
  7. 下降傾向 → trend: "down", risk: "high"

もちろん、本気でやるならもっと複雑にできますが、記事の段階ではこのくらいの“ゆるさ”がちょうどいいです。

server.mjsMCPサーバー本体)

以下が実際に動作するMCPサーバーのコードです。

// server.mjs

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import initSqlJs from 'sql.js';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// SQLite を開く
const SQL = await initSqlJs();
const dbBuffer = readFileSync(join(__dirname, 'items.db'));
const db = new SQL.Database(dbBuffer);

// MCPサーバーを初期化
const server = new Server(
  {
    name: 'vintage-price-risk',
    version: '0.1.0',
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// ツール一覧を返すハンドラ
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'judge_vintage_price_risk',
        description:
          'ブランド古着の相場傾向から、価格リスク(上がりそう/下がりそう)をざっくり判定する。',
        inputSchema: {
          type: 'object',
          properties: {
            brand: { type: 'string', description: 'ブランド名' },
            item_type: { type: 'string', description: 'アイテム種別(T-shirt, Sneakers, Bag など)' },
            model_name: { type: 'string', description: '商品名・モデル名' },
            color: { type: 'string', description: '色' },
            size: { type: 'string', description: 'サイズ' },
            year: { type: 'number', description: 'アイテムの年式' },
          },
          required: ['brand', 'item_type'],
        },
      },
    ],
  };
});

// ツール実行ハンドラ
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name !== 'judge_vintage_price_risk') {
    throw new Error(`Unknown tool: ${request.params.name}`);
  }

  const { brand, item_type, model_name, color, size, year } = request.params.arguments;

  // 1. ベースとなるクエリを組み立てる
  let query = `
    SELECT year, avg_price
    FROM items
    WHERE brand = ?
      AND item_type = ?
  `;
  const params = [brand, item_type];

  // 任意項目で少しずつ絞り込む(あれば使う)
  if (model_name) {
    query += ` AND model_name = ?`;
    params.push(model_name);
  }
  if (color) {
    query += ` AND color = ?`;
    params.push(color);
  }
  if (size) {
    query += ` AND size = ?`;
    params.push(size);
  }

  query += ` ORDER BY year ASC`;

  const result = db.exec(query, params);
  const rows = result.length > 0 ? result[0].values.map(row => ({ year: row[0], avg_price: row[1] })) : [];

  // 2. データが少なすぎる場合
  if (rows.length < 2) {
    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify({
            risk: 'unknown',
            trend: 'unknown',
            score: 0.0,
            reason:
              '該当データが少なすぎるため、価格リスクを判定できませんでした。ブランドや条件を変えてみてください。',
            sampleYears: rows.map((r) => r.year),
          }),
        },
      ],
    };
  }

  // 3. 推移をざっくり計算する(最後と最初の比だけ見るシンプル版)
  const first = rows[0];
  const last = rows[rows.length - 1];

  const diff = last.avg_price - first.avg_price;
  const rate = diff / first.avg_price; // 変化率

  let trend = 'flat';
  let risk = 'medium';
  let score = 0.5;

  if (rate > 0.15) {
    trend = 'up';
    risk = 'low';
    score = 0.8;
  } else if (rate < -0.15) {
    trend = 'down';
    risk = 'high';
    score = 0.2;
  }

  // 年式指定があれば、それも軽くコメントに反映する
  let yearComment = '';
  if (year) {
    const closest = rows.reduce((prev, curr) => {
      return Math.abs(curr.year - year) < Math.abs(prev.year - year) ? curr : prev;
    });
    yearComment = `指定された年式 ${year} 年に最も近いデータは ${closest.year} 年の平均相場 ${closest.avg_price} 円です。`;
  }

  // 4. 結果を返す
  return {
    content: [
      {
        type: 'text',
        text: JSON.stringify({
          risk,
          trend,
          score,
          rate,
          sampleYears: rows.map((r) => r.year),
          reason: `ブランド「${brand}」の「${item_type}」について、初期の平均相場 ${first.avg_price} 円から直近の平均相場 ${last.avg_price} 円へ変化しています(変化率: ${(rate * 100).toFixed(1)}%)。${yearComment}`,
        }),
      },
    ],
  };
});

// MCPサーバーを起動(標準入出力で待ち受け)
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('Vintage Price Risk MCP server running on stdio');
}

main().catch(console.error);

ざっくり動作イメージ

この MCP サーバーが立ち上がると、Claude(MCP対応クライアント)からは、だいたいこんなイメージで呼ばれます。

  • Claude に:

    Nike の Dunk Low Panda で、スニーカー、サイズ 27.5、2020年あたりの相場の傾向を見て。上がりそうか、下がりそうかざっくり教えて。」

  • Claude は judge_vintage_price_risk ツールを呼び出し、brand="Nike", item_type="Sneakers", … を渡す

  • MCPサーバーが SQLite を検索して、JSON で risk, trend, score, reason を返す
  • Claude がそれを読み取り、人間向けの文章でまとめ直す

という流れです。

この章のゴール

この章のゴールは、SQLite のミニDBをMCPを通じて「古着・ブランド価格リスク判定ツール」として公開できるというところまで持っていくことでした。
ロジック自体はものすごく単純ですが、「自分で定義した相場ロジックを、AIのツールとして組み込めた」というところが一番大きなポイントです。

Claude に聞いてみる:「このアイテム、今買うとどう?」

ここまでで、

  • items.db(ミニ相場DB / SQLite
  • judge_vintage_price_risk ツールを持った MCP サーバー

が用意できました。
この章では、いよいよ Claude 側からこのMCPを呼び出して使ってみる パートです。

ざっくり全体像

やりたいことはシンプルです。

  1. ユーザーが Claude に自然言語で質問する
  2. Claude が「この質問には judge_vintage_price_risk ツールを使うのが良さそう」と判断
  3. MCPサーバーに対して、必要なパラメータを投げる
  4. MCPサーバーが SQLite を検索し、リスク判定結果を JSON で返す
  5. Claude がその JSON を読み、日本語の解説に変換して返してくれる

最終的に人間から見えるのは、 「AIが過去の相場を見ながらコメントしているような回答」です。

想定プロンプト例①:シンプルな例

まずは、Supreme の Tシャツから。

「Supreme の Box Logo Tee で、白の L サイズ、2021年のモデルって、
いま買うと相場的にどう?上がりそう、それとも下がりそう?」

Claude の内部では、だいたいこんなパラメータで judge_vintage_price_risk が呼ばれているイメージです。

{
  "brand": "Supreme",
  "item_type": "T-shirt",
  "model_name": "Box Logo Tee",
  "color": "White",
  "size": "L",
  "year": 2021
}

MCPサーバー側は、この条件をもとに items テーブルを検索します。

MCPサーバーからのレスポンス例(イメージ)

例えば、こんな JSON が返ってくるとします。

{
  "risk": "low",
  "trend": "up",
  "score": 0.78,
  "rate": 0.21,
  "sampleYears": [2020, 2021],
  "reason": "ブランド「Supreme」の「T-shirt」について、初期の平均相場 21000 円から直近の平均相場 25500 円へ変化しています(変化率: 21.0%)。指定された年式 2021 年に最も近いデータは 2021 年の平均相場 25500 円です。"
}

これをそのまま人間に見せるとちょっと無骨なので、Claude がいい感じに自然文にまとめてくれます。

Claude の回答イメージ

例えば、こんな感じになりえます:

Supreme の Box Logo Tee(White / L / 2021年)について、過去データを見ると平均相場はおよそ 21,000円 → 25,500円 と 約21% 上昇 しています。

直近までの推移だけ見ると 緩やかに値上がり傾向 にあり、いまの水準で購入するリスクはそこまで高くない、という判定になりました。

もちろん市場全体のトレンドやコンディションにもよりますが、「相場が大きく崩れているカテゴリ」ではない、という程度のニュアンスで捉えてもらえれば良いと思います。

MCPが「数字ベースの評価」を担当し、Claude が「文章化・解釈」を担当するイメージです。

想定プロンプト例②:スニーカー・サイズ込み

次に、スニーカーの例を見てみます。

Nike の Dunk Low Retro 'Panda' で、ブラック/ホワイト、27.5cm、2020年頃の相場って今後どうなりそう?ざっくり傾向だけ教えて。」

内部的には、こういう呼び出しになるイメージです。

{
  "brand": "Nike",
  "item_type": "Sneakers",
  "model_name": "Dunk Low Retro \"Panda\"",
  "color": "Black/White",
  "size": "27.5",
  "year": 2020
}

もし items.db に、

  • 2018年:19,000円
  • 2020年:28,000円
  • 2021年:32,000円

みたいなデータが入っていれば、かなり強い上昇トレンドとして判定されるはずです。

Claude の回答イメージ(スニーカー)

Nike Dunk Low Retro "Panda"(Black/White / 27.5cm)について、手元の相場データでは 2018年から2021年にかけて 約19,000円 → 約32,000円 と価格が上昇しており、全体としては強めの上昇傾向になっています。

この傾向だけ見ると、短期的に「暴落リスクが高いカテゴリ」というよりは、「人気が続いているモデル」寄りの動きです。

もちろん再販やモデルチェンジで変わる可能性はありますが、過去数年のデータだけで見れば、いまの価格で買うリスクは比較的低め という判定になります。

このように、数字を“文章の温度感”に変換するところをAIに任せるのがポイントです。

条件があいまいな場合はどうなる?

例えば、以下のようにざっくりした質問をすることもできます。

「COMME des GARÇONS の Tシャツ全般で、最近の相場って上がってる印象?下がってる印象?年式まではあまり気にしてない。」

この場合、Claude が

  • brand = "COMME des GARÇONS"
  • item_type = "T-shirt"

だけを渡して、model_name や color は指定せずに呼び出す、という動きをしてくれるかもしれません。
MCPサーバー側では「該当件数が少ない」「バラつきが大きい」などの状況もふまえて、

  • risk: "unknown"
  • trend: "flat"

などを返すようにしておくと、Claude側でちゃんと

「データがまだ少なめなので断言はできませんが、現時点の傾向としては…」

のようなニュアンスをつけて説明してくれます。

実際に使ってみると見えてくること

実際にいくつかパターンを試すと、

  • 「ブランド × アイテム」だけだと大雑把すぎる
  • 「モデル名・カラー・サイズ」まで入れると、それっぽい話になる
  • データの行数が少ないとすぐに unknown 判定になる
  • 逆に、データが増えてくると“相場のクセ”がはっきり見え始める

といった感覚が分かってきます。

この「データが増えるほど相場感が育っていく」感覚は、実際に試してみるとけっこう楽しいポイントです。

この章のまとめ

この章では、実際に Claude から

「このアイテム、今買うとどう?」

と聞いてみたときの

  • プロンプト例
  • MCPツールへのパラメータの渡り方(イメージ)
  • 戻ってくるJSON
  • Claude が生成する自然文

という一連の流れを見てきました。
MCPが “数字とロジック” を、Claude が “文章と解釈” を担当することで、「自分で定義した相場判定ロジックを、会話の中で使えるようになる」というのが一番のポイントです。

使ってみて気づいたこと & 「データを自動で集めてDBを作る」ならどうする?

ここまでで、 ミニ相場DB(SQLite) → MCP → Claude という流れで、

「このアイテム、今買うとどう?」

を AI にざっくり判定させる仕組みが完成しました。
実際に動かしてみると、 いくつか気づきや改善点、そして 「これ、もっと実用的にするならどうしたらよい?」 という考えも自然と湧いてきます。

この章では、そのあたりをゆるくまとめながら、最後に「データを自動で集めてDBを作る」アイデアまで触れていきます。

まず使ってみて感じたこと

1. モデル名・カラー・サイズはやっぱり重要

古着・スニーカー市場は “個別の特徴で値動きが変わる”世界なので、この3つを入れたことで判定の説得力が一気に上がります。

2. データが少ないとすぐに unknown 判定になる

これはSQLiteの行数を増やせば解決します。
逆にいうと「自分専用の相場データが増えるほど、AIが賢くなる」感じが楽しい。

3. 判定ロジックはシンプルで十分

複雑な回帰や機械学習をする必要はなく、「過去の平均相場の推移を見るだけ」で意外と"人間っぽい"判断が返ってきます。

今後やりたい改善ポイント

ここからは、もっと現実的に使えるための改善案です。

改善1:データ件数を増やす(精度アップの王道)

  • モデル名・カラーごとに最低3年ぶん
  • サイズ違い(スニーカー)は3〜5サイズ
  • バッグなら状態(美品 / 使用感あり)も欲しい

DBが育つほど、AIが「相場のクセ」を掴む速度が速くなるのが面白いところ。

改善2:「コンディション」を追加したくなる

古着は状態がすべてです。
例えば:

  • 新品
  • 未使用に近い
  • 目立った傷汚れなし
  • 使用感あり

これを DB に追加するだけで、より"それっぽい"相場判定になります。

改善3:年式じゃなく「リリースシーズン」に対応したい

スニーカーやデザイナーズブランドは、FW(秋冬)/ SS(春夏)で相場が違うことがあります。
例えば:

  • FW のコートはリリース年よりシーズンの方が重要
  • SS のTシャツは夏前に値段が上がる
  • スニーカーは“初回発売年”が重要

後からカラム追加すれば大丈夫なので、SQLite の柔軟性が活きます。

「検索して対象データを集めてDBを作る」ならどうする?

この記事で一番触れたかった部分かもしれません。
将来的に、手作業でデータを追加するのではなく、検索して集めてDBを作る という方向にも広げられます。
ここでは主要な方法を3つ紹介します。

方法1:公式API(あるなら)を使う

もし利用しているサービスに公式API があれば、それが一番安全で確実です。
- StockX(非公式APIが有名だけど公式も一部あり)
- Grailed(APIあり)
- eBay(API豊富)
- 国内なら一部の小規模マーケットにAPIが存在

APIで検索 → JSONSQLiteに入れるだけで以下が自動化できます:

  • ブランドで検索
  • モデルごとの相場を取得
  • 最新の販売価格を更新
  • データ差分だけ更新

方法2:スクレイピング(規約に注意)

メルカリやラクマなど、HTMLスクレイピングは禁止 or グレー なケースが多いです。
そのためブログで明確に推奨はできませんが、
一般論としては:

  • Playwright / Puppeteer でブラウザ経由の取得
  • BeautifulSoup / Cheerio でHTML解析
  • “出品中価格” ではなく “売却済み価格” を対象にする

などがあります。

ただし、規約がNGな場合は絶対にやらないのが前提です。

自動データ収集 → SQLite更新 の例(擬似コード

SQLite を自動で更新する流れの疑似コードも載せておきます。

import initSqlJs from 'sql.js';
import { readFileSync, writeFileSync } from 'fs';

async function updateDbFromApi(apiResults) {
  const SQL = await initSqlJs();
  const dbBuffer = readFileSync('./items.db');
  const db = new SQL.Database(dbBuffer);

  const insert = db.prepare(`
    INSERT INTO items
    (brand, item_type, model_name, color, size, year, avg_price, currency)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?)
  `);

  for (const row of apiResults) {
    insert.run([
      row.brand,
      row.item_type,
      row.model_name,
      row.color,
      row.size,
      row.year,
      row.avg_price,
      row.currency
    ]);
  }

  insert.free();

  // 更新したDBをファイルに書き戻す
  const data = db.export();
  writeFileSync('./items.db', Buffer.from(data));
  db.close();
}

これを

  1. APIで相場取得
  2. 正規化してJSONにまとめる
  3. 上記関数でSQLiteへ投入

と繋げると「自動でミニ相場DBが育っていく」 世界が実現できます。

この章のまとめ

  • 最初はミニDBでも、データが増えるほどAIが賢くなる
  • モデル名・色・サイズを入れると判定の“実在感”が増す
  • データ収集の自動化は、API → DB更新が最も現実的
  • 企業データを使えば一気にレベルアップも可能
  • SQLite なので構造変更も簡単で、育てるのが楽しい

そして何より、

「相場感」という“肌感覚”の部分を、AIと自作DBで再現できるという面白さ

ここに尽きるかもしれません。

最後に

今回作った 古着・ブランド価格リスク判定MCP は、まだまだ原始的な仕組みですが、

  • 自分の価値観
  • 自分の相場観
  • 自分のデータ

を AI に持たせる第一歩としてはちょうどよい題材でした。
実験素材としても遊びとしても優秀なので、ぜひ SQLite の行数を増やしながら、自分だけの「相場AI」を育ててみてください。