はじめに
プリザンター 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] フィルタが適用されており、認証・検証のパイプラインが統一されています。
[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 テーブルと照合しています。
var jsonDeserializedRequestApi = RequestDataString.Deserialize<Api>();
if (jsonDeserializedRequestApi?.ApiKey.IsNullOrEmpty() == false)
{
ApiKey = jsonDeserializedRequestApi.ApiKey;
SetUser(userModel: GetUser(where: Rds.UsersWhere()
.ApiKey(ApiKey)));
}
リクエスト/レスポンスモデル
API のリクエストは Api クラスで定義されています。
[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 パラメータファイルで制御します。
{
"Enabled": true
}
Enabled を true に設定してサービスを再起動すると、/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 を使ったアプリケーション内ログが記録されます。
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 からの接続方法を詳しく見ていきます。