RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/AIモデル
AIモデル/2026-04-02上級

Rork × MCP(Model Context Protocol)実装ガイド — AIツールを自在に統合する次世代モバイルアプリ開発

Anthropic が提唱するMCP(Model Context Protocol)をRorkアプリに統合する完全ガイド。アーキテクチャ設計からストリーミング対応・認証・プロダクション運用まで、実装コード付きで体系的に解説します。

MCP3Model Context ProtocolRork515AI統合2Claude4ツール統合React Native209advanced3

取り組みの背景:MCPがモバイルアプリ開発の常識を変える

2024年末にAnthropicが発表した**MCP(Model Context Protocol)**は、AIモデルと外部ツール・データソースを接続するための標準プロトコルです。2026年現在、デスクトップアプリやサーバーサイドでのMCP活用は急速に普及しましたが、モバイルアプリへの統合はまだ多くの開発者にとって未踏の領域です。

RorkのようなAIファーストなモバイルアプリ開発環境でMCPを活用できれば、以下のような強力な機能が実現します。

  • 動的ツール統合: データベース操作・Web検索・コード実行などをAIが自律的に呼び出す
  • コンテキスト拡張: RAGを超えた、リアルタイムデータへのアクセス
  • マルチプロバイダー対応: Claude・Gemini・GPT-4oを同一インターフェースで切り替える
  • カスタムツールの追加: 自社APIをMCPサーバーとして公開し、AIに呼び出させる

ここではRorkアプリにMCPを統合するための完全な実装ガイドを提供します。アーキテクチャ設計から実装コード、プロダクション運用まで、すぐに活用できる知識を体系的にまとめましました。

対象読者はRorkでのアプリ開発経験があり、Rork × Claude API で作る AI アシスタントアプリやRork × AI Function Calling で構築するインテリジェントアシスタントアプリを読んだ方、あるいはそれと同等の知識をお持ちの上級開発者を想定しています。


MCPとは何か:アーキテクチャと基本概念

プロトコルの全体像

MCPは以下の3つの役割で構成されます。

  • MCPホスト(Host): AIモデルを呼び出すアプリケーション。今回はRorkアプリがこの役割を担う
  • MCPクライアント(Client): ホスト内でMCPサーバーとの通信を管理するライブラリ
  • MCPサーバー(Server): ツール(tools)・リソース(resources)・プロンプト(prompts)を提供するサービス
[Rorkアプリ(MCPホスト)]
      ↓ MCPクライアント
[MCPサーバー群]
  ├── Brave Search MCP Server
  ├── Supabase MCP Server
  ├── GitHub MCP Server
  └── カスタムAPIサーバー

トランスポート層

MCPのトランスポートには主に2種類あります。

  • stdio: プロセス間通信(デスクトップ/サーバー向け)
  • SSE(Server-Sent Events): HTTP経由のイベントストリーム(モバイルアプリに最適
  • Streamable HTTP: 2025年に追加された新プロトコル(サーバー側で推奨)

モバイルアプリではネットワーク経由での通信が前提となるため、SSEまたはStreamable HTTPを使うのが基本です。

ツール定義の仕組み

MCPサーバーは tools/list エンドポイントでツール一覧をJSON Schemaで提供します。クライアントはこれをAIモデルに渡し、モデルが必要に応じて tools/call を呼び出す流れです。

{
  "name": "search_web",
  "description": "Webを検索して最新情報を取得する",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "検索クエリ" },
      "maxResults": { "type": "number", "default": 5 }
    },
    "required": ["query"]
  }
}

前提知識・環境準備

必要な環境

  • Rork Max(カスタムコード編集・ネイティブモジュール対応が必要)
  • Node.js 20以上(MCPサーバーのローカルテスト用)
  • Anthropic APIキー(Claude claude-3-5-sonnetまたはclaude-opus-4以上を推奨)

使用するパッケージ

Rorkアプリ側(React Native)に以下を追加します。

