ビジネスを強化する: アクセス制御を使用して既存のサービスに AI ツールを接続する

> 本記事は元々 [blog.logto.io](https://blog.logto.io/ja/connect-ai-tools-to-your-service) に掲載されたものです。

アクセス制御を使用して既存のサービスに AI ツールを接続するためのガイドへようこそ！

特に LLM との統合（[モデル コンテキスト プロトコル](https://modelcontextprotocol.io/)を使用）およびさまざまな AI エージェントを通じて、アクセス制御の課題に対処しながら、既存のサービスを AI ツールに対応させる方法を探ります。

このガイドを通じて、次のことを学びます:

- **シームレスな AI 統合**: AI ツールをサービスに接続し、データと機能を AI 環境で利用可能にする方法を学びます
- **強化された API セキュリティ**: 効果的なアクセス制御により、データとユーザーのプライバシーを保護するために API インターフェースを改善します
- **ユーザー向けに個別化された AI 体験**: 個々のユーザーに AI 支援体験を作成し、パーソナル アクセス トークンを通じて実現します

完全なチュートリアル資料、**完全なデモ プロジェクト [ソース コード](https://github.com/logto-io/rbac-sample)（フロントエンド、バックエンド、MCP サーバーを含む）**、AI 対応サービスをゼロから構築するための実用的なガイドも提供します。

このガイドがあなたのビジネスをどのように向上させるか:

- **競争優位性**: サービスの技術能力とユーザー エクスペリエンスを向上させ、競争力のある市場で際立たせます
- **ユーザー価値の強化**: AI ツールを通じて製品の深い価値をユーザーに提供し、保持率と満足度を向上させます
- **将来に備えたサービス**: AI エコシステムとの統合により、AI 主導のビジネス環境に備え、革新的な成長の道を開きます

さあ、始めましょう！

<Note>
このガイドでは、MCP (モデル コンテキスト プロトコル) を例として使用しますが、このプロトコルの実践はすべての AI エージェントに適用されます。
</Note>

## MCP とは何か、そしてそれがどのように AI ツールをサービスに接続するか

[MCP (モデル コンテキスト プロトコル)](https://modelcontextprotocol.io/) は、大規模言語モデル (LLM) にコンテキスト情報を提供する方法を標準化するオープンでユニバーサルなプロトコルです。

MCP は複数の主要コンポーネントから構成されており、AI ツールがあなたのサービスにアクセスできるようになります:

```mermaid
graph LR
    subgraph "MCP Host(クロード デスクトップ、カーソル、など)"
        UI[ユーザー インターフェース]
        subgraph "MCP 統合による LLM"
            IntegratedLLM[大規模言語モデル]
            IntegratedClient[MCP クライアント]
            IntegratedLLM <--> IntegratedClient

        end
        UI <--> IntegratedLLM
    end
    
    subgraph MCPServer
        Tool[ツール: fetch_service_data]
    end

    IntegratedClient <--> MCPServer
    
    
    Tool <--> YourService[あなたのサービス]
```

このガイドでは、MCP サーバーがサービスと AI ツールの間の重要な接続ポイントであることだけを知っていれば十分です。MCP サーバーは LLM が使用するためのツールを一連提供し、これらのツールはあなた自身のサービスと相互作用します。MCP の詳細については、[MCP (モデル コンテキスト プロトコル) とは何か、どのように機能するか](https://blog.logto.io/what-is-mcp) を参照できます。ここでは、MCP サーバーだけに焦点を当てます。

ロールベースのアクセス制御 (RBAC) ポリシーを統合したコンテンツ管理システム (CMS) を例として使用します。MCP サーバーを作成し、現在のユーザーが CMS 内で利用可能な記事の数を LLM に取得させるための `get-available-article-count` ツールを定義します:

```typescript
// Register tools
server.tool(
  "get-available-article-count",
  "Get available articles count form the content management system",
  {},
  async () => {
    const articles = await fetch(
      `${CMS_API_BASE}/api/articles`,
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    ).json();

    return {
      content: [
        {
          type: "text",
          text: `コンテンツ管理システムには ${articles.length} 件の記事が利用可能です`,
        },
      ],
    };
  }
);
```

これは、MCP サーバーをサービスに接続するための重要なコードです。このツールの実装では、サービスの `api/articles` エンドポイントにリクエストを送り、結果を返します。

しかし、これはまだ不十分です。なぜなら、サービスの API が公共ではないかもしれないからです。各エンドポイントにはアクセス制御が必要で、異なるユーザーが異なるリソースとデータにアクセスできるようにする必要があります。

次に、サービスにアクセス制御を追加する方法を説明します。

## MCP サーバーのアクセス制御を実装する方法

AI ツールを通じてシステムにアクセスするユーザーは、直接的にシステムを使用する可能性のある個々のユーザーであるため、MCP サーバーは AI ツールを通じて対話するときにその代表者として機能します。

したがって、ユーザーが AI ツールを通じてサービスにアクセスする場合、次の2つの実践的なアクセス制御の課題が生じます:

- MCP サーバーがユーザーのようにシステムにログインする方法？
- もとのシステムがすでに独自の認証メカニズムを持っているとき、MCP サーバーに対応するためにシステムのアクセス制御メカニズムを再設計する必要があるのでしょうか？これは特に大きなコストと労力がかかります。

この問題を解決する鍵は次の通りです:

**MCP サーバーがユーザーの資格情報やインタラクティブなサインインなしでサービスへのアクセスをユーザーから許可される方法は？**

この問題を解決すれば、MCP サーバーを通じて直接サービスと相互作用でき、元のユーザー向けに設計されたアクセス制御メカニズムを引き続き使用することができます。MCP サーバー専用の新しいシステムを再設計する必要がありません！

しかし、これが可能ですか？

もちろんです！この問題は、**パーソナル アクセス トークン**を使用して完全に解決できます！

パーソナル アクセス トークン (PAT) は、ユーザーが資格情報やインタラクティブなサインインを使わずにアクセス トークンを安全に付与する方法を提供します。これは CI/CD、スクリプト、またはリソースにプログラムでアクセスする必要があるアプリケーションに適しています。

ワークフローの流れは次の通りです:

```mermaid
sequenceDiagram
    actor User as ユーザー
    participant AITools as AIツール
    participant MCPServer as MCPサーバー
    participant Service as あなたのサービスAPI
    autonumber
    
    User->>Service: パーソナル アクセス トークン (PAT) を作成
    Service-->>User: PAT の生成結果を返す
    User->>MCPServer: PAT を設定
    
    Note over User,Service: 通常の使用フロー
    User->>AITools: リクエストを行う
    AITools->>MCPServer: MCP サーバーからツールを呼び出す
    MCPServer->>Service: API 呼び出し(PAT 使用)
    Service->>Service: PAT の検証とアクセス権の確認
    Service-->>MCPServer: ユーザー権限に基づいたデータを返す
    MCPServer-->>AITools: 結果を処理して返す
    AITools-->>User: 結果を表示
```

したがって、システムがパーソナル アクセス トークン (PAT) をサポートしている限り、AI ツールと既存のサービス間のアクセス制御の課題を解決し、認証メカニズムを再設計することなく、データのセキュリティとユーザーのプライバシー保護を確保できます。

次は、これを実際に実装する方法を見てみましょう。

## MCP サーバーのアクセス制御の実装

このセクションでは、既存の CMS システムを基礎として MCP サーバーのアクセス制御を実装します。

[実践における RBAC: アプリケーションの安全な認証の実装](https://blog.logto.io/rbac-in-practice) にある完全な CMS サンプル チュートリアルとソース コードをチェックアウトできますが、これは必須ではありません。ここで基本的な原則をすべて取り上げます。

CMS サンプルは、包括的な認証および認可ソリューションを提供する人気のオープンソースアイデンティティ プラットフォームである [Logto](https://logto.io) に基づいていますが、このプラットフォームの技術的な実装はこの記事の焦点ではありません。

### サービスに対する権限とアクセス制御ポリシーの設計

アクセス制御を実装する最初のステップは、システムのための権限とアクセス制御ポリシーを設計することです。

クテンツ管理システム (CMS) の例では、[RBAC (ロールベースのアクセス制御)](https://auth-wiki.logto.io/rbac) に基づいて次のような API エンドポイントを設計し、各エンドポイントにアクセスするために必要な権限を指定しました。

| エンドポイント                        | アクセス制御ロジック                                                        |
| ------------------------------------------- | ---------------------------------------------------------------------------- |
| GET /api/articles                  | - `list:articles` 権限を持つユーザーまたは自分の記事が見える著者               |
| GET /api/articles/:id             | - `read:articles` 権限を持つユーザーまたはその記事の著者                       |
| POST /api/articles                | - `create:articles` 権限を持つユーザー                                        |
| PATCH /api/articles/:id           | - `update:articles` 権限を持つユーザーまたはその記事の著者                     |
| DELETE /api/articles/:id          | - `delete:articles` 権限を持つユーザーまたはその記事の著者                     |
| PATCH /api/articles/:id/published | - `publish:articles` 権限を持つユーザーのみ                                   |

システムの権限設計は次の通りです:

| 権限                   | 説明                                         |
| ----------------------- | ------------------------------------------- |
| list:articles          | システム内のすべての記事のリストを見る      |
| read:articles          | 任意の記事の全文を読む                      |
| create:articles        | 新しい記事を作成する                        |
| update:articles        | 任意の記事を修正する                        |
| delete:articles        | 任意の記事を削除する                        |
| publish:articles       | 公開ステータスを変更する                    |

これらの権限に基づいて、CMS システムのために次の役割を定義しました。

| 権限/役割              | 👑 管理者                           | 📝 出版者                              | ✍️ 著者                                    |
| ----------------------- | ------------------------------------------- | ----------------------------------------------------- | ------------------------------------------- |
| **説明**               | コンテンツ管理のためのフルシステムアクセス         | すべての記事を見て公開ステータスを制御することができる | システム内で新しい記事を作成することができる     |
| list:articles           | ✅                                        | ✅                                                   | ❌                                         |
| read:articles           | ✅                                        | ✅                                                   | ❌                                         |
| create:articles         | ✅                                        | ❌                                                    | ✅                                         |
| update:articles         | ✅                                        | ❌                                                    | ❌                                         |
| delete:articles         | ✅                                        | ❌                                                    | ❌                                         |
| publish:articles        | ✅                                        | ✅                                                   | ❌                                         |

**ノート**: 著者は、ロールの権限に関係なく、自分の記事に対して自動的に読み取り/更新/削除権限を持ちます。

次に、システム内のユーザーにロールを割り当てます (CMS デモを例として使用):

| ユーザー名          | ロール      |
| ------------------- | -------------- |
| アレックス           | 管理者     |
| ボブ                 | 出版者     |
| チャールズ           | 著者      |

そして、上記の記事 _実践における RBAC_ で言及されているように、Logto で内部的なロールを設定しました。

![Logto ロール](https://uploads.strapi.logto.io/roles_2e2b60c85b.png)

### サービス API にアクセス制御ポリシーを適用する

CMS サンプルへのユーザーのログイン方法は次の通りです:

```mermaid
sequenceDiagram
    actor User
    participant CMS as CMS フロントエンド
    participant Auth as 認証サーバー
    participant API as CMS APIサービス
    autonumber
    
    User->>CMS: ログインを開始
    CMS->>Auth: ログインページにリダイレクト
    User->>Auth: 資格情報を入力
    Auth->>CMS: ログイン後に戻る
    CMS->>Auth: CMS API へのアクセス トークンを要求
    Auth->>CMS: アクセス トークンを返す
    User->>CMS: CMS 機能を要求
    CMS->>API: アクセス トークンを使って API を呼び出す
    API->>API: トークンと権限を検証
    API->>CMS: 要求されたデータを返す
    CMS->>User: データ/コンテンツを表示
```

したがって、サービス API にアクセス制御を適用することは、ステップ 9 でアクセス トークンを検証し、権限を確認するミドルウェアを追加するのと同様に簡単です。

コア実装は次の通りです ([RBAC サンプル - バックエンド](https://github.com/logto-io/rbac-sample/tree/main/backend) の完全な実装を参照):

```javascript
const requireAuth = (requiredScopes = []) => {
  return async (req, res, next) => {
    try {
      // トークンを取得
      const token = getTokenFromHeader(req.headers);

      // トークンを検証
      const payload = await verifyJwt(token);

      // ユーザー情報をリクエストに追加
      req.user = {
        id: payload.sub,
        // スコープはユーザーが持っている権限
        scopes: payload.scope?.split(" ") || [],
      };

      // 必要な権限を検証
      if (!hasScopes(req.user.scopes, requiredScopes)) {
        throw new Error("権限が不十分です");
      }

      next();
    } catch (error) {
      res.status(401).json({ error: "未認証" });
    }
  };
};
```

認証が必要な API エンドポイントにミドルウェアを適用します:

```javascript
router.get('/articles', requireAuth(), async (req, res) => {
  try {
    // ユーザーが list:articles スコープを持っている場合、すべての記事を返す
    if (hasScopes(req.user.scopes, ['list:articles'])) {
      const articles = await articleDB.list();
      return res.json(articles);
    }

    // それ以外の場合は、ユーザーの記事のみを返す
    const articles = await articleDB.listByOwner(req.user.id);
    res.json(articles);
  } catch (error) {
    res.status(500).json({ error: '記事の取得に失敗しました' });
  }
});
```

これで、CMS システムにアクセス制御を追加し、ユーザーにロールを割り当てました。

ユーザーがログインし、CMS API のためのアクセス トークンを取得した後、このトークンを使用して CMS API にアクセスできます。アクセス トークンにはユーザーの権限情報が含まれています。これにより、ユーザーの権限に基づいてどのデータを返すかを制御できます。

次のステップは、MCP サーバーでパーソナル アクセス トークンを使用することです。

### パーソナル アクセス トークンがユーザーをどのように表すかを理解する

上記の CMS 認証フローを参照してください。ユーザーはログイン後に CMS API のアクセス トークンを取得します。このアクセス トークンは、CMS API にアクセスするための資格情報です。

ログイン後にユーザーが取得するのと同様のアクセス トークンを取得するだけで済みます。次に、これを使用して CMS API にアクセスできます。

ここでパーソナル アクセス トークンが役立ちます。それらを使用すると、通常のログイン後にユーザーが取得するのと同様のアクセス トークンを取得できます。

ここで必要な手順は次の通りです:
1. ユーザーのためにパーソナル アクセス トークンを作成する
2. このパーソナル アクセス トークンを使用して認証サービスのトークン エンドポイントから交換トークンを要求する。これにより、ログイン後に取得するのと同様のアクセス トークンを取得できます
3. MCP サービス ツールでこのアクセス トークンを使用し、CMS API にアクセスする

この例では、Logto を使用してデモを行います。Logto はパーソナル アクセス トークンとトークン エクスチェンジをサポートしています。他のシステムを使用している場合でも、このアプローチに従って独自のパーソナル アクセス トークン サポートを実装できます。

### ユーザーのためにパーソナル アクセス トークンを作成する

Logto コンソール > ユーザー管理で、詳細ページからユーザーのためにパーソナル アクセス トークンを作成できます:

![Logto コンソールでのパーソナル アクセス トークンの作成](https://uploads.strapi.logto.io/user_details_58a20e8356.png)

パーソナル アクセス トークンを作成するときに、有効期限を必要に応じて設定できます。

<Note>
Logto コンソールからパーソナル アクセス トークンを作成するだけでなく、Logto の[管理 API](https://docs.logto.io/integrate-logto/interact-with-management-api)を使用してユーザーのためにパーソナル アクセス トークンを作成することもできます 。
</Note>

### MCP サーバーでパーソナル アクセス トークンを使用する

ユーザーのパーソナル アクセス トークンを持ったので、MCP サーバーで使用できます。

まず、Logto の [パーソナル アクセス トークン ドキュメント](https://docs.logto.io/user-management/personal-access-token) に従い、Logto のトークン エンドポイントから CMS API にアクセスするためのアクセス トークンを取得します。完全なソース コードは[こちら](https://github.com/logto-io/rbac-sample/blob/main/mcp-server/src/lib.ts)で確認できます。

```javascript
export const exchangeAccessToken = async ({
  tokenEndpoint,
  clientId,
  resource,
  scope,
  personalAccessToken,
}: ExchangeAccessTokenOptions): Promise<AccessToken> => {
  const body = new URLSearchParams({
    client_id: clientId,
    grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
    subject_token: personalAccessToken,
    subject_token_type: "urn:logto:token-type:personal_access_token",
    resource,
    scope,
  });

  const accessTokenResponse = await makeRequest<AccessTokenResponse>(
    tokenEndpoint,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body,
    }
  );

  if (!accessTokenResponse) {
    throw new Error("アクセス トークンの交換に失敗しました");
  }

  return {
    ...accessTokenResponse,
    // 有効期限を計算
    expired_at: Date.now() + accessTokenResponse.expires_in * 1000,
  };
};
```

MCP サーバーでは、`exchangeAccessToken` 関数からのアクセス トークンを使用して CMS API データを取得します。

```typescript
const accessToken = await exchangeAccessToken({
  tokenEndpoint: TOKEN_ENDPOINT,
  clientId: CMS_CLIENT_ID,
  resource: CMS_API_RESOURCE,
  scope:
    "create:articles delete:articles list:articles publish:articles read:articles update:articles",
  personalAccessToken: PERSONAL_ACCESS_TOKEN,
});

// アクセス トークンを使用して CMS API データを取得
const articles = await fetch(
  `${CMS_API_BASE}/api/articles`,
  {
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
  }
).json();
```

この方法では、MCP サーバーはユーザーの認証情報なしで CMS API にアクセスすることができます。代わりに、ユーザーのパーソナル アクセス トークンを使用します。

[RBC サンプル - MCP サーバー](https://github.com/logto-io/rbac-sample/blob/main/mcp-server)で完全なコードを見つけることができます。

Claude Desktop でこの MCP サーバーをローカルにデプロイする方法については、[MCP サーバーデプロイ ガイド](https://modelcontextprotocol.io/quickstart/server)をご覧ください。

このサーバーを [Cursor](https://docs.cursor.com/context/model-context-protocol)、[Cline](https://docs.cline.bot/mcp-servers/mcp-quickstart)、[Windsurf](https://docs.codeium.com/windsurf/mcp#mcp-integration) など、さまざまな AI IDE にもデプロイできます。

### アクセス制御をテストする

Claude Desktop でこの実装をテストしましょう。

私たちの CMS では、アレックスとチャールズがそれぞれ 1 記事を作成しました。

アレックスは管理者の役割を持っているため、すべての記事を見ることができますが、著者であるチャールズは自分の記事のみを見ることができます。

Claude に利用可能な記事数を尋ねると、`get-available-article-count` ツールを使用して許可を求めてきます:

![ツールの使用許可を求める](https://uploads.strapi.logto.io/ask_to_use_tool_0286203020.png)

MCP にアレックスのパーソナル アクセス トークンを使用し、-Claude に利用可能な記事の数を尋ねると、Claude は `get-available-article-count` ツールを呼び出して、2 件の記事があると教えてくれます。

![アレックスの回答](https://uploads.strapi.logto.io/answer_for_alex_8b38d775ee.png)

チャールズのパーソナル アクセス トークンに切り替えて同じ質問をすると、Claude は 1 件の記事しかないと伝えます。

![チャールズの回答](https://uploads.strapi.logto.io/answer_for_charles_dc4cbe3309.png)

素晴らしいですね！パーソナル アクセス トークンを使用して CMS API にアクセスし、正確なデータを取得することができました。

これは私たちが望んでいたことそのものです: 各ユーザーのためにパーソナル アクセス トークンを作成し、ユーザーが MCP サーバーにトークンを設定すると、それぞれのユーザーに対して個別化された AI エクスペリエンスを作成します。

まとめのセクションを書くのを手伝ってください:

## まとめ

このガイドでは、適切なアクセス制御を維持しながら AI ツールを既存のサービスに接続する方法を探りました。RBAC 実装を伴う CMS システムを使用して、パーソナル アクセス トークン (PAT) がどのように認証の課題を優雅に解決できるかを示しました。

この実装のための完全なソース コードを [RBAC サンプル リポジトリ](https://github.com/logto-io/rbac-sample) で見つけることができます。このリポジトリには、CMS バックエンド、フロントエンド、および MCP サーバーの実装が含まれます。

MCP サーバーをユーザーに配布する際は、パーソナル アクセス トークンを設定可能にすることを忘れないようにしましょう。これにより、各ユーザーが以下を行うことができます:
- MCP サーバーに独自の PAT を設定する
- 特定の権限に基づいてリソースにアクセスする
- 役割とアクセス レベルを反映した個別化された AI エクスペリエンスを得る

このアプローチは、AI 統合を安全に保ちながら、システム内の各ユーザーに応じたカスタマイズされたエクスペリエンスを提供します。

この AI 統合の旅でビジネスの大成功を祈っています！これらの新しい AI 機能でサービスが繁栄し、成長することを願っています！ 🚀