shwld.io

個人開発アプリにMCP/DXT統合を実装してClaude Desktopから操作できるようにした感動体験


個人開発しているノートサービス REVELUP.dev に、MCP(Model Context Protocol)を実装し、DXT(Desktop Extension)を使ってClaude Desktopから直接操作できるようにしました。Claudeに「下書きを作って」とお願いするだけで、自分のアプリに記事が作成される瞬間の感動は想像以上でした。

REVELUP.devとは

REVELUP.devは、プライベートなメモから始めて、知り合いだけに見せるメモ、そして最終的には公開記事へと段階を踏んで技術アウトプットできるサービスです。気軽にメモを貯めながら、徐々に公開レベルを上げていける仕組みになっています。

元々は、アプリ内で貯めたメモを集めて記事にする機能を実装しようと考えていました。しかし、MCPの登場により、アプリ内での開発を待たずに、この記事化の流れを実現できるのではないかと思い立ちました。

サーバーサイドでのMCP実装

まず、REVELUP.devのAPIサーバー側にMCPサーバーを実装しました。@modelcontextprotocol/sdkを使用して、既存のAPIエンドポイントをMCPプロトコルでラップする形で実装しています。

import { Server } from "@modelcontextprotocol/sdk/server/index.js";

export const RevelupMCPServer = (context: McpApiUserContext) => {
  const server = new Server(
    {
      name: "revelup-dev-api",
      version: "0.0.1",
      description: "MCP server for Revelup.dev API",
    },
    {
      capabilities: {
        tools: { listChanged: true },
        resources: { subscribe: true, listChanged: true },
        prompts: { listChanged: true },
        logging: {},
      },
    },
  );

  setToolsCallHandler(server, context);
  setToolsListHandler(server, context);

  return server;
}

FastifyプラグインとしてHTTPエンドポイント /mcp を公開し、StreamableHTTPServerTransportを使用してMCPクライアントからのリクエストを処理します。

import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

export const mcpHttpPlugin: FastifyPluginAsync<McpHttpPluginOptions> = async (fastify, options) => {
  fastify.post(endpoint, async (req, reply) => {
    // 認証とレート制限のチェック
    const context = await createMcpContext(req);

    if (!mcpRateLimiter.isAllowed(context.sessionId)) {
      // レート制限の処理
    }

    const server = await createServer(context);
    const transport = new StreamableHTTPServerTransport({
      sessionIdGenerator: undefined,
    });

    await server.connect(transport);
    await transport.handleRequest(req.raw, reply.raw, req.body);
  });
};

実装したツールは3つです:

  1. createarticledraft: Markdownから記事の下書きを作成

  2. create_note: メモを作成

  3. search_notes: メモを検索

例えば、記事の下書き作成は以下のように実装しています:

export const CreateArticleDraft: Tool<Params> = {
  info: {
    name: 'create_article_draft',
    description: 'Create an article draft from markdown content',
    inputSchema: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        markdown: { type: 'string' },
      },
      required: ['title', 'markdown'],
    },
  },
  call: async (args, context) => {
    const htmlString = new showdown.Converter().makeHtml(args.markdown);
    const notes = await context.db.article.create({
      data: {
        title: args.title,
        userProfileId: context.currentUser.userProfile.id,
        content: htmlString,
        editorVersion: "0.0.0",
        published: false,
      },
    })
    return {
      content: [{
        type: 'text' as const,
        text: 'Article draft created',
      }]
    }
  },
};

DXTを使ったClaude Desktop統合

サーバーサイドのMCP実装ができたら、次はClaude DesktopからアクセスできるようにDXT(Desktop Extension)を作成しました。DXTは、リモートのMCPサーバーとClaude Desktopを橋渡しするプロキシサーバーとして動作します。

class RevelupMCPServer {
  private apiKey: string;
  private baseUrl: string = "https://api.revelup.dev";

  private async callAPI(endpoint: string, method: string = 'GET', body: any = null): Promise<any> {
    const url = `${this.baseUrl}${endpoint}`;

    const options: RequestInit = {
      method,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json, text/event-stream'
      }
    };

    // APIコールの実装
  }

  async run(): Promise<void> {
    const server = new Server(
      {
        name: "revelup-dev",
        version: "0.0.1"
      },
      {
        capabilities: {
          tools: {}
        }
      }
    );

    // リモートのMCPサーバーへツールリストをプロキシ
    server.setRequestHandler(
      ListToolsRequestSchema,
      async () => {
        const mcpRequest = {
          jsonrpc: "2.0",
          id: Date.now(),
          method: "tools/list",
          params: {}
        };

        const response = await this.callAPI('/mcp', 'POST', mcpRequest);
        return { tools: response.result.tools };
      }
    );

    const transport = new StdioServerTransport();
    await server.connect(transport);
  }
}

DXTの主な役割は:

Claude Desktopへの設定

DXTをClaude Desktopにインストールする手順は以下の通りです:

  1. DXTパッケージをビルド

  2. Claude Desktopの設定画面を開く

  3. MCP拡張機能のセクションでDXTをインストール

  1. インストールが完了すると、API Keyの入力を求められるので、REVELUP.devのAPIキーを入力します。

  1. インストールできた

実際に使ってみた感動

設定が完了すると、Claude Desktopから直接REVELUP.devの機能が使えるようになりました。

「REVELUP.devで『MCPの実装について』というタイトルで下書きを作成して」とClaudeに伝えるだけで、実際にアプリ内に下書きが作成されます。この瞬間の感動は忘れられません。自分が作ったアプリを、AIアシスタントが直接操作してくれる体験は、まるで魔法のようでした。

さらに、「最近のメモを検索して」と伝えれば、貯めていたメモを検索して内容を確認できます。これらのメモを元に、Claudeと対話しながら記事を構成していくことも可能です。

技術的な学び

この実装を通じて、MCPとDXTの組み合わせの可能性を実感しました:

  1. サーバーサイドMCPの利点: 既存のAPIにMCPレイヤーを追加するだけで、AI統合が可能に

  2. DXTによるセキュアな接続: API Keyの管理とプロキシ処理により、安全にリモートMCPサーバーへ接続

  3. 開発体験の向上: アプリ内に複雑なAI統合機能を実装する前に、MCPで素早くプロトタイプを作れる

  4. StreamableHTTPTransportの採用: SSE Transportから移行し、より安定した通信を実現

まとめ

MCPとDXTを使うことで、個人開発のアプリにAIアシスタント機能を簡単に追加できました。サーバーサイドにMCPを実装し、DXTでClaude Desktopと統合することで、「AIが自分のアプリを操作する」体験を実現できたのは、この技術スタックならではの利点だと感じています。

この記事は、Claude Desktopで執筆してREVELUP.devへ下書き投稿した記念すべき最初の投稿です。

個人開発アプリにMCP/DXT統合を実装してClaude Desktopから操作できるようにした感動体験
shwld
2025/08/06
小学一年生の娘がサンタに感じる不信感11選
shwld
2024/12/23
ストリートファイター6でマスターランク到達できたときのメモ
shwld
2024/12/05
Line Notifyサービス終了。移行先どうしよう
shwld
2024/10/08