# MCPクライアントSDK(React Native対応フォーク)
npm install @modelcontextprotocol/sdk
 
# HTTPクライアント(fetch APIのストリーミング対応補完)
npm install eventsource
 
# Anthropic SDK
npm install @anthropic-ai/sdk

MCPサーバーのセットアップ(バックエンド)

npm create cloudflare@latest my-mcp-server -- --template worker
cd my-mcp-server
npm install @modelcontextprotocol/sdk

MCPサーバーの実装(Cloudflare Workers)

基本的なMCPサーバー構造

// src/index.ts(Cloudflare Workers MCPサーバー)
import { McpAgent } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
 
export class MyMCPServer extends McpAgent {
  server = new McpServer({
    name: "my-mobile-mcp-server",
    version: "1.0.0",
  });
 
  async init() {
    // ツール1: データベース検索
    this.server.tool(
      "search_products",
      "商品データベースを検索する",
      {
        query: z.string().describe("検索キーワード"),
        category: z.string().optional().describe("カテゴリ絞り込み"),
        limit: z.number().default(10).describe("最大取得件数"),
      },
      async ({ query, category, limit }) => {
        // Supabaseなどのデータベースから検索
        const results = await searchProductsFromDB(query, category, limit);
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(results, null, 2),
            },
          ],
        };
      }
    );
 
    // ツール2: 在庫確認
    this.server.tool(
      "check_stock",
      "商品の在庫数を確認する",
      {
        productId: z.string().describe("商品ID"),
      },
      async ({ productId }) => {
        const stock = await getStockFromDB(productId);
        return {
          content: [
            {
              type: "text",
              text: `商品ID ${productId} の在庫: ${stock}個`,
            },
          ],
        };
      }
    );
  }
}
 
// Streamable HTTP トランスポートでエクスポート
export default new OAuthProvider({
  apiHandlers: {
    "/mcp": MyMCPServer.mount("/mcp"),
  },
  // 認証設定(後述)
});

Cloudflare Workersへのデプロイ

# wrangler.toml の設定
# [[routes]]
# pattern = "mcp.yourdomain.com/*"
 
npx wrangler deploy
# → https://mcp.yourdomain.com にデプロイされる

Rorkアプリ側の実装

Step 1: MCPクライアントの初期化

// lib/mcp-client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
 
export interface MCPClientConfig {
  serverUrl: string;
  apiKey?: string;
  timeout?: number;
}
 
export class MobileMCPClient {
  private client: Client;
  private transport: SSEClientTransport;
  private isConnected: boolean = false;
 
  constructor(private config: MCPClientConfig) {
    this.transport = new SSEClientTransport(
      new URL(config.serverUrl),
      {
        // モバイルネットワーク向けのタイムアウト設定
        requestInit: {
          headers: {
            Authorization: `Bearer ${config.apiKey}`,
            "X-App-Version": "1.0.0",
          },
        },
      }
    );
 
    this.client = new Client(
      { name: "rork-mobile-app", version: "1.0.0" },
      { capabilities: { tools: {} } }
    );
  }
 
  async connect(): Promise<void> {
    if (this.isConnected) return;
    await this.client.connect(this.transport);
    this.isConnected = true;
    console.log("✅ MCP Server に接続しました");
  }
 
  async listTools() {
    await this.connect();
    const { tools } = await this.client.listTools();
    return tools;
  }
 
  async callTool(name: string, args: Record<string, unknown>) {
    await this.connect();
    const result = await this.client.callTool({ name, arguments: args });
    return result;
  }
 
  async disconnect(): Promise<void> {
    if (!this.isConnected) return;
    await this.client.close();
    this.isConnected = false;
  }
}
 
// シングルトンインスタンス
export const mcpClient = new MobileMCPClient({
  serverUrl: process.env.EXPO_PUBLIC_MCP_SERVER_URL!,
  apiKey: process.env.EXPO_PUBLIC_MCP_API_KEY,
  timeout: 30000,
});

