1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プリザンターのMCPサーバの実装を詳しくみてみる[前編:アーキテクチャ編]

1
Posted at

はじめに

プリザンター 1.5.2.0 で、MCP(Model Context Protocol)サーバ機能が実装されました。MCP は、AI エージェント(Claude Desktop、Visual Studio Code など)と外部システムをつなぐ標準プロトコルです。これにより、自然言語で「このサイトのレコード一覧を取得して」と頼むだけでプリザンターのデータ操作が可能になります。

本記事(前後編)では、この MCP サーバが既存の API と比較してどのように実装されているかを、ソースコード レベルで解説します。

テーマ
前編(本記事) アーキテクチャ編 — MCP プロトコルの概要と既存 API との設計比較
後編 ツール実装編 — MCP ツールの設計とクライアント連携の仕組み

バージョン 1.5.2.0 を対象にしています

MCP(Model Context Protocol)とは

MCP は Anthropic 社が策定したオープンプロトコルで、AI アプリケーションと外部ツール・データソースを標準的な方法で接続するための仕組みです。

従来、AI エージェントと業務システムを連携するには、システムごとに個別のアダプターを開発する必要がありました。MCP はこの「N×M 統合問題」を解決し、1 つのプロトコルであらゆる AI クライアントとサーバをつなぎます。

MCP の 3 つの機能カテゴリ

MCP サーバは、以下の 3 種類の機能を提供できます。

カテゴリ 説明 プリザンターでの利用
Tools(ツール) AI が呼び出せるアクション(関数) レコード取得・更新、ビュー操作など
Resources(リソース) コンテキスト情報としてのデータ 現時点では未使用
Prompts(プロンプト) テンプレート化されたワークフロー 現時点では未使用

プリザンターの MCP サーバでは、主に Tools が実装されています。

既存 API のアーキテクチャ

MCP サーバの設計を理解するために、まず既存の API の仕組みを整理します。

リクエスト処理の全体フロー

既存の API は、ASP.NET Core のコントローラベースで実装されています。すべての API エンドポイントは POST メソッドを使用し、リクエストボディに JSON を含めます。

コントローラの実装

API コントローラには [CheckApiContextAttributes] フィルタが適用されており、認証・検証のパイプラインが統一されています。

Implem.Pleasanter/Controllers/Api/ItemsController.cs
[CheckApiContextAttributes]
[AllowAnonymous]
[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
    [HttpPost("{id}/Get")]
    public ContentResult Get(long id)
    {
        var body = default(string);
        using (var reader = new StreamReader(Request.Body))
            body = reader.ReadToEnd();
        var context = new Context(
            sessionStatus: User?.Identity?.IsAuthenticated == true,
            sessionData: User?.Identity?.IsAuthenticated == true,
            apiRequestBody: body,
            contentType: Request.ContentType,
            api: true);
        var log = new SysLogModel(context: context);
        var result = context.Authenticated
            ? new ItemModel(context: context, referenceId: id)
                .GetByApi(context: context)
            : ApiResults.Unauthorized(context: context);
        log.Finish(context: context, responseSize: result.Content.Length);
        return result.ToHttpResponse(request: Request);
    }
}

認証方式:リクエストボディ内の ApiKey

既存 API の特徴的な設計として、API キーをリクエストボディの JSON 内に含める方式があります。

{
    "ApiKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "ApiVersion": 1.1
}

Context クラスの初期化時に、リクエストボディをデシリアライズして ApiKey を取り出し、Users テーブルと照合しています。

Implem.Pleasanter/Libraries/Requests/Context.cs
var jsonDeserializedRequestApi = RequestDataString.Deserialize<Api>();
if (jsonDeserializedRequestApi?.ApiKey.IsNullOrEmpty() == false)
{
    ApiKey = jsonDeserializedRequestApi.ApiKey;
    SetUser(userModel: GetUser(where: Rds.UsersWhere()
        .ApiKey(ApiKey)));
}

リクエスト/レスポンスモデル

API のリクエストは Api クラスで定義されています。

