@vendure/mcp-plugin 3.8.0-minor-bootstrap.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/api-extensions.d.ts +2 -0
- package/lib/api/api-extensions.js +239 -0
- package/lib/api/api-extensions.js.map +1 -0
- package/lib/api/mcp-actor.service.d.ts +19 -0
- package/lib/api/mcp-actor.service.js +52 -0
- package/lib/api/mcp-actor.service.js.map +1 -0
- package/lib/api/mcp-admin.resolver.d.ts +105 -0
- package/lib/api/mcp-admin.resolver.js +463 -0
- package/lib/api/mcp-admin.resolver.js.map +1 -0
- package/lib/api/mcp-shop.resolver.d.ts +25 -0
- package/lib/api/mcp-shop.resolver.js +74 -0
- package/lib/api/mcp-shop.resolver.js.map +1 -0
- package/lib/check-options.d.ts +7 -0
- package/lib/check-options.js +130 -0
- package/lib/check-options.js.map +1 -0
- package/lib/constants.d.ts +48 -0
- package/lib/constants.js +72 -0
- package/lib/constants.js.map +1 -0
- package/lib/delete-in-batches.d.ts +5 -0
- package/lib/delete-in-batches.js +28 -0
- package/lib/delete-in-batches.js.map +1 -0
- package/lib/entities/index.d.ts +5 -0
- package/lib/entities/index.js +22 -0
- package/lib/entities/index.js.map +1 -0
- package/lib/entities/mcp-authorization-code.entity.d.ts +33 -0
- package/lib/entities/mcp-authorization-code.entity.js +77 -0
- package/lib/entities/mcp-authorization-code.entity.js.map +1 -0
- package/lib/entities/mcp-authorization-request.entity.d.ts +31 -0
- package/lib/entities/mcp-authorization-request.entity.js +73 -0
- package/lib/entities/mcp-authorization-request.entity.js.map +1 -0
- package/lib/entities/mcp-oauth-client.entity.d.ts +56 -0
- package/lib/entities/mcp-oauth-client.entity.js +70 -0
- package/lib/entities/mcp-oauth-client.entity.js.map +1 -0
- package/lib/entities/mcp-oauth-grant.entity.d.ts +77 -0
- package/lib/entities/mcp-oauth-grant.entity.js +121 -0
- package/lib/entities/mcp-oauth-grant.entity.js.map +1 -0
- package/lib/entities/mcp-tool-call-log.entity.d.ts +50 -0
- package/lib/entities/mcp-tool-call-log.entity.js +101 -0
- package/lib/entities/mcp-tool-call-log.entity.js.map +1 -0
- package/lib/events/mcp-tool-call.event.d.ts +17 -0
- package/lib/events/mcp-tool-call.event.js +23 -0
- package/lib/events/mcp-tool-call.event.js.map +1 -0
- package/lib/get-client-ip.d.ts +2 -0
- package/lib/get-client-ip.js +10 -0
- package/lib/get-client-ip.js.map +1 -0
- package/lib/get-language-code.d.ts +3 -0
- package/lib/get-language-code.js +12 -0
- package/lib/get-language-code.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +26 -0
- package/lib/index.js.map +1 -0
- package/lib/internal-types.d.ts +27 -0
- package/lib/internal-types.js +3 -0
- package/lib/internal-types.js.map +1 -0
- package/lib/logging/mcp-tool-call-log-retention.service.d.ts +8 -0
- package/lib/logging/mcp-tool-call-log-retention.service.js +54 -0
- package/lib/logging/mcp-tool-call-log-retention.service.js.map +1 -0
- package/lib/logging/mcp-tool-call-log.service.d.ts +24 -0
- package/lib/logging/mcp-tool-call-log.service.js +128 -0
- package/lib/logging/mcp-tool-call-log.service.js.map +1 -0
- package/lib/oauth/cimd/cimd-client-resolver.service.d.ts +18 -0
- package/lib/oauth/cimd/cimd-client-resolver.service.js +109 -0
- package/lib/oauth/cimd/cimd-client-resolver.service.js.map +1 -0
- package/lib/oauth/cimd/cimd-document.d.ts +11 -0
- package/lib/oauth/cimd/cimd-document.js +66 -0
- package/lib/oauth/cimd/cimd-document.js.map +1 -0
- package/lib/oauth/cimd/cimd-fetch.d.ts +14 -0
- package/lib/oauth/cimd/cimd-fetch.js +192 -0
- package/lib/oauth/cimd/cimd-fetch.js.map +1 -0
- package/lib/oauth/cimd/cimd-url.d.ts +5 -0
- package/lib/oauth/cimd/cimd-url.js +94 -0
- package/lib/oauth/cimd/cimd-url.js.map +1 -0
- package/lib/oauth/grant-session.service.d.ts +19 -0
- package/lib/oauth/grant-session.service.js +141 -0
- package/lib/oauth/grant-session.service.js.map +1 -0
- package/lib/oauth/oauth-error.d.ts +18 -0
- package/lib/oauth/oauth-error.js +60 -0
- package/lib/oauth/oauth-error.js.map +1 -0
- package/lib/oauth/oauth-metadata.service.d.ts +34 -0
- package/lib/oauth/oauth-metadata.service.js +107 -0
- package/lib/oauth/oauth-metadata.service.js.map +1 -0
- package/lib/oauth/oauth-retention.service.d.ts +23 -0
- package/lib/oauth/oauth-retention.service.js +103 -0
- package/lib/oauth/oauth-retention.service.js.map +1 -0
- package/lib/oauth/oauth-types.d.ts +61 -0
- package/lib/oauth/oauth-types.js +32 -0
- package/lib/oauth/oauth-types.js.map +1 -0
- package/lib/oauth/oauth-utils.d.ts +20 -0
- package/lib/oauth/oauth-utils.js +111 -0
- package/lib/oauth/oauth-utils.js.map +1 -0
- package/lib/oauth/oauth.controller.d.ts +31 -0
- package/lib/oauth/oauth.controller.js +132 -0
- package/lib/oauth/oauth.controller.js.map +1 -0
- package/lib/oauth/oauth.service.d.ts +69 -0
- package/lib/oauth/oauth.service.js +650 -0
- package/lib/oauth/oauth.service.js.map +1 -0
- package/lib/oauth/token-hash.d.ts +6 -0
- package/lib/oauth/token-hash.js +21 -0
- package/lib/oauth/token-hash.js.map +1 -0
- package/lib/plugin.d.ts +54 -0
- package/lib/plugin.js +171 -0
- package/lib/plugin.js.map +1 -0
- package/lib/rate-limit/ip-bucket-key.d.ts +1 -0
- package/lib/rate-limit/ip-bucket-key.js +35 -0
- package/lib/rate-limit/ip-bucket-key.js.map +1 -0
- package/lib/rate-limit/mcp-oauth-rate-limit.guard.d.ts +20 -0
- package/lib/rate-limit/mcp-oauth-rate-limit.guard.js +63 -0
- package/lib/rate-limit/mcp-oauth-rate-limit.guard.js.map +1 -0
- package/lib/rate-limit/mcp-rate-limiter.service.d.ts +47 -0
- package/lib/rate-limit/mcp-rate-limiter.service.js +248 -0
- package/lib/rate-limit/mcp-rate-limiter.service.js.map +1 -0
- package/lib/registry/bm25.d.ts +12 -0
- package/lib/registry/bm25.js +60 -0
- package/lib/registry/bm25.js.map +1 -0
- package/lib/registry/mcp-tool-execution.service.d.ts +45 -0
- package/lib/registry/mcp-tool-execution.service.js +72 -0
- package/lib/registry/mcp-tool-execution.service.js.map +1 -0
- package/lib/registry/mcp-tool-registry.service.d.ts +89 -0
- package/lib/registry/mcp-tool-registry.service.js +668 -0
- package/lib/registry/mcp-tool-registry.service.js.map +1 -0
- package/lib/registry/mcp-tool-schema.service.d.ts +42 -0
- package/lib/registry/mcp-tool-schema.service.js +229 -0
- package/lib/registry/mcp-tool-schema.service.js.map +1 -0
- package/lib/registry/registry-types.d.ts +32 -0
- package/lib/registry/registry-types.js +3 -0
- package/lib/registry/registry-types.js.map +1 -0
- package/lib/resolve-options.d.ts +7 -0
- package/lib/resolve-options.js +85 -0
- package/lib/resolve-options.js.map +1 -0
- package/lib/shared/endpoint-paths.d.ts +8 -0
- package/lib/shared/endpoint-paths.js +12 -0
- package/lib/shared/endpoint-paths.js.map +1 -0
- package/lib/shared/loopback.d.ts +2 -0
- package/lib/shared/loopback.js +9 -0
- package/lib/shared/loopback.js.map +1 -0
- package/lib/shop-session/mcp-shop-session.service.d.ts +47 -0
- package/lib/shop-session/mcp-shop-session.service.js +132 -0
- package/lib/shop-session/mcp-shop-session.service.js.map +1 -0
- package/lib/tasks/mcp-oauth-retention.task.d.ts +9 -0
- package/lib/tasks/mcp-oauth-retention.task.js +21 -0
- package/lib/tasks/mcp-oauth-retention.task.js.map +1 -0
- package/lib/tasks/mcp-tool-call-log-retention.task.d.ts +7 -0
- package/lib/tasks/mcp-tool-call-log-retention.task.js +22 -0
- package/lib/tasks/mcp-tool-call-log-retention.task.js.map +1 -0
- package/lib/tools/built-in/active-order.service.d.ts +26 -0
- package/lib/tools/built-in/active-order.service.js +125 -0
- package/lib/tools/built-in/active-order.service.js.map +1 -0
- package/lib/tools/built-in/admin/add-customer-to-group.tool.d.ts +23 -0
- package/lib/tools/built-in/admin/add-customer-to-group.tool.js +68 -0
- package/lib/tools/built-in/admin/add-customer-to-group.tool.js.map +1 -0
- package/lib/tools/built-in/admin/add-note-to-order.tool.d.ts +104 -0
- package/lib/tools/built-in/admin/add-note-to-order.tool.js +66 -0
- package/lib/tools/built-in/admin/add-note-to-order.tool.js.map +1 -0
- package/lib/tools/built-in/admin/adjust-stock.tool.d.ts +26 -0
- package/lib/tools/built-in/admin/adjust-stock.tool.js +88 -0
- package/lib/tools/built-in/admin/adjust-stock.tool.js.map +1 -0
- package/lib/tools/built-in/admin/cancel-order.tool.d.ts +17 -0
- package/lib/tools/built-in/admin/cancel-order.tool.js +60 -0
- package/lib/tools/built-in/admin/cancel-order.tool.js.map +1 -0
- package/lib/tools/built-in/admin/channel-access.d.ts +2 -0
- package/lib/tools/built-in/admin/channel-access.js +9 -0
- package/lib/tools/built-in/admin/channel-access.js.map +1 -0
- package/lib/tools/built-in/admin/create-customer.tool.d.ts +41 -0
- package/lib/tools/built-in/admin/create-customer.tool.js +57 -0
- package/lib/tools/built-in/admin/create-customer.tool.js.map +1 -0
- package/lib/tools/built-in/admin/create-fulfillment.tool.d.ts +118 -0
- package/lib/tools/built-in/admin/create-fulfillment.tool.js +156 -0
- package/lib/tools/built-in/admin/create-fulfillment.tool.js.map +1 -0
- package/lib/tools/built-in/admin/create-product.tool.d.ts +52 -0
- package/lib/tools/built-in/admin/create-product.tool.js +61 -0
- package/lib/tools/built-in/admin/create-product.tool.js.map +1 -0
- package/lib/tools/built-in/admin/create-variant.tool.d.ts +48 -0
- package/lib/tools/built-in/admin/create-variant.tool.js +79 -0
- package/lib/tools/built-in/admin/create-variant.tool.js.map +1 -0
- package/lib/tools/built-in/admin/entity-field-schemas.d.ts +36 -0
- package/lib/tools/built-in/admin/entity-field-schemas.js +63 -0
- package/lib/tools/built-in/admin/entity-field-schemas.js.map +1 -0
- package/lib/tools/built-in/admin/get-customer.tool.d.ts +28 -0
- package/lib/tools/built-in/admin/get-customer.tool.js +55 -0
- package/lib/tools/built-in/admin/get-customer.tool.js.map +1 -0
- package/lib/tools/built-in/admin/get-order.tool.d.ts +100 -0
- package/lib/tools/built-in/admin/get-order.tool.js +68 -0
- package/lib/tools/built-in/admin/get-order.tool.js.map +1 -0
- package/lib/tools/built-in/admin/get-product.tool.d.ts +69 -0
- package/lib/tools/built-in/admin/get-product.tool.js +77 -0
- package/lib/tools/built-in/admin/get-product.tool.js.map +1 -0
- package/lib/tools/built-in/admin/get-stock-levels.tool.d.ts +23 -0
- package/lib/tools/built-in/admin/get-stock-levels.tool.js +61 -0
- package/lib/tools/built-in/admin/get-stock-levels.tool.js.map +1 -0
- package/lib/tools/built-in/admin/index.d.ts +25 -0
- package/lib/tools/built-in/admin/index.js +54 -0
- package/lib/tools/built-in/admin/index.js.map +1 -0
- package/lib/tools/built-in/admin/list-channels.tool.d.ts +24 -0
- package/lib/tools/built-in/admin/list-channels.tool.js +56 -0
- package/lib/tools/built-in/admin/list-channels.tool.js.map +1 -0
- package/lib/tools/built-in/admin/list-customer-groups.tool.d.ts +23 -0
- package/lib/tools/built-in/admin/list-customer-groups.tool.js +52 -0
- package/lib/tools/built-in/admin/list-customer-groups.tool.js.map +1 -0
- package/lib/tools/built-in/admin/list-customers.tool.d.ts +62 -0
- package/lib/tools/built-in/admin/list-customers.tool.js +66 -0
- package/lib/tools/built-in/admin/list-customers.tool.js.map +1 -0
- package/lib/tools/built-in/admin/list-orders.tool.d.ts +142 -0
- package/lib/tools/built-in/admin/list-orders.tool.js +87 -0
- package/lib/tools/built-in/admin/list-orders.tool.js.map +1 -0
- package/lib/tools/built-in/admin/list-products.tool.d.ts +63 -0
- package/lib/tools/built-in/admin/list-products.tool.js +71 -0
- package/lib/tools/built-in/admin/list-products.tool.js.map +1 -0
- package/lib/tools/built-in/admin/refund-order.tool.d.ts +38 -0
- package/lib/tools/built-in/admin/refund-order.tool.js +115 -0
- package/lib/tools/built-in/admin/refund-order.tool.js.map +1 -0
- package/lib/tools/built-in/admin/set-active-channel.tool.d.ts +22 -0
- package/lib/tools/built-in/admin/set-active-channel.tool.js +84 -0
- package/lib/tools/built-in/admin/set-active-channel.tool.js.map +1 -0
- package/lib/tools/built-in/admin/translation-schemas.d.ts +12 -0
- package/lib/tools/built-in/admin/translation-schemas.js +17 -0
- package/lib/tools/built-in/admin/translation-schemas.js.map +1 -0
- package/lib/tools/built-in/admin/update-customer.tool.d.ts +42 -0
- package/lib/tools/built-in/admin/update-customer.tool.js +59 -0
- package/lib/tools/built-in/admin/update-customer.tool.js.map +1 -0
- package/lib/tools/built-in/admin/update-order-state.tool.d.ts +16 -0
- package/lib/tools/built-in/admin/update-order-state.tool.js +58 -0
- package/lib/tools/built-in/admin/update-order-state.tool.js.map +1 -0
- package/lib/tools/built-in/admin/update-product.tool.d.ts +53 -0
- package/lib/tools/built-in/admin/update-product.tool.js +68 -0
- package/lib/tools/built-in/admin/update-product.tool.js.map +1 -0
- package/lib/tools/built-in/admin/update-variant.tool.d.ts +46 -0
- package/lib/tools/built-in/admin/update-variant.tool.js +77 -0
- package/lib/tools/built-in/admin/update-variant.tool.js.map +1 -0
- package/lib/tools/built-in/admin/upload-asset.tool.d.ts +32 -0
- package/lib/tools/built-in/admin/upload-asset.tool.js +56 -0
- package/lib/tools/built-in/admin/upload-asset.tool.js.map +1 -0
- package/lib/tools/built-in/catalog-query.service.d.ts +21 -0
- package/lib/tools/built-in/catalog-query.service.js +128 -0
- package/lib/tools/built-in/catalog-query.service.js.map +1 -0
- package/lib/tools/built-in/custom-field-input.service.d.ts +10 -0
- package/lib/tools/built-in/custom-field-input.service.js +64 -0
- package/lib/tools/built-in/custom-field-input.service.js.map +1 -0
- package/lib/tools/built-in/email-schema.d.ts +2 -0
- package/lib/tools/built-in/email-schema.js +12 -0
- package/lib/tools/built-in/email-schema.js.map +1 -0
- package/lib/tools/built-in/id-schema.d.ts +3 -0
- package/lib/tools/built-in/id-schema.js +11 -0
- package/lib/tools/built-in/id-schema.js.map +1 -0
- package/lib/tools/built-in/int32-schema.d.ts +4 -0
- package/lib/tools/built-in/int32-schema.js +8 -0
- package/lib/tools/built-in/int32-schema.js.map +1 -0
- package/lib/tools/built-in/list-helpers.d.ts +48 -0
- package/lib/tools/built-in/list-helpers.js +76 -0
- package/lib/tools/built-in/list-helpers.js.map +1 -0
- package/lib/tools/built-in/order-list-helpers.d.ts +20 -0
- package/lib/tools/built-in/order-list-helpers.js +48 -0
- package/lib/tools/built-in/order-list-helpers.js.map +1 -0
- package/lib/tools/built-in/providers.d.ts +2 -0
- package/lib/tools/built-in/providers.js +7 -0
- package/lib/tools/built-in/providers.js.map +1 -0
- package/lib/tools/built-in/remote-asset.d.ts +4 -0
- package/lib/tools/built-in/remote-asset.js +54 -0
- package/lib/tools/built-in/remote-asset.js.map +1 -0
- package/lib/tools/built-in/serializer.service.d.ts +327 -0
- package/lib/tools/built-in/serializer.service.js +413 -0
- package/lib/tools/built-in/serializer.service.js.map +1 -0
- package/lib/tools/built-in/shop/add-to-cart.tool.d.ts +21 -0
- package/lib/tools/built-in/shop/add-to-cart.tool.js +100 -0
- package/lib/tools/built-in/shop/add-to-cart.tool.js.map +1 -0
- package/lib/tools/built-in/shop/address-schema.d.ts +15 -0
- package/lib/tools/built-in/shop/address-schema.js +20 -0
- package/lib/tools/built-in/shop/address-schema.js.map +1 -0
- package/lib/tools/built-in/shop/apply-coupon-code.tool.d.ts +17 -0
- package/lib/tools/built-in/shop/apply-coupon-code.tool.js +62 -0
- package/lib/tools/built-in/shop/apply-coupon-code.tool.js.map +1 -0
- package/lib/tools/built-in/shop/collection-lookup.d.ts +15 -0
- package/lib/tools/built-in/shop/collection-lookup.js +35 -0
- package/lib/tools/built-in/shop/collection-lookup.js.map +1 -0
- package/lib/tools/built-in/shop/get-cart.tool.d.ts +94 -0
- package/lib/tools/built-in/shop/get-cart.tool.js +55 -0
- package/lib/tools/built-in/shop/get-cart.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-collection.tool.d.ts +42 -0
- package/lib/tools/built-in/shop/get-collection.tool.js +64 -0
- package/lib/tools/built-in/shop/get-collection.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-eligible-payment-methods.tool.d.ts +26 -0
- package/lib/tools/built-in/shop/get-eligible-payment-methods.tool.js +58 -0
- package/lib/tools/built-in/shop/get-eligible-payment-methods.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-eligible-shipping-methods.tool.d.ts +30 -0
- package/lib/tools/built-in/shop/get-eligible-shipping-methods.tool.js +59 -0
- package/lib/tools/built-in/shop/get-eligible-shipping-methods.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-my-account.tool.d.ts +22 -0
- package/lib/tools/built-in/shop/get-my-account.tool.js +57 -0
- package/lib/tools/built-in/shop/get-my-account.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-order.tool.d.ts +100 -0
- package/lib/tools/built-in/shop/get-order.tool.js +67 -0
- package/lib/tools/built-in/shop/get-order.tool.js.map +1 -0
- package/lib/tools/built-in/shop/get-product.tool.d.ts +57 -0
- package/lib/tools/built-in/shop/get-product.tool.js +81 -0
- package/lib/tools/built-in/shop/get-product.tool.js.map +1 -0
- package/lib/tools/built-in/shop/index.d.ts +19 -0
- package/lib/tools/built-in/shop/index.js +42 -0
- package/lib/tools/built-in/shop/index.js.map +1 -0
- package/lib/tools/built-in/shop/list-collections.tool.d.ts +42 -0
- package/lib/tools/built-in/shop/list-collections.tool.js +75 -0
- package/lib/tools/built-in/shop/list-collections.tool.js.map +1 -0
- package/lib/tools/built-in/shop/list-my-orders.tool.d.ts +100 -0
- package/lib/tools/built-in/shop/list-my-orders.tool.js +63 -0
- package/lib/tools/built-in/shop/list-my-orders.tool.js.map +1 -0
- package/lib/tools/built-in/shop/place-order.tool.d.ts +188 -0
- package/lib/tools/built-in/shop/place-order.tool.js +152 -0
- package/lib/tools/built-in/shop/place-order.tool.js.map +1 -0
- package/lib/tools/built-in/shop/product-search-query.d.ts +4 -0
- package/lib/tools/built-in/shop/product-search-query.js +34 -0
- package/lib/tools/built-in/shop/product-search-query.js.map +1 -0
- package/lib/tools/built-in/shop/remove-coupon-code.tool.d.ts +17 -0
- package/lib/tools/built-in/shop/remove-coupon-code.tool.js +63 -0
- package/lib/tools/built-in/shop/remove-coupon-code.tool.js.map +1 -0
- package/lib/tools/built-in/shop/remove-from-cart.tool.d.ts +17 -0
- package/lib/tools/built-in/shop/remove-from-cart.tool.js +58 -0
- package/lib/tools/built-in/shop/remove-from-cart.tool.js.map +1 -0
- package/lib/tools/built-in/shop/search-products.tool.d.ts +48 -0
- package/lib/tools/built-in/shop/search-products.tool.js +95 -0
- package/lib/tools/built-in/shop/search-products.tool.js.map +1 -0
- package/lib/tools/built-in/shop/set-checkout-details.tool.d.ts +56 -0
- package/lib/tools/built-in/shop/set-checkout-details.tool.js +187 -0
- package/lib/tools/built-in/shop/set-checkout-details.tool.js.map +1 -0
- package/lib/tools/built-in/shop/set-shipping-method.tool.d.ts +17 -0
- package/lib/tools/built-in/shop/set-shipping-method.tool.js +58 -0
- package/lib/tools/built-in/shop/set-shipping-method.tool.js.map +1 -0
- package/lib/tools/built-in/shop/update-cart-line.tool.d.ts +18 -0
- package/lib/tools/built-in/shop/update-cart-line.tool.js +60 -0
- package/lib/tools/built-in/shop/update-cart-line.tool.js.map +1 -0
- package/lib/tools/built-in/string-schemas.d.ts +4 -0
- package/lib/tools/built-in/string-schemas.js +13 -0
- package/lib/tools/built-in/string-schemas.js.map +1 -0
- package/lib/transport/mcp-server.factory.d.ts +13 -0
- package/lib/transport/mcp-server.factory.js +32 -0
- package/lib/transport/mcp-server.factory.js.map +1 -0
- package/lib/transport/mcp-transport.controller.d.ts +77 -0
- package/lib/transport/mcp-transport.controller.js +442 -0
- package/lib/transport/mcp-transport.controller.js.map +1 -0
- package/lib/types.d.ts +432 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/package.json +42 -0
- package/src/dashboard/components/activity-block.tsx +72 -0
- package/src/dashboard/components/actor-cell.tsx +31 -0
- package/src/dashboard/components/connection-dialog.tsx +106 -0
- package/src/dashboard/components/empty-cell.tsx +7 -0
- package/src/dashboard/components/grants-block.tsx +218 -0
- package/src/dashboard/components/stats-block.tsx +275 -0
- package/src/dashboard/components/tools-block.tsx +274 -0
- package/src/dashboard/components/tooltip-button.tsx +28 -0
- package/src/dashboard/components/use-mcp-table-state.ts +47 -0
- package/src/dashboard/i18n/ar.po +311 -0
- package/src/dashboard/i18n/bg.po +311 -0
- package/src/dashboard/i18n/cs.po +311 -0
- package/src/dashboard/i18n/de.po +311 -0
- package/src/dashboard/i18n/en.po +311 -0
- package/src/dashboard/i18n/es.po +311 -0
- package/src/dashboard/i18n/fa.po +311 -0
- package/src/dashboard/i18n/fr.po +311 -0
- package/src/dashboard/i18n/he.po +311 -0
- package/src/dashboard/i18n/hr.po +311 -0
- package/src/dashboard/i18n/hu.po +311 -0
- package/src/dashboard/i18n/it.po +311 -0
- package/src/dashboard/i18n/ja.po +311 -0
- package/src/dashboard/i18n/ko.po +311 -0
- package/src/dashboard/i18n/nb.po +311 -0
- package/src/dashboard/i18n/ne.po +311 -0
- package/src/dashboard/i18n/nl.po +311 -0
- package/src/dashboard/i18n/pl.po +311 -0
- package/src/dashboard/i18n/pt_BR.po +311 -0
- package/src/dashboard/i18n/pt_PT.po +311 -0
- package/src/dashboard/i18n/ro.po +311 -0
- package/src/dashboard/i18n/ru.po +311 -0
- package/src/dashboard/i18n/sv.po +311 -0
- package/src/dashboard/i18n/tr.po +311 -0
- package/src/dashboard/i18n/uk.po +311 -0
- package/src/dashboard/i18n/uz.po +311 -0
- package/src/dashboard/i18n/zh_Hans.po +311 -0
- package/src/dashboard/i18n/zh_Hant.po +311 -0
- package/src/dashboard/index.tsx +30 -0
- package/src/dashboard/mcp-activity-route.tsx +38 -0
- package/src/dashboard/mcp-authorize-route.tsx +369 -0
- package/src/dashboard/mcp-grants-route.tsx +38 -0
- package/src/dashboard/mcp-overview-route.tsx +46 -0
- package/src/dashboard/mcp-server-redirect-route.tsx +15 -0
- package/src/dashboard/mcp-tools-route.tsx +38 -0
- package/src/dashboard/mcp.graphql.ts +127 -0
- package/src/dashboard/published-files.spec.ts +54 -0
- package/src/dashboard/tsconfig.json +9 -0
- package/src/shared/endpoint-paths.ts +8 -0
- package/src/shared/loopback.ts +6 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Trans } from '@lingui/react/macro';
|
|
2
|
+
import {
|
|
3
|
+
api,
|
|
4
|
+
Button,
|
|
5
|
+
CopyableText,
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogClose,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogFooter,
|
|
11
|
+
DialogHeader,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
DialogTrigger,
|
|
14
|
+
Separator,
|
|
15
|
+
useQuery,
|
|
16
|
+
} from '@vendure/dashboard';
|
|
17
|
+
import { ExternalLinkIcon, PlugIcon } from 'lucide-react';
|
|
18
|
+
|
|
19
|
+
import { mcpServerConfigQuery } from '../mcp.graphql';
|
|
20
|
+
|
|
21
|
+
const SETUP_GUIDE_URL = 'https://docs.vendure.io/guides/mcp-server/quick-start/';
|
|
22
|
+
|
|
23
|
+
function CopyableField({ label, value }: { label: React.ReactNode; value: string }) {
|
|
24
|
+
return (
|
|
25
|
+
<div className="space-y-1.5">
|
|
26
|
+
<div className="text-xs font-medium text-muted-foreground">{label}</div>
|
|
27
|
+
<CopyableText value={value} className="justify-between rounded-md border bg-muted/50 px-3 py-2">
|
|
28
|
+
<code className="min-w-0 flex-1 truncate font-mono text-xs select-all" title={value}>
|
|
29
|
+
{value}
|
|
30
|
+
</code>
|
|
31
|
+
</CopyableText>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Behind a header button rather than on the page, so it doesn't compete with the day-to-day blocks.
|
|
37
|
+
export function ConnectionDialog() {
|
|
38
|
+
const { data, isLoading } = useQuery({
|
|
39
|
+
queryKey: ['mcp-server-config'],
|
|
40
|
+
queryFn: () => api.query(mcpServerConfigQuery),
|
|
41
|
+
});
|
|
42
|
+
const config = data?.mcpServerConfig;
|
|
43
|
+
// Clients reach the server on its OAuth issuer origin, which can differ from the dashboard's own origin.
|
|
44
|
+
const origin = config?.issuer ?? window.location.origin;
|
|
45
|
+
const adminUrl = `${origin}/mcp/admin`;
|
|
46
|
+
const shopUrl = `${origin}/mcp/shop`;
|
|
47
|
+
const inspectorCommand = 'npx @modelcontextprotocol/inspector';
|
|
48
|
+
// Until the config arrives both endpoints are shown, so the dialog does not flash empty.
|
|
49
|
+
const showAdminUrl = isLoading || config?.oauthConfigured !== false;
|
|
50
|
+
const showShopUrl = isLoading || config?.shopAccess !== 'disabled';
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Dialog>
|
|
54
|
+
<DialogTrigger render={<Button variant="outline" />}>
|
|
55
|
+
<PlugIcon className="h-4 w-4" />
|
|
56
|
+
<Trans>Connect a client</Trans>
|
|
57
|
+
</DialogTrigger>
|
|
58
|
+
<DialogContent className="sm:max-w-lg">
|
|
59
|
+
<DialogHeader>
|
|
60
|
+
<DialogTitle>
|
|
61
|
+
<Trans>Connect a client</Trans>
|
|
62
|
+
</DialogTitle>
|
|
63
|
+
<DialogDescription>
|
|
64
|
+
<Trans>Connect an MCP client to your Vendure server using the endpoints below.</Trans>
|
|
65
|
+
</DialogDescription>
|
|
66
|
+
</DialogHeader>
|
|
67
|
+
|
|
68
|
+
<div className="space-y-4">
|
|
69
|
+
{showAdminUrl ? (
|
|
70
|
+
<CopyableField label={<Trans>Admin API</Trans>} value={adminUrl} />
|
|
71
|
+
) : (
|
|
72
|
+
<p className="text-sm text-muted-foreground">
|
|
73
|
+
<Trans>
|
|
74
|
+
The admin endpoint needs OAuth. Add an oauth block to McpPlugin.init to enable
|
|
75
|
+
it.
|
|
76
|
+
</Trans>
|
|
77
|
+
</p>
|
|
78
|
+
)}
|
|
79
|
+
{showShopUrl ? (
|
|
80
|
+
<CopyableField label={<Trans>Shop API</Trans>} value={shopUrl} />
|
|
81
|
+
) : (
|
|
82
|
+
<p className="text-sm text-muted-foreground">
|
|
83
|
+
<Trans>The shop endpoint is disabled (shopAccess: 'disabled').</Trans>
|
|
84
|
+
</p>
|
|
85
|
+
)}
|
|
86
|
+
<Separator />
|
|
87
|
+
<CopyableField label={<Trans>Test with MCP Inspector</Trans>} value={inspectorCommand} />
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<DialogFooter className="sm:items-center sm:justify-between">
|
|
91
|
+
<Button
|
|
92
|
+
variant="link"
|
|
93
|
+
className="px-0"
|
|
94
|
+
render={<a href={SETUP_GUIDE_URL} target="_blank" rel="noreferrer noopener" />}
|
|
95
|
+
>
|
|
96
|
+
<ExternalLinkIcon className="h-3.5 w-3.5" />
|
|
97
|
+
<Trans>Setup guide for connecting MCP clients</Trans>
|
|
98
|
+
</Button>
|
|
99
|
+
<DialogClose render={<Button variant="outline" />}>
|
|
100
|
+
<Trans>Close</Trans>
|
|
101
|
+
</DialogClose>
|
|
102
|
+
</DialogFooter>
|
|
103
|
+
</DialogContent>
|
|
104
|
+
</Dialog>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Trans, useLingui } from '@lingui/react/macro';
|
|
2
|
+
import {
|
|
3
|
+
Alert,
|
|
4
|
+
AlertDescription,
|
|
5
|
+
api,
|
|
6
|
+
Badge,
|
|
7
|
+
Button,
|
|
8
|
+
ConfirmationDialog,
|
|
9
|
+
DropdownMenu,
|
|
10
|
+
DropdownMenuContent,
|
|
11
|
+
DropdownMenuGroup,
|
|
12
|
+
DropdownMenuItem,
|
|
13
|
+
DropdownMenuTrigger,
|
|
14
|
+
PaginatedListDataTable,
|
|
15
|
+
type ResultOf,
|
|
16
|
+
toast,
|
|
17
|
+
useMutation,
|
|
18
|
+
usePermissions,
|
|
19
|
+
useQuery,
|
|
20
|
+
} from '@vendure/dashboard';
|
|
21
|
+
import { BanIcon, EllipsisIcon, InfoIcon } from 'lucide-react';
|
|
22
|
+
import { useRef } from 'react';
|
|
23
|
+
|
|
24
|
+
import { mcpOauthGrantsQuery, mcpServerConfigQuery, revokeMcpOauthGrantMutation } from '../mcp.graphql';
|
|
25
|
+
|
|
26
|
+
import { ActorCell } from './actor-cell';
|
|
27
|
+
import { EmptyCell } from './empty-cell';
|
|
28
|
+
import { useMcpTableState } from './use-mcp-table-state';
|
|
29
|
+
|
|
30
|
+
type Grant = ResultOf<typeof mcpOauthGrantsQuery>['mcpOauthGrants']['items'][number];
|
|
31
|
+
|
|
32
|
+
function GrantStatusBadge({ status }: { status: Grant['status'] }) {
|
|
33
|
+
if (status === 'revoked') {
|
|
34
|
+
return (
|
|
35
|
+
<Badge variant="destructive">
|
|
36
|
+
<Trans>Revoked</Trans>
|
|
37
|
+
</Badge>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (status === 'expired') {
|
|
41
|
+
return (
|
|
42
|
+
<Badge variant="secondary">
|
|
43
|
+
<Trans>Expired</Trans>
|
|
44
|
+
</Badge>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return (
|
|
48
|
+
<Badge variant="default">
|
|
49
|
+
<Trans>Active</Trans>
|
|
50
|
+
</Badge>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function GrantsBlock() {
|
|
55
|
+
const { t } = useLingui();
|
|
56
|
+
const { hasPermissions } = usePermissions();
|
|
57
|
+
const canUpdate = hasPermissions(['UpdateMcpServer']);
|
|
58
|
+
const tableState = useMcpTableState({
|
|
59
|
+
defaultSorting: [{ id: 'lastActivityAt', desc: true }],
|
|
60
|
+
defaultVisibility: {
|
|
61
|
+
id: false,
|
|
62
|
+
createdAt: false,
|
|
63
|
+
updatedAt: false,
|
|
64
|
+
actorId: false,
|
|
65
|
+
channelId: false,
|
|
66
|
+
revokedAt: false,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
const refreshTable = useRef<() => void>(() => {
|
|
70
|
+
/* the table replaces this when it mounts */
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const { data: configData } = useQuery({
|
|
74
|
+
queryKey: ['mcp-server-config'],
|
|
75
|
+
queryFn: () => api.query(mcpServerConfigQuery),
|
|
76
|
+
});
|
|
77
|
+
const oauthMissing = configData?.mcpServerConfig.oauthConfigured === false;
|
|
78
|
+
|
|
79
|
+
const revoke = useMutation({
|
|
80
|
+
mutationFn: (vars: { id: string }) => api.mutate(revokeMcpOauthGrantMutation, vars),
|
|
81
|
+
onSuccess: result => {
|
|
82
|
+
if (result.revokeMcpOauthGrant) {
|
|
83
|
+
toast.success(t`Grant revoked`);
|
|
84
|
+
} else {
|
|
85
|
+
toast.error(t`The grant could not be revoked; it may have already been removed`);
|
|
86
|
+
}
|
|
87
|
+
refreshTable.current();
|
|
88
|
+
},
|
|
89
|
+
onError: () => {
|
|
90
|
+
toast.error(t`Could not revoke grant`);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div className="space-y-4">
|
|
96
|
+
{oauthMissing ? (
|
|
97
|
+
<Alert>
|
|
98
|
+
<InfoIcon className="h-4 w-4" />
|
|
99
|
+
<AlertDescription>
|
|
100
|
+
<Trans>
|
|
101
|
+
OAuth is not configured, so no client can be granted access. Add an oauth block to
|
|
102
|
+
McpPlugin.init to use grants.
|
|
103
|
+
</Trans>
|
|
104
|
+
</AlertDescription>
|
|
105
|
+
</Alert>
|
|
106
|
+
) : null}
|
|
107
|
+
<PaginatedListDataTable
|
|
108
|
+
listQuery={mcpOauthGrantsQuery}
|
|
109
|
+
registerRefresher={refresher => {
|
|
110
|
+
refreshTable.current = refresher;
|
|
111
|
+
}}
|
|
112
|
+
{...tableState}
|
|
113
|
+
includeSelectionColumn={false}
|
|
114
|
+
customizeColumns={{
|
|
115
|
+
oauthClientName: {
|
|
116
|
+
header: () => <Trans>Client</Trans>,
|
|
117
|
+
cell: ({ row }) =>
|
|
118
|
+
row.original.oauthClientName ? (
|
|
119
|
+
<span className="font-medium">{row.original.oauthClientName}</span>
|
|
120
|
+
) : (
|
|
121
|
+
<EmptyCell />
|
|
122
|
+
),
|
|
123
|
+
},
|
|
124
|
+
actorName: {
|
|
125
|
+
header: () => <Trans>Granted to</Trans>,
|
|
126
|
+
meta: { dependencies: ['actorType', 'customerId'] },
|
|
127
|
+
// No database column to sort or filter by; it's looked up per row.
|
|
128
|
+
enableSorting: false,
|
|
129
|
+
enableColumnFilter: false,
|
|
130
|
+
cell: ({ row }) => (
|
|
131
|
+
<ActorCell
|
|
132
|
+
actorType={row.original.actorType ?? null}
|
|
133
|
+
actorName={row.original.actorName ?? null}
|
|
134
|
+
customerId={row.original.customerId ?? null}
|
|
135
|
+
/>
|
|
136
|
+
),
|
|
137
|
+
},
|
|
138
|
+
actorType: {
|
|
139
|
+
header: () => <Trans>Actor type</Trans>,
|
|
140
|
+
cell: ({ row }) =>
|
|
141
|
+
row.original.actorType ? (
|
|
142
|
+
<Badge variant="outline">{row.original.actorType}</Badge>
|
|
143
|
+
) : (
|
|
144
|
+
<EmptyCell />
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
// Fetched only to feed the "Granted to" cell; no database column to sort or filter by.
|
|
148
|
+
customerId: { meta: { disabled: true } },
|
|
149
|
+
lastActivityAt: { header: () => <Trans>Last activity</Trans> },
|
|
150
|
+
expiresAt: { header: () => <Trans>Expires</Trans> },
|
|
151
|
+
status: {
|
|
152
|
+
header: () => <Trans>Status</Trans>,
|
|
153
|
+
cell: ({ row }) => <GrantStatusBadge status={row.original.status} />,
|
|
154
|
+
},
|
|
155
|
+
}}
|
|
156
|
+
additionalColumns={{
|
|
157
|
+
actions: {
|
|
158
|
+
header: () => <Trans>Actions</Trans>,
|
|
159
|
+
meta: { dependencies: ['id', 'revokedAt'] },
|
|
160
|
+
enableHiding: false,
|
|
161
|
+
// Shows a disabled control rather than nothing, so the row doesn't look broken.
|
|
162
|
+
cell: ({ row }) =>
|
|
163
|
+
row.original.revokedAt != null || !canUpdate ? (
|
|
164
|
+
<Button
|
|
165
|
+
variant="ghost"
|
|
166
|
+
size="icon"
|
|
167
|
+
disabled
|
|
168
|
+
aria-label={
|
|
169
|
+
row.original.revokedAt != null
|
|
170
|
+
? t`No actions available for a revoked grant`
|
|
171
|
+
: t`Revoking needs the UpdateMcpServer permission`
|
|
172
|
+
}
|
|
173
|
+
>
|
|
174
|
+
<EllipsisIcon />
|
|
175
|
+
</Button>
|
|
176
|
+
) : (
|
|
177
|
+
<DropdownMenu>
|
|
178
|
+
<DropdownMenuTrigger render={<Button variant="ghost" size="icon" />}>
|
|
179
|
+
<EllipsisIcon />
|
|
180
|
+
</DropdownMenuTrigger>
|
|
181
|
+
<DropdownMenuContent className="min-w-56">
|
|
182
|
+
<DropdownMenuGroup>
|
|
183
|
+
<ConfirmationDialog
|
|
184
|
+
title={t`Revoke grant`}
|
|
185
|
+
description={t`This immediately revokes the client's access. The client will need to authorize again to reconnect.`}
|
|
186
|
+
confirmText={t`Revoke`}
|
|
187
|
+
onConfirm={() => revoke.mutate({ id: row.original.id })}
|
|
188
|
+
>
|
|
189
|
+
<DropdownMenuItem closeOnClick={false}>
|
|
190
|
+
<div className="flex items-center gap-2">
|
|
191
|
+
<BanIcon className="w-4 h-4" />
|
|
192
|
+
<Trans>Revoke</Trans>
|
|
193
|
+
</div>
|
|
194
|
+
</DropdownMenuItem>
|
|
195
|
+
</ConfirmationDialog>
|
|
196
|
+
</DropdownMenuGroup>
|
|
197
|
+
</DropdownMenuContent>
|
|
198
|
+
</DropdownMenu>
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
}}
|
|
202
|
+
// "actions" must stay last, so every other column is named here rather than left to append after it.
|
|
203
|
+
defaultColumnOrder={[
|
|
204
|
+
'oauthClientName',
|
|
205
|
+
'actorName',
|
|
206
|
+
'actorType',
|
|
207
|
+
'status',
|
|
208
|
+
'lastActivityAt',
|
|
209
|
+
'expiresAt',
|
|
210
|
+
'actorId',
|
|
211
|
+
'channelId',
|
|
212
|
+
'revokedAt',
|
|
213
|
+
'actions',
|
|
214
|
+
]}
|
|
215
|
+
/>
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { Trans, useLingui } from '@lingui/react/macro';
|
|
2
|
+
import {
|
|
3
|
+
Alert,
|
|
4
|
+
AlertDescription,
|
|
5
|
+
api,
|
|
6
|
+
Empty,
|
|
7
|
+
EmptyDescription,
|
|
8
|
+
EmptyHeader,
|
|
9
|
+
EmptyMedia,
|
|
10
|
+
EmptyTitle,
|
|
11
|
+
Link,
|
|
12
|
+
Progress,
|
|
13
|
+
Select,
|
|
14
|
+
SelectContent,
|
|
15
|
+
SelectItem,
|
|
16
|
+
SelectTrigger,
|
|
17
|
+
SelectValue,
|
|
18
|
+
Skeleton,
|
|
19
|
+
useQuery,
|
|
20
|
+
} from '@vendure/dashboard';
|
|
21
|
+
import {
|
|
22
|
+
ActivityIcon,
|
|
23
|
+
CircleCheckIcon,
|
|
24
|
+
CircleXIcon,
|
|
25
|
+
ClockIcon,
|
|
26
|
+
GaugeIcon,
|
|
27
|
+
InfoIcon,
|
|
28
|
+
TrendingUpIcon,
|
|
29
|
+
TriangleAlert,
|
|
30
|
+
} from 'lucide-react';
|
|
31
|
+
import { useState } from 'react';
|
|
32
|
+
|
|
33
|
+
import { mcpStatsQuery } from '../mcp.graphql';
|
|
34
|
+
|
|
35
|
+
import { TooltipButton } from './tooltip-button';
|
|
36
|
+
|
|
37
|
+
type TimeRange = '1h' | '24h' | '7d' | '30d';
|
|
38
|
+
|
|
39
|
+
function StatHint({ children }: { children: React.ReactNode }) {
|
|
40
|
+
const { t } = useLingui();
|
|
41
|
+
return (
|
|
42
|
+
<TooltipButton
|
|
43
|
+
tooltip={children}
|
|
44
|
+
label={t`What this number means`}
|
|
45
|
+
className="ml-1 inline-flex h-4 w-4 min-w-0 p-0 align-text-bottom text-muted-foreground"
|
|
46
|
+
>
|
|
47
|
+
<InfoIcon className="h-3 w-3" />
|
|
48
|
+
</TooltipButton>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function StatTile({
|
|
53
|
+
icon,
|
|
54
|
+
label,
|
|
55
|
+
value,
|
|
56
|
+
hint,
|
|
57
|
+
children,
|
|
58
|
+
}: {
|
|
59
|
+
icon: React.ReactNode;
|
|
60
|
+
label: React.ReactNode;
|
|
61
|
+
value: React.ReactNode;
|
|
62
|
+
hint?: React.ReactNode;
|
|
63
|
+
children?: React.ReactNode;
|
|
64
|
+
}) {
|
|
65
|
+
return (
|
|
66
|
+
<div className="rounded-md border border-border p-3 space-y-1">
|
|
67
|
+
<div className="flex items-start gap-1.5 text-xs text-muted-foreground">
|
|
68
|
+
<span className="mt-px shrink-0">{icon}</span>
|
|
69
|
+
<span>
|
|
70
|
+
{label}
|
|
71
|
+
{hint ? <StatHint>{hint}</StatHint> : null}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div className="text-2xl font-semibold tabular-nums">{value}</div>
|
|
75
|
+
{children}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const regionsClasses = 'grid gap-4 @4xl:grid-cols-3';
|
|
81
|
+
|
|
82
|
+
const tilesClasses = '@4xl:col-span-2 grid grid-cols-2 @2xl:grid-cols-3 gap-3';
|
|
83
|
+
|
|
84
|
+
function StatsSkeleton() {
|
|
85
|
+
return (
|
|
86
|
+
<div className={regionsClasses}>
|
|
87
|
+
<div className={tilesClasses}>
|
|
88
|
+
{Array.from({ length: 6 }).map((_, index) => (
|
|
89
|
+
<Skeleton key={index} className="h-19 w-full" />
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
<div className="space-y-2">
|
|
93
|
+
<Skeleton className="h-5 w-24" />
|
|
94
|
+
<Skeleton className="h-6 w-full" />
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function TopToolsList({ tools }: { tools: Array<{ toolName: string; count: number }> }) {
|
|
101
|
+
const topFive = tools.slice(0, 5);
|
|
102
|
+
const maxCount = Math.max(...topFive.map(tool => tool.count));
|
|
103
|
+
return (
|
|
104
|
+
<div className="space-y-2">
|
|
105
|
+
{topFive.map(tool => (
|
|
106
|
+
<div key={tool.toolName} className="space-y-1">
|
|
107
|
+
<div className="flex items-baseline justify-between gap-3">
|
|
108
|
+
<span className="font-mono text-sm truncate">{tool.toolName}</span>
|
|
109
|
+
<span className="text-sm tabular-nums text-muted-foreground">{tool.count}</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="h-1 rounded-full bg-primary/20">
|
|
112
|
+
<div
|
|
113
|
+
className="h-1 rounded-full bg-primary"
|
|
114
|
+
style={{ width: `${(tool.count / maxCount) * 100}%` }}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function NoCallsRecorded() {
|
|
124
|
+
return (
|
|
125
|
+
<Empty className="border border-dashed p-6">
|
|
126
|
+
<EmptyHeader>
|
|
127
|
+
<EmptyMedia variant="icon">
|
|
128
|
+
<ActivityIcon />
|
|
129
|
+
</EmptyMedia>
|
|
130
|
+
<EmptyTitle>
|
|
131
|
+
<Trans>No tool calls yet</Trans>
|
|
132
|
+
</EmptyTitle>
|
|
133
|
+
<EmptyDescription>
|
|
134
|
+
<Trans>No calls recorded in this period.</Trans>
|
|
135
|
+
</EmptyDescription>
|
|
136
|
+
</EmptyHeader>
|
|
137
|
+
</Empty>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function formatLatency(ms: number | null): string {
|
|
142
|
+
return ms == null ? '—' : `${ms} ms`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function StatsBlock() {
|
|
146
|
+
const { t } = useLingui();
|
|
147
|
+
const [timeRange, setTimeRange] = useState<TimeRange>('24h');
|
|
148
|
+
|
|
149
|
+
const rangeLabels: Record<TimeRange, string> = {
|
|
150
|
+
'1h': t`Last hour`,
|
|
151
|
+
'24h': t`Last 24 hours`,
|
|
152
|
+
'7d': t`Last 7 days`,
|
|
153
|
+
'30d': t`Last 30 days`,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const { data, isLoading, error } = useQuery({
|
|
157
|
+
queryKey: ['mcp-stats', timeRange],
|
|
158
|
+
queryFn: () => api.query(mcpStatsQuery, { timeRange }),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const stats = data?.mcpStats;
|
|
162
|
+
|
|
163
|
+
if (error) {
|
|
164
|
+
return (
|
|
165
|
+
<Alert variant="destructive">
|
|
166
|
+
<TriangleAlert className="h-4 w-4" />
|
|
167
|
+
<AlertDescription>
|
|
168
|
+
<Trans>Error loading MCP statistics: {error.message}</Trans>
|
|
169
|
+
</AlertDescription>
|
|
170
|
+
</Alert>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const successRate = stats?.successRate ?? 0;
|
|
175
|
+
// The API reports the error rate, not a count, so the tile works the count back out.
|
|
176
|
+
const failedCalls = Math.round((stats?.totalCalls ?? 0) * (stats?.errorRate ?? 0));
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<div className="space-y-4">
|
|
180
|
+
<div className="flex items-center justify-between gap-2">
|
|
181
|
+
<div className="text-sm text-muted-foreground">
|
|
182
|
+
<Trans>Usage over the selected period</Trans>
|
|
183
|
+
</div>
|
|
184
|
+
<Select
|
|
185
|
+
items={rangeLabels}
|
|
186
|
+
value={timeRange}
|
|
187
|
+
onValueChange={value => {
|
|
188
|
+
if (value) setTimeRange(value);
|
|
189
|
+
}}
|
|
190
|
+
>
|
|
191
|
+
<SelectTrigger className="w-40">
|
|
192
|
+
<SelectValue />
|
|
193
|
+
</SelectTrigger>
|
|
194
|
+
<SelectContent>
|
|
195
|
+
{(Object.keys(rangeLabels) as TimeRange[]).map(key => (
|
|
196
|
+
<SelectItem key={key} value={key}>
|
|
197
|
+
{rangeLabels[key]}
|
|
198
|
+
</SelectItem>
|
|
199
|
+
))}
|
|
200
|
+
</SelectContent>
|
|
201
|
+
</Select>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
{isLoading && !stats ? (
|
|
205
|
+
<StatsSkeleton />
|
|
206
|
+
) : (
|
|
207
|
+
<div className={regionsClasses}>
|
|
208
|
+
<div className={tilesClasses}>
|
|
209
|
+
<StatTile
|
|
210
|
+
icon={<ActivityIcon className="h-3.5 w-3.5" />}
|
|
211
|
+
label={<Trans>Total calls</Trans>}
|
|
212
|
+
value={stats?.totalCalls ?? 0}
|
|
213
|
+
/>
|
|
214
|
+
<StatTile
|
|
215
|
+
icon={<CircleCheckIcon className="h-3.5 w-3.5" />}
|
|
216
|
+
label={<Trans>Success rate</Trans>}
|
|
217
|
+
value={`${(successRate * 100).toFixed(1)}%`}
|
|
218
|
+
>
|
|
219
|
+
<Progress className="pt-1" value={successRate * 100} />
|
|
220
|
+
</StatTile>
|
|
221
|
+
<StatTile
|
|
222
|
+
icon={<CircleXIcon className="h-3.5 w-3.5" />}
|
|
223
|
+
label={<Trans>Failed calls</Trans>}
|
|
224
|
+
value={failedCalls}
|
|
225
|
+
/>
|
|
226
|
+
<StatTile
|
|
227
|
+
icon={<GaugeIcon className="h-3.5 w-3.5" />}
|
|
228
|
+
label={<Trans>p50 latency</Trans>}
|
|
229
|
+
value={formatLatency(stats?.p50LatencyMs ?? null)}
|
|
230
|
+
hint={<Trans>Half of the calls in this period finished faster than this.</Trans>}
|
|
231
|
+
/>
|
|
232
|
+
<StatTile
|
|
233
|
+
icon={<ClockIcon className="h-3.5 w-3.5" />}
|
|
234
|
+
label={<Trans>p95 latency</Trans>}
|
|
235
|
+
value={formatLatency(stats?.p95LatencyMs ?? null)}
|
|
236
|
+
hint={
|
|
237
|
+
<Trans>
|
|
238
|
+
95 out of 100 calls in this period finished faster than this. It shows how
|
|
239
|
+
slow the worst calls are.
|
|
240
|
+
</Trans>
|
|
241
|
+
}
|
|
242
|
+
/>
|
|
243
|
+
<StatTile
|
|
244
|
+
icon={<TrendingUpIcon className="h-3.5 w-3.5" />}
|
|
245
|
+
label={<Trans>Calls per hour</Trans>}
|
|
246
|
+
value={(stats?.callsPerHour ?? 0).toFixed(1)}
|
|
247
|
+
hint={
|
|
248
|
+
<Trans>Average number of tool calls per hour over the selected period.</Trans>
|
|
249
|
+
}
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div className="space-y-2">
|
|
254
|
+
<div className="text-sm font-medium">
|
|
255
|
+
<Trans>Top tools</Trans>
|
|
256
|
+
</div>
|
|
257
|
+
{stats && stats.topTools.length > 0 ? (
|
|
258
|
+
<>
|
|
259
|
+
<TopToolsList tools={stats.topTools} />
|
|
260
|
+
<Link
|
|
261
|
+
to="/mcp-server/activity"
|
|
262
|
+
className="inline-block text-sm text-primary hover:underline"
|
|
263
|
+
>
|
|
264
|
+
<Trans>See all activity</Trans>
|
|
265
|
+
</Link>
|
|
266
|
+
</>
|
|
267
|
+
) : (
|
|
268
|
+
<NoCallsRecorded />
|
|
269
|
+
)}
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
);
|
|
275
|
+
}
|