Step 2: AnthropicとMCPを統合するAIサービス

// lib/ai-mcp-service.ts
import Anthropic from "@anthropic-ai/sdk";
import { mcpClient } from "./mcp-client";
 
const anthropic = new Anthropic({
  apiKey: process.env.EXPO_PUBLIC_ANTHROPIC_API_KEY,
});
 
export interface ConversationMessage {
  role: "user" | "assistant";
  content: string;
}
 
export async function* streamWithMCP(
  userMessage: string,
  conversationHistory: ConversationMessage[]
): AsyncGenerator<string> {
  // Step 1: MCPサーバーからツール一覧を取得
  const mcpTools = await mcpClient.listTools();
 
  // Step 2: MCP ツールを Anthropic ツール形式に変換
  const anthropicTools: Anthropic.Tool[] = mcpTools.map((tool) => ({
    name: tool.name,
    description: tool.description || "",
    input_schema: tool.inputSchema as Anthropic.Tool.InputSchema,
  }));
 
  const messages: Anthropic.MessageParam[] = [
    ...conversationHistory.map((m) => ({
      role: m.role as "user" | "assistant",
      content: m.content,
    })),
    { role: "user", content: userMessage },
  ];
 
  // Step 3: Claudeにメッセージを送信(ツール使用許可)
  let response = await anthropic.messages.create({
    model: "claude-opus-4-5",
    max_tokens: 4096,
    tools: anthropicTools,
    messages,
    stream: false,
  });
 
  // Step 4: ツール呼び出しループ
  while (response.stop_reason === "tool_use") {
    const toolUseBlocks = response.content.filter(
      (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
    );
 
    // ツール結果を格納
    const toolResults: Anthropic.ToolResultBlockParam[] = [];
 
    for (const toolUse of toolUseBlocks) {
      console.log(`🔧 ツール呼び出し: ${toolUse.name}`, toolUse.input);
 
      // MCPサーバーにツール実行を依頼
      const mcpResult = await mcpClient.callTool(
        toolUse.name,
        toolUse.input as Record<string, unknown>
      );
 
      const resultText =
        mcpResult.content
          .filter((c): c is { type: "text"; text: string } => c.type === "text")
          .map((c) => c.text)
          .join("\n") || "ツール実行完了";
 
      toolResults.push({
        type: "tool_result",
        tool_use_id: toolUse.id,
        content: resultText,
      });
    }
 
    // ツール結果をClaudeに返して続きを生成
    messages.push(
      { role: "assistant", content: response.content },
      { role: "user", content: toolResults }
    );
 
    response = await anthropic.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 4096,
      tools: anthropicTools,
      messages,
      stream: false,
    });
  }
 
  // Step 5: 最終テキスト応答をストリーミングで返す
  const finalText = response.content
    .filter((block): block is Anthropic.TextBlock => block.type === "text")
    .map((block) => block.text)
    .join("");
 
  // チャンクに分けてyield(UI更新用)
  const chunkSize = 10;
  for (let i = 0; i < finalText.length; i += chunkSize) {
    yield finalText.slice(i, i + chunkSize);
    // UIのレンダリングを優先するための非同期ポーズ
    await new Promise((resolve) => setTimeout(resolve, 0));
  }
}

Step 3: React NativeのUIコンポーネント

// components/MCPChatScreen.tsx
import React, { useState, useRef, useCallback } from "react";
import {
  View,
  Text,
  TextInput,
  FlatList,
  TouchableOpacity,
  ActivityIndicator,
  StyleSheet,
  KeyboardAvoidingView,
  Platform,
} from "react-native";
import { streamWithMCP, ConversationMessage } from "../lib/ai-mcp-service";
 
interface Message extends ConversationMessage {
  id: string;
  isStreaming?: boolean;
}
 
