MedRecPro Drug Label Server について
MedRecPro Drug Label Serverは、MCPクライアントとMedRecPro Web APIをつなぐOAuth 2.1ゲートウェイです。MedRecProアプリにアクセスするクライアントを対象とし、READMEには通信方式と認証構成が記載されていますが、薬剤ラベル検索ツールの説明はありません。
主な機能
- 01OAuth 2.1認証ゲートウェイ
- 02Streamable HTTPによるMCP通信
- 03GoogleとMicrosoftでのサインイン
- 04ヘルスチェックと技術ドキュメントのエンドポイント
活用シーン
- 01MCPクライアントをMedRecPro Web APIに接続
- 02GoogleまたはMicrosoft経由でクライアントを認証
- 03サービス状態の確認とエンドポイント文書の参照
MCP 対応
`/mcp`でMCP Streamable HTTPエンドポイントを提供し、MCPクライアントとMedRecPro Web APIの間でOAuth 2.1ゲートウェイとして動作します。READMEには公開するMCPツールの一覧がありません。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://www.medrecpro.com/mcpclaude mcp add --transport http com-medrecpro-drug-label-server https://www.medrecpro.com/mcp{"mcpServers":{"com-medrecpro-drug-label-server":{"type":"http","url":"https://www.medrecpro.com/mcp"}}}Cursor で開く{"servers":{"com-medrecpro-drug-label-server":{"type":"http","url":"https://www.medrecpro.com/mcp"}}}VS Code で開く{"mcpServers":{"com-medrecpro-drug-label-server":{"type":"http","url":"https://www.medrecpro.com/mcp"}}}{"mcpServers":{"com-medrecpro-drug-label-server":{"serverUrl":"https://www.medrecpro.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
MedRecPro MCP サーバー
MedRecPro アプリケーション用の MCP(Model Context Protocol)サーバーです。MCP クライアント(Claude など)と MedRecPro Web API の間で、OAuth 2.1 ゲートウェイとして動作します。
バージョン: 1.0.0 ランタイム: ASP.NET Core 8.0 本番 URL: https://www.medrecpro.com/mcp
アーキテクチャ
Azure App Service: "MedRecPro" (Windows, IIS)
+--------------------------------------------------+
| |
+------------------+ | / site\wwwroot MedRecProStatic |
| Claude / MCP | HTTPS | /api site\wwwroot\api MedRecPro API |
| Client |------->| /mcp site\wwwroot\mcp MedRecProMCP |
+------------------+ | |
| +--------------------------------------------------+
v |
+------------------+ v
| Cloudflare | +------------------+
| (CDN/WAF/DNS) | | Azure Key Vault |
+------------------+ | (medrecprovault)|
+------------------+
MCP サーバーは、メインの MedRecPro UI および API と同じ Azure App Service 上で、/mcp に IIS 仮想アプリケーションとして実行されます。IIS はパスベースのルーティングを処理し、3 つの個別の ASP.NET Core プロセスに振り分けます。
| 仮想パス | 物理パス | プロジェクト | 用途 |
|---|---|---|---|
/ | site\wwwroot | MedRecProStatic | UI/静的コンテンツ |
/api | site\wwwroot\api | MedRecPro | Web API |
/mcp | site\wwwroot\mcp | MedRecProMCP | MCP サーバー(このプロジェクト) |
エンドポイント
IIS 仮想アプリケーションにより、すべてのエンドポイントの外部パスには /mcp が付加されます。
| 外部 URL | メソッド | 説明 |
|---|---|---|
/mcp | POST | MCP Streamable HTTP トランスポート(JSON-RPC) |
/mcp/health | GET | ヘルスチェック(JSON ステータスを返します) |
/mcp/docs | GET | HTML 技術ドキュメントページ |
/mcp/getting-started | GET | HTML はじめ方ページ(ディレクトリ掲載用のユーザー向けページ) |
/mcp/docs/images/{filename} | GET | 埋め込みスクリーンショット画像(PNG)を提供します |
/mcp/.well-known/oauth-protected-resource | GET | 保護対象リソースメタデータ(RFC 9728) |
/mcp/.well-known/oauth-authorization-server | GET | 認可サーバーメタデータ(RFC 8414) |
/mcp/oauth/authorize | GET | OAuth 認可エンドポイント |
/mcp/oauth/token | POST | トークン交換エンドポイント |
/mcp/oauth/register | POST | 動的クライアント登録(RFC 7591) |
/mcp/oauth/callback/google | GET | Google OAuth コールバック |
/mcp/oauth/callback/microsoft | GET | Microsoft OAuth コールバック |
注:
GET /mcpは HTTP 405(Method Not Allowed)を返します。これは正しい動作です。MCP トランスポートが受け付けるのは POST リクエストのみです。ブラウザーからアクセスできるページには、/mcp/docs(技術ドキュメント)または/mcp/getting-started(ユーザー向けガイド)を使用してください。
認証フロー
1. Claude sends POST to /mcp (unauthenticated)
2. Server returns 401 with WWW-Authenticate header pointing to PRM
3. Claude fetches /mcp/.well-known/oauth-protected-resource
4. Claude fetches /mcp/.well-known/oauth-authorization-server
5. Claude registers via /mcp/oauth/register (Dynamic Client Registration)
6. Claude redirects user to /mcp/oauth/authorize?provider=google
7. User authenticates with Google/Microsoft
8. Provider redirects to /mcp/oauth/callback/{provider}
9. MCP server resolves upstream IdP email to numeric DB user ID via POST /api/users/resolve-mcp
(auto-provisions user if they don't exist in the database)
10. MCP server issues authorization code with numeric `sub` claim (standard JWT name), redirects to Claude
11. Claude exchanges code for tokens via /mcp/oauth/token
12. Claude sends authenticated POST to /mcp with Bearer MCP JWT
13. MCP server forwards MCP JWT to MedRecPro API for each tool call (McpBearer auth scheme)
ユーザー解決と自動プロビジョニング
OAuth コールバック(ステップ 9)では、MCP サーバーが上流の ID プロバイダーの識別子(Google の sub/Microsoft の GUID)を MedRecPro データベースの数値ユーザー ID にマッピングする必要があります。API の getEncryptedIdFromClaim() メソッドは、数値の NameIdentifier クレームを想定しています。この解決処理がないと、すべての API 呼び出しが 401 で失敗します。
仕組み:
OAuthEndpoints.csが上流 IdP のクレームからメールアドレス、表示名、プロバイダーを抽出しますUserResolutionServiceが一時的な MCP JWT を生成し、POST /api/users/resolve-mcpを呼び出します- API の
UsersController.ResolveMcpUser()がメールアドレスでユーザーを検索します:- ユーザーが存在する場合: 暗号化されたデータベースのユーザー ID を返します
- ユーザーが存在しない場合: 新しいユーザーレコードを自動プロビジョニングし(
AuthController.createUserForExternalLogin()のデフォルトに合わせて、EmailConfirmed=true、Timezone="UTC"、Locale="en-US"、パスワードなし)、暗号化された ID を返します
UserResolutionServiceが、共有のSecurity:DB:PKSecretを使用してStringCipherによって暗号化 ID を復号しますOAuthEndpoints.csが上流のNameIdentifierクレームを数値のデータベースユーザー ID に置き換えます- トークン作成時に
McpTokenService.normalizeClaimType()がClaimTypes.NameIdentifierを標準の JWTsubクレームに変換し、二重マッピングを防ぐためにOutboundClaimTypeMapがクリアされます - MCP JWT が数値ユーザー ID を
subクレームとして発行され、すべての API 呼び出しが成功するようになります
主要なアーキテクチャ:
TokenForwardingHandlerは MCP JWT を API に直接転送します(上流の Google/Microsoft トークンではありません)。API のMcpBearer認証スキームが、これらの MCP 署名付き JWT を検証します。- MCP サーバーと API はどちらも、ユーザー ID の
StringCipherによる暗号化/復号に Azure Key Vault のSecurity:DB:PKSecretを共有して使用します。 UserResolutionServiceは、解決処理中にトークン転送が循環するのを防ぐため、専用の"MedRecProApiDirect"という名前付き HttpClient(TokenForwardingHandlerなし)を使用します。- クレームの正規化:
McpTokenServiceは、トークン作成前に .NET のClaimTypesURI を標準の JWT 短縮名(sub、name、email、given_name、family_name)に正規化します。両方の JWT ハンドラーでMapInboundClaims = falseを設定するため、読み戻したときにクレームは短縮名のまま保持されます。API のClaimHelperは、ClaimTypes.NameIdentifier(Cookie 認証)と"sub"(MCP JWT 認証)の両方からユーザー ID を解決します。
コンパイラーディレクティブ(#if DEBUG)
ルートパスではコンパイラーディレクティブを使用して、IIS による仮想アプリケーションパスの除去に対応します。これは、MedRecPro API プロジェクトの ApiControllerBase と同じパターンに従っています。
問題: IIS は、アプリに転送する前にリクエストから /mcp プレフィックスを除去します。www.medrecpro.com/mcp/oauth/authorize へのリクエストは、Kestrel には /oauth/authorize として届きます。ルートではこの点を考慮する必要があります。
| コンポーネント | DEBUG(ローカル開発) | RELEASE(Azure/IIS) |
|---|---|---|
| MCP トランスポート | MapMcp("/mcp") | MapMcp("/") |
| ヘルスチェック | GET / | GET /health |
| ドキュメント | GET /mcp/docs | GET /docs |
| はじめに | GET /mcp/getting-started | GET /getting-started |
| 画像配信 | GET /mcp/docs/images/{filename} | GET /docs/images/{filename} |
| OAuth グループ | /mcp/oauth | /oauth |
| Well-known メタデータ | /mcp/.well-known/* | /.well-known/* |
| PRM リダイレクト | /mcp/.well-known/oauth-protected-resource が SDK パスにリダイレクト | 不要(IIS が処理) |
コンパイラーディレクティブがあるファイル:
Program.cs- MCP トランスポート、ヘルスチェック、ドキュメント、はじめに、画像配信、PRM リダイレクトEndpoints/OAuthEndpoints.cs- OAuth ルートグループのプレフィックスEndpoints/OAuthMetadataEndpoints.cs- Well-known メタデータのパス
設定駆動(ディレクティブ不要):
- OAuth コールバック URL - 実行時に
McpServer:ServerUrlから構築 - OAuth メタデータドキュメントの内容 - 実行時に
McpServer:ServerUrlから構築 - 保護リソースメタデータ - 実行時に
McpServer:ServerUrlから構築
セットアップガイド
前提条件
- .NET 8.0 SDK
- 以下を備えた Azure サブスクリプション:
- App Service(Windows、IIS)— MedRecPro と共有
- Key Vault(
medrecprovault) - Application Insights(任意)
medrecpro.comドメインを持つ Cloudflare アカウント- OAuth 2.0 認証情報を持つ Google Cloud Console プロジェクト
- Microsoft Entra ID アプリ登録
1. ローカル開発環境のセットアップ
クローンと復元
git clone <repo-url>
cd MedRecProMCP
dotnet restore
ユーザーシークレットの設定
dotnet user-secrets init
dotnet user-secrets set "McpServer:JwtSigningKey" "<min-32-char-key>"
dotnet user-secrets set "Jwt:Key" "<min-32-char-key>"
dotnet user-secrets set "Jwt:Issuer" "http://localhost:5233/mcp"
dotnet user-secrets set "Jwt:Audience" "http://localhost:5233/mcp"
dotnet user-secrets set "Jwt:ExpirationMinutes" "60"
dotnet user-secrets set "Jwt:UpstreamTokenEncryptionKey" "<32-char-aes-key>"
dotnet user-secrets set "Authentication:Google:ClientId" "<google-client-id>"
dotnet user-secrets set "Authentication:Google:ClientSecret" "<google-client-secret>"
dotnet user-secrets set "Authentication:Microsoft:ClientId" "<microsoft-app-id>"
dotnet user-secrets set "Authentication:Microsoft:ClientSecret:Dev" "<microsoft-client-secret>"
dotnet user-secrets set "Authentication:Microsoft:TenantId" "<azure-tenant-id>"
dotnet user-secrets set "Security:DB:PKSecret" "<encryption-key-must-match-api>"
ローカルで実行
dotnet run
サーバーは http://localhost:5233 で実行されます。DEBUG モードでは、エンドポイントに /mcp プレフィックスが付きます:
- ヘルスチェック: http://localhost:5233/
- MCP トランスポート: http://localhost:5233/mcp (POST のみ)
- ドキュメント: http://localhost:5233/mcp/docs
- はじめに: http://localhost:5233/mcp/getting-started
- スクリーンショット画像: http://localhost:5233/mcp/docs/images/{filename}
- OAuth メタデータ: http://localhost:5233/mcp/.well-known/oauth-authorization-server
2. Azure App Service のセットアップ
仮想アプリケーションの追加
Azure Portal で:
- App Service "MedRecPro" > Configuration > Path mappings に移動します
- "+ Add virtual application or directory" をクリックします
- 以下を設定します:
- Virtual path:
/mcp - Physical path:
site\wwwroot\mcp - Type: Application にチェックを入れます
- Virtual path:
- Save をクリックします
Key Vault シークレット
Azure Key Vault(medrecprovault)に以下のシークレットが存在することを確認してください。両方のアプリが同じ Key Vault を使用するため、これらは MedRecPro API と共有されます:
| シークレット名 | 説明 |
|---|---|
McpServer--JwtSigningKey | MCP トークン用の JWT 署名キー(32 文字以上) |
Jwt--Key | JWT 署名キー |
Jwt--Issuer | JWT 発行者クレーム |
Jwt--Audience | JWT オーディエンスクレーム |
Jwt--ExpirationMinutes | トークンの有効期限(例:60) |
Jwt--UpstreamTokenEncryptionKey | アップストリームトークン用 AES 暗号化キー |
Authentication--Google--ClientId | Google OAuth クライアント ID |
Authentication--Google--ClientSecret | Google OAuth クライアントシークレット |
Authentication--Microsoft--ClientId | Microsoft Entra アプリ ID |
Authentication--Microsoft--ClientSecret--Prod | Microsoft クライアントシークレット(本番環境) |
Authentication--Microsoft--TenantId | Azure AD テナント ID |
Security--DB--PKSecret | ユーザー ID の暗号化/復号に使用する共有暗号化キー(API と一致している必要があります) |
注: Key Vault では区切り文字として
--を使用します。ASP.NET Core はこれらを構成内で:に変換します(例:Jwt--KeyはJwt:Keyになります)。
マネージド ID
App Service には、Key Vault シークレットに対する Get および List 権限を持つ、システム割り当てのマネージド ID が必要です。MCP 仮想アプリケーションは API と同じ App Service を共有するため、既存のマネージド ID はすでにアクセス権を持っているはずです。
3. OAuth プロバイダーの構成
Google Cloud Console
- Google Cloud Console > APIs & Services > Credentials に移動します
- OAuth 2.0 クライアント ID を編集します
- 承認済みリダイレクト URI を追加します:
https://www.medrecpro.com/mcp/oauth/callback/google(本番環境)http://localhost:5233/mcp/oauth/callback/google(開発環境)
Microsoft Entra ID
- Azure Portal > Microsoft Entra ID > App registrations に移動します
- アプリを選択し、Authentication に移動します
- リダイレクト URI を追加します:
https://www.medrecpro.com/mcp/oauth/callback/microsoft(本番環境)http://localhost:5233/mcp/oauth/callback/microsoft(開発環境)
4. Cloudflare の構成
MCP サーバーは同じドメイン(www.medrecpro.com)で実行されるため、DNS の変更は不要です。以下のルールを設定します:
キャッシュルール — /mcp のキャッシュをバイパス
Caching > Cache Rules > Create rule
- Rule name:
Bypass cache for MCP server - When: Hostname が
www.medrecpro.comと等しく、かつ URI Path が/mcpで始まる - Then: Cache eligibility:Bypass cache
変換ルール — SSE のレスポンスバッファリングを無効にする
ルール > 変換ルール > レスポンスヘッダーを変更 > ルールを作成
- ルール名:
Disable buffering for MCP SSE - 条件: ホスト名が
www.medrecpro.comと等しく、かつ URI パスが/mcpで始まる - 処理: 静的ヘッダー
X-Accel-Bufferingをnoに設定
これにより、MCP Streamable HTTP トランスポートで使用される Server-Sent Events が Cloudflare によってバッファリングされなくなります。
WAF ルール(任意)
/mcp または /mcp/oauth/* への POST リクエストをブロックする可能性のある既存の WAF ルールがある場合にのみ必要です。WAF にカスタムルールがない場合は、この手順を省略できます。
5. デプロイ
Visual Studio から発行
- ソリューション エクスプローラーで MedRecProMCP を右クリックし、発行 を選択します
- "MedRecProMCP - Web Deploy" プロファイルを選択します
- 設定を確認します:
- 構成:Release
- ターゲット フレームワーク:net8.0
- デプロイ モード:フレームワーク依存
- 発行 をクリックします
発行プロファイルは、<DeployIisAppPath>MedRecPro/mcp</DeployIisAppPath> の設定を使用して site\wwwroot\mcp にデプロイします。
CLI から発行
dotnet publish -c Release -o ./publish
次に、Azure CLI または zip デプロイを使用して、/mcp 仮想アプリケーションパスにデプロイします。
6. 検証
デプロイ後、各エンドポイントを確認します:
# Health check — should return JSON with status "running"
curl https://www.medrecpro.com/mcp/health
# MCP transport — should return 405 (GET not allowed, POST only)
curl -i https://www.medrecpro.com/mcp
# OAuth Authorization Server Metadata — should return JSON
curl https://www.medrecpro.com/mcp/.well-known/oauth-authorization-server
# Protected Resource Metadata — should return JSON
curl https://www.medrecpro.com/mcp/.well-known/oauth-protected-resource
# Documentation page — should return HTML
curl https://www.medrecpro.com/mcp/docs
# Getting-started page — should return HTML with screenshots
curl https://www.medrecpro.com/mcp/getting-started
# Screenshot images — should return PNG image data
curl -I https://www.medrecpro.com/mcp/docs/images/MCP-Adverse-Example.PNG
# Main site still works
curl https://www.medrecpro.com
curl https://www.medrecpro.com/api
構成リファレンス
appsettings.json(基本)
すべての環境で共有される、シークレット以外の構成です。
| キー | 説明 | デフォルト |
|---|---|---|
McpServer:ServerUrl | MCP サーバーのベース URL(/mcp を含む) | https://www.medrecpro.com/mcp |
McpServer:ServerName | 表示名 | MedRecPro MCP Server |
McpServer:ScopesSupported | OAuth スコープ | openid, profile, email, mcp:tools, mcp:read, mcp:write |
McpServer:EnableDynamicClientRegistration | RFC 7591 による登録を許可 | true |
McpServer:MaxRegisteredClients | 動的クライアントの最大数 | 1000 |
McpServer:ClientRegistrationExpirationHours | クライアントの TTL | 24 |
MedRecProApi:BaseUrl | MedRecPro API の URL | https://www.medrecpro.com/api |
MedRecProApi:TimeoutSeconds | HTTP クライアントのタイムアウト | 30 |
MedRecProApi:RetryCount | HTTP リトライ回数 | 3 |
Security:DB:PKSecret | StringCipher 用の共有暗号化キー(API と一致させる必要があります) | (Key Vault) |
KeyVaultUrl | Azure Key Vault の URL | (基本設定では空、Production で設定) |
appsettings.Development.json
| キー | 上書き値 |
|---|---|
McpServer:ServerUrl | http://localhost:5233/mcp |
MedRecProApi:BaseUrl | http://localhost:5093/api |
MedRecProApi:ValidateSslCertificate | false |
appsettings.Production.json
| キー | 上書き値 |
|---|---|
McpServer:ServerUrl | https://www.medrecpro.com/mcp |
MedRecProApi:BaseUrl | https://www.medrecpro.com/api |
KeyVaultUrl | https://medrecprovault.vault.azure.net/ |
プロジェクト構成
MedRecProMCP/
Program.cs # App startup, DI, middleware, endpoint mappings
MedRecProMCP.csproj # Project file (.NET 8.0)
MedRecProMCP.slnx # Solution file
MedRecProMCP.http # HTTP request test file
web.config # IIS configuration (OutOfProcess hosting)
server.json # MCP registry metadata (see MCP Registry below)
Documentation.md # Anthropic Connectors Directory submission doc
appsettings.json # Base configuration
appsettings.Development.json # Local dev overrides
appsettings.Production.json # Azure production overrides
Configuration/
McpServerSettings.cs # MCP server config model
MedRecProApiSettings.cs # API client config model
JwtSettings.cs # JWT config model
OAuthProviderSettings.cs # OAuth provider config model (Google, Microsoft)
Endpoints/
OAuthEndpoints.cs # OAuth authorize, token, register, callbacks
OAuthMetadataEndpoints.cs # .well-known metadata endpoints
Services/
IMcpTokenService.cs # Token service interface
McpTokenService.cs # JWT token generation and validation
IOAuthService.cs # OAuth service interface
OAuthService.cs # OAuth flow orchestration
IClientRegistrationService.cs # Client registration interface
ClientRegistrationService.cs # Dynamic Client Registration (RFC 7591)
IPkceService.cs # PKCE service interface
PkceService.cs # PKCE implementation
IPersistedCacheService.cs # Persisted cache interface
FilePersistedCacheService.cs # File-based persistent cache (PKCE, registrations)
MedRecProApiClient.cs # Typed HTTP client for MedRecPro API
IUserResolutionService.cs # User resolution service interface
UserResolutionService.cs # Resolves upstream IdP email to numeric DB user ID
Handlers/
TokenForwardingHandler.cs # Forwards MCP JWT to API (DelegatingHandler)
Helpers/
StringCipher.cs # AES encryption/decryption (copy from API for user ID handling)
Models/
AiAgentDtos.cs # AI/Claude integration models
WorkPlanModels.cs # Work plan and execution models
Tools/
DrugLabelTools.cs # MCP tools for drug labels, patent expiration (annotated)
UserTools.cs # MCP tools for user/account operations (annotated)
Templates/
McpDocumentation.html # Embedded HTML technical documentation template
McpGettingStarted.html # Embedded HTML getting-started page (user-facing)
Images/
MCP-Adverse-Example.PNG # Screenshot: warnings/adverse effects lookup
MCP-Authentication-Example.PNG # Screenshot: user profile/authentication status
MCP-Full-Label-Example.PNG # Screenshot: complete label export
MCP-Indication-Example.PNG # Screenshot: drug indications lookup
MCP-Starting-Dose-Example.PNG # Screenshot: dosage information lookup
PowerShell/
test-mcp.ps1 # MCP endpoint test script
test-mcp-detailed.ps1 # Detailed MCP test with verbose output
test-mcp-root.ps1 # Root endpoint test script
Properties/
launchSettings.json # Local development profiles
PublishProfiles/
MedRecProMCP - Web Deploy.pubxml # Azure deployment profile
Docs/
DeploymentGuide.md # Legacy deployment guide (subdomain approach)
Claude.ai コネクターとの統合
このセクションでは、Claude.ai の「設定 > コネクター」で MCP サーバーをカスタムコネクターとして接続する手順について説明します。IIS 仮想アプリケーション、Cloudflare、Azure のアーキテクチャに固有の数多くの障害に直面しながら、複数のセッションにわたって取り組みました。
Anthropic コネクターディレクトリへの提出
Anthropic コネクターディレクトリへの提出資料:
Documentation.md— Anthropic のテンプレートに沿った提出用ドキュメント(説明、機能、セットアップ、スクリーンショット付きの例)/mcp/getting-started— ディレクトリの掲載ページからリンクされる、ユーザー向け HTML ページ- ツールのアノテーション — 5 つすべてのツールに
ReadOnly、Destructive、OpenWorldの安全性アノテーションを含めています - 認証 — PKCE を使用した OAuth 2.1 で、動的クライアント登録(RFC 7591)をサポートしています。特別なアカウントは不要です。レビュー担当者は Google または Microsoft の任意のアカウントで認証でき、自動的にプロビジョニングされます。
接続ステータス
| コンポーネント | ステータス |
|---|---|
| OAuth 2.1 フロー(PKCE S256) | 動作中 |
MCP セッションの確立(initialize) | 動作中 |
ツールの一覧表示(tools/list) | 動作中 |
ツールの実行(tools/call) | 動作中 |
| 下流 API 呼び出し(MCP -> MedRecPro API) | 動作中 |
| MCP ユーザーの解決(メールアドレス -> 数値の DB ID) | 動作中 |
| MCP ユーザーの自動プロビジョニング(新規ユーザー) | 動作中 |
| JWT クレームの正規化(sub、name、email) | 動作中 |
| UsersController [Authorize(Policy = "ApiAccess")] | 動作中 |
ツールの安全性アノテーション
7 つのツールすべてに、[McpServerTool] 属性のプロパティを使用して MCP の安全性アノテーションが宣言されています(ModelContextProtocol SDK v0.7.0-preview.1 でサポート)。
| ツール | タイトル | 読み取り専用 | 破壊的 | オープンワールド |
|---|---|---|---|---|
search_drug_labels | 医薬品ラベルを検索 | true | false | false |
export_drug_label_markdown | 医薬品ラベルをエクスポート | true | false | false |
search_expiring_patents | 期限切れ間近の特許を検索 | true | false | false |
search_by_pharmacologic_class | 薬理クラスで検索 | true | false | false |
get_my_profile | 自分のプロフィールを取得 | true | false | false |
get_my_activity | 自分のアクティビティを取得 | true | false | false |
get_my_activity_by_date_range | 期間を指定してアクティビティを取得 | true | false | false |
アノテーションの理由:
- すべてのツールは読み取り専用です。どのツールもデータを変更しません
- すべてのツールで
OpenWorld = falseを使用しています。すべてのデータは、コンソールアプリケーション経由で登録された MedRecPro データベース内に完結しているためです
発生した問題と修正
統合中に以下の問題が順番に発生しました。次の問題を確認するには、それぞれを解決する必要がありました。
1. PKCE 検証の失敗
症状: OAuth トークンの交換が PKCE の不一致により失敗しました。
根本原因: PKCE の検証子とチャレンジのペアが、認可フロー全体で正しく保存および照合されていませんでした。
修正: PkceService.cs の PKCE 保存および検証ロジックを修正しました。
2. ディスカバリーエンドポイントが 302 リダイレクトを返す
症状: Claude の MCP SDK が /.well-known/oauth-protected-resource および /.well-known/oauth-authorization-server に対して JSON ではなく 302 リダイレクトを受信しました。
根本原因: IIS のパスベースルーティングと /mcp の仮想アプリケーションにより、ディスカバリー URL の解決で問題が発生しました。MCP SDK はドメインルートの /.well-known/* を想定していますが、MCP サーバーは /mcp 配下のリクエストのみを処理します。
修正: MedRecProStatic/Program.cs(ルートサイト)に well-known エンドポイントを直接追加し、OAuth メタデータを静的な JSON レスポンスとして返すようにしました。これにより、リダイレクトを完全に回避できます。
3. MCP トランスポートに [Authorize] がない
症状: 認証なしで Claude が接続でき、401 チャレンジが送信されませんでした。
根本原因: MapMcp() エンドポイントに .RequireAuthorization() がありませんでした。
修正: Program.cs の MapMcp("/") 呼び出しに .RequireAuthorization() を追加しました(RELEASE 構成)。
4. MCP トランスポートの [AllowAnonymous]
症状: .RequireAuthorization() を追加しても、MCP トランスポートは 401 を返しませんでした。
根本原因: MCP SDK のデフォルトトランスポートミドルウェアが、内部で [AllowAnonymous] を適用していました。
修正: McpAuthenticationHandler チャレンジスキームを使用し、未認証のリクエストに resource_metadata URI を含む WWW-Authenticate ヘッダーが返されるようにしました。
5. IIS が 401 を HTML エラーページに置き換える
症状: Claude は WWW-Authenticate ヘッダーを含む JSON の 401 レスポンスではなく、HTML エラーページを受信しました。
根本原因: IIS は HTTP エラーレスポンスを傍受し、独自の HTML ページに置き換えます。
修正: MedRecProStatic(ルートサイト)と MedRecProMCP の両方の web.config に <httpErrors existingResponse="PassThrough" /> を追加しました。ルートサイトの設定は子の仮想アプリケーションに継承されるため、特に重要です。
6. 401 応答に含まれる resource_metadata URL が誤っている
症状: Claude が保護対象リソースメタデータ(PRM)エンドポイントを見つけられませんでした。
根本原因: WWW-Authenticate ヘッダーの resource_metadata URI が誤ったパスを指していました。
修正: McpAuthenticationHandler の構成で ResourceMetadataUri を {ServerUrl}/.well-known/oauth-protected-resource に明示的に設定しました。
7. PRM エンドポイントが 404 を返す
症状: URL を修正した後、PRM エンドポイントが 404 を返しました。
根本原因: ルート登録の順序と IIS によるパスの除去により、エンドポイントがマッピングされていませんでした。
修正: OAuthMetadataEndpoints.cs に正しいルーティングで PRM エンドポイントの登録を明示的に追加しました。
8. Cloudflare の「Manage AI Bots」WAF ルールによる Claude のブロック
症状: Claude のリクエストがサーバーに到達しませんでした(Cloudflare が 403 を返しました)。 根本原因: Cloudflare の管理対象 WAF ルール「Block AI Bots」が、Claude-User(Anthropic のクローラーのユーザーエージェント)からのすべてのリクエストをブロックしていました。AI Crawl Control ダッシュボードには、ブロックされたリクエストが 149 件、許可されたリクエストが 0 件と表示されていました。 修正(Cloudflare ダッシュボード):
- Security > Settings > Block AI Bots Scope — 「広告のあるホスト名のみブロック」に変更
- Security > AI Crawl Control > Crawlers —
Claude-User(Anthropic)を許可に設定
9. JWT オーディエンスの検証に失敗(IDX10214)
症状: IDX10214: Audience validation failed. Audiences: 'https://www.medrecpro.com/mcp'. Did not match: validationParameters.ValidAudience: 'MedRecUsers'
根本原因: McpTokenService はオーディエンスを ServerUrl(https://www.medrecpro.com/mcp)に設定したトークンを発行しますが、JWT Bearer ハンドラーは MedRecUsers(Jwt:Audience の構成値)のみを受け入れていました。
修正: 単一値の ValidAudience を ValidAudiences(配列)に変更し、jwtSettings.Audience と mcpSettings.ServerUrl.TrimEnd('/') の両方を受け入れるようにしました。
10. JWT 発行者の検証に失敗(IDX10205)
症状: IDX10205: Issuer validation failed. Issuer: 'https://www.medrecpro.com/mcp'. Did not match: validationParameters.ValidIssuer: 'MedRecPro'
根本原因: オーディエンスの場合と同じ二重トークンの問題です。McpTokenService は発行者に ServerUrl を使用しますが、JWT ハンドラーは MedRecPro のみを受け入れていました。
修正: 単一値の ValidIssuer を ValidIssuers(配列)に変更し、jwtSettings.Issuer と mcpSettings.ServerUrl.TrimEnd('/') の両方を受け入れるようにしました。
11. Cloudflare の Bot Fight Mode による下流 API 呼び出しのブロック
症状: MCP ツールは実行されましたが、403 を返しました。MCP サーバーから https://www.medrecpro.com/api/... への HTTP 呼び出しがブロックされていました。
根本原因: MCP サーバー(Azure 上で実行)は、パブリック API URL にアウトバウンド HTTP リクエストを送信します。これらのリクエストは Cloudflare を経由し、空の User-Agent ヘッダーを持つ Azure の IP アドレスから送信されたため、Bot Fight Mode によって検知されました。
修正(2 部構成):
- コード —
Program.csの両方の HttpClient 登録にUser-Agent: MedRecProMCP/1.0 (Internal-API-Client)ヘッダーを追加しました - Cloudflare — WAF カスタムルールでは Bot Fight Mode をスキップできませんが、リクエストにIP Access Ruleが一致すれば発動しません。Azure App Service のアウトバウンド IP 32 個すべてに対して、アクションを Allow に設定した IP Access Rules を追加しました:
# Get all possible outbound IPs for the App Service az webapp show --resource-group <rg> --name <app> \ --query possibleOutboundIpAddresses --output tsv # Add each IP as a Cloudflare IP Access Rule (Allow) # Use Cloudflare API with Global API Key: for ip in $IPS; do curl -s -X POST \ "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/firewall/access_rules/rules" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $API_KEY" \ -H "Content-Type: application/json" \ --data "{\"mode\":\"whitelist\",\"configuration\":{\"target\":\"ip\",\"value\":\"$ip\"},\"notes\":\"Azure App Service outbound IP\"}" done
12. Azure SQL Database のコールドスタートによるタイムアウト
症状: アイドル状態の後、最初のツール呼び出しが Database 'MedRecProDB' is not currently available または Execution Timeout Expired(コマンドタイムアウト 30 秒)で失敗します。
根本原因: Azure SQL Serverless は、一定時間操作がないと自動的に一時停止します。再開に 15~30 秒以上かかり、HttpClient のタイムアウト(30 秒)と SQL コマンドのタイムアウト(30 秒)の両方を超過します。
ステータス: 既知の問題です。データベースがウォームアップすると、後続のリクエストは成功します。緩和策として、自動一時停止までの時間を延長する、UseSqlServer で EnableRetryOnFailure を有効にする、または MedRecProApi の設定で TimeoutSeconds を増やす方法があります。
13. JWT クレーム型のマッピング不一致(ツール呼び出し時に 401)
症状: OAuth ログインが成功して MCP JWT が生成された後、API にアクセスするすべてのツール呼び出しが 401 を返します。ログには [Auth] Token validated for user: unknown と表示され、getEncryptedIdFromClaim() が UnauthorizedAccessException: Unable to determine user ID from authentication context をスローします。
根本原因: JwtSecurityTokenHandler.OutboundClaimTypeMap は、JWT のシリアライズ時に ClaimTypes.NameIdentifier を "sub" に、ClaimTypes.Name を "unique_name" に暗黙的に変換します。API 側の getEncryptedIdFromClaim() は c.Type.Contains("NameIdentifier") を検索していましたが、これは "sub" と一致しませんでした。さらに、NameClaimType = "name" は "name" クレームを想定していましたが、JWT に含まれていたのは "unique_name" だったため、Identity.Name は null になっていました。
修正(3 つの対応):
- McpTokenService — トークンの作成前に
ClaimTypes.*URI を標準の JWT 短縮名(sub、name、email、given_name、family_name)に明示的にマッピングするnormalizeClaimType()を追加しました。二重マッピングを防ぐため、OutboundClaimTypeMapをクリアしました。 - 両方の JWT ハンドラー — MCP サーバーと API の
McpBearerハンドラーにMapInboundClaims = falseを追加し、ClaimsPrincipalに読み込む際にクレームが元の短縮名を保持するようにしました。 - API のクレーム読み取り処理 —
ClaimHelper.csを作成し、ClaimTypes.NameIdentifier(Cookie 認証)と"sub"(MCP JWT)の両方からユーザー ID を解決できるようにしました。UsersController、AiController、AuthController、LabelController、RequireActorAttributeFilter、RequireUserRoleAttributeFilter、ActivityLogActionFilter、LogHelperに分散していた 9 か所の NameIdentifier 参照を、共通ヘルパーを使うように更新しました。
14. UsersController に [Authorize] がない(MCP ツール呼び出し時に 401)
症状: JWT クレームの正規化(Issue #13)を修正した後、MCP 側のログには [Auth] Token validated for user: Christopher Barnes と正しく表示されるようになりましたが、API のツール呼び出しは依然として 401 を返します。ClaimHelper.GetEncryptedUserIdOrThrow は、User.Claims が空のため例外をスローします。IIS のログには Logon User: Anonymous と表示されます。API 側からの [MCP Auth] ログはありません。
根本原因: UsersController には、クラスレベルにも個々のエンドポイントにも [Authorize] 属性がありませんでした(resolve-mcp を除く)。[Authorize] がないと、ASP.NET Core の JWT Bearer ハンドラーは McpBearer トークンに対して呼び出されず、リクエストは匿名として処理されて User.Claims が空になります。Identity ミドルウェアはすべてのリクエストでセッション Cookie から User.Claims を設定するため、Cookie 認証は [Authorize] がなくても機能していました。一方、JWT Bearer スキームでは、検証を実行するために明示的な [Authorize] が必要です。
修正: UsersController クラスに [Authorize(Policy = "ApiAccess")] を追加しました。ApiAccess ポリシー(Program.cs)は IdentityConstants.ApplicationScheme(Cookie)と "McpBearer"(JWT)の両方を受け入れるため、既存の Cookie 認証の動作を維持しながら、MCP リクエストで JWT ハンドラーが呼び出されるようになります。一般公開を維持する必要がある signup と authenticate のエンドポイントには [AllowAnonymous] を追加しました。また、SecurityTokenException のログ出力を暗黙的に抑制していた OnAuthenticationFailed ハンドラーも修正しました。
15. GetMyActivity / GetMyActivityByDateRange がサイレントに失敗する
症状: Issue #14 を修正した後、GetMyProfile は正常に 200 を返しますが、GetMyActivity と GetMyActivityByDateRange はすぐに完了し、アクティビティエンドポイントへの 2 回目の HTTP リクエストが発生しません。MCP ツールは Claude に {"error":"Could not determine user ID"} を返します。
根本原因(A — MCP 側): UserTools.cs は profile.TryGetProperty("encryptedId", ...) を呼び出しますが、API は Newtonsoft.Json と CamelCasePropertyNamesContractResolver を使用してシリアライズします。実際の JSON プロパティ名は "encryptedUserId"(キャメルケースで、元の検索キーでは「User」が抜けていました)です。大文字小文字を区別する TryGetProperty の検索が失敗するため、2 回目の API 呼び出しが行われません。
根本原因(B — API 側): UsersController.cs の GetUserActivity(452 行目)と GetUserActivityByDateRange(630 行目)では、if (!isSelf || !claimsUser.IsUserAdmin()) が使われていました。OR ではなく AND にすべきでした。この条件により、一般ユーザーが自分自身のアクティビティログを閲覧できませんでした。対象ユーザーであり、かつ管理者でもあるユーザーだけがチェックを通過できる状態でした。
修正: JSON プロパティ名のキャメルケースに合わせるため、UserTools.cs の "encryptedId" を "encryptedUserId" に(両方の箇所で)変更しました。UsersController.cs の両方の認可チェックで || を && に変更し、すべてのユーザーが自分自身のデータにアクセスでき、管理者は任意のユーザーのログにアクセスできるようにしました。
得られた教訓
-
IIS の仮想アプリケーションはパスのプレフィックスを削除します。
/mcp/oauth/authorizeへのリクエストは、Kestrel には/oauth/authorizeとして届きます。RELEASE ビルドでは、すべてのルートマッピングでこれを考慮する必要があります。#if DEBUGディレクティブを使用してください。 -
OAuth のディスカバリーはドメインのルートに配置する必要があります。 MCP SDK は
/.well-known/*を MCP エンドポイントのパスではなく、ドメインを基準に解決します。これらのエンドポイントは MCP 仮想アプリケーションではなく、ルートサイト(MedRecProStatic)から提供してください。 -
httpErrors existingResponse="PassThrough"は非常に重要です。 これがないと、IIS は OAuth チャレンジに必要な 401 レスポンスを HTML エラーページに置き換えます。子仮想アプリケーションはこの設定を継承するため、ルートサイトのweb.configに設定する必要があります。 -
Cloudflare には、互いに独立したボットブロックシステムが複数あります。
- 「Block AI Bots」(WAF 管理ルール)— AI クローラーのアクセスを制御します。AI Crawl Control で Claude-User を許可してください。
- 「Bot Fight Mode」 — ホスティングプロバイダーの IP からの自動トラフィックをブロックします。WAF ルールでは回避できません。回避するには IP Access Rules を使用するしかありません。
-
Cloudflare 経由のサーバー間通信には、ホワイトリスト登録が必要です。 サーバーが自分自身のパブリックドメインに HTTP リクエストを送信すると、そのリクエストは Cloudflare を経由し、ボットトラフィックとして検出されます。送信側の HttpClient には必ず
User-Agentヘッダーを設定し、Cloudflare IP Access Rules でサーバーの送信元 IP をホワイトリストに登録してください。 -
Azure App Service から localhost への接続はできません。 サンドボックスにより、
127.0.0.1:80への送信ソケット接続が禁止されています。同じ App Service 内のサーバー間通信には、パブリックホスト名を使用する必要があります。 -
発行元が異なる JWT トークンには、
ValidIssuers/ValidAudiences配列が必要です。 MCP サーバーが既存のユーザー認証システムとは異なる発行元/オーディエンス値でトークンを発行する場合、JWT Bearer ハンドラーで両方を受け入れる必要があります。単数形のプロパティではなく、複数形の配列プロパティを使用してください。 -
Azure SQL Serverless のコールドスタートは、問題が連鎖する原因になることがあります。 一時停止中のデータベースの再開には、15~30 秒以上かかります。データベースが起動する前に MCP HttpClient のタイムアウト(30 秒)に達すると、ツール呼び出しは失敗します。サーバーレスデータベースでは、
EnableRetryOnFailureと余裕のあるタイムアウトの設定を検討してください。 -
Cloudflare API の認証: Global API Key では
X-Auth-EmailとX-Auth-Keyヘッダーを使います。Authorization: Bearerではありません。API Token(スコープ付き)ではAuthorization: Bearerを使います。誤った形式を使うとUnable to authenticate requestが返されます。 -
JwtSecurityTokenHandlerはクレームタイプを暗黙的に変更します。OutboundClaimTypeMapは、JWT のシリアル化時にClaimTypes.NameIdentifierを"sub"に、ClaimTypes.Nameを"unique_name"に変換します。受信側では、MapInboundClaims(既定値はtrue)によってこの変換が元に戻る場合と戻らない場合があります。これはハンドラーの実装に依存します(.NET 8 のJsonWebTokenHandlerでは元に戻りません)。クレームタイプがエンドツーエンドで予測可能になるよう、トークンの作成前に必ずクレームを標準的な JWT の短縮名に明示的に正規化し、OutboundClaimTypeMapをクリアして、JWT ハンドラーでMapInboundClaims = falseを設定してください。 -
JWT Bearer スキームで検証を実行するには、
[Authorize]が必要です。 すべてのリクエストでグローバルに実行され、セッション Cookie からUser.Claimsを設定する Cookie/Identity ミドルウェアとは異なり、JWT Bearer ハンドラーは、エンドポイントに[Authorize](またはそのスキームを参照するポリシー)が指定されている場合にのみトークンを検証します。指定がない場合、Authorizationヘッダー内の Bearer トークンは無視され、リクエストは匿名として処理され、User.Claimsは空になります。コントローラーに公開エンドポイントと保護されたエンドポイントが混在する場合は、クラスレベルで[Authorize(Policy = "...")]を使用し、公開エンドポイントには[AllowAnonymous]を指定してください。 -
JSON のプロパティ名は、API のシリアル化時の大文字と小文字の形式に一致させる必要があります。 MedRecPro API は、PascalCase(camelCase への変換なし)で Newtonsoft.Json を使用しています。MCP プロジェクトで
System.Text.Jsonを使って API の応答を解析する場合、TryGetProperty()では大文字と小文字が区別されます。"encryptedId"は"EncryptedUserId"に一致しません。API が返す正確なプロパティ名を必ず確認してください。 -
認可ロジックにおけるド・モルガンの法則。
if (!isSelf || !isAdmin)はif (!(isSelf && isAdmin))と等価です。これは、どちらか一方ではなく、両方の条件が真であることを要求します。「自分自身または管理者なら許可」するには、if (!isSelf && !isAdmin)を使用してください。
トラブルシューティング
502 Bad Gateway
MCP アプリが起動時にクラッシュしています。次を確認してください。
- Kudu コンソール —
https://<app>.scm.azurewebsites.netにアクセスし、LogFiles/に移動してstdout-mcp*ログファイルを探します - stdout ログを有効にする —
site\wwwroot\mcp\web.configでstdoutLogEnabled="true"に設定し、URL に再度アクセスしてログを確認します - よくある原因: Key Vault にアクセスできないことです。
appsettings.Production.jsonでKeyVaultUrlが設定されていることと、マネージド ID にアクセス権があることを確認してください
IDX10703: key length is zero
JWT 署名キーが空です。これは、Key Vault のシークレットが読み込まれていないことを意味します。
appsettings.Production.jsonでKeyVaultUrlがhttps://medrecprovault.vault.azure.net/に設定されていることを確認します- App Service のマネージド ID に、Key Vault のシークレットに対する
GetおよびListのアクセス許可があることを確認します - App Service の環境変数で、
ASPNETCORE_ENVIRONMENTがProductionに設定されていることを確認します
IDX10214 / IDX10205: Audience または Issuer の検証に失敗
McpTokenService が発行する JWT トークンでは、ServerUrl が発行者と対象者の両方として使用されます。JWT Bearer ハンドラーは、MCP の値と既存のユーザー認証値の両方を受け入れる必要があります。
ValidIssuers = new[] { jwtSettings.Issuer, mcpSettings.ServerUrl.TrimEnd('/') }
ValidAudiences = new[] { jwtSettings.Audience, mcpSettings.ServerUrl.TrimEnd('/') }
/mcp で 405 Method Not Allowed
これは想定どおりの動作です。/mcp の MCP Streamable HTTP トランスポートは POST リクエストのみを受け付けます。ブラウザーは GET を送信するため、405 が返されます。
下流 API の呼び出しで 403 Forbidden
MCP サーバーから https://www.medrecpro.com/api/... への送信 HTTP 呼び出しが、Cloudflare によってブロックされています。
- Cloudflare Firewall Events を確認する — ソースが
botFightまたはmanagedChallengeのブロックを探します - IP アクセスルールを確認する — Azure App Service のすべての送信 IP を Cloudflare で許可リストに登録する必要があります(Security > WAF > Tools > IP Access Rules、アクション:Allow)
- User-Agent ヘッダーを確認する — HttpClient は空でない User-Agent を送信する必要があります。
Program.csでclient.DefaultRequestHeaders.Add("User-Agent", ...)を確認してください - 送信 IP を取得する:
az webapp show --resource-group <rg> --name <app> --query possibleOutboundIpAddresses --output tsv
OAuth コールバックエラー
- Google Cloud Console と Microsoft Entra ID にリダイレクト URI が登録されていることを確認します
McpServer:ServerUrlに/mcpが含まれていることを確認します(例:https://www.medrecpro.com/mcp)- コールバック URL は
{ServerUrl}/oauth/callback/{provider}として構築されます
SSE 接続の切断
- Cloudflare の変換ルールで、
/mcpパスに対してX-Accel-Buffering: noが設定されていることを確認します - Cloudflare のキャッシュルールで、
/mcpパスがキャッシュをバイパスすることを確認します - Azure App Service の常時接続が有効になっていることを確認します
最初のツール呼び出しでデータベースがタイムアウトする
Azure SQL Serverless が一時停止している可能性があります。最初のリクエストで再開が開始され、15~30 秒以上かかることがあります。
- 再試行 — データベースの起動後、2 回目の試行で通常は成功します
- 自動一時停止までの時間を延長 — テスト中は Azure Portal でサーバーレスの自動一時停止までの時間を 10~15 分に設定します
- 再試行ロジックを追加 —
UseSqlServer()の設定でEnableRetryOnFailure()を検討します
MCP レジストリへの公開
このサーバーは、MCP クライアントが発見できるよう、公式の MCP Registry に登録されています。
レジストリエントリ: com.medrecpro/drug-label-server
レジストリ検索: https://registry.modelcontextprotocol.io/v0.1/servers?search=medrecpro
前提条件
-
mcp-publisher CLI — GitHub リリースからインストールします:
# Windows (PowerShell) $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq "Arm64") { "arm64" } else { "amd64" } Invoke-WebRequest -Uri "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_windows_$arch.tar.gz" -OutFile "mcp-publisher.tar.gz" tar xf mcp-publisher.tar.gz mcp-publisher.exe rm mcp-publisher.tar.gz -
Ed25519 キーペア — DNS ドメインの検証に使用します(ローカルに保存し、リポジトリには保存しません)
-
DNS TXT レコード — Cloudflare ですでに設定されています:
medrecpro.com TXT "v=MCPv1; k=ed25519; p=<public-key>"
server.json
レジストリのメタデータファイルは MedRecProMCP/server.json にあります:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.medrecpro/drug-label-server",
"title": "MedRecPro Drug Label Server",
"description": "Search and export FDA drug labels by brand name, generic ingredient, or UNII code.",
"version": "1.0.0",
"websiteUrl": "https://www.medrecpro.com",
"icons": [
{
"src": "https://www.medrecpro.com/favicon.svg",
"mimeType": "image/svg+xml",
"sizes": ["any"]
},
{
"src": "https://www.medrecpro.com/favicon-96x96.png",
"mimeType": "image/png",
"sizes": ["96x96"]
}
],
"repository": {
"url": "https://github.com/chriserikbarnes/MedRecPro",
"source": "github",
"subfolder": "MedRecProMCP"
},
"remotes": [
{
"type": "streamable-http",
"url": "https://www.medrecpro.com/mcp"
}
]
}
主なポイント:
nameにはcom.medrecpro/名前空間を使用します(DNS による検証済み)iconsには、クライアントでの表示用に SVG(スケーラブル)と 96x96 PNG を指定しますremotesは、これがホスト型サーバーであることを宣言します(npm/PyPI パッケージではありません)packagesは、このサーバーがパッケージとして配布されないため省略します
公開手順
-
DNS 検証で認証します:
mcp-publisher.exe login dns --domain=medrecpro.com --private-key=<64-char-hex-private-key>⚠️ 秘密鍵は、リポジトリ外にあるローカルスクリプトに保存されています。
C:\Users\{user}\{folder}\{publisher-script}.ps1を参照してください -
レジストリに公開します:
mcp-publisher.exe publish server.json -
掲載を確認します:
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=medrecpro"
更新を公開するタイミング
ツールの追加、削除、名前変更、サーバー URL の変更、または説明やメタデータの更新を行う場合は、server.json の version を上げて再公開します。
- ツールの追加、削除、名前変更
- サーバー URL の変更
- 説明またはメタデータの更新
レジストリには各バージョンが個別に保存されます。公開してもコードはデプロイされません。カタログエントリが更新されるだけです。
後方互換性の維持
デプロイ済みのサーバーは単一インスタンスであり、バージョン管理されたパッケージではないため、破壊的変更は避けてください。
| ✅ 安全な変更 | ❌ 破壊的変更 |
|---|---|
| 新しいツールの追加 | 既存ツールの削除 |
| オプションパラメーターの追加 | パラメーターの削除または名前変更 |
| 新しいレスポンスフィールドの追加 | レスポンス構造の変更 |
| バグ修正/ロジックの改善 | ツール名の変更 |
| 説明の改善 | 必須フィールドの削除 |
DNS 検証リファレンス
キーペアを再生成する場合や、新しいマシンで設定する場合:
# Generate Ed25519 keypair (use Git Bash on Windows)
openssl genpkey -algorithm Ed25519 -out mcp-key.pem
# Extract public key (Base64) — goes in DNS TXT record
openssl pkey -in mcp-key.pem -pubout -outform DER | tail -c 32 | base64
# Extract private key (64-char hex) — used with CLI
openssl pkey -in mcp-key.pem -noout -text 2>&1 | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n'
DNS TXT レコードの形式(Cloudflare):
- タイプ: TXT
- 名前:
@(ルートドメイン) - 内容:
v=MCPv1; k=ed25519; p=<base64-public-key>
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。