ProGear MCP Servers
ProGear MCP 服务器
一个用于 ProGear 篮球装备演示的 MCP 网关,托管四个领域——库存(Inventory)、客户(Customer)、销售(Sales)和定价(Pricing)——每个领域都使用真正的 MCP 协议(Streamable HTTP 传输),并由您自己的 Okta 组织(其自己的自定义授权服务器 + 每个领域的范围集)保护。
这是 ProGearSalesAI 的一个刻意精简的姊妹项目:没有 Auth0 FGA,没有 LangGraph 编排器,没有前端。网关本身只验证它收到的任何 bearer token——它不关心调用方是如何获得该 token 的。packages/local-tester(仅本地,不部署)演示了调用方可能的一种方式:人工 PKCE 登录 + 一个代理执行 ID-JAG 交换来铸造该 token,镜像了原应用的跨应用访问流程。
部署形态
一个进程,一个 Render 服务,一个构建/启动命令。 packages/gateway 在单个 Express 应用后面将全部 4 个领域挂载在不同的路径上:
挂载点 | 范围 | 工具 |
|
|
|
|
|
|
|
|
|
|
|
|
每个挂载点都针对自己的 Okta 自定义授权服务器进行验证(每个领域有不同的 issuer/audience),即使它们都在同一个进程中运行——为库存授权服务器签发的 token 不能用于 /customer/mcp,并且在每个挂载点内,每次工具调用都会根据调用方 token 中授予的范围检查其所需范围(缺少 inventory:write 的 token 可以调用 check_stock,但不能调用 update_inventory_quantity)。
packages/mcp-inventory、mcp-customer、mcp-sales、mcp-pricing 也仍然可以作为独立服务器工作(它们自己的 server.ts + /mcp + /health,单领域环境变量),如果您想将它们拆分回单独的部署——网关只是导入每个服务器的工具注册逻辑(./tools 导出)并将其挂载在自己的认证配置下,而不是自己调用 .listen()。
Related MCP server: Meraki MCP Server
数据
从 ProGearSalesAI 演示数据集的移植快照中填充:90 个 SKU 库存、90 个定价条目、34 个客户、层级/批量折扣表(packages/shared/src/data/initial_data.json)。销售订单/报价仅存储在内存中。所有状态在进程重启时重置——这是一个工具服务器,不是记录系统。
项目结构
packages/
shared/ # ported data + store, JWKS auth + scope enforcement, HTTP/MCP transport helper
mcp-inventory/ mcp-customer/ mcp-sales/ mcp-pricing/ # tool definitions + standalone entrypoint each
gateway/ # the actual deployment: mounts all 4 at /inventory, /customer, /sales, /pricing
local-tester/ # local-only: PKCE login + agent ID-JAG exchange, calls the deployed gateway (see its own README)本地开发
npm install
npm run build # builds shared + all 4 domains + gateway, in dependency order
npm run dev:gateway # tsx watch, all 4 mounts on one port (default 3000)如果没有为某个挂载点设置相关的 Okta 环境变量,该挂载点会在每个 /mcp 请求上返回 500,除非您设置 ALLOW_INSECURE=true,这会跳过 token 验证并在每个挂载点上授予所有范围——仅限本地开发,绝不要在部署环境中设置此变量。
Okta 设置
设置 OKTA_DOMAIN 一次,再加上每个领域的 OKTA_<DOMAIN>_AUTH_SERVER_ID + OKTA_<DOMAIN>_AUDIENCE——这些是 ProGearSalesAI 后端中已经使用的完全相同的环境变量名(OKTA_CUSTOMER_AUTH_SERVER_ID、OKTA_INVENTORY_AUDIENCE 等),因此现有值可以直接复制过来:
OKTA_DOMAIN=https://your-org.okta.com
OKTA_INVENTORY_AUTH_SERVER_ID=... OKTA_INVENTORY_AUDIENCE=api://progear-inventory
OKTA_CUSTOMER_AUTH_SERVER_ID=... OKTA_CUSTOMER_AUDIENCE=api://progear-customer
OKTA_SALES_AUTH_SERVER_ID=... OKTA_SALES_AUDIENCE=api://progear-sales
OKTA_PRICING_AUTH_SERVER_ID=... OKTA_PRICING_AUDIENCE=api://progear-pricing有关完整列表,请参阅 .env.example,包括 ProGearSalesAI 风格 .env 中哪些变量在此不适用(Anthropic 密钥、CORS、AI 代理自己的私钥/客户端 ID——此网关只验证传入的 token,它不自行签发任何 token)。Token 通过签名 + issuer + audience 针对每个领域自己的 Okta JWKS 端点进行验证(jose 的 createRemoteJWKSet)——此端不需要共享密钥。
部署到 Render
单个服务,可以通过仪表板或附带的 Blueprint 进行部署。
手动(新建 → Web 服务):
字段 | 值 |
语言 | Node |
根目录 | (留空——npm workspaces monorepo,构建从仓库根目录运行) |
构建命令 |
|
启动命令 |
|
健康检查路径 |
|
Blueprint: 仓库根目录下的 render.yaml 定义了同一个 progear-mcp-gateway 服务——新建 → Blueprint,指向此仓库,然后填写它提示的 9 个 Okta 环境变量(标记为 sync: false)。
连接代理
每个挂载点通过 POST/GET/DELETE <mount>/mcp 在 Streamable HTTP 上暴露 MCP(无状态——请求之间不保留会话),外加它自己的 GET <mount>/health;还有一个列出所有挂载点的顶层 GET /health。
从 Okta 获取相关自定义授权服务器 + 范围的访问 token(例如,为服务/代理身份使用 client-credentials 授权),然后:
Claude Code CLI:
claude mcp add --transport http progear-inventory \
https://<your-render-url>/inventory/mcp \
--header "Authorization: Bearer <token>"对每个领域重复(/customer/mcp、/sales/mcp、/pricing/mcp),使用范围限定到该领域 audience 的 token。
任何其他 MCP 客户端 / 代理 SDK: 将请求指向挂载点的 /mcp URL,并在每个请求上携带 Authorization: Bearer <token> 头。
OAuth 发现(无静态 token)
实现 MCP 授权规范的客户端可以自行找到 Okta,而不是被直接交给一个 token。每个挂载点在网关的根路径发布 RFC 9728 受保护资源元数据,按路径限定到它所描述的端点:
GET /.well-known/oauth-protected-resource/inventory/mcp
GET /.well-known/oauth-protected-resource/customer/mcp
GET /.well-known/oauth-protected-resource/sales/mcp
GET /.well-known/oauth-protected-resource/pricing/mcp{
"resource": "https://<your-render-url>/inventory/mcp",
"authorization_servers": ["https://your-org.okta.com/oauth2/<inventory-auth-server-id>"],
"scopes_supported": ["inventory:read", "inventory:write", "inventory:alert"],
"bearer_methods_supported": ["header"],
"resource_name": "ProGear Inventory MCP"
}来自 /mcp 的 401 现在也会携带该指针,因此冷启动调用该端点的客户端可以得知在哪里进行身份验证:
WWW-Authenticate: Bearer resource_metadata="https://<your-render-url>/.well-known/oauth-protected-resource/inventory/mcp"(当确实提供了 token 但验证失败时,挑战还会携带 error="invalid_token" 和 error_description。)
这些文档中的 URL 是从传入请求派生的(X-Forwarded-Proto + Host,并启用了 trust proxy——在 Render 上是正确的)。仅当网关前面有东西重写了 Host 头时,才设置 PUBLIC_BASE_URL=https://<your-render-url>。
要让客户端完成流程,请在您的 Okta 组织中注册一个 OIDC 公共客户端(Authorization Code + PKCE),添加客户端的重定向 URI(Claude.ai 使用 https://claude.ai/api/mcp/auth_callback),并在该自定义授权服务器的访问策略中授予领域的范围。
要实现完全零配置连接,仍然缺少的是: 动态客户端注册。Okta 的 /oauth2/v1/clients 端点需要 SSWS API token,因此无法为匿名注册做广告——坚持使用 DCR 的客户端(目前是 VS Code / Copilot)需要在其前面加一个注册垫片。接受预注册 client_id 的客户端可以按原样使用上述发现机制。
This server cannot be deployed
Maintenance
Related MCP Connectors
Unified gateway exposing 150+ tools across all NexGenData MCP servers via one endpoint.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Unified MCP server for 70+ eCommerce platforms: products, orders, customers, and more.
Search multi-merchant supply, checkout, and track orders via MCP.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceAggregates multiple MCP servers behind a single, secure endpoint with unified tool/resource discovery, OAuth authentication, and resilient request routing. Enables users to manage and interact with multiple MCP backends through one centralized interface with load balancing and circuit breakers.2-
- FlicenseNot gradedqualityDmaintenanceExposes a curated subset of the Cisco Meraki Dashboard API to MCP-aware clients with role-based access control.3-
- FlicenseNot gradedqualityBmaintenanceMCP gateway demo for basketball equipment, exposing inventory, customer, sales, and pricing tools with Okta-scoped auth.-
- FlicenseNot gradedqualityBmaintenanceEnables MCP clients to query and manage basketball-equipment inventory, customers, sales orders, and pricing through four secured domain-specific endpoints using Okta authentication.-