export const MCPChatScreen: React.FC = () => {
  const [messages, setMessages] = useState<Message[]>([]);
  const [inputText, setInputText] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const flatListRef = useRef<FlatList>(null);
 
  const sendMessage = useCallback(async () => {
    if (!inputText.trim() || isLoading) return;
 
    const userMessage: Message = {
      id: Date.now().toString(),
      role: "user",
      content: inputText.trim(),
    };
 
    const assistantMessage: Message = {
      id: (Date.now() + 1).toString(),
      role: "assistant",
      content: "",
      isStreaming: true,
    };
 
    const conversationHistory: ConversationMessage[] = messages.map((m) => ({
      role: m.role,
      content: m.content,
    }));
 
    setMessages((prev) => [...prev, userMessage, assistantMessage]);
    setInputText("");
    setIsLoading(true);
 
    try {
      const stream = streamWithMCP(userMessage.content, conversationHistory);
 
      for await (const chunk of stream) {
        setMessages((prev) =>
          prev.map((m) =>
            m.id === assistantMessage.id
              ? { ...m, content: m.content + chunk }
              : m
          )
        );
        // 最下部にスクロール
        flatListRef.current?.scrollToEnd({ animated: false });
      }
 
      // ストリーミング完了
      setMessages((prev) =>
        prev.map((m) =>
          m.id === assistantMessage.id ? { ...m, isStreaming: false } : m
        )
      );
    } catch (error) {
      console.error("MCP チャットエラー:", error);
      setMessages((prev) =>
        prev.map((m) =>
          m.id === assistantMessage.id
            ? {
                ...m,
                content: "エラーが発生しました。もう一度お試しください。",
                isStreaming: false,
              }
            : m
        )
      );
    } finally {
      setIsLoading(false);
    }
  }, [inputText, isLoading, messages]);
 
  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={Platform.OS === "ios" ? "padding" : "height"}
    >
      <FlatList
        ref={flatListRef}
        data={messages}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <View
            style={[
              styles.messageBubble,
              item.role === "user" ? styles.userBubble : styles.assistantBubble,
            ]}
          >
            <Text style={styles.messageText}>{item.content}</Text>
            {item.isStreaming && (
              <ActivityIndicator size="small" color="#666" />
            )}
          </View>
        )}
        contentContainerStyle={styles.messageList}
        onContentSizeChange={() =>
          flatListRef.current?.scrollToEnd({ animated: true })
        }
      />
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          value={inputText}
          onChangeText={setInputText}
          placeholder="メッセージを入力..."
          multiline
          editable={!isLoading}
          onSubmitEditing={sendMessage}
        />
        <TouchableOpacity
          style={[styles.sendButton, isLoading && styles.disabled]}
          onPress={sendMessage}
          disabled={isLoading}
        >
          <Text style={styles.sendButtonText}>送信</Text>
        </TouchableOpacity>
      </View>
    </KeyboardAvoidingView>
  );
};
 
const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: "#f5f5f5" },
  messageList: { padding: 16, gap: 8 },
  messageBubble: {
    maxWidth: "80%",
    padding: 12,
    borderRadius: 16,
    gap: 4,
  },
  userBubble: {
    alignSelf: "flex-end",
    backgroundColor: "#007AFF",
  },
  assistantBubble: {
    alignSelf: "flex-start",
    backgroundColor: "#fff",
    shadowColor: "#000",
    shadowOpacity: 0.05,
    shadowRadius: 4,
    elevation: 2,
  },
  messageText: { fontSize: 15, lineHeight: 22 },
  inputContainer: {
    flexDirection: "row",
    padding: 12,
    backgroundColor: "#fff",
    gap: 8,
    borderTopWidth: 1,
    borderTopColor: "#e0e0e0",
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: "#e0e0e0",
    borderRadius: 20,
    paddingHorizontal: 16,
    paddingVertical: 8,
    maxHeight: 100,
    fontSize: 15,
  },
  sendButton: {
    backgroundColor: "#007AFF",
    borderRadius: 20,
    paddingHorizontal: 16,
    paddingVertical: 8,
    justifyContent: "center",
  },
  disabled: { opacity: 0.5 },
  sendButtonText: { color: "#fff", fontWeight: "600" },
});

