MCP Server完全セットアップガイド
MCP(Model Context Protocol)サーバーを使用することで、AIアシスタントが築古不動産投資シミュレーターを直接操作できるようになります。このガイドでは、Claude Desktop、VSCode、API経由での接続方法を詳しく解説します。
🎯 MCPサーバーの特徴
統合開発環境:Claude Desktop、VSCodeで直接利用可能
リアルタイム計算:AIが投資シミュレーションをリアルタイムで実行
自動化されたワークフロー:複数の物件比較や分析を自動実行
セキュアな接続:OAuth認証とTLS暗号化で安全
エラーハンドリング:詳細なエラー情報とリトライ機能
🖥️ Claude Desktop セットアップ
1. 設定ファイルの作成
Claude Desktopの設定ディレクトリに設定ファイルを作成します。
macOS
~/Library/Application Support/Claude/claude_desktop_config.json
Windows
%APPDATA%\Claude\claude_desktop_config.json
Linux
~/.config/claude/claude_desktop_config.json
2. 設定ファイルの内容
{
"mcpServers": {
"kominka-simulator": {
"command": "node",
"args": [
"server.js"
],
"cwd": "/path/to/kominka-mcp-server",
"env": {
"API_BASE_URL": "https://kominka-apart-sim.vercel.app/api",
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SERVICE_ROLE_KEY": "your-service-role-key",
"JWT_SECRET": "your-jwt-secret"
}
}
}
}
3. サーバーファイルの準備
NPM パッケージのインストール
mkdir kominka-mcp-server
cd kominka-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk axios ws jsonwebtoken
npm install --save-dev @types/node typescript
server.js の作成
#!/usr/bin/env node
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
const axios = require('axios');
const jwt = require('jsonwebtoken');
class KominkaSimulatorServer {
constructor() {
this.server = new Server(
{
name: 'kominka-simulator',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.apiBaseUrl = process.env.API_BASE_URL || 'https://kominka-apart-sim.vercel.app/api';
this.supabaseUrl = process.env.SUPABASE_URL;
this.supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
this.jwtSecret = process.env.JWT_SECRET;
this.setupTools();
}
setupTools() {
// 新規シミュレーション作成ツール
this.server.setRequestHandler({
method: 'tools/call',
schema: {
name: 'create_simulation',
description: '新しい不動産投資シミュレーションを作成',
inputSchema: {
type: 'object',
properties: {
title: { type: 'string', description: 'シミュレーション名' },
property_type: { type: 'string', enum: ['house', 'apartment'] },
property_price: { type: 'number', description: '物件価格(円)' },
annual_rent: { type: 'number', description: '年間家賃収入(円)' },
vacancy_rate: { type: 'number', description: '空室率(%)' },
expense_rate: { type: 'number', description: '経費率(%)' },
use_loan: { type: 'boolean', description: 'ローン利用有無' },
loan_amount: { type: 'number', description: 'ローン金額(円)' },
loan_interest_rate: { type: 'number', description: 'ローン金利(%)' },
loan_term: { type: 'number', description: 'ローン期間(年)' }
},
required: ['title', 'property_type', 'property_price', 'annual_rent']
}
}
}, async (request) => {
try {
const response = await axios.post(`${this.apiBaseUrl}/simulations`, request.params, {
headers: {
'Authorization': `Bearer ${this.generateJWT()}`,
'Content-Type': 'application/json'
}
});
return {
content: [
{
type: 'text',
text: `シミュレーション「${request.params.title}」を作成しました。\n\n` +
`📊 結果:\n` +
`- 表面利回り: ${response.data.results.gross_yield}%\n` +
`- 実質利回り: ${response.data.results.net_yield}%\n` +
`- 月間キャッシュフロー: ${response.data.results.monthly_cash_flow.toLocaleString()}円\n` +
`- ROI: ${response.data.results.roi}%\n` +
`- 共有URL: https://kominka-apart-sim.vercel.app/share/${response.data.share_code}`
}
]
};
} catch (error) {
throw new Error(`シミュレーション作成エラー: ${error.response?.data?.error?.message || error.message}`);
}
});
// シミュレーション一覧取得ツール
this.server.setRequestHandler({
method: 'tools/call',
schema: {
name: 'list_simulations',
description: '保存済みシミュレーション一覧を取得',
inputSchema: {
type: 'object',
properties: {
limit: { type: 'number', description: '取得件数(最大100)', default: 10 },
sort: { type: 'string', enum: ['created_at', 'updated_at', 'property_price'] },
order: { type: 'string', enum: ['asc', 'desc'] }
}
}
}
}, async (request) => {
try {
const params = new URLSearchParams();
if (request.params.limit) params.append('limit', request.params.limit);
if (request.params.sort) params.append('sort', request.params.sort);
if (request.params.order) params.append('order', request.params.order);
const response = await axios.get(`${this.apiBaseUrl}/simulations?${params}`, {
headers: {
'Authorization': `Bearer ${this.generateJWT()}`
}
});
const simulations = response.data.simulations;
const summary = simulations.map(sim =>
`📋 ${sim.title} (${sim.property_type === 'house' ? '戸建て' : 'アパート'})\n` +
` 価格: ${sim.property_price.toLocaleString()}円\n` +
` 利回り: ${sim.results.gross_yield}%\n` +
` 作成日: ${new Date(sim.created_at).toLocaleDateString('ja-JP')}`
).join('\n\n');
return {
content: [
{
type: 'text',
text: `📊 シミュレーション一覧 (${simulations.length}件)\n\n${summary}`
}
]
};
} catch (error) {
throw new Error(`シミュレーション一覧取得エラー: ${error.response?.data?.error?.message || error.message}`);
}
});
// リアルタイム計算ツール
this.server.setRequestHandler({
method: 'tools/call',
schema: {
name: 'calculate_metrics',
description: '投資指標をリアルタイムで計算(保存なし)',
inputSchema: {
type: 'object',
properties: {
property_price: { type: 'number', description: '物件価格(円)' },
annual_rent: { type: 'number', description: '年間家賃収入(円)' },
vacancy_rate: { type: 'number', description: '空室率(%)', default: 5 },
expense_rate: { type: 'number', description: '経費率(%)', default: 20 },
use_loan: { type: 'boolean', description: 'ローン利用有無', default: false },
loan_amount: { type: 'number', description: 'ローン金額(円)' },
loan_interest_rate: { type: 'number', description: 'ローン金利(%)' },
loan_term: { type: 'number', description: 'ローン期間(年)' }
},
required: ['property_price', 'annual_rent']
}
}
}, async (request) => {
try {
const response = await axios.post(`${this.apiBaseUrl}/simulations/calculate`, request.params, {
headers: {
'Authorization': `Bearer ${this.generateJWT()}`,
'Content-Type': 'application/json'
}
});
const results = response.data.results;
return {
content: [
{
type: 'text',
text: `🔢 投資指標計算結果\n\n` +
`📊 基本指標:\n` +
`- 表面利回り: ${results.gross_yield}%\n` +
`- 実質利回り: ${results.net_yield}%\n` +
`- 月間キャッシュフロー: ${results.monthly_cash_flow.toLocaleString()}円\n` +
`- 年間キャッシュフロー: ${results.annual_cash_flow.toLocaleString()}円\n` +
`- ROI: ${results.roi}%\n\n` +
`💰 初期費用:\n` +
`- 総初期費用: ${results.total_initial_cost.toLocaleString()}円\n` +
`${results.monthly_loan_payment ? `- 月間ローン返済額: ${results.monthly_loan_payment.toLocaleString()}円` : ''}`
}
]
};
} catch (error) {
throw new Error(`計算エラー: ${error.response?.data?.error?.message || error.message}`);
}
});
}
generateJWT() {
return jwt.sign(
{ sub: 'mcp-server', aud: 'kominka-simulator' },
this.jwtSecret,
{ expiresIn: '1h' }
);
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
const server = new KominkaSimulatorServer();
server.run().catch(err => {
// Handle server errors
});
🔧 VSCode セットアップ
1. 拡張機能のインストール
VSCode Marketplaceから「MCP Client」拡張機能をインストールします。
2. ワークスペース設定
プロジェクトの.vscode/settings.jsonに設定を追加:
{
"mcp.servers": {
"kominka-simulator": {
"command": "node",
"args": ["path/to/server.js"],
"env": {
"API_BASE_URL": "https://kominka-apart-sim.vercel.app/api",
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SERVICE_ROLE_KEY": "your-service-role-key",
"JWT_SECRET": "your-jwt-secret"
}
}
},
"mcp.autoConnect": true
}
3. 使用方法
コマンドパレット:Ctrl+Shift+P → "MCP: Call Tool"
チャット機能:VSCodeのチャットでMCPツールを直接呼び出し
インテリセンス:型定義によるコード補完
🌐 API経由でのMCP接続
WebSocket接続
WebSocketを使用してMCPサーバーと直接通信できます。
接続例(JavaScript)
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
// JWT トークン生成
const token = jwt.sign(
{ sub: 'api-client', aud: 'kominka-simulator' },
'your-jwt-secret',
{ expiresIn: '1h' }
);
// WebSocket接続
const ws = new WebSocket('wss://kominka-apart-sim.vercel.app/mcp', {
headers: {
'Authorization': `Bearer ${token}`
}
});
ws.on('open', () => {
// ツール呼び出し
ws.send(JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'calculate_metrics',
arguments: {
property_price: 8000000,
annual_rent: 960000,
vacancy_rate: 5,
expense_rate: 20
}
}
}));
});
ws.on('message', (data) => {
const response = JSON.parse(data);
});
ws.on('error', (error) => {
});
HTTP API ラッパー
// MCPツールをHTTP APIとして呼び出し
const response = await fetch('https://kominka-apart-sim.vercel.app/api/mcp/tools/call', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
tool: 'create_simulation',
arguments: {
title: 'テスト物件',
property_type: 'house',
property_price: 8000000,
annual_rent: 960000
}
})
});
const result = await response.json();
🔐 認証とセキュリティ設定
環境変数の設定
セキュリティのため、認証情報は環境変数で管理します。
.env ファイルの例
# MCP Server Configuration
API_BASE_URL=https://kominka-apart-sim.vercel.app/api
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT_SECRET=your-super-secret-jwt-key-here
# OAuth Configuration (optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
権限管理
MCP専用JWT:MCPサーバー専用のJWTトークン
スコープ制限:読み取り・書き込み権限の細かい制御
IPアドレス制限:特定のIPからのアクセスのみ許可
レート制限:過度なAPI呼び出しの防止
🔍 トラブルシューティング
よくある問題と解決方法
1. 接続エラー
症状:MCPサーバーに接続できない
原因:設定ファイルのパスが間違っている
解決方法:設定ファイルの絶対パスを確認
2. 認証エラー
症状:401 Unauthorized エラー
原因:JWT トークンの有効期限切れ
解決方法:JWTトークンを再生成
3. 計算エラー
症状:計算結果が返らない
原因:入力値の範囲エラー
解決方法:物件価格は100万円以上、利回りは妥当な範囲内
デバッグ方法
# ログレベルを設定
export DEBUG=mcp:*
node server.js
# 詳細なエラー情報を出力
export NODE_ENV=development
export LOG_LEVEL=debug
📚 実用例
AIアシスタントとの対話例
基本的な計算
ユーザー: "築30年の戸建て、価格800万円、年間家賃120万円の投資シミュレーションを作成して"
AIアシスタント: MCPツールを呼び出して計算します...
[create_simulation ツール実行]
- 表面利回り: 15.0%
- 実質利回り: 12.35%
- 月間キャッシュフロー: 65,000円
- ROI: 22.5%
この物件は高利回りで収益性が良好です。
複数物件の比較
ユーザー: "3つの物件を比較してベストな投資先を教えて"
AIアシスタント:
物件A: 利回り15% ROI 22%
物件B: 利回り12% ROI 18%
物件C: 利回り18% ROI 25%
→ 物件Cがベストな投資先です。理由:...
🔄 自動更新とメンテナンス
定期メンテナンス
JWTトークンの更新:1時間ごとに自動更新
接続の監視:WebSocket接続の自動復旧
ログの管理:ログファイルの自動ローテーション
アップデート通知
新機能や重要な更新がある場合、MCPサーバーが自動的に通知します。
🔗 関連リンク
API認証・セキュリティガイド
エンドポイント詳細リファレンス
API完全ガイド
MCP仕様書