Implem.Pleasanter/Libraries/Requests/Api.cs
[Serializable]
public class Api
{
    public decimal ApiVersion { get; set; } = Parameters.Api.Version;
    public string ApiKey { get; set; }
    public View View { get; set; }
    public List<string> Keys { get; set; }
    public int Offset { get; set; }
    public int PageSize { get; set; }
    public Sqls.TableTypes TableType { get; set; }
    public string Token { get; set; }
}

レスポンスはプリザンター独自の ApiResponse 形式で統一されています。

{
    "StatusCode": 200,
    "LimitPerDate": 10000,
    "LimitRemaining": 9950,
    "Response": {
        "Offset": 0,
        "PageSize": 200,
        "TotalCount": 42,
        "Data": [
            { "ResultId": 1, "Title": "レコード1", ... }
        ]
    }
}

MCP サーバのアーキテクチャ

プロトコルの基本構造

MCP は JSON-RPC 2.0 をベースにしたプロトコルです。クライアントとサーバの間でやり取りされるメッセージは、すべて JSON-RPC の形式に従います。

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "GetItems",
        "arguments": {
            "siteId": 12345,
            "pageSize": 50
        }
    }
}

API が「URL パス+HTTP メソッド」でエンドポイントを区別するのに対し、MCP は 単一のエンドポイントに対して method フィールドで操作を指定します。

トランスポート層:Streamable HTTP

プリザンターの MCP サーバは Streamable HTTP トランスポートを採用しています。エンドポイントは /mcp です。

項目 API MCP サーバ
エンドポイント 操作ごとに異なる URL /mcp の単一エンドポイント
HTTP メソッド すべて POST POST(メッセージ送信)
メッセージ形式 独自 JSON JSON-RPC 2.0
ストリーミング 非対応 SSE で対応可能
セッション管理 ステートレス Mcp-Session-Id ヘッダで管理

認証方式の違い

MCP サーバでは、API キーの送信方法が変わりました。

項目 API MCP サーバ
API キーの送信先 リクエストボディ(JSON 内) HTTP ヘッダ(X-Api-Key
認証のタイミング Context 生成時にボディをパース リクエストヘッダから直接取得
セッション認証 Cookie ベースも可 API キー認証のみ

API ではリクエストボディの ApiKey フィールドに含めていましたが、MCP サーバではヘッダベースの X-Api-Key で認証します。これは MCP プロトコルの仕様で、ツール呼び出しのパラメータ(arguments)に認証情報を含めず、トランスポート層で認証を行うためです。

# API のリクエスト
POST /api/items/12345/Get HTTP/1.1
Content-Type: application/json

{"ApiKey":"xxx-xxx","ApiVersion":1.1}

# MCP サーバのリクエスト
POST /mcp HTTP/1.1
Content-Type: application/json
X-Api-Key: xxx-xxx

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"GetItems","arguments":{"siteId":12345}}}

ASP.NET Core での MCP 統合

プリザンターの MCP サーバは、ModelContextProtocol.AspNetCore NuGet パッケージを利用して ASP.NET Core アプリケーションに統合されています。

既存の API は MapControllerRoute でコントローラベースのルーティングが設定されています。MCP サーバは、これに加えて MapMcp("/mcp") でエンドポイントをマッピングする形で統合されています。

// 既存の API ルーティング(Startup.cs)
endpoints.MapControllerRoute(
    name: "Default",
    pattern: "{controller}/{action}",
    defaults: new { Controller = "Items", Action = "Index" });

// MCP エンドポイントの追加
app.MapMcp("/mcp");

MCP サーバの有効化

MCP サーバの動作は McpServer.json パラメータファイルで制御します。

App_Data/Parameters/McpServer.json
{
    "Enabled": true
}

Enabledtrue に設定してサービスを再起動すると、/mcp エンドポイントが有効になります。

リクエスト処理フローの比較

ST API のフロー

API では、1 つのリクエストが以下のパイプラインを通ります。

HTTP POST → フィルタ(IP/JSON/CSRF) → コントローラ → Context生成(認証)
         → モデル(権限チェック→DB問合せ) → ApiResults → JSON レスポンス

各操作(Get / Create / Update / Delete)が個別のコントローラアクションとして定義されているため、URL パスだけで何をするか明確です。

MCP サーバのフロー

MCP サーバでは、すべてのリクエストが /mcp に到達し、JSON-RPC の method で処理が分岐します。