認証・セキュリティの実装

APIキーの安全な管理

モバイルアプリでのAPIキー管理は特に注意が必要です。クライアントサイドにAPIキーを直接埋め込むのは避け、以下のパターンを採用します。

// ❌ 危険:APIキーを直接埋め込む
const mcpClient = new MobileMCPClient({
  serverUrl: "https://mcp.yourdomain.com/mcp",
  apiKey: "sk-ant-XXXX", // 絶対にNG
});
 
// ✅ 安全:バックエンドプロキシ経由でAPIキーを隠蔽
// Rorkアプリ → 自社バックエンド(認証済み) → MCPサーバー

JWTトークンによる認証フロー

// lib/mcp-auth.ts
import * as SecureStore from "expo-secure-store";
 
export async function getMCPToken(): Promise<string> {
  // キャッシュされたトークンを確認
  const cached = await SecureStore.getItemAsync("mcp_token");
  if (cached) {
    const { token, expiresAt } = JSON.parse(cached);
    // 5分以上残っていれば再利用
    if (Date.now() < expiresAt - 300000) {
      return token;
    }
  }
 
  // バックエンドから新しいトークンを取得
  const supabaseToken = await getSupabaseToken(); // Supabaseセッショントークン
  const response = await fetch(
    `${process.env.EXPO_PUBLIC_API_BASE_URL}/api/mcp-token`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${supabaseToken}`,
        "Content-Type": "application/json",
      },
    }
  );
 
  const { token, expiresIn } = await response.json();
  await SecureStore.setItemAsync(
    "mcp_token",
    JSON.stringify({
      token,
      expiresAt: Date.now() + expiresIn * 1000,
    })
  );
 
  return token;
}

レート制限とタイムアウトの設定

// lib/mcp-rate-limiter.ts
export class MCPRateLimiter {
  private requestCount = 0;
  private resetTime = Date.now() + 60000;
  private readonly maxRequestsPerMinute: number;
 
  constructor(maxRequestsPerMinute = 20) {
    this.maxRequestsPerMinute = maxRequestsPerMinute;
  }
 
  async throttle(): Promise<void> {
    if (Date.now() > this.resetTime) {
      this.requestCount = 0;
      this.resetTime = Date.now() + 60000;
    }
 
    if (this.requestCount >= this.maxRequestsPerMinute) {
      const waitMs = this.resetTime - Date.now();
      console.log(`レート制限: ${waitMs}ms 待機します`);
      await new Promise((resolve) => setTimeout(resolve, waitMs));
      this.requestCount = 0;
      this.resetTime = Date.now() + 60000;
    }
 
    this.requestCount++;
  }
}

実際のユースケース:ECアプリでのMCP活用例

シナリオ:AI商品アドバイザー

MCPを使った実践的なユースケースとして、ECアプリの「AI商品アドバイザー」を考えます。ユーザーが「1万円以内でプレゼントを探している」と言うと、AIが以下を自律的に実行します。

  1. search_productsツールで条件に合う商品を検索
  2. check_stockツールで在庫を確認
  3. get_reviewsツールで評価を取得
  4. 結果を総合して自然な推薦文を生成
// この会話フローが自動で実現される
// ユーザー: 「彼女への誕生日プレゼント、予算1万円でおすすめは?」
//
// AI内部処理:
// 1. search_products({ query: "誕生日 プレゼント 女性", maxPrice: 10000, limit: 5 })
// 2. check_stock({ productId: "P001" }) × 5件
// 3. get_reviews({ productId: "P001", sortBy: "rating" })
//
// AI返答:
// 「1万円以内で特に評価が高いのは、◯◯(¥8,900・在庫あり・★4.8)です。
// レビューでは『見た目が可愛い』という声が多く、誕生日ギフトに最適です。」

このフローはコードを一切変更せず、MCPサーバーにツールを追加するだけで機能を拡張できます。まさにMCPの真価です。


よくあるエラーと対処法

エラー1: SSEセッションが頻繁に切断される

モバイルアプリはバックグラウンド移行やネットワーク切り替え時にSSE接続が切れます。

// 自動再接続ロジックの実装
class ReconnectingMCPClient extends MobileMCPClient {
  private reconnectAttempts = 0;
  private readonly maxReconnects = 5;
 
  async callToolWithRetry(
    name: string,
    args: Record<string, unknown>,
    retries = 3
  ) {
    for (let i = 0; i < retries; i++) {
      try {
        return await this.callTool(name, args);
      } catch (error: unknown) {
        if (
          error instanceof Error &&
          error.message.includes("connection") &&
          i < retries - 1
        ) {
          console.log(
            `再接続試行 ${i + 1}/${retries}...`
          );
          this.isConnected = false;
          await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
          continue;
        }
        throw error;
      }
    }
  }
}

エラー2: Tool not found エラー

MCPサーバーのツール名とクライアントからの呼び出し名が一致しない場合に発生します。

// デバッグ:利用可能なツール一覧を出力
const tools = await mcpClient.listTools();
console.log("利用可能なツール:", tools.map((t) => t.name));
// → ["search_products", "check_stock", "get_reviews"]

エラー3: Android で EventSource is not defined

React Native は標準で EventSource をサポートしていません。

// polyfill のインポート(App.tsx の最上部)
import "eventsource-polyfill";
// または
import EventSource from "react-native-event-source";
global.EventSource = EventSource;

まとめ

MCP(Model Context Protocol)をRorkアプリに統合することで、AIが外部ツールを自律的に呼び出すインテリジェントなモバイルアプリを構築できます。本記事で学んだポイントをまとめます。

  • MCPのアーキテクチャ: ホスト・クライアント・サーバーの3層構造と、モバイルアプリに適したSSE/Streamable HTTPトランスポート
  • 実装の核心: MCPツール一覧をAnthropicのツール定義に変換し、ツール呼び出しループで自律エージェントを実現
  • プロダクション品質: JWTトークン認証・レート制限・自動再接続によるモバイル特有の課題への対応
  • 拡張性: MCPサーバーにツールを追加するだけで、アプリ側コードを変更せずに機能を拡張できる

MCPは2026年に最も注目すべきAIインフラの一つです。Rork × Gemini 2.0 Flash 完全ガイドで学んだGeminiとの統合と組み合わせることで、マルチAIプロバイダー対応のアプリも構築できます。ぜひこのガイドを参考に、MCPを活用したオリジナルのインテリジェントアプリを作成してみてください。

MCPについてさらに深く

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

AI モデル2026-06-19
Rork Max に月 $200 を払う前に、Expo でどこまで届くかを3階層で見極める
ウィジェットや Live Activities が欲しくなると Rork Max が視野に入りますが、その多くは標準 Rork の Expo 構成でも届きます。機能ごとに「Expo で届く・自作モジュールで届く・Max が現実解」の3階層に分け、課金前に実機で見極める手順を整理しました。
AI モデル2026-06-14
Rork(Expo)製アプリから Apple Foundation Models を呼ぶ — オンデバイスAIをネイティブモジュールで橋渡しする
Rork が生成する Expo(React Native)アプリから iOS のオンデバイスAI、Apple Foundation Models を呼ぶには、Swift 側のネイティブモジュールを挟む必要があります。Expo Modules API で橋渡しを書き、未対応端末ではクラウドへ逃がす構成を実装します。
AI モデル2026-06-13
オンデバイスAIを一次経路にして、重い処理だけクラウドへ逃がす推論ルーターをRorkアプリに組む
Rork(Expo)で生成したアプリに、オンデバイス→Private Cloud Compute→外部API(Claude/Gemini)の順で推論を流す段階フォールバック型ルーターを実装します。予算管理・タイムアウト・キャッシュ・画像入力の振り分けまで、動くTypeScriptで解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →