Skip to main content
Glama
curtismu7

mcp-resource-server

by curtismu7

mcp-resource-server

10のモック業界(銀行、ヘルスケア、政府、製造、小売、スポーツ用品、大学、ワークフォース、Abercrombie & Fitch、航空)にわたる読み取り中心のツールと、一連の投資ツールを公開するMCPサーバーです。各業界は独自のバンドルされたSQLiteデータベースを読み取ります。実行に他のサービスは必要ありません。投資ツールは、必要に応じて、提供する銀行APIにプロキシすることもできます(下記参照)。

前提条件

  • Docker + Docker Compose

  • ベアラートークンを発行・検証するためのPingOne環境(または、正しいaud/scopeクレームを持つJWTを発行し、JWKSエンドポイントを公開できる任意のOAuth AS。このサーバーは標準のOIDCディスカバリのみに依存しており、PingOne固有のものには依存しません)

Related MCP server: mock-mcp

クイックスタート

cp .env.example .env

.envを編集します。MCP_RESOURCE_SERVER_RESOURCE_URI、PINGONE_ENVIRONMENT_ID、PINGONE_REGIONを自分のPingOne環境に合わせて設定します。実際のトークンができるまでPINGONE_ISSUERはコメントアウトしたままにします(「認証モード」を参照)。

docker compose up --build

サーバーはhttp://localhost:8081で待ち受けます。SQLiteデータベースは./dataに永続化されます(初回使用時にseed/からシードされます。再起動しても空でないデータベースは再シードされません)。

実行確認

curl http://localhost:8081/health
curl http://localhost:8081/.well-known/oauth-protected-resource

2番目の呼び出しは、リソースのアドバタイズされたスコープと、PINGONE_ENVIRONMENT_ID/PINGONE_REGIONが設定されている場合はその認可サーバーを返します。これは、MCPクライアントがOAuthディスカバリに使用するRFC 9728メタデータです。

認証モード

トークンの署名が検証されるかどうかは、JWKSソースが設定されているかどうかで決まります。STRICT_AUTHではありません。

  • JWKSソース設定あり(PINGONE_ISSUER、PINGONE_JWKS_URI、またはPINGONE_BASE_URL)— すべてのトークンはPingOne環境のキーに対して検証され、失敗した場合は拒否されます。STRICT_AUTHは効果がありません。実際のトークンが流れ始めたらこの方法で実行します。

  • JWKSソースなし — STRICT_AUTH=false(同梱のデフォルト)は、コンソール警告付きで整形式のトークンを受け入れます。PingOneを配線する前に手作りのトークンですべてのツールを試すことができます。STRICT_AUTH=trueは代わりにすべてのトークンを拒否します。デフォルトを自分以外の人が到達できる状態にしないでください。

.env.exampleには、その理由から3つのJWKS変数すべてがコメントアウトされて同梱されています。実際のトークンができたら1つをコメント解除してください。

ベアラートークンの取得

すべてのツール呼び出しには、audクレームがMCP_RESOURCE_SERVER_RESOURCE_URIと一致し、scopeクレームが呼び出すツールをカバーするベアラートークンが必要です(最新の権威あるリストはtools/listを参照してください。これはこのサーバー自身のレジストリから生成されます)。

ローカルテスト(STRICT_AUTH=false) — 正しいクレームを持つ整形式のJWTであれば機能します。署名はチェックされません。

node -e "
const b64 = s => Buffer.from(JSON.stringify(s)).toString('base64url');
const header = b64({alg:'none',typ:'JWT'});
const payload = b64({sub:'test-user',scope:'airlines:read',aud:'your-resource-uri',exp:Math.floor(Date.now()/1000)+3600});
console.log(header+'.'+payload+'.');
"

(audを自分のMCP_RESOURCE_SERVER_RESOURCE_URIの値に、scopeをテストするツールに合わせて置き換えてください)

実トークン(STRICT_AUTH=true) — PingOne環境から発行します。PingOneトークンエンドポイントに対するクライアントクレデンシャルグラントで、このサーバーのオーディエンスをリソースとして要求します:

curl -s -X POST "https://auth.pingone.<region>/<env-id>/as/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<your PingOne worker app client id>" \
  -d "client_secret=<your PingOne worker app client secret>" \
  -d "scope=<space-separated scopes, e.g. banking:read airlines:read>" \
  -d "resource=<MCP_RESOURCE_SERVER_RESOURCE_URI value>"

これには、そのクライアントのアプリがPingOneでこのリソースとそれらのスコープに対して認可されている必要があります(Applications → アプリ → Resources)。これはこのサーバーが代わりに行うPingOne側のセットアップ手順です。

ツールを直接呼び出す(動作確認)

TOKEN="<paste a token from above>"
curl -s -X POST http://localhost:8081/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_airline_bookings","arguments":{}}}'

MCPクライアントの接続

サーバーは同じポートでWebSocketとHTTP(ストリーミング可能、POST /mcp)の両方でMCPを話します — ws://localhost:8081またはhttp://localhost:8081/mcp。

MCP Inspector(公式開発ツール。任意のサーバーで動作し、手動ヘッダーを設定できるため、これをテストする最も信頼性の高い方法です):

npx @modelcontextprotocol/inspector

Transportを「Streamable HTTP」に、URLをhttp://localhost:8081/mcpに設定し、接続設定でInspectorにAuthorization: Bearer <token>ヘッダーを追加してから接続します。

Claude Desktop / Cursor / Windsurf(静的設定、HTTPトランスポート):

{
  "mcpServers": {
    "mcp-resource-server": {
      "url": "http://localhost:8081/mcp",
      "transport": "http"
    }
  }
}
  • Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Cursor: プロジェクトルートの.cursor/mcp.json

  • Windsurf: ~/.codeium/windsurf/mcp_config.json

これらの設定には静的ベアラートークンのフィールドがありません。クライアントが保護されたツールを呼び出すと、/.well-known/oauth-protected-resourceを読み取り、認可サーバーとしてPingOne環境を見つけ、サインインを促します。これは、PingOne環境にその特定のMCPクライアントアプリ用のOAuthクライアントが登録され、そのクライアント自身のドキュメントで指定されたリダイレクトURIを使用している場合にのみ機能します。これはこのサーバーの外部にあるPingOne側のセットアップ手順です。設定を編集した後、クライアントを再起動してください。

投資ツール

get_investment_accounts、get_investment_balance、get_portfolio_summary、get_investment_transactionsは、他のすべての業界と同様に、バンドルされたSQLiteデータベース(初回使用時にseed/invest.seed.jsonからシードされるdata/invest.db)からそのまま動作します。

BANKING_API_BASE_URLは、独自の銀行APIを実行していて、これらの4つのツールが呼び出し元のベアラートークンをそのAPIに転送し、そのAPIが返すものを返すようにしたい場合にのみ設定します。設定すると、バンドルされた投資データベースは使用されません。

ツールの追加

ツールはコードであり、設定ではありません。カタログ(tools/list)、ツールごとのスコープゲート、/.well-known/oauth-protected-resourceでアドバタイズされるscopes_supportedはすべてsrc/tools/registry.tsのALL_TOOLSから派生します。したがって、業界のリストに追加したツールは、イメージを再ビルドすると(クイックスタートの--buildコマンド)どこでも有効になります。

1. 既存の業界にツールを追加する

2つの編集で、レジストリの変更はありません:

  1. その業界のsrc/tools/<vertical>Tools.ts配列にツール定義を追加します。例:sportingGoodsTools.ts内:

    {
      name: 'gear_return_status',
      description: 'Show the status of a sporting-goods return.',
      inputSchema: {
        type: 'object',
        properties: { orderId: { type: 'string', description: 'Order ID' } },
        required: ['orderId'],
      },
      requiredScopes: ['read'],   // the bearer token must carry every scope listed
      readOnly: true,
      intentHints: ['check my gear return'],   // required — tests/registry.test.ts asserts it
    },
  2. src/tools/<vertical>ToolHandler.tsのswitchに一致するcase 'gear_return_status':を追加します。ハンドラーはJSONを返すだけです。その業界のsrc/db/<vertical>Db.tsから読み取るか、他の何かから読み取ります。

2. 新しい業界を追加する

上記と同じ2つのファイル(<VERTICAL>_TOOLS: McpToolDef[]をエクスポートするsrc/tools/<vertical>Tools.tsと、dispatch<Vertical>Toolをエクスポートするsrc/tools/<vertical>ToolHandler.ts)に加えて:

  • データ(オプション):src/db/<vertical>Db.ts + seed/<vertical>.seed.json。sportingGoodsDb.tsをコピーします。これはdata/<vertical>.dbを開き、スキーマを作成し、テーブルが空の場合にのみシードを適用します。Dockerfileはすでにseed/をコピーし、composeファイルはすでにdata/をマウントします。

  • 登録:src/tools/registry.tsで、2つのエクスポートをインポートし、<VERTICAL>_TOOLSをALL_TOOLSにスプレッドし、const <VERTICAL>_TOOL_NAMES = new Set(<VERTICAL>_TOOLS.map((t) => t.name))を追加し、dispatch()に1行追加します: if (<VERTICAL>_TOOL_NAMES.has(toolName)) return dispatch<Vertical>Tool(toolName, args, subject); (subjectはトークンのsubです。銀行や航空のように、読み取りが呼び出し元にスコープされる必要がある場合は、ハンドラーでそれを受け入れます。)

  • リソース(オプション):tools/listは自動ですが、MCP リソース(resources/list、resources/read)はsrc/index.tsの手動管理されたRESOURCE_CATALOGから来ます。業界がそのリストツールをリソースとしても公開する必要がある場合は、そこにエントリを追加します。

注意点

  • requiredScopesは、PingOneリソースが実際に付与するスコープである必要があります。いずれかが欠けているトークンはtools/callで403になり、tools/listはそのトークンからツールを完全に隠します。

  • ツール名はグローバルです。dispatch()は最初に一致する名前セットでルーティングするため、2つの業界で名前を再利用すると、最初にチェックされた方に黙って送られます。

  • テンプレートには、investではなくデータバックアップの業界(例:スポーツ用品)を使用してください。investはdispatch()のフォールスルーであり、不要なプロキシ対SQLiteの切り替えを伴います。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A lightweight MCP server that simulates financial data interactions with dummy authentication and static JSON datasets for testing financial applications.
    2
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    A minimal local HTTP MCP mock server for development and testing, providing predictable tool responses with OAuth token support and zero dependencies.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    A production-grade MCP server for a fictional digital bank, exposing tools for an AI copilot to service customers across the full risk spectrum from read-only lookups to money movement and destructive admin actions, with OAuth 2.1 security and a realistic dataset.
    21 npm
    1
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    A Test/Sandbox MCP server that integrates with the SnapTrade API Sandbox environment to provide portfolio oversight, market data, and trading capabilities.
    -