ライフサイクルの違い

MCP 通信にはライフサイクルがあり、API のような単発リクエストとは異なるフェーズを経ます。

フェーズ 内容
initialize クライアントとサーバがプロトコルバージョンと対応機能を交換
initialized 初期化完了の通知
tools/list サーバが提供するツールの一覧を返す
tools/call 指定ツールを実行し結果を返す
shutdown セッション終了

API では各リクエストが独立していますが、MCP ではセッションが維持され、クライアントは事前に利用可能なツール一覧を取得してからツールを呼び出します。

エラーハンドリングの違い

API のエラー

API では、HTTP ステータスコードとプリザンター独自の StatusCode フィールドでエラーを表現します。

{
    "StatusCode": 401,
    "Message": "Unauthorized"
}

プリザンター固有のステータスコードも定義されています。

ステータス 意味
200 成功
400 不正なリクエスト
401 認証エラー
403 権限不足
404 未検出
422 バリデーションエラー
429 API 上限超過
500 サーバエラー

MCP のエラー

MCP では JSON-RPC 2.0 のエラー形式に従います。

{
    "jsonrpc": "2.0",
    "id": 1,
    "error": {
        "code": -32602,
        "message": "Invalid params",
        "data": "siteId is required"
    }
}
JSON-RPC エラーコード 意味
-32700 パースエラー
-32600 不正なリクエスト
-32601 メソッド未検出
-32602 不正なパラメータ
-32603 内部エラー

API のプリザンター独自ステータスコード(429: API 上限超過 など)は、MCP サーバ側で JSON-RPC エラーの data フィールドにマッピングされます。

ログと運用管理

API のログ

API では SysLogModel を使ったアプリケーション内ログが記録されます。

Implem.Pleasanter/Controllers/Api/ItemsController.cs
var log = new SysLogModel(context: context);
var result = context.Authenticated
    ? new ItemModel(context: context, referenceId: id).GetByApi(context: context)
    : ApiResults.Unauthorized(context: context);
log.Finish(context: context, responseSize: result.Content.Length);

MCP のログ

MCP サーバには専用のログ管理機能が用意されており、以下の URL でアクセスできます。

http(s)://{サーバ名}/{パス}/mcplogs

MCP ログには以下の項目が記録されます。

項目 説明
ユーザー API キーに紐づくユーザー
API キー 使用された API キー
経過時間 リクエスト処理にかかった時間
リクエスト内容 JSON-RPC リクエスト本文
レスポンス内容 JSON-RPC レスポンス本文

ログはデータベースに記録され、CSV 出力や不要ログの削除にも対応しています。

レート制限の比較

項目 API MCP サーバ
制限単位 サイトごとの 1 日あたりの呼び出し回数 McpServer.json で設定
超過時の挙動 HTTP 429 + OverLimitApi メッセージ JSON-RPC エラーレスポンス
レスポンスヘッダ LimitPerDate / LimitRemaining MCP レスポンスに含む

API ではサイト単位の呼び出し回数制限が Api.LimitPerSite で設定されていました。MCP サーバでは McpServer.json で独自のレート制限を設定できます。

まとめ

本記事では、プリザンター 1.5.2.0 の MCP サーバと既存 API のアーキテクチャを比較しました。

観点 API MCP サーバ
プロトコル HTTP(独自 JSON) JSON-RPC 2.0 over Streamable HTTP
エンドポイント 操作ごとに個別 URL /mcp の単一エンドポイント
認証 ボディ内 ApiKey ヘッダ X-Api-Key
セッション ステートレス Mcp-Session-Id で管理
エラー形式 独自 StatusCode JSON-RPC エラーコード
ログ SysLog テーブル 専用 MCP ログ(/mcplogs
ASP.NET 統合 MapControllerRoute MapMcp
NuGet パッケージ 不要(組み込み) ModelContextProtocol.AspNetCore

MCP サーバは既存の API とは異なるプロトコル層で動作しますが、内部のデータアクセスやビジネスロジックは既存の仕組みを再利用しています。つまり、アクセスする「入口」が増えたという位置づけです。

次回(後編)では、MCP ツールの具体的な実装と、Claude Desktop や VS Code からの接続方法を詳しく見ていきます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?