@fangorn-network/westmarch 0.0.20-dev → 2026.10.2-0.0-dev
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/README.md +33 -3
- package/docs/app-to-agent.md +100 -27
- package/package.json +9 -5
- package/plugin/scripts/fx.mjs +7 -9
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-RUyAWRzV.js +1 -0
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-ZV-LlYBe.js +31 -0
- package/site/dist/assets/Address-H8kD1d9O-CGQnt7Pu.js +17 -0
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CKn2JLwq.js +6 -0
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-9oIP9fma.js +1 -0
- package/site/dist/assets/ArrowsRightLeftIcon-BEhBD_6N.js +1 -0
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-D1wLlSJs.js +1 -0
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-CSBbHTyz.js +1 -0
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BsRq-xBt.js +1 -0
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BPdhsKvN.js +103 -0
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-CEGNdrkr.js +1 -0
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-Da9P7eSx.js +68 -0
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-BecgMnD_.js +1 -0
- package/site/dist/assets/CheckCircleIcon-DBiWFjO6.js +1 -0
- package/site/dist/assets/CheckCircleIcon-DzG2ROJZ.js +1 -0
- package/site/dist/assets/Checkbox-D1EDeo41-DMHcj9o_.js +52 -0
- package/site/dist/assets/ChevronDownIcon-2Os56gUt.js +1 -0
- package/site/dist/assets/Chip-CZKIKt9K-BWzs9fj5.js +26 -0
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-CFvcSiDs.js +16 -0
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-BozkCg8q.js +3 -0
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-DaCnbBzh.js +10 -0
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-DUkCLkxD.js +1 -0
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-Dv_5nMkZ.js +1 -0
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-DSGEeB3Y.js +1 -0
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-C-s4s_Lq.js +95 -0
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-BKX7fdYr.js +74 -0
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-DSoAuMFZ.js +7 -0
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-CZTXyfV0.js +39 -0
- package/site/dist/assets/CopyableText-CQapvaMr-DHO818I0.js +28 -0
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-DW4nRGfz.js +1 -0
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-DH8Nnb4Y.js +22 -0
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-gfUS_uV5.js +1 -0
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DZj9HTHc.js +1 -0
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-eHYsDK9W.js +187 -0
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DK_XVgVk.js +8 -0
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-6gRZzhLe.js +1 -0
- package/site/dist/assets/{EmailInputForm-Cqo1mda8-B2NG3K5V.js → EmailInputForm-Cqo1mda8-CZD4r5LM.js} +11 -11
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-BZu2ae0k.js +1 -0
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-86pviemJ.js +1 -0
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-vDcvT53Y.js +23 -0
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-rNJAtSJc.js +1 -0
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-I8Q95280.js +1 -0
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-Coi7OxoI.js +1 -0
- package/site/dist/assets/EnrollTotp-Dibew4dp-DC7FrDgo.js +66 -0
- package/site/dist/assets/EnvelopeIcon-DY6ERnW7.js +1 -0
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BvESwN99.js +21 -0
- package/site/dist/assets/{ErrorMessage-D8VaAP5m-CrZOnUyg.js → ErrorMessage-D8VaAP5m-oSruKN8L.js} +2 -2
- package/site/dist/assets/ErrorScreen-DipdTWzE-DnKGxH1Z.js +4 -0
- package/site/dist/assets/ExclamationCircleIcon-BZhlqH0r.js +1 -0
- package/site/dist/assets/ExclamationTriangleIcon-CkAOJIYV.js +1 -0
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-4pi7jooW.js +75 -0
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-z2XCMaLL.js +28 -0
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-CBVA9v1-.js +491 -0
- package/site/dist/assets/FingerPrintIcon-ra2dqmJO.js +1 -0
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-DwAwc6Ny.js +1 -0
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-CZszQsZf.js +1 -0
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-DfX6nvFQ.js +58 -0
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-CDS_sk_t.js +1 -0
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-CPfNQemT.js +1 -0
- package/site/dist/assets/GlobeAltIcon-SEUEIe_E.js +1 -0
- package/site/dist/assets/GooglePay-B53WnudL-aap7zwag.js +1 -0
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-DgSjCjQI.js +4 -0
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-DO4wICml.js +1 -0
- package/site/dist/assets/InfoBanner-Cb3p1z12-CDWt2ADo.js +22 -0
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-Ba19XoBr.js +1 -0
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-DGpewEch.js +1 -0
- package/site/dist/assets/{JsonTree-BHzNC-ic-DcNcbSoM.js → JsonTree-BHzNC-ic-pAEq1bl9.js} +3 -3
- package/site/dist/assets/{LabelXs-oqZNqbm_-iafrj25N.js → LabelXs-oqZNqbm_-D09YjVR4.js} +2 -2
- package/site/dist/assets/LandingScreen-CGWUoSUG-CUOCWUXd.js +1 -0
- package/site/dist/assets/{Layouts-BMRfo5hw-CeCOyCLK.js → Layouts-BMRfo5hw-D2u1-w8g.js} +16 -16
- package/site/dist/assets/Link-BdDilT2T-BYiP1zvW.js +40 -0
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-Tb6cAepT.js +77 -0
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-pq0NF2JO.js +1 -0
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-D9MOmDqg.js +117 -0
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-B80UJqAZ.js +1 -0
- package/site/dist/assets/{LoadingSkeleton-BMsgO5PV-CiEyS5PZ.js → LoadingSkeleton-BMsgO5PV-BRMh4Fv4.js} +6 -6
- package/site/dist/assets/LockClosedIcon-BqkoEL9J.js +1 -0
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DlnOM-Kh.js +1 -0
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-DSShupq9.js +1 -0
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-DUPV_SLA.js +1 -0
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-D96GpzXX.js +1 -0
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-CYQDa4ND.js +1 -0
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-CJtSAXGN.js +1 -0
- package/site/dist/assets/ModalFooter-BCuEK_nz-D2I8KWtk.js +403 -0
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-Bx5aHy-z.js +16 -0
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-CS6988X2.js +1 -0
- package/site/dist/assets/OpenLink-CUpJ1mOr-EZWVSX2r.js +39 -0
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-BY4eK5Jh.js +1 -0
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-LXys76u9.js +6 -0
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-RczvLvmo.js +20 -0
- package/site/dist/assets/{PhArrowCircleDown-D97G-BOA.js → PhArrowCircleDown-BtlNV0TZ.js} +5 -5
- package/site/dist/assets/PhArrowClockwise-mOiWYLMV.js +14 -0
- package/site/dist/assets/PhArrowDown-CkoOD89h.js +14 -0
- package/site/dist/assets/PhArrowLeft-C0jlxVhM.js +14 -0
- package/site/dist/assets/PhArrowRight-BI-V03Xf.js +14 -0
- package/site/dist/assets/{PhArrowSquareOut-Bk2CMG3I.js → PhArrowSquareOut-DnQ7n_B4.js} +5 -5
- package/site/dist/assets/PhArrowUp-izKvURUW.js +14 -0
- package/site/dist/assets/PhArrowUpRight-Bn-JhHsY.js +14 -0
- package/site/dist/assets/{PhArrowsClockwise-BXRn1GEl.js → PhArrowsClockwise-Brtx2Re-.js} +5 -5
- package/site/dist/assets/{PhArrowsDownUp-DM09Jo_3.js → PhArrowsDownUp-PZosTqZG.js} +5 -5
- package/site/dist/assets/PhArrowsLeftRight-CYsRQ2qh.js +14 -0
- package/site/dist/assets/{PhBank-fHbgCqqZ.js → PhBank-hhPAIPVb.js} +5 -5
- package/site/dist/assets/PhBrowser-BjzAmrHO.js +14 -0
- package/site/dist/assets/PhCaretDown-ddSjwcwm.js +14 -0
- package/site/dist/assets/PhCaretLeft-B7YLoNEF.js +14 -0
- package/site/dist/assets/PhCaretRight-BY8D5MIg.js +14 -0
- package/site/dist/assets/PhCaretUp-BG10nSut.js +14 -0
- package/site/dist/assets/PhCheck-DrKd7pBC.js +14 -0
- package/site/dist/assets/{PhCircleHalf-MJZeRBGF.js → PhCircleHalf-Bk9C4DvT.js} +5 -5
- package/site/dist/assets/PhClock-Sj17weCB.js +14 -0
- package/site/dist/assets/{PhCompass-hYn3HhGN.js → PhCompass-Df1ugFO-.js} +5 -5
- package/site/dist/assets/PhCopy-rgttky8E.js +14 -0
- package/site/dist/assets/{PhCreditCard-Fy4pzwtt.js → PhCreditCard-CZpdid2n.js} +5 -5
- package/site/dist/assets/{PhCurrencyDollar-BgiaenCi.js → PhCurrencyDollar-B6IKKjue.js} +5 -5
- package/site/dist/assets/{PhDesktop-CxrzCSv5.js → PhDesktop-BuCDXYJj.js} +5 -5
- package/site/dist/assets/PhDeviceMobile-CnybhXY-.js +14 -0
- package/site/dist/assets/PhDotsThree-CSAEcba1.js +14 -0
- package/site/dist/assets/PhEnvelope-SmaNeXoQ.js +14 -0
- package/site/dist/assets/PhFunnelSimple-DKx35ITq.js +14 -0
- package/site/dist/assets/{PhGlobe-DvmSc9_A.js → PhGlobe-q1mqj65V.js} +5 -5
- package/site/dist/assets/{PhIdentificationCard-CfkZm-5K.js → PhIdentificationCard-BeLXJpfZ.js} +5 -5
- package/site/dist/assets/{PhImage-Cf0J2ZfJ.js → PhImage-BYrKfN9k.js} +5 -5
- package/site/dist/assets/{PhInfo-Bwi51-2X.js → PhInfo-X33f06Ej.js} +5 -5
- package/site/dist/assets/{PhLightbulb-C4FZV7Es.js → PhLightbulb-DMZJsowR.js} +5 -5
- package/site/dist/assets/PhMagnifyingGlass-B6D0sWFL.js +14 -0
- package/site/dist/assets/{PhPaperPlaneRight-zxQVvPLX.js → PhPaperPlaneRight-Dvo-nXr9.js} +5 -5
- package/site/dist/assets/PhPlus-CBvZvLax.js +14 -0
- package/site/dist/assets/{PhPower-CFyWDmgD.js → PhPower-D8-AcNM6.js} +5 -5
- package/site/dist/assets/{PhPuzzlePiece-BjoNVfST.js → PhPuzzlePiece-C-7mYqGO.js} +5 -5
- package/site/dist/assets/{PhQrCode-CP3tFauY.js → PhQrCode-uIXlI5ER.js} +5 -5
- package/site/dist/assets/{PhQuestion-wOWJBd3G.js → PhQuestion-rUoqC2sC.js} +5 -5
- package/site/dist/assets/{PhQuestionMark-CV0k9C0Y.js → PhQuestionMark-W55Txvvb.js} +5 -5
- package/site/dist/assets/{PhSealCheck-vIKzREuN.js → PhSealCheck-BeVLq9PH.js} +5 -5
- package/site/dist/assets/{PhSignOut-CxELV-i0.js → PhSignOut-Cq2PivQ6.js} +5 -5
- package/site/dist/assets/{PhSpinner-CGDmbzUd.js → PhSpinner-CZMtAFdX.js} +5 -5
- package/site/dist/assets/{PhTrash-C9PD0SAt.js → PhTrash-BamrmMsN.js} +5 -5
- package/site/dist/assets/{PhUser-0sWNXQeZ.js → PhUser-A2fxqIV0.js} +5 -5
- package/site/dist/assets/{PhVault-6JTskUcC.js → PhVault-B8m1usHw.js} +5 -5
- package/site/dist/assets/{PhWarning-CoKs3gz6.js → PhWarning-CpkID9oi.js} +5 -5
- package/site/dist/assets/PhWarningCircle-Cm58gXb9.js +14 -0
- package/site/dist/assets/PhX-C3b4cCEy.js +14 -0
- package/site/dist/assets/PhoneIcon-CzbssTb8.js +1 -0
- package/site/dist/assets/PinInput-DbZ0b1i1-1DtLWL81.js +247 -0
- package/site/dist/assets/QrCode-DbnZwlkH-ChwcUk_h.js +22 -0
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-C79jd345.js +1 -0
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C9c0x-yq.js +1 -0
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-PNqHb6CI.js +7 -0
- package/site/dist/assets/{Screen-D30meWsY-CCeVNuWs.js → Screen-D30meWsY-DDum2qlY.js} +22 -22
- package/site/dist/assets/{ScreenHeader-CHmc4-Lu-DjyrH7IK.js → ScreenHeader-CHmc4-Lu-BqrAEXbV.js} +4 -4
- package/site/dist/assets/ScreenLayout-OwaQQcxH-B4Z8FjFp.js +1 -0
- package/site/dist/assets/{SelectSourceAsset-CWFog6gm-D7yTw87h.js → SelectSourceAsset-CWFog6gm-8iXuqbAs.js} +18 -18
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-CUpQZ9wq.js +14 -0
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-ZzvPLj2s.js +15 -0
- package/site/dist/assets/ShieldCheckIcon-Bjwe_-PV.js +1 -0
- package/site/dist/assets/SignRequestScreen-BHKv32KR-0qGeNipB.js +26 -0
- package/site/dist/assets/{StackedContainer-B2vaEl56-eQCM2cmv.js → StackedContainer-B2vaEl56-C-ojzCoQ.js} +2 -2
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-C3lgJb68.js +20 -0
- package/site/dist/assets/{Subtitle-CV-2yKE4-zxWw2m1Q.js → Subtitle-CV-2yKE4-o-1FQLlX.js} +2 -2
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-l35_C2DG.js +1 -0
- package/site/dist/assets/{Title-BnzYV3Is-B_JpTatT.js → Title-BnzYV3Is-RX1f0RV-.js} +2 -2
- package/site/dist/assets/TodoList-DnyULl18-JxWWU9KA.js +36 -0
- package/site/dist/assets/TransactionDetails-e9nesl30-C91nJPM9.js +109 -0
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-Cpm-4xzm.js +178 -0
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-BWCH7-Si.js +31 -0
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-BWMeJabk.js +6 -0
- package/site/dist/assets/TurnstileWrapper-B7sNddys-Dgr80Gih.js +1 -0
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-Clk4zk-8.js +1 -0
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-BgRsoR3B.js +1 -0
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D-SU-vAz.js +1 -0
- package/site/dist/assets/{Value-DTgR824E-BRuIGiec.js → Value-DTgR824E-DZpvBCWi.js} +7 -7
- package/site/dist/assets/WalletCards-DH1rqayz-UuZ4i_Ze.js +1 -0
- package/site/dist/assets/WalletIcon-B1i03Vqc.js +1 -0
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-TXTxmb8L.js +29 -0
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-CbrFb0ON.js +1 -0
- package/site/dist/assets/WalletLink-DK5LB5Ha-BYQZV7UV.js +20 -0
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-CNgSPnTS.js +1 -0
- package/site/dist/assets/WarningBanner-ZZqCEtZK-DNZUUOph.js +21 -0
- package/site/dist/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/site/dist/assets/analytics-mkkvFRju-DOXuftJB.js +1 -0
- package/site/dist/assets/basic-C9wn6QoQ.js +1575 -0
- package/site/dist/assets/bytes-CjWw8TJh.js +1 -0
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-tV1Idewc.js +1 -0
- package/site/dist/assets/ccip-BhHEqVIW.js +1 -0
- package/site/dist/assets/check-C_DTyjLS.js +1 -0
- package/site/dist/assets/chevron-down-iklXXH-z.js +1 -0
- package/site/dist/assets/circle-alert-KEOUF48T.js +1 -0
- package/site/dist/assets/circle-check-big-BJ_ADwB4.js +1 -0
- package/site/dist/assets/circle-x-BSfWmhYk.js +1 -0
- package/site/dist/assets/client-BnDcP42J.js +9 -0
- package/site/dist/assets/client-DH86IrJA.js +125 -0
- package/site/dist/assets/coinbase-DCPC2L_R-2ivYfoMv.js +3 -0
- package/site/dist/assets/copy-sK00DOfH.js +1 -0
- package/site/dist/assets/core-CRE213RM.js +211 -0
- package/site/dist/assets/createLucideIcon-D9OK_uxG.js +1 -0
- package/site/dist/assets/custom-V1wex-Di.js +1 -0
- package/site/dist/assets/dijkstra-COg3n3zL.js +1 -0
- package/site/dist/assets/embed.worker-BRIYO7m8.js +1 -0
- package/site/dist/assets/encodePacked-DyXYq3Cc.js +1 -0
- package/site/dist/assets/ethers-zTjbodk5-DSYOi6tU.js +1 -0
- package/site/dist/assets/external-link-Cdp8NBio.js +1 -0
- package/site/dist/assets/fallback-DiFue5Zm.js +1 -0
- package/site/dist/assets/farcaster-DPlSjvF5-DP2DLoHZ.js +1 -0
- package/site/dist/assets/features-B6BTj_BL.js +5 -0
- package/site/dist/assets/fingerprint-pattern-gFJTz5e4.js +1 -0
- package/site/dist/assets/floating-ui.react-D9ndYqYK.js +1 -0
- package/site/dist/assets/floating-ui.react-dom-CNbOgOFt.js +1 -0
- package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-CkAr4Oc0.js +1 -0
- package/site/dist/assets/getChainName-DjpPdUSc-c2urPd0g.js +1 -0
- package/site/dist/assets/getErc20Balance-jXNpFf0N-mFQ9Iqk-.js +1 -0
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-Dx5he_uG.js +1 -0
- package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-C446pzMl.js +1 -0
- package/site/dist/assets/getTransactionCount-80UHlwAV.js +1 -0
- package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-FDalV59C.js +1 -0
- package/site/dist/assets/hashTypedData-Beq57Ogb.js +22 -0
- package/site/dist/assets/hooks.module-ClpaQ1Tg.js +1 -0
- package/site/dist/assets/hourglass-CB7z_I9H.js +1 -0
- package/site/dist/assets/http-BocEfKYb.js +19 -0
- package/site/dist/assets/index-0knDOgU9.js +1 -0
- package/site/dist/assets/index-9jNeS_nC.js +1 -0
- package/site/dist/assets/index-B--T-Fmt.js +16 -0
- package/site/dist/assets/index-BDkarAkX.js +2 -0
- package/site/dist/assets/index-BMfMy017.js +679 -0
- package/site/dist/assets/index-BOd8jv8-.js +1 -0
- package/site/dist/assets/index-BdEw5wyl-2VGMzHIs.js +1 -0
- package/site/dist/assets/index-C8ThRelw.js +9 -0
- package/site/dist/assets/{index-CWARkn2w-Cezl_uBr.js → index-CWARkn2w-D6ikWJWj.js} +7 -7
- package/site/dist/assets/{wui-ux-by-reown-D34ILNLS.js → index-CztIxJB6.js} +296 -296
- package/site/dist/assets/index-D4LdLFDC.js +1 -0
- package/site/dist/assets/index-D6T-s6sR.js +1 -0
- package/site/dist/assets/index-D7396TWe.js +1 -0
- package/site/dist/assets/index-DdxtHe81.js +2 -0
- package/site/dist/assets/index-DvMddJcd-D7AEQrzj.js +12 -0
- package/site/dist/assets/index-nibyPLVP.js +1 -0
- package/site/dist/assets/index.browser-B6Bt5URJ.js +1 -0
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-D7xtzRqA.js +1 -0
- package/site/dist/assets/landmark-CMLKifhk.js +1 -0
- package/site/dist/assets/lock-BkyjNE8h.js +1 -0
- package/site/dist/assets/mail-B6-Tq9Ld.js +1 -0
- package/site/dist/assets/native-CJ5et6AR.js +1 -0
- package/site/dist/assets/nonceManager-zkW7cM66.js +1 -0
- package/site/dist/assets/parseEther-C7aOvuze.js +1 -0
- package/site/dist/assets/parseSignature-BIjcuWdB.js +1 -0
- package/site/dist/assets/preload-helper-PPVm8Dsz.js +1 -0
- package/site/dist/assets/privateKeyToAccount-CRvvpHWf.js +1 -0
- package/site/dist/assets/property-CnFDNXw5.js +3 -0
- package/site/dist/assets/react-auth_false-DedQs79w.js +1 -0
- package/site/dist/assets/reservoir-x-nGuZkT-DFxAFt2v.js +1 -0
- package/site/dist/assets/roles-DV_6FRBZ.js +1 -0
- package/site/dist/assets/safe-url-D7SRPu33-A8zMgOTd.js +1 -0
- package/site/dist/assets/serializeErc6492Signature-CeJeL3h6.js +1 -0
- package/site/dist/assets/serializeTransaction-L-_Ej-jW.js +8 -0
- package/site/dist/assets/{shared-DRZUmnL5-xqAUARWo.js → shared-DRZUmnL5-MWD-C-pp.js} +33 -33
- package/site/dist/assets/{shared-FM0rljBt--Avg6q2R.js → shared-FM0rljBt-c4eSjzGj.js} +6 -6
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-CF2QteTJ.js +1 -0
- package/site/dist/assets/simulateTransaction-CfuOrae4-BHUMPf6Q.js +1 -0
- package/site/dist/assets/smartphone-DAN5rY0T.js +1 -0
- package/site/dist/assets/stripe.esm-Dv8C3q95.js +2 -0
- package/site/dist/assets/styles-BsotlekN-Cjuu2SDV.js +9 -0
- package/site/dist/assets/{styles-Cm9H63WO-Br4QtzUL.js → styles-Cm9H63WO-Cv1TbqYi.js} +17 -17
- package/site/dist/assets/{styles-DVyDvTdj-BTABn2K8.js → styles-DVyDvTdj-CI4xZNHp.js} +8 -8
- package/site/dist/assets/{styles-hslXy6xG-D-49b1rk.js → styles-hslXy6xG-DeVcFoDD.js} +23 -23
- package/site/dist/assets/telegram-B-JqnkqZ-DTjJLkIF.js +1 -0
- package/site/dist/assets/to-ui-error-DWe-qwS3-Dx3yzcV0.js +4 -0
- package/site/dist/assets/toAccount-Bq6rbpbI.js +1 -0
- package/site/dist/assets/transaction-BNTP-bFm-CrebgH-D.js +1 -0
- package/site/dist/assets/transactionReceipt-BwJl-gjg.js +1 -0
- package/site/dist/assets/transfer-6YztDh-t-DU6hH7CZ.js +1 -0
- package/site/dist/assets/transformers.web-BEKVh7pD.js +40 -0
- package/site/dist/assets/transformers.web-aWa49tv1.js +40 -0
- package/site/dist/assets/triangle-alert-ndoiBs4y.js +1 -0
- package/site/dist/assets/twitch-5IOe4sIQ-BXviIywg.js +1 -0
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-C7axYJ--.js +1 -0
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-CR4CrguU.js +1 -0
- package/site/dist/assets/useI18n-C-5n_noF-C_t8QqBJ.js +1 -0
- package/site/dist/assets/useWalletBalance-CZnP5f_f-BnSHLVI_.js +1 -0
- package/site/dist/assets/w3m-modal-Bz5KWTQ-.js +1174 -0
- package/site/dist/assets/wallet-DTM31trz.js +2 -0
- package/site/dist/assets/wallet-UESEqPei.js +1 -0
- package/site/dist/assets/wallet-connect-BvJtUsDt-CnvUnFbz.js +1 -0
- package/site/dist/assets/walletconnect-v2-3frQFwbg-CzQk99gS.js +15 -0
- package/site/dist/assets/x-B2_XdOVQ.js +1 -0
- package/site/dist/index.html +118 -6
- package/site/feed.js +16 -1
- package/site/no-model.js +4 -0
- package/site/worker.js +597 -58
- package/src/agent/agent-card.js +20 -11
- package/src/agent/mcp.js +150 -316
- package/src/agent/view-tools.js +53 -12
- package/src/agent/x402.js +379 -44
- package/src/core/embed.js +51 -52
- package/src/core/embed.worker.js +1 -1
- package/src/core/shard.js +7 -3
- package/src/discover/apps.js +4 -3
- package/src/discover/explore.js +36 -22
- package/src/market/reactions.js +2 -2
- package/src/publish/devnet.js +95 -0
- package/src/publish/lint.js +2 -1
- package/src/publish/ship.js +517 -236
- package/src/publish/view-cli.js +11 -10
- package/src/publish/view.js +359 -206
- package/src/taste/taste-doc.js +3 -2
- package/src/taste/taste.js +2 -2
- package/src/taste/vault.js +3 -1
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-BOfmiSH1.js +0 -1
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-D_EsIeJu.js +0 -31
- package/site/dist/assets/Address-H8kD1d9O-C85sJ79B.js +0 -17
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-DdEPFOww.js +0 -6
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-DhVy9iGN.js +0 -1
- package/site/dist/assets/ApiController-CYdiyu9B.js +0 -5
- package/site/dist/assets/ArrowsRightLeftIcon-cp60yobq.js +0 -1
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-8rbYiYYE.js +0 -1
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-2pkNfCno.js +0 -1
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-7AQt25_k.js +0 -1
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BZY30TGs.js +0 -103
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-BILOOLi_.js +0 -1
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-CvsbQcFv.js +0 -68
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-D8eDcAkc.js +0 -1
- package/site/dist/assets/CheckCircleIcon-BM409mGI.js +0 -1
- package/site/dist/assets/CheckCircleIcon-NCOQc0Gs.js +0 -1
- package/site/dist/assets/Checkbox-D1EDeo41-rHlvsZzP.js +0 -52
- package/site/dist/assets/ChevronDownIcon-CW-4MSpE.js +0 -1
- package/site/dist/assets/Chip-CZKIKt9K-CutJG010.js +0 -26
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DLs9zX-Q.js +0 -16
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-N9J6T_YL.js +0 -3
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-h0uYIUi6.js +0 -10
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-LeuDMN1E.js +0 -1
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-DaRa59tZ.js +0 -1
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-crHzh-TL.js +0 -1
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-BEA4FmhI.js +0 -95
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-CMQIad63.js +0 -74
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-BeWLchcf.js +0 -7
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-wu3a3kw4.js +0 -1
- package/site/dist/assets/ConnectorUtil-Cq4lWnfe.js +0 -21
- package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-DujUHNzW.js +0 -39
- package/site/dist/assets/CopyableText-CQapvaMr-DMIdpDaU.js +0 -28
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-Csju14vF.js +0 -1
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-CBOrbNLo.js +0 -22
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-BL5hzNUI.js +0 -1
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-fcO51q5H.js +0 -1
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-B3vY888G.js +0 -187
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DmdQaFI2.js +0 -8
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-BoupRyfV.js +0 -1
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-D_AVgO4s.js +0 -1
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-CLsJbPYQ.js +0 -1
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-C9sAExzE.js +0 -23
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-DxaWAAKa.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-CxrfLr5q.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-DHZRGoTN.js +0 -1
- package/site/dist/assets/EnrollTotp-Dibew4dp-SA2pvNEc.js +0 -66
- package/site/dist/assets/EnvelopeIcon-Dh2vSVj4.js +0 -1
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BKOYTyCi.js +0 -21
- package/site/dist/assets/ErrorScreen-DipdTWzE-DcxVjMO4.js +0 -1
- package/site/dist/assets/ErrorScreen-DipdTWzE-c8g8En21.js +0 -4
- package/site/dist/assets/ExclamationCircleIcon-DUA2wMfO.js +0 -1
- package/site/dist/assets/ExclamationTriangleIcon-eZfaqcFq.js +0 -1
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-s_s5M2CZ.js +0 -75
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-BHBR4k8H.js +0 -28
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-BH_sU6EV.js +0 -491
- package/site/dist/assets/FingerPrintIcon-Dm6kxmg7.js +0 -1
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-B8TRV36j.js +0 -1
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-BQdbJ5Bb.js +0 -1
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-9rPtyA3d.js +0 -58
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-GaXigGI9.js +0 -1
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-UsmtTqv4.js +0 -1
- package/site/dist/assets/GlobeAltIcon-vqrVV5ho.js +0 -1
- package/site/dist/assets/GooglePay-B53WnudL-BX5_WtCx.js +0 -1
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-D-I8j7NO.js +0 -4
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-BY3j50El.js +0 -1
- package/site/dist/assets/InfoBanner-Cb3p1z12-DLBl_Ywy.js +0 -22
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-DLSV_NjP.js +0 -1
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-CxreyXoD.js +0 -1
- package/site/dist/assets/LandingScreen-CGWUoSUG-DK1EY-6v.js +0 -1
- package/site/dist/assets/Link-BdDilT2T-BEDEdHuS.js +0 -40
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-ClWoqvEL.js +0 -77
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-C3v7glH0.js +0 -1
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-D72Gb0LW.js +0 -117
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-DYIl5Kr2.js +0 -1
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-C0DuD14j.js +0 -1
- package/site/dist/assets/Loader-UAZqxsnw-Cy7hEE2f.js +0 -62
- package/site/dist/assets/LockClosedIcon-BgY_5v_Z.js +0 -1
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DhUMiJZJ.js +0 -1
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-tXiZDHmN.js +0 -1
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-CaW7xeCC.js +0 -1
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-CeRqvx8k.js +0 -1
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-BkN1k4lh.js +0 -1
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-CXSqLVbE.js +0 -1
- package/site/dist/assets/ModalFooter-BCuEK_nz-c-khvG4Y.js +0 -403
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-BRFN2eXr.js +0 -16
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-CeiGcSia.js +0 -1
- package/site/dist/assets/OpenLink-CUpJ1mOr-DfAvJRyK.js +0 -39
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-CIf5I7wU.js +0 -1
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-CLoL7QC-.js +0 -6
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-B9F67IYV.js +0 -20
- package/site/dist/assets/PhArrowClockwise-DVgyFuez.js +0 -14
- package/site/dist/assets/PhArrowDown-87b1BizM.js +0 -14
- package/site/dist/assets/PhArrowLeft-Da0MfnbK.js +0 -14
- package/site/dist/assets/PhArrowRight-AdrIL4DW.js +0 -14
- package/site/dist/assets/PhArrowUp-4sgyKPGx.js +0 -14
- package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
- package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.js +0 -14
- package/site/dist/assets/PhBrowser-2-9m-AkM.js +0 -14
- package/site/dist/assets/PhCaretDown-BDNabFuL.js +0 -14
- package/site/dist/assets/PhCaretLeft-CI460R-A.js +0 -14
- package/site/dist/assets/PhCaretRight-D7ZS3Ls8.js +0 -14
- package/site/dist/assets/PhCaretUp-C-iIfyvO.js +0 -14
- package/site/dist/assets/PhCheck-DxQXn57r.js +0 -14
- package/site/dist/assets/PhClock-x3MS3Mwi.js +0 -14
- package/site/dist/assets/PhCopy-CWNYcABI.js +0 -14
- package/site/dist/assets/PhDeviceMobile-CsyA5Goi.js +0 -14
- package/site/dist/assets/PhDotsThree-D-k1BiYg.js +0 -14
- package/site/dist/assets/PhEnvelope-D8kzeNox.js +0 -14
- package/site/dist/assets/PhFunnelSimple-CfQs5DAW.js +0 -14
- package/site/dist/assets/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
- package/site/dist/assets/PhPlus-C4UoW-2n.js +0 -14
- package/site/dist/assets/PhWarningCircle-BXHw1fCt.js +0 -14
- package/site/dist/assets/PhX-DX0SFIqC.js +0 -14
- package/site/dist/assets/PhoneIcon-CvIiPwYQ.js +0 -1
- package/site/dist/assets/PinInput-DbZ0b1i1-CDXZBdQx.js +0 -247
- package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CtQWBiV2.js +0 -1
- package/site/dist/assets/QrCode-DbnZwlkH-h6Bhoe5U.js +0 -22
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-D-A5P3PX.js +0 -1
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C8lTSeSr.js +0 -1
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-P5P3plkH.js +0 -7
- package/site/dist/assets/SIWXUtil-TUCxa7aA.js +0 -1
- package/site/dist/assets/ScreenLayout-OwaQQcxH-CrQM6kvA.js +0 -1
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-f0iDIGmw.js +0 -14
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-kq1zvA7d.js +0 -11
- package/site/dist/assets/ShieldCheckIcon-o6RHYev1.js +0 -1
- package/site/dist/assets/SignRequestScreen-BHKv32KR-DDpMYyJ1.js +0 -26
- package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-DPwhuzcI.js +0 -1
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-BJ-onCjv.js +0 -20
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-NWlMgNRX.js +0 -1
- package/site/dist/assets/TodoList-DnyULl18-C8Eyy28X.js +0 -36
- package/site/dist/assets/TransactionDetails-e9nesl30-C4MpIHR-.js +0 -109
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-p1T9WVMx.js +0 -178
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-88IQcRnY.js +0 -31
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-1fDAIxAf.js +0 -6
- package/site/dist/assets/TurnstileWrapper-B7sNddys-Jwy1tJtm.js +0 -1
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-Jj2DQW8D.js +0 -1
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-DwYIUBqi.js +0 -1
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D7m70C4b.js +0 -1
- package/site/dist/assets/WalletCards-DH1rqayz-Bgp9Fsgs.js +0 -1
- package/site/dist/assets/WalletIcon-gKf0gTw6.js +0 -1
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-DpNSAGte.js +0 -29
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DG-RuO-F.js +0 -1
- package/site/dist/assets/WalletLink-DK5LB5Ha-DHaL350n.js +0 -20
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-CUyIJFzt.js +0 -1
- package/site/dist/assets/WarningBanner-ZZqCEtZK-2eU4Qo74.js +0 -21
- package/site/dist/assets/__vite-browser-external-CitKSmYk.js +0 -1
- package/site/dist/assets/_esm-B26FZg5Y.js +0 -7
- package/site/dist/assets/_esm-BdeM6pxJ.js +0 -1
- package/site/dist/assets/accounts-D96UKWkC.js +0 -1
- package/site/dist/assets/accounts-DiZ-0VmN.js +0 -1
- package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
- package/site/dist/assets/baseSepolia-DX-qGsik.js +0 -1
- package/site/dist/assets/basic-oIwwSyu4.js +0 -1575
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
- package/site/dist/assets/ccip-65sIfSPR.js +0 -1
- package/site/dist/assets/ccip-BZvRTL6g.js +0 -7
- package/site/dist/assets/ccip-DA_zG341.js +0 -1
- package/site/dist/assets/chain-DM3oH6Px.js +0 -8
- package/site/dist/assets/check-BPgcwEPP.js +0 -1
- package/site/dist/assets/chevron-down-BSsbXkK-.js +0 -1
- package/site/dist/assets/circle-alert-DWaeLZNj.js +0 -1
- package/site/dist/assets/circle-check-big-Chb1ivw9.js +0 -1
- package/site/dist/assets/circle-x-AV9Cet0R.js +0 -1
- package/site/dist/assets/client-CZG0ndth.js +0 -2
- package/site/dist/assets/client-Dsa7_3V3.js +0 -9
- package/site/dist/assets/coinbase-DCPC2L_R-D3aIgpyd.js +0 -3
- package/site/dist/assets/copy-Ckr0AkL6.js +0 -1
- package/site/dist/assets/core-snws5xwv.js +0 -12
- package/site/dist/assets/createLucideIcon-IPW50ckY.js +0 -1
- package/site/dist/assets/defineChain-CiuCXUZW.js +0 -1
- package/site/dist/assets/dijkstra-Drfl93V4.js +0 -1
- package/site/dist/assets/dist-Cm7pNAtL.js +0 -1
- package/site/dist/assets/dist-CoS6E-3x.js +0 -1
- package/site/dist/assets/dist-Dl07uGq1.js +0 -1
- package/site/dist/assets/dist-DnGANz51.js +0 -16
- package/site/dist/assets/embed.worker-ugGhEqCV.js +0 -1
- package/site/dist/assets/errors-BQ3N-RVt-BLqjTPNR.js +0 -1
- package/site/dist/assets/esm-B5cbIQaz.js +0 -37
- package/site/dist/assets/esm-ByALO6mA.js +0 -1
- package/site/dist/assets/esm-C3DslVJx.js +0 -1
- package/site/dist/assets/esm-Ci1ogKuK.js +0 -1
- package/site/dist/assets/esm-n2lWo7kz.js +0 -1
- package/site/dist/assets/ethers-zTjbodk5-wHhL_BQ1.js +0 -1
- package/site/dist/assets/eventemitter3-CL76jPsW.js +0 -1
- package/site/dist/assets/external-link-D-uehwM2.js +0 -1
- package/site/dist/assets/farcaster-DPlSjvF5-BqTvDXBR.js +0 -1
- package/site/dist/assets/features-DQ0UYy6K.js +0 -2
- package/site/dist/assets/fingerprint-pattern-D8ytA16Q.js +0 -1
- package/site/dist/assets/floating-ui.react-dom-DKWOL9UG.js +0 -1
- package/site/dist/assets/floating-ui.react-xRkl9O3u.js +0 -1
- package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-BVqOKQif.js +0 -1
- package/site/dist/assets/formatter-CVbp4SlJ.js +0 -1
- package/site/dist/assets/get-entropy-details-for-user-dHRH5Gpi-Dukf7_kJ.js +0 -1
- package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
- package/site/dist/assets/getErc20Balance-jXNpFf0N-Bb9WM31M.js +0 -1
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-KPrdn04K.js +0 -1
- package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-Gx4_wxON.js +0 -1
- package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-r2UnDeEy.js +0 -1
- package/site/dist/assets/guards-BIW-GiMJ-CHfXo8XI.js +0 -1
- package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
- package/site/dist/assets/hourglass-CPG1HZmf.js +0 -1
- package/site/dist/assets/id-UqEwL2BI-BkKm533U.js +0 -1
- package/site/dist/assets/index-1HYFYA-W.js +0 -8
- package/site/dist/assets/index-BdEw5wyl-ChSJvPZk.js +0 -1
- package/site/dist/assets/index-DvMddJcd-BatvgC-S.js +0 -12
- package/site/dist/assets/index-YiCw0Y_x-CX5i3Z87.js +0 -437
- package/site/dist/assets/index.browser-B-i-Lj3J.js +0 -1
- package/site/dist/assets/index.browser-BMmUcykv.js +0 -1
- package/site/dist/assets/index.es-BmqyoBEM.js +0 -2
- package/site/dist/assets/index.es-C1v1or--.js +0 -3
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-By6r0dVB.js +0 -1
- package/site/dist/assets/jsx-runtime-BbDfbRii.js +0 -1
- package/site/dist/assets/landmark-CH6LV6F0.js +0 -1
- package/site/dist/assets/lib-BsS8z8Lj.js +0 -1
- package/site/dist/assets/localBatchGatewayRequest-3kLrX_c7.js +0 -32
- package/site/dist/assets/lock-DcskI4Bb.js +0 -1
- package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
- package/site/dist/assets/mail-Bs0r5yOi.js +0 -1
- package/site/dist/assets/modal-context-CwmSeFcv-DruX9J1E.js +0 -1
- package/site/dist/assets/native-BKj27wfc.js +0 -1
- package/site/dist/assets/ofetch.CWycOUEr-CHp-crOQ.js +0 -1
- package/site/dist/assets/parseAbi-Csg-8t59.js +0 -2
- package/site/dist/assets/parseAbiParameters-BWbIMYe4.js +0 -1
- package/site/dist/assets/parseEther-VjhVo3dd.js +0 -1
- package/site/dist/assets/pkce-DXF0yKjP-ChQhE0st.js +0 -1
- package/site/dist/assets/preload-helper-uBIymjUX.js +0 -1
- package/site/dist/assets/privy-context-81KmsBw2-CjWGzyg7.js +0 -2
- package/site/dist/assets/property-DuZ9DLP4.js +0 -3
- package/site/dist/assets/react-DCXkXSrv.js +0 -1
- package/site/dist/assets/react-DQnMl2Xv.js +0 -1
- package/site/dist/assets/react-DrJ0MmMO.js +0 -1
- package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
- package/site/dist/assets/react-dom-5dW7aKoP.js +0 -1
- package/site/dist/assets/reservoir-x-nGuZkT-BMX127i6.js +0 -1
- package/site/dist/assets/roles-32M1l9jI.js +0 -1
- package/site/dist/assets/roles-DKPW79Ca.js +0 -1
- package/site/dist/assets/rolldown-runtime-BcKkbAw3.js +0 -1
- package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
- package/site/dist/assets/secp256k1-C4nzcPo-.js +0 -1
- package/site/dist/assets/secp256k1-D92aGNnU.js +0 -1
- package/site/dist/assets/secp256k1-DmbwyFau.js +0 -1
- package/site/dist/assets/secp256k1-_MleGpqL.js +0 -1
- package/site/dist/assets/secp256k1-xl2og-wO.js +0 -1
- package/site/dist/assets/serializeAuthorizationList-CX8hGL56.js +0 -1
- package/site/dist/assets/serializeSignature-DfxkPnu-.js +0 -2
- package/site/dist/assets/sha2-BU_QyRTx.js +0 -1
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-BK_FBkaE.js +0 -1
- package/site/dist/assets/simulateTransaction-CfuOrae4-64lWYJAL.js +0 -1
- package/site/dist/assets/smartphone-CcEZ-XAy.js +0 -1
- package/site/dist/assets/src-BBjkfi-Q.js +0 -1
- package/site/dist/assets/storage-Ufl800Ne-D0bZBw-H.js +0 -9
- package/site/dist/assets/stringify-BlDm7tuc.js +0 -21
- package/site/dist/assets/stripe.esm-CZRDpc-N.js +0 -2
- package/site/dist/assets/styles-BsotlekN-CXEB4Ud9.js +0 -9
- package/site/dist/assets/telegram-B-JqnkqZ-RBoY3PLx.js +0 -1
- package/site/dist/assets/to-ui-error-DWe-qwS3-Cx2bk1kZ.js +0 -4
- package/site/dist/assets/toViemAccount-B5iDGq1b-Ba8L7zed.js +0 -2
- package/site/dist/assets/transaction-BNTP-bFm-M5tJx8vY.js +0 -1
- package/site/dist/assets/transfer-6YztDh-t-BVQkTvG-.js +0 -1
- package/site/dist/assets/transformers.web-CVP3pJOS.js +0 -40
- package/site/dist/assets/transformers.web-D8W1u_I2.js +0 -49
- package/site/dist/assets/triangle-alert-CWjYH75H.js +0 -1
- package/site/dist/assets/twitch-5IOe4sIQ-lDtgk0os.js +0 -1
- package/site/dist/assets/types-4CuOD23i.js +0 -1
- package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-LUIVFBSd.js +0 -1
- package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-CC2pq27z.js +0 -1
- package/site/dist/assets/useActiveWallet-B-yZYGc6-D7Ik-LxJ.js +0 -123
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-D1hmQfpA.js +0 -1
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-ZnbuJ-vP.js +0 -1
- package/site/dist/assets/useI18n-C-5n_noF-BcqC76yj.js +0 -1
- package/site/dist/assets/useWalletBalance-CZnP5f_f-Dw2GIJ4g.js +0 -1
- package/site/dist/assets/useWallets-X1ndvJ_U-DRjz7uYD.js +0 -1
- package/site/dist/assets/utils-BkR7EQjg.js +0 -1
- package/site/dist/assets/utils-DJhBNOZA.js +0 -1
- package/site/dist/assets/utils-DdckVfQr.js +0 -1
- package/site/dist/assets/w3m-modal-BeVrBOIf.js +0 -1174
- package/site/dist/assets/wallet-Bn85Sg2W.js +0 -1
- package/site/dist/assets/wallet-Bnzeiqed.js +0 -2
- package/site/dist/assets/wallet-connect-BvJtUsDt-Y03hhqFN.js +0 -1
- package/site/dist/assets/walletconnect-registry-xxG8XLCb-D1SSFvMp.js +0 -1
- package/site/dist/assets/walletconnect-v2-3frQFwbg-CrtLXofr.js +0 -12
- package/site/dist/assets/x-rlSp9U7W.js +0 -1
package/src/agent/mcp.js
CHANGED
|
@@ -1,50 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Every Fangorn app's
|
|
2
|
+
// Every Fangorn app's tools, behind one stdio MCP server.
|
|
3
3
|
//
|
|
4
|
-
// fangorn-mcp [--
|
|
4
|
+
// fangorn-mcp [--from-block <n>]
|
|
5
5
|
// claude mcp add fangorn -- fangorn-mcp
|
|
6
|
-
// claude mcp add fangorn -e FANGORN_MCP_CDP=ws://browser:9222 -- fangorn-mcp
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// server per app would mean one registration per app. Instead this server is
|
|
11
|
-
// the directory and the browser both:
|
|
7
|
+
// One MCP server for every app, so an agent registers once. It is a directory
|
|
8
|
+
// and a proxy:
|
|
12
9
|
//
|
|
13
10
|
// list-apps apps read off the chain (AppAgentChanged → verified cards)
|
|
14
|
-
// open-app verify one app's card
|
|
15
|
-
//
|
|
11
|
+
// open-app verify one app's card and add its tools to this server as
|
|
12
|
+
// `<app>__<tool>` (tools/list_changed)
|
|
16
13
|
// call-app-tool the same call by name, for clients that ignore list_changed
|
|
17
14
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
15
|
+
// An app's tools are its own MCP server's (the card's `mcp`, the app's Worker at
|
|
16
|
+
// /mcp), relayed. The Worker alone reads the app's lens from R2, so nothing is
|
|
17
|
+
// downloaded here and access is the app's to gate.
|
|
18
|
+
// A private app's paid tools answer with x402's PaymentRequired. With FANGORN_MCP_WALLET_KEY set,
|
|
19
|
+
// this server pays: a pass when the card sells one at or under FANGORN_MCP_MAX_PASS (USDC; unset,
|
|
20
|
+
// never), else that one call at or under FANGORN_MCP_MAX_PRICE (default 0.10). Without a wallet the
|
|
21
|
+
// price is handed back to the agent, to say to the person.
|
|
25
22
|
|
|
26
|
-
import { spawn } from "node:child_process";
|
|
27
|
-
import { mkdirSync, readFileSync, existsSync, rmSync, writeFileSync, renameSync } from "node:fs";
|
|
28
|
-
import { createHash } from "node:crypto";
|
|
29
23
|
import net from "node:net";
|
|
30
24
|
import { homedir } from "node:os";
|
|
31
25
|
import { createInterface } from "node:readline";
|
|
32
26
|
import { APP_EXTENSION, listApps, toApp } from "../discover/apps.js";
|
|
33
27
|
|
|
34
|
-
// The current AppRegistry's first event on Arbitrum Sepolia. A reader's
|
|
35
|
-
// default, not deployment config: pass --from-block for another deployment.
|
|
36
|
-
const DEFAULT_FROM_BLOCK = 311637349n;
|
|
37
28
|
const log = (...a) => console.error("[fangorn-mcp]", ...a); // stdout is the protocol
|
|
38
29
|
// FANGORN_MCP_TRACE=1: step timings on stderr, for finding where an answer waits.
|
|
39
30
|
const T0 = performance.now();
|
|
40
31
|
const trace = process.env.FANGORN_MCP_TRACE ? (what) => log(`${Math.round(performance.now() - T0)}ms ${what}`) : () => {};
|
|
41
32
|
|
|
33
|
+
// FANGORN_NETWORK: the SDK's network name ("baseSepolia"); unset, its default.
|
|
34
|
+
const network = async () => (await import("../publish/view.js")).network();
|
|
35
|
+
|
|
42
36
|
let client;
|
|
43
37
|
async function fangorn() {
|
|
44
38
|
if (!client) {
|
|
45
|
-
const [{ Fangorn
|
|
39
|
+
const [{ Fangorn }, { generatePrivateKey }] = await Promise.all([
|
|
46
40
|
import("@fangorn-network/sdk"), import("viem/accounts")]);
|
|
47
|
-
client = Fangorn.create({ privateKey: generatePrivateKey(), config:
|
|
41
|
+
client = Fangorn.create({ privateKey: generatePrivateKey(), config: await network() }); // reads only
|
|
48
42
|
// list-apps verifies every card and open-app verifies one again: once a minute is enough.
|
|
49
43
|
const verify = client.discoverApp.bind(client), seen = new Map();
|
|
50
44
|
client.discoverApp = (url) => {
|
|
@@ -58,62 +52,66 @@ async function fangorn() {
|
|
|
58
52
|
return client;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
|
-
/** A card URL →
|
|
62
|
-
* Fangorn extension) opens unverified: the caller asked for it by URL. */
|
|
55
|
+
/** A card URL → its app's MCP endpoint (the card's `mcp`), once the card verifies on chain. */
|
|
63
56
|
async function resolveCard(cardUrl) {
|
|
64
57
|
const card = await (await fetch(cardUrl)).json();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const page = new URL(card.url);
|
|
69
|
-
if (page.protocol !== "https:" && page.protocol !== "http:") throw new Error(`card.url is not http(s): ${card.url}`);
|
|
70
|
-
return { card, page: page.toString(), verified: fangornApp, views: app?.views ?? [], paid: app?.paid ?? null };
|
|
58
|
+
if (!card.capabilities?.extensions?.some((e) => e.uri === APP_EXTENSION)) throw new Error(`${cardUrl} is not a Fangorn app card`);
|
|
59
|
+
const { mcp } = toApp(await (await fangorn()).discoverApp(cardUrl), cardUrl);
|
|
60
|
+
return { card, mcp };
|
|
71
61
|
}
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
writeFileSync(`${f}.tmp`, b); renameSync(`${f}.tmp`, f);
|
|
91
|
-
return new Response(b);
|
|
92
|
-
});
|
|
93
|
-
if (existsSync(f)) { refresh.catch(() => {}); return new Response(readFileSync(f)); }
|
|
94
|
-
return refresh;
|
|
63
|
+
/** An app's own MCP server over streamable HTTP → `{ tools, call }`.
|
|
64
|
+
* The app's Worker is stateless (one JSON body per POST); a session id or an SSE
|
|
65
|
+
* reply from any other server is followed too. */
|
|
66
|
+
export async function remoteTools(url, fetcher = fetch, { access = null, wallet = process.env.FANGORN_MCP_WALLET_KEY,
|
|
67
|
+
maxCall = process.env.FANGORN_MCP_MAX_PRICE ?? "0.10", maxPass = process.env.FANGORN_MCP_MAX_PASS } = {}) {
|
|
68
|
+
let id = 0, session, bearer;
|
|
69
|
+
const rpc = async (method, params) => {
|
|
70
|
+
const r = await fetcher(url, { method: "POST", body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method, params }),
|
|
71
|
+
headers: { "content-type": "application/json", accept: "application/json, text/event-stream", ...(session && { "mcp-session-id": session }),
|
|
72
|
+
...(bearer && { authorization: `Bearer ${bearer}` }) } });
|
|
73
|
+
session ??= r.headers.get("mcp-session-id") ?? undefined;
|
|
74
|
+
let body = await r.text();
|
|
75
|
+
if (!r.ok) throw new Error(`${url}: HTTP ${r.status} ${body.slice(0, 200)}`);
|
|
76
|
+
if (r.headers.get("content-type")?.includes("text/event-stream")) body = body.split("\n").filter((l) => l.startsWith("data:")).pop()?.slice(5) ?? "";
|
|
77
|
+
const m = JSON.parse(body);
|
|
78
|
+
if (m.error) throw new Error(`${url}: ${m.error.message}`);
|
|
79
|
+
return m.result;
|
|
95
80
|
};
|
|
81
|
+
await rpc("initialize", { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "fangorn-mcp", version: "0.1.0" } });
|
|
82
|
+
const { tools } = await rpc("tools/list", {});
|
|
83
|
+
const usdc = (n) => BigInt(Math.round(Number(n) * 10 ** (access?.decimals ?? 6)));
|
|
84
|
+
const call = async (name, args) => {
|
|
85
|
+
const params = { name, arguments: args ?? {} };
|
|
86
|
+
const r = await rpc("tools/call", params);
|
|
87
|
+
const asked = r?.isError && r.structuredContent?.x402Version === 2 ? r.structuredContent : null;
|
|
88
|
+
if (!asked) return r;
|
|
89
|
+
if (!wallet) return { ...r, content: [...r.content, { type: "text", text: "This server has no wallet (FANGORN_MCP_WALLET_KEY), so nothing was paid: tell the person the price." }] };
|
|
90
|
+
const x = await import("./x402.js");
|
|
91
|
+
const account = (await import("viem/accounts")).privateKeyToAccount(`0x${wallet.trim().replace(/^0x/i, "")}`); // a key file may lack 0x
|
|
92
|
+
if (access && maxPass != null && BigInt(access.pass) <= usdc(maxPass)) {
|
|
93
|
+
bearer = (await x.buyPass(access, { account, fetchImpl: fetcher })).token;
|
|
94
|
+
return rpc("tools/call", params);
|
|
95
|
+
}
|
|
96
|
+
const payment = await x.signPayment(x.choose(asked.accepts, { maxPrice: usdc(maxCall) }), account, { resource: asked.resource });
|
|
97
|
+
return rpc("tools/call", { ...params, _meta: { "x402/payment": payment } });
|
|
98
|
+
};
|
|
99
|
+
return { tools, call };
|
|
96
100
|
}
|
|
97
101
|
|
|
102
|
+
// ── the network ─────────────────────────────────────────────────────────────
|
|
103
|
+
// Catalogs, manifests and cards change on a rebake: held for a minute, so one
|
|
104
|
+
// search (or resolving then verifying a card) does not fetch each twice.
|
|
105
|
+
const CACHE = `${homedir()}/.cache/fangorn-mcp`; // the embedding model, for find-apps
|
|
98
106
|
function cachingFetch(real = globalThis.fetch) {
|
|
99
|
-
mkdirSync(`${CACHE}/blobs`, { recursive: true });
|
|
100
107
|
const memo = new Map();
|
|
101
108
|
return async (input, init) => {
|
|
102
109
|
const url = String(input?.url ?? input);
|
|
103
110
|
if ((init?.method ?? input?.method ?? "GET") !== "GET" || !/^https?:/.test(url)) return real(input, init);
|
|
104
111
|
const path = new URL(url).pathname;
|
|
105
|
-
if (/-[0-9a-f]{12}\.[a-z.]+$/.test(path)) {
|
|
106
|
-
const f = `${CACHE}/blobs/${createHash("sha256").update(url).digest("hex")}`;
|
|
107
|
-
if (existsSync(f)) return new Response(readFileSync(f));
|
|
108
|
-
const r = await real(input, init);
|
|
109
|
-
if (!r.ok) return r;
|
|
110
|
-
const b = new Uint8Array(await r.arrayBuffer());
|
|
111
|
-
writeFileSync(`${f}.tmp`, b); renameSync(`${f}.tmp`, f); // never a torn file
|
|
112
|
-
return new Response(b, { headers: r.headers });
|
|
113
|
-
}
|
|
114
112
|
// A card, catalog or manifest is small: 8s without one means the host is
|
|
115
113
|
// down, and a dead card in the directory must not stall a listing for a
|
|
116
|
-
// TCP timeout.
|
|
114
|
+
// TCP timeout.
|
|
117
115
|
init = { ...init, signal: init?.signal ?? AbortSignal.timeout(8000) };
|
|
118
116
|
if (/\/cdn\/catalog$|\/manifest$|\/agent-card\.json$/.test(path)) {
|
|
119
117
|
const hit = memo.get(url);
|
|
@@ -128,140 +126,6 @@ function cachingFetch(real = globalThis.fetch) {
|
|
|
128
126
|
};
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
// ── the browser ─────────────────────────────────────────────────────────────
|
|
132
|
-
// Anything that speaks the Chrome DevTools Protocol and has WebMCP: a headless
|
|
133
|
-
// Chromium service, a hosted browser, or the local Chrome. `--cdp` (or
|
|
134
|
-
// FANGORN_MCP_CDP) names it as http(s)://host:port or a ws(s):// browser
|
|
135
|
-
// endpoint. Without it, a local Chrome is reused if one is already serving
|
|
136
|
-
// this profile (another session's), else launched.
|
|
137
|
-
//
|
|
138
|
-
// Everything goes over the one browser-level WebSocket (Target.* plus flat
|
|
139
|
-
// sessions). That is the endpoint every CDP host exposes, where the per-tab
|
|
140
|
-
// /json HTTP routes are not.
|
|
141
|
-
|
|
142
|
-
const PROFILE = `${homedir()}/.cache/westmarch-mcp`;
|
|
143
|
-
|
|
144
|
-
/** An http(s) DevTools address → its browser WebSocket, reached via the host we were given. */
|
|
145
|
-
async function browserWs(http) {
|
|
146
|
-
const v = await (await fetch(new URL("/json/version", http), { signal: AbortSignal.timeout(3000) })).json();
|
|
147
|
-
const ws = new URL(v.webSocketDebuggerUrl), base = new URL(http);
|
|
148
|
-
ws.host = base.host; // the service reports its own view of itself
|
|
149
|
-
if (base.protocol === "https:") ws.protocol = "wss:";
|
|
150
|
-
return ws.toString();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async function localChrome({ headed }) {
|
|
154
|
-
mkdirSync(PROFILE, { recursive: true });
|
|
155
|
-
const portFile = `${PROFILE}/DevToolsActivePort`;
|
|
156
|
-
if (existsSync(portFile)) {
|
|
157
|
-
const ws = await browserWs(`http://127.0.0.1:${readFileSync(portFile, "utf-8").split("\n")[0]}`).catch(() => null);
|
|
158
|
-
if (ws) { log("reusing the Chrome already serving this profile"); return { ws }; }
|
|
159
|
-
rmSync(portFile, { force: true }); // stale: that Chrome is gone
|
|
160
|
-
}
|
|
161
|
-
const bin = process.env.CHROME ?? "google-chrome";
|
|
162
|
-
const proc = spawn(bin, [
|
|
163
|
-
...(headed ? [] : ["--headless=new"]),
|
|
164
|
-
"--enable-features=WebMCP", "--remote-debugging-port=0", "--no-first-run",
|
|
165
|
-
"--no-default-browser-check", `--user-data-dir=${PROFILE}`, "about:blank",
|
|
166
|
-
], { stdio: "ignore" });
|
|
167
|
-
const failed = new Promise((_, j) => proc.on("error", (e) => j(new Error(
|
|
168
|
-
`no browser: cannot launch ${bin} (${e.code}). Point --cdp / FANGORN_MCP_CDP at a WebMCP browser, or set CHROME.`))));
|
|
169
|
-
// 30s: a cold start on a loaded machine or CI box has taken 16s.
|
|
170
|
-
for (let i = 0; i < 300; i++) {
|
|
171
|
-
await Promise.race([new Promise((r) => setTimeout(r, 100)), failed]);
|
|
172
|
-
if (existsSync(portFile)) return { ws: await browserWs(`http://127.0.0.1:${readFileSync(portFile, "utf-8").split("\n")[0]}`), proc };
|
|
173
|
-
}
|
|
174
|
-
proc.kill();
|
|
175
|
-
throw new Error(`${bin} did not start`);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
let conn;
|
|
179
|
-
/** The browser connection, opened once and reopened after it drops. */
|
|
180
|
-
function browser(opts) {
|
|
181
|
-
return conn ??= (async () => {
|
|
182
|
-
const { cdp } = opts;
|
|
183
|
-
const { ws: url, proc } = !cdp ? await localChrome(opts)
|
|
184
|
-
: /^wss?:/.test(cdp) ? { ws: cdp } : { ws: await browserWs(cdp) };
|
|
185
|
-
const ws = new WebSocket(url);
|
|
186
|
-
await new Promise((r, j) => { ws.onopen = r; ws.onerror = () => j(new Error(`cannot connect to the browser at ${url}`)); });
|
|
187
|
-
let id = 0; const pending = new Map(), dead = new Set();
|
|
188
|
-
ws.onmessage = (m) => {
|
|
189
|
-
const d = JSON.parse(m.data);
|
|
190
|
-
if (d.method === "Target.detachedFromTarget") dead.add(d.params.sessionId);
|
|
191
|
-
if (d.id !== undefined) { pending.get(d.id)?.(d); pending.delete(d.id); }
|
|
192
|
-
};
|
|
193
|
-
ws.onclose = () => { conn = null; for (const r of pending.values()) r({ error: { message: "browser connection closed" } }); };
|
|
194
|
-
const send = (method, params = {}, sessionId) => new Promise((res, rej) => {
|
|
195
|
-
if (ws.readyState !== WebSocket.OPEN) return rej(new Error("browser connection closed"));
|
|
196
|
-
pending.set(++id, (d) => (d.error ? rej(new Error(d.error.message)) : res(d.result)));
|
|
197
|
-
ws.send(JSON.stringify({ id, method, params, ...(sessionId && { sessionId }) }));
|
|
198
|
-
});
|
|
199
|
-
const tabs = new Set();
|
|
200
|
-
// Close what we opened. A shared or remote browser outlives this process.
|
|
201
|
-
const bye = async () => {
|
|
202
|
-
await Promise.race([Promise.all([...tabs].map((t) => send("Target.closeTarget", { targetId: t }).catch(() => {}))),
|
|
203
|
-
new Promise((r) => setTimeout(r, 500))]);
|
|
204
|
-
// A local Chrome may be serving another session: leave it running
|
|
205
|
-
// while anyone else has a tab open; the last one out closes it.
|
|
206
|
-
const others = await Promise.race([send("Target.getTargets").then((r) => r.targetInfos.filter((t) => t.type === "page" && t.url !== "about:blank").length).catch(() => 0),
|
|
207
|
-
new Promise((r) => setTimeout(() => r(0), 500))]);
|
|
208
|
-
// Never a --cdp browser: that one is somebody's service.
|
|
209
|
-
if (!cdp && !others) await Promise.race([send("Browser.close").catch(() => {}), new Promise((r) => setTimeout(r, 500))]);
|
|
210
|
-
proc?.kill();
|
|
211
|
-
process.exit(0);
|
|
212
|
-
};
|
|
213
|
-
process.once("SIGINT", bye); process.once("SIGTERM", bye); process.stdin.once("end", bye);
|
|
214
|
-
log(`browser: ${cdp ?? (proc ? "launched local Chrome" : "local Chrome")}`);
|
|
215
|
-
return { send, dead, tabs };
|
|
216
|
-
})().catch((e) => { conn = null; throw e; });
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** A new tab on `page`; returns `ev(expr)`, which evaluates in it. */
|
|
220
|
-
async function openTab(page, opts) {
|
|
221
|
-
const { send, dead, tabs } = await browser(opts);
|
|
222
|
-
const { targetId } = await send("Target.createTarget", { url: page });
|
|
223
|
-
tabs.add(targetId);
|
|
224
|
-
const { sessionId } = await send("Target.attachToTarget", { targetId, flatten: true });
|
|
225
|
-
return async (expression) => {
|
|
226
|
-
if (dead.has(sessionId)) throw new Error(`tab closed: ${page}`);
|
|
227
|
-
const r = await send("Runtime.evaluate", { expression, awaitPromise: true, returnByValue: true }, sessionId)
|
|
228
|
-
.catch((e) => { throw new Error(`tab closed: ${page} (${e.message})`); });
|
|
229
|
-
if (r.exceptionDetails) throw new Error(r.exceptionDetails.exception?.description ?? r.exceptionDetails.text);
|
|
230
|
-
return r.result.value;
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/** The tab's tools in MCP's shape. Waits for the page to register them. */
|
|
235
|
-
async function tabTools(ev) {
|
|
236
|
-
let hasWebMCP = false;
|
|
237
|
-
for (let i = 0; i < 150; i++) {
|
|
238
|
-
const got = await ev(`(async () => {
|
|
239
|
-
const mc = document.modelContext;
|
|
240
|
-
if (!mc?.getTools) return { webmcp: false, loaded: location.protocol.startsWith("http") && document.readyState === "complete" };
|
|
241
|
-
return { webmcp: true, tools: (await mc.getTools()).map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })) };
|
|
242
|
-
})()`).catch(() => null);
|
|
243
|
-
hasWebMCP ||= !!got?.webmcp;
|
|
244
|
-
// modelContext is there from the first script or never; no need to wait out the page.
|
|
245
|
-
if (got && !got.webmcp && got.loaded) break;
|
|
246
|
-
if (got?.tools?.length) return got.tools.map((t) => ({ ...t, inputSchema: t.inputSchema ? JSON.parse(t.inputSchema) : { type: "object" } }));
|
|
247
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
248
|
-
}
|
|
249
|
-
throw new Error(hasWebMCP
|
|
250
|
-
? "the page registered no WebMCP tools in 30s (is card.url the page that registers them?)"
|
|
251
|
-
: "this browser has no WebMCP (document.modelContext.getTools): it needs Chrome 150+ with --enable-features=WebMCP, or a Chromium built with it");
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/** One call, relayed. WebMCP takes the arguments as a JSON string and returns one. */
|
|
255
|
-
async function tabCall(ev, name, args) {
|
|
256
|
-
const out = await ev(`document.modelContext.getTools().then((ts) => {
|
|
257
|
-
const t = ts.find((t) => t.name === ${JSON.stringify(name)});
|
|
258
|
-
if (!t) throw new Error("no tool " + ${JSON.stringify(name)});
|
|
259
|
-
return document.modelContext.executeTool(t, ${JSON.stringify(JSON.stringify(args ?? {}))});
|
|
260
|
-
})`);
|
|
261
|
-
try { const r = JSON.parse(out); if (Array.isArray(r?.content)) return r; } catch {}
|
|
262
|
-
return { content: [{ type: "text", text: String(out) }] };
|
|
263
|
-
}
|
|
264
|
-
|
|
265
129
|
/** JSON-RPC over newline-delimited stdio. Returns `notify` for server → client messages. */
|
|
266
130
|
export function serve(handlers, { input = process.stdin, output = process.stdout } = {}) {
|
|
267
131
|
const send = (m) => output.write(JSON.stringify({ jsonrpc: "2.0", ...m }) + "\n");
|
|
@@ -282,7 +146,7 @@ const slug = (name) => String(name).toLowerCase().replace(/[^a-z0-9-]+/g, "-").r
|
|
|
282
146
|
|
|
283
147
|
const META = [
|
|
284
148
|
{ name: "list-apps",
|
|
285
|
-
description: "List the Fangorn apps registered on chain whose agent cards verify: name, description, card URL, and
|
|
149
|
+
description: "List the Fangorn apps registered on chain whose agent cards verify: name, description, card URL, and its appId. Filter with `query`. Call open-app on one to use its tools.",
|
|
286
150
|
inputSchema: { type: "object", properties: { query: { type: "string", description: "Case-insensitive match on name or description" } } } },
|
|
287
151
|
{ name: "find-apps",
|
|
288
152
|
description: "Find Fangorn apps for a question, ranked by what their data is about (e.g. \"where can I learn about weather?\", \"music\"). Each app carries its site, agent card, ERC-8004 agent with an 8004scan link, ERC-8004 reputation (feedback count and average), record count and bound block. Only apps whose cards verify on chain. `relevant: true` marks the ones worth opening; the rest are sorted, not relevant. With no query, lists every app. Then open-app.",
|
|
@@ -290,8 +154,8 @@ const META = [
|
|
|
290
154
|
query: { type: "string", description: "What the person is looking for, in their words" },
|
|
291
155
|
limit: { type: "integer", minimum: 1, maximum: 50, default: 10 } } } },
|
|
292
156
|
{ name: "open-app",
|
|
293
|
-
description: "Verify an app's card against the chain and add its tools to this server as `<app>__<tool>`.
|
|
294
|
-
inputSchema: { type: "object", properties: { app: { type: "string" }
|
|
157
|
+
description: "Verify an app's card against the chain and add its tools to this server as `<app>__<tool>`. The tools are the app's own MCP server's (typically describe, search, get, similar, count, browse). `app` is a name from list-apps, an appId, or a card URL.",
|
|
158
|
+
inputSchema: { type: "object", properties: { app: { type: "string" } }, required: ["app"] } },
|
|
295
159
|
{ name: "call-app-tool",
|
|
296
160
|
description: "Call one tool of an opened app. Same as calling `<app>__<tool>` directly.",
|
|
297
161
|
inputSchema: { type: "object", properties: { app: { type: "string" }, tool: { type: "string" }, arguments: { type: "object" } }, required: ["app", "tool"] } },
|
|
@@ -302,52 +166,34 @@ const META = [
|
|
|
302
166
|
* findApps() → { apps: [{ name, desc, card, appId }], rejected }
|
|
303
167
|
* exploreApps(query) → { apps: ranked explore.js entries, ranked_by }
|
|
304
168
|
* findByName(name) → { card, appId } | null (optional: a direct registry read)
|
|
305
|
-
* resolveCard(url) → { card,
|
|
306
|
-
*
|
|
307
|
-
* openTab(page) → ev
|
|
308
|
-
* tabTools(ev), tabCall(ev, name, args)
|
|
169
|
+
* resolveCard(url) → { card, mcp }
|
|
170
|
+
* remoteTools(url) → { tools, call(name, args) } (the app's own MCP server)
|
|
309
171
|
* notify(method) set after serve()
|
|
310
172
|
*/
|
|
311
173
|
export function handlers(deps) {
|
|
312
|
-
const open = new Map(); // slug → { name, card,
|
|
174
|
+
const open = new Map(); // slug → { slug, name, card, appId, tools, call }
|
|
313
175
|
|
|
314
176
|
const findOpen = (app) => open.get(slug(app)) ?? [...open.values()].find((o) => o.card === app || o.appId === app);
|
|
315
|
-
const retool = (o) => {
|
|
316
|
-
const taken = new Set(o.views?.tools.map((t) => t.name));
|
|
317
|
-
// A page tool that shares a data tool's name is kept, under `page-<name>`.
|
|
318
|
-
o.pageNames = new Map((o.pageTools ?? []).map((t) => [taken.has(t.name) ? `page-${t.name}` : t.name, t.name]));
|
|
319
|
-
o.tools = [...(o.views?.tools ?? []), ...(o.pageTools ?? []).map((t) => ({ ...t, name: taken.has(t.name) ? `page-${t.name}` : t.name }))];
|
|
320
|
-
};
|
|
321
|
-
async function openPage(o) {
|
|
322
|
-
o.ev = await deps.openTab(o.page);
|
|
323
|
-
o.pageTools = await deps.tabTools(o.ev);
|
|
324
|
-
}
|
|
325
177
|
|
|
326
|
-
async function openApp(app
|
|
178
|
+
async function openApp(app) {
|
|
327
179
|
const hit = findOpen(app);
|
|
328
|
-
if (hit
|
|
329
|
-
let
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (!a) throw new Error(`no verified app named ${JSON.stringify(app)}; see list-apps`);
|
|
338
|
-
({ card: cardUrl, appId } = a);
|
|
339
|
-
}
|
|
340
|
-
trace(`open ${app}: resolve ${cardUrl}`);
|
|
341
|
-
const { card, page: url, verified, views, paid } = await deps.resolveCard(cardUrl);
|
|
342
|
-
trace(`open ${app}: verified`);
|
|
343
|
-
let s = slug(card.name ?? app);
|
|
344
|
-
while (open.has(s)) s += "-";
|
|
345
|
-
o = { slug: s, name: card.name, card: cardUrl, appId, verified, page: url,
|
|
346
|
-
views: deps.viewTools?.({ name: card.name, desc: card.description, views, paid }) ?? null };
|
|
180
|
+
if (hit) return hit;
|
|
181
|
+
let cardUrl = app, appId;
|
|
182
|
+
if (!/^https?:\/\//.test(app)) {
|
|
183
|
+
// One registry read when the name is the app's own; the scan only when it is not.
|
|
184
|
+
trace(`open ${app}: lookup`);
|
|
185
|
+
const a = await deps.findByName?.(app)
|
|
186
|
+
?? (await deps.findApps()).apps.find((x) => x.appId === app || slug(x.name) === slug(app));
|
|
187
|
+
if (!a) throw new Error(`no verified app named ${JSON.stringify(app)}; see list-apps`);
|
|
188
|
+
({ card: cardUrl, appId } = a);
|
|
347
189
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
190
|
+
trace(`open ${app}: resolve ${cardUrl}`);
|
|
191
|
+
const { card, mcp } = await deps.resolveCard(cardUrl);
|
|
192
|
+
if (!mcp) throw new Error(`${card.name ?? cardUrl} has no MCP server (its card has no \`mcp\`)`);
|
|
193
|
+
let s = slug(card.name ?? app);
|
|
194
|
+
while (open.has(s)) s += "-";
|
|
195
|
+
const access = card.capabilities?.extensions?.find((e) => e.uri === APP_EXTENSION)?.params?.access ?? null;
|
|
196
|
+
const o = { slug: s, name: card.name, card: cardUrl, appId, ...await deps.remoteTools(mcp, { access }) };
|
|
351
197
|
trace(`open ${app}: ready`);
|
|
352
198
|
open.set(o.slug, o);
|
|
353
199
|
deps.notify?.("notifications/tools/list_changed");
|
|
@@ -357,18 +203,8 @@ export function handlers(deps) {
|
|
|
357
203
|
async function call(app, tool, args) {
|
|
358
204
|
const o = findOpen(app);
|
|
359
205
|
if (!o) throw new Error(`${app} is not open; call open-app first`);
|
|
360
|
-
if (!o.
|
|
361
|
-
|
|
362
|
-
throw new Error(`${o.slug} has no tool ${tool}${o.ev ? "" : " (its page tools load with open-app page: true)"}`);
|
|
363
|
-
}
|
|
364
|
-
const name = o.pageNames.get(tool);
|
|
365
|
-
try { return await deps.tabCall(o.ev, name, args); }
|
|
366
|
-
catch (e) {
|
|
367
|
-
if (!/tab closed/.test(e.message)) throw e;
|
|
368
|
-
// The tab or the whole browser went away. Reopen once; the tools keep their names.
|
|
369
|
-
await openPage(o);
|
|
370
|
-
return deps.tabCall(o.ev, name, args);
|
|
371
|
-
}
|
|
206
|
+
if (!o.tools.some((t) => t.name === tool)) throw new Error(`${o.slug} has no tool ${tool}`);
|
|
207
|
+
return o.call(tool, args);
|
|
372
208
|
}
|
|
373
209
|
|
|
374
210
|
const run = {
|
|
@@ -378,7 +214,7 @@ export function handlers(deps) {
|
|
|
378
214
|
return text({
|
|
379
215
|
apps: apps.filter((a) => !q || `${a.name} ${a.desc}`.toLowerCase().includes(q)).map((a) => ({
|
|
380
216
|
app: slug(a.name), name: a.name, description: a.desc, card: a.card, appId: a.appId,
|
|
381
|
-
|
|
217
|
+
open: open.has(slug(a.name)),
|
|
382
218
|
})),
|
|
383
219
|
unverified: rejected.length,
|
|
384
220
|
});
|
|
@@ -388,10 +224,9 @@ export function handlers(deps) {
|
|
|
388
224
|
return text({ query: query ?? null, ranked_by, apps: apps.slice(0, Math.min(50, Math.max(1, limit)))
|
|
389
225
|
.map((a) => ({ ...a, open: open.has(a.app) })) });
|
|
390
226
|
},
|
|
391
|
-
"open-app": async ({ app
|
|
392
|
-
const o = await openApp(app
|
|
393
|
-
return text({ app: o.slug, name: o.name,
|
|
394
|
-
data_tools: !!o.views, page_tools: o.ev ? o.page : false,
|
|
227
|
+
"open-app": async ({ app }) => {
|
|
228
|
+
const o = await openApp(app);
|
|
229
|
+
return text({ app: o.slug, name: o.name, card: o.card,
|
|
395
230
|
call_as: `${o.slug}__<tool>, or call-app-tool`, tools: o.tools });
|
|
396
231
|
},
|
|
397
232
|
"call-app-tool": async ({ app, tool, arguments: args }) => call(app, tool, args),
|
|
@@ -402,7 +237,7 @@ export function handlers(deps) {
|
|
|
402
237
|
protocolVersion: p.protocolVersion ?? "2025-06-18",
|
|
403
238
|
capabilities: { tools: { listChanged: true } },
|
|
404
239
|
serverInfo: { name: "fangorn-mcp", version: "0.1.0" },
|
|
405
|
-
instructions: "Fangorn apps are
|
|
240
|
+
instructions: "Fangorn apps are anchored on chain and each serves its own MCP. list-apps to find one, open-app to load it, then call its tools as <app>__<tool>. Start with <app>__describe when it exists.",
|
|
406
241
|
}),
|
|
407
242
|
ping: async () => ({}),
|
|
408
243
|
"tools/list": async () => ({ tools: [
|
|
@@ -427,15 +262,22 @@ if (process.argv[2] === "--selfcheck") {
|
|
|
427
262
|
const input = new PassThrough(), output = new PassThrough();
|
|
428
263
|
const replies = [];
|
|
429
264
|
createInterface({ input: output }).on("line", (l) => replies.push(JSON.parse(l)));
|
|
265
|
+
const posts = [];
|
|
266
|
+
// The app's Worker: initialize, tools/list, tools/call over JSON-RPC POSTs.
|
|
267
|
+
const remote = await remoteTools("https://k.test/mcp", async (url, init) => {
|
|
268
|
+
const m = JSON.parse(init.body);
|
|
269
|
+
posts.push(m.method);
|
|
270
|
+
const result = m.method === "tools/list" ? { tools: [{ name: "search" }] }
|
|
271
|
+
: m.method === "tools/call" ? text({ via: "remote", ...m.params }) : {};
|
|
272
|
+
return new Response(JSON.stringify({ jsonrpc: "2.0", id: m.id, result }), { headers: { "content-type": "application/json" } });
|
|
273
|
+
});
|
|
430
274
|
let opened = 0;
|
|
431
275
|
const deps = {
|
|
432
|
-
findApps: async () => ({ apps: [{ name: "Kings Foil", desc: "trials", card: "https://k.test/card", appId: "0xk"
|
|
276
|
+
findApps: async () => ({ apps: [{ name: "Kings Foil", desc: "trials", card: "https://k.test/card", appId: "0xk" },
|
|
277
|
+
{ name: "Bare", desc: "", card: "https://b.test/card", appId: "0xb" }], rejected: [{}] }),
|
|
433
278
|
exploreApps: async (q) => ({ ranked_by: q ? "meaning" : null, apps: [{ app: "kings-foil", name: "Kings Foil", relevant: true }, { app: "b", name: "B", relevant: false }] }),
|
|
434
|
-
resolveCard: async () => ({ card: { name: "Kings Foil" },
|
|
435
|
-
|
|
436
|
-
tabTools: async () => [{ name: "greet", description: "Hi.", inputSchema: { type: "object" } }],
|
|
437
|
-
tabCall: async (ev, name, args) => (name === "boom" ? Promise.reject(new Error("no tool boom"))
|
|
438
|
-
: ev === "dead" ? Promise.reject(new Error("tab closed: x")) : text({ ev, name, args })),
|
|
279
|
+
resolveCard: async (url) => (url.includes("b.test") ? { card: { name: "Bare" }, mcp: null } : { card: { name: "Kings Foil" }, mcp: "https://k.test/mcp" }),
|
|
280
|
+
remoteTools: async () => (opened++, remote),
|
|
439
281
|
};
|
|
440
282
|
deps.notify = serve(handlers(deps), { input, output });
|
|
441
283
|
const rpc = (id, method, params) => input.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
@@ -445,10 +287,10 @@ if (process.argv[2] === "--selfcheck") {
|
|
|
445
287
|
const body = (id) => JSON.parse(res(id).result.content[0].text);
|
|
446
288
|
const assert = (c, m) => { if (!c) throw new Error(m); };
|
|
447
289
|
|
|
448
|
-
rpc(1, "initialize", {}); rpc(2, "tools/list"); call(3, "list-apps", { query: "TRIAL" }); call(4, "kings-
|
|
290
|
+
rpc(1, "initialize", {}); rpc(2, "tools/list"); call(3, "list-apps", { query: "TRIAL" }); call(4, "kings-foil__search"); await wait();
|
|
449
291
|
assert(res(1).result.capabilities.tools.listChanged, "advertises list_changed");
|
|
450
292
|
assert(res(2).result.tools.length === 4, "only the meta tools before anything is open");
|
|
451
|
-
assert(body(3).apps[0].app === "kings-foil" && body(3).unverified === 1, "list-apps filters and slugs");
|
|
293
|
+
assert(body(3).apps.length === 1 && body(3).apps[0].app === "kings-foil" && body(3).unverified === 1, "list-apps filters and slugs");
|
|
452
294
|
assert(res(4).result.isError && /not open/.test(res(4).result.content[0].text), "an unopened app's tool is an error");
|
|
453
295
|
|
|
454
296
|
call(30, "find-apps", { query: "trials", limit: 1 }); await wait();
|
|
@@ -456,40 +298,44 @@ if (process.argv[2] === "--selfcheck") {
|
|
|
456
298
|
|
|
457
299
|
call(5, "open-app", { app: "Kings Foil" }); await wait();
|
|
458
300
|
call(6, "open-app", { app: "https://k.test/card" }); await wait();
|
|
459
|
-
assert(body(5).tools[0].name === "
|
|
460
|
-
call(50, "kings-foil__greet", { who: "b" }); await wait();
|
|
461
|
-
assert(body(50).ev === "ev" && opened === 2, "a dead tab is reopened and the call retried");
|
|
301
|
+
assert(body(5).tools[0].name === "search" && opened === 1, "open once, by name or by card URL");
|
|
462
302
|
assert(replies.some((r) => r.method === "notifications/tools/list_changed"), "opening notifies");
|
|
463
|
-
rpc(7, "tools/list"); call(8, "kings-
|
|
464
|
-
call(10, "call-app-tool", { app: "kings-foil", tool: "boom" }); call(11, "open-app", { app: "nope" }); rpc(12, "nope"); await wait();
|
|
465
|
-
assert(res(7).result.tools.some((t) => t.name === "kings-
|
|
466
|
-
assert(body(8).
|
|
303
|
+
rpc(7, "tools/list"); call(8, "kings-foil__search", { query: "x" }); call(9, "call-app-tool", { app: "kings-foil", tool: "search" });
|
|
304
|
+
call(10, "call-app-tool", { app: "kings-foil", tool: "boom" }); call(11, "open-app", { app: "nope" }); call(13, "open-app", { app: "Bare" }); rpc(12, "nope"); await wait();
|
|
305
|
+
assert(res(7).result.tools.some((t) => t.name === "kings-foil__search"), "opened tools are listed under the app");
|
|
306
|
+
assert(body(8).via === "remote" && body(8).arguments.query === "x" && body(9).name === "search", "both call paths reach the app's server");
|
|
307
|
+
assert(posts.join() === "initialize,tools/list,tools/call,tools/call", `initialize, list, then calls: ${posts}`);
|
|
467
308
|
assert(res(10).result.isError && res(11).result.isError, "failures are tool errors");
|
|
309
|
+
assert(res(13).result.isError && /no MCP server/.test(res(13).result.content[0].text), "an app without `mcp` cannot open");
|
|
468
310
|
assert(res(12).error.code === -32601, "unknown method");
|
|
469
|
-
|
|
470
|
-
//
|
|
471
|
-
{
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
492
|
-
|
|
311
|
+
// A private app: a paid tool answers with PaymentRequired; with a wallet this server pays the
|
|
312
|
+
// call (under FANGORN_MCP_MAX_PRICE), or buys a pass when the card sells one under FANGORN_MCP_MAX_PASS.
|
|
313
|
+
const { generatePrivateKey } = await import("viem/accounts");
|
|
314
|
+
const req = { scheme: "exact", network: "eip155:84532", amount: "10000", asset: `0x${"aa".repeat(20)}`, payTo: `0x${"5e".repeat(20)}`,
|
|
315
|
+
maxTimeoutSeconds: 120, extra: { name: "USDC", version: "2" } };
|
|
316
|
+
const asked = { x402Version: 2, error: "paid", resource: { url: "https://p.test/mcp" }, accepts: [req] };
|
|
317
|
+
const seen = [];
|
|
318
|
+
const paidServer = async (url, init) => {
|
|
319
|
+
if (url === "https://p.test/pass") {
|
|
320
|
+
if (!init.headers?.["PAYMENT-SIGNATURE"]) return new Response("{}", { status: 402, headers: { "PAYMENT-REQUIRED": btoa(JSON.stringify({ ...asked, accepts: [{ ...req, amount: "2000000" }] })) } });
|
|
321
|
+
return new Response(JSON.stringify({ token: "pass.tok", expires: 9e9 }));
|
|
322
|
+
}
|
|
323
|
+
const m = JSON.parse(init.body);
|
|
324
|
+
const paid = m.params?._meta?.["x402/payment"], pass = init.headers.authorization === "Bearer pass.tok";
|
|
325
|
+
if (m.method === "tools/call") seen.push(pass ? "pass" : paid ? `paid ${paid.accepted.amount}` : "asked");
|
|
326
|
+
const result = m.method === "tools/list" ? { tools: [{ name: "search" }] } : m.method !== "tools/call" ? {}
|
|
327
|
+
: paid || pass ? text({ hits: [1] }) : { isError: true, structuredContent: asked, content: [{ type: "text", text: JSON.stringify(asked) }] };
|
|
328
|
+
return new Response(JSON.stringify({ jsonrpc: "2.0", id: m.id, result }), { headers: { "content-type": "application/json" } });
|
|
329
|
+
};
|
|
330
|
+
const broke = await remoteTools("https://p.test/mcp", paidServer, { wallet: undefined });
|
|
331
|
+
if (!(await broke.call("search", {})).content.at(-1).text.includes("no wallet")) throw new Error("no wallet: the price goes back to the agent");
|
|
332
|
+
const access = { pass_url: "https://p.test/pass", pass: "2000000", call: "10000", decimals: 6 };
|
|
333
|
+
const perCall = await remoteTools("https://p.test/mcp", paidServer, { access, wallet: generatePrivateKey(), maxCall: "0.05" });
|
|
334
|
+
if (JSON.parse((await perCall.call("search", {})).content[0].text).hits[0] !== 1) throw new Error("a paid call");
|
|
335
|
+
const passer = await remoteTools("https://p.test/mcp", paidServer, { access, wallet: generatePrivateKey(), maxPass: "5" });
|
|
336
|
+
await passer.call("search", {}); await passer.call("search", {});
|
|
337
|
+
if (seen.join() !== "asked,asked,paid 10000,asked,pass,pass") throw new Error(`payments: ${seen}`);
|
|
338
|
+
console.log("mcp.js self-check ok — one server, apps opened on demand, calls relayed to each app's own MCP server; a private app's tools paid per call or with a pass bought once, and with no wallet the price is handed back");
|
|
493
339
|
process.exit(0);
|
|
494
340
|
}
|
|
495
341
|
|
|
@@ -499,22 +345,16 @@ globalThis.fetch = cachingFetch();
|
|
|
499
345
|
// host with no working IPv6, every attempt times out and fetch fails outright.
|
|
500
346
|
net.setDefaultAutoSelectFamilyAttemptTimeout?.(2000);
|
|
501
347
|
const vt = await import("./view-tools.js");
|
|
502
|
-
const stale = staleFetch(globalThis.fetch);
|
|
503
348
|
const fb = argv.indexOf("--from-block");
|
|
504
|
-
|
|
505
|
-
const
|
|
506
|
-
const ci = argv.indexOf("--cdp");
|
|
507
|
-
const cdp = ci >= 0 ? argv[ci + 1] : process.env.FANGORN_MCP_CDP || undefined;
|
|
349
|
+
// The SDK's deployment by default: pass --from-block for another one.
|
|
350
|
+
const fromBlock = fb >= 0 ? BigInt(argv[fb + 1]) : (await network()).appRegistryFromBlock;
|
|
508
351
|
let found, foundAt = 0, explored, exploredAt = 0;
|
|
509
352
|
const deps = {
|
|
510
353
|
// ponytail: cached for a minute. The scan is a few RPC calls plus a fetch per card.
|
|
511
354
|
findApps: async () => {
|
|
512
355
|
if (!found || Date.now() - foundAt > 60_000) {
|
|
513
356
|
const { apps, rejected } = await listApps(await fangorn(), { fromBlock });
|
|
514
|
-
found = {
|
|
515
|
-
const card = await (await fetch(a.card)).json().catch(() => ({}));
|
|
516
|
-
return { ...a, tools: card.skills?.filter((s) => s.tags?.includes("webmcp")).map((s) => s.id) ?? [] };
|
|
517
|
-
})) };
|
|
357
|
+
found = { apps, rejected };
|
|
518
358
|
foundAt = Date.now();
|
|
519
359
|
}
|
|
520
360
|
return found;
|
|
@@ -522,8 +362,8 @@ const deps = {
|
|
|
522
362
|
// ponytail: cached for a minute, like findApps. Two getLogs, a card and catalog per app.
|
|
523
363
|
exploreApps: async (query) => {
|
|
524
364
|
if (!explored || Date.now() - exploredAt > 60_000) {
|
|
525
|
-
const [ex, { createPublicClient, http },
|
|
526
|
-
explored = { ex, dir: await ex.readDirectory(createPublicClient({ chain:
|
|
365
|
+
const [ex, { createPublicClient, http }, net] = await Promise.all([import("../discover/explore.js"), import("viem"), network()]);
|
|
366
|
+
explored = { ex, dir: await ex.readDirectory(createPublicClient({ chain: net.chain, transport: http(net.rpcUrl) }), { chain: ex.chainOf(net) }) };
|
|
527
367
|
exploredAt = Date.now();
|
|
528
368
|
}
|
|
529
369
|
const { ex, dir } = explored;
|
|
@@ -542,13 +382,7 @@ const deps = {
|
|
|
542
382
|
return null;
|
|
543
383
|
},
|
|
544
384
|
resolveCard,
|
|
545
|
-
|
|
546
|
-
const v = vt.viewTools(app, { fetchCatalog: stale });
|
|
547
|
-
if (v) vt.warm({ cacheDir: `${CACHE}/models` }); // already started at initialize; this is the fallback
|
|
548
|
-
return v;
|
|
549
|
-
},
|
|
550
|
-
openTab: (page) => openTab(page, { headed, cdp }),
|
|
551
|
-
tabTools, tabCall,
|
|
385
|
+
remoteTools: (url, opts) => remoteTools(url, fetch, opts),
|
|
552
386
|
};
|
|
553
387
|
const h = handlers(deps);
|
|
554
388
|
// The client starts this server with the session, long before an agent opens an
|
|
@@ -565,4 +399,4 @@ h.initialize = async (p) => {
|
|
|
565
399
|
return reply(p);
|
|
566
400
|
};
|
|
567
401
|
deps.notify = serve(h);
|
|
568
|
-
log(`ready: apps from block ${fromBlock}
|
|
402
|
+
log(`ready: apps from block ${fromBlock}`);
|