This commit is contained in:
AdsPower
2025-03-27 19:41:01 +08:00
commit f94ce14868
17 changed files with 1594 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.pnpm-store/
# Build output
dist/
build/
out/
.output/
# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
.DS_Store
*.sublime-workspace
*.sublime-project
# Environment variables
.env
.env.local
.env.*.local
.env.development
.env.test
.env.production
# Cache and temporary files
.cache/
.temp/
.tmp/
coverage/
*.log
.eslintcache
# System files
Thumbs.db
.DS_Store
*.pem
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Local files
*.local
# Testing
coverage/
.nyc_output/
# Typescript
*.tsbuildinfo
+29
View File
@@ -0,0 +1,29 @@
{
"name": "adspower-local-api-mcp",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"bin": {
"adspower": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod 755 ./build/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"files": [
"build"
],
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.7.0",
"axios": "^1.8.4",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/node": "^22.13.13",
"typescript": "^5.8.2"
}
}
+829
View File
@@ -0,0 +1,829 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
'@modelcontextprotocol/sdk':
specifier: ^1.7.0
version: 1.7.0
axios:
specifier: ^1.8.4
version: 1.8.4
zod:
specifier: ^3.24.2
version: 3.24.2
devDependencies:
'@types/node':
specifier: ^22.13.13
version: 22.13.13
typescript:
specifier: ^5.8.2
version: 5.8.2
packages:
'@modelcontextprotocol/sdk@1.7.0':
resolution: {integrity: sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==}
engines: {node: '>=18'}
'@types/node@22.13.13':
resolution: {integrity: sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==}
accepts@2.0.0:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.8.4:
resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
body-parser@2.1.0:
resolution: {integrity: sha512-/hPxh61E+ll0Ujp24Ilm64cykicul1ypfwjVttduAiEdtnJFvLePSrIPk+HMImtNv5270wOGCb1Tns2rybMkoQ==}
engines: {node: '>=18'}
bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
call-bound@1.0.4:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
content-disposition@1.0.0:
resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
engines: {node: '>= 0.6'}
content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
cookie-signature@1.2.2:
resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
engines: {node: '>=6.6.0'}
cookie@0.7.1:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
debug@4.3.6:
resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.0:
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
etag@1.8.1:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
eventsource-parser@3.0.0:
resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==}
engines: {node: '>=18.0.0'}
eventsource@3.0.5:
resolution: {integrity: sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==}
engines: {node: '>=18.0.0'}
express-rate-limit@7.5.0:
resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==}
engines: {node: '>= 16'}
peerDependencies:
express: ^4.11 || 5 || ^5.0.0-beta.1
express@5.0.1:
resolution: {integrity: sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==}
engines: {node: '>= 18'}
finalhandler@2.1.0:
resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
engines: {node: '>= 0.8'}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
form-data@4.0.2:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
fresh@0.5.2:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
fresh@2.0.0:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
iconv-lite@0.5.2:
resolution: {integrity: sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==}
engines: {node: '>=0.10.0'}
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
media-typer@1.1.0:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'}
merge-descriptors@2.0.0:
resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
engines: {node: '>=18'}
methods@1.1.2:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-db@1.54.0:
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
mime-types@3.0.0:
resolution: {integrity: sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w==}
engines: {node: '>= 0.6'}
ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
negotiator@1.0.0:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
path-to-regexp@8.2.0:
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
engines: {node: '>=16'}
pkce-challenge@4.1.0:
resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==}
engines: {node: '>=16.20.0'}
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
qs@6.13.0:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
engines: {node: '>=0.6'}
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
raw-body@3.0.0:
resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
engines: {node: '>= 0.8'}
router@2.1.0:
resolution: {integrity: sha512-/m/NSLxeYEgWNtyC+WtNHCF7jbGxOibVWKnn+1Psff4dJGOfoXP+MuC/f2CwSmyiHdOIzYnYFp4W6GxWfekaLA==}
engines: {node: '>= 18'}
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
send@1.1.0:
resolution: {integrity: sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==}
engines: {node: '>= 18'}
serve-static@2.1.0:
resolution: {integrity: sha512-A3We5UfEjG8Z7VkDv6uItWw6HY2bBSBJT1KtVESn6EOoOr2jAxNhxWCLY3jDE2WcuHXByWju74ck3ZgLwL8xmA==}
engines: {node: '>= 18'}
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
side-channel-map@1.0.1:
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
engines: {node: '>= 0.4'}
side-channel-weakmap@1.0.2:
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
engines: {node: '>= 0.4'}
side-channel@1.1.0:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
statuses@2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
engines: {node: '>= 0.8'}
toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
type-is@2.0.0:
resolution: {integrity: sha512-gd0sGezQYCbWSbkZr75mln4YBidWUN60+devscpLF5mtRDUpiaTvKpBNrdaCvel1NdR2k6vclXybU5fBd2i+nw==}
engines: {node: '>= 0.6'}
typescript@5.8.2:
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
zod-to-json-schema@3.24.5:
resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
peerDependencies:
zod: ^3.24.1
zod@3.24.2:
resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
snapshots:
'@modelcontextprotocol/sdk@1.7.0':
dependencies:
content-type: 1.0.5
cors: 2.8.5
eventsource: 3.0.5
express: 5.0.1
express-rate-limit: 7.5.0(express@5.0.1)
pkce-challenge: 4.1.0
raw-body: 3.0.0
zod: 3.24.2
zod-to-json-schema: 3.24.5(zod@3.24.2)
transitivePeerDependencies:
- supports-color
'@types/node@22.13.13':
dependencies:
undici-types: 6.20.0
accepts@2.0.0:
dependencies:
mime-types: 3.0.0
negotiator: 1.0.0
asynckit@0.4.0: {}
axios@1.8.4:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.2
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
body-parser@2.1.0:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
debug: 4.4.0
http-errors: 2.0.0
iconv-lite: 0.5.2
on-finished: 2.4.1
qs: 6.14.0
raw-body: 3.0.0
type-is: 2.0.0
transitivePeerDependencies:
- supports-color
bytes@3.1.2: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
call-bound@1.0.4:
dependencies:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
content-disposition@1.0.0:
dependencies:
safe-buffer: 5.2.1
content-type@1.0.5: {}
cookie-signature@1.2.2: {}
cookie@0.7.1: {}
cors@2.8.5:
dependencies:
object-assign: 4.1.1
vary: 1.1.2
debug@4.3.6:
dependencies:
ms: 2.1.2
debug@4.4.0:
dependencies:
ms: 2.1.3
delayed-stream@1.0.0: {}
depd@2.0.0: {}
destroy@1.2.0: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
ee-first@1.1.1: {}
encodeurl@2.0.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
escape-html@1.0.3: {}
etag@1.8.1: {}
eventsource-parser@3.0.0: {}
eventsource@3.0.5:
dependencies:
eventsource-parser: 3.0.0
express-rate-limit@7.5.0(express@5.0.1):
dependencies:
express: 5.0.1
express@5.0.1:
dependencies:
accepts: 2.0.0
body-parser: 2.1.0
content-disposition: 1.0.0
content-type: 1.0.5
cookie: 0.7.1
cookie-signature: 1.2.2
debug: 4.3.6
depd: 2.0.0
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
finalhandler: 2.1.0
fresh: 2.0.0
http-errors: 2.0.0
merge-descriptors: 2.0.0
methods: 1.1.2
mime-types: 3.0.0
on-finished: 2.4.1
once: 1.4.0
parseurl: 1.3.3
proxy-addr: 2.0.7
qs: 6.13.0
range-parser: 1.2.1
router: 2.1.0
safe-buffer: 5.2.1
send: 1.1.0
serve-static: 2.1.0
setprototypeof: 1.2.0
statuses: 2.0.1
type-is: 2.0.0
utils-merge: 1.0.1
vary: 1.1.2
transitivePeerDependencies:
- supports-color
finalhandler@2.1.0:
dependencies:
debug: 4.4.0
encodeurl: 2.0.0
escape-html: 1.0.3
on-finished: 2.4.1
parseurl: 1.3.3
statuses: 2.0.1
transitivePeerDependencies:
- supports-color
follow-redirects@1.15.9: {}
form-data@4.0.2:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
forwarded@0.2.0: {}
fresh@0.5.2: {}
fresh@2.0.0: {}
function-bind@1.1.2: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
gopd@1.2.0: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
http-errors@2.0.0:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.1
toidentifier: 1.0.1
iconv-lite@0.5.2:
dependencies:
safer-buffer: 2.1.2
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
inherits@2.0.4: {}
ipaddr.js@1.9.1: {}
is-promise@4.0.0: {}
math-intrinsics@1.1.0: {}
media-typer@1.1.0: {}
merge-descriptors@2.0.0: {}
methods@1.1.2: {}
mime-db@1.52.0: {}
mime-db@1.54.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
mime-types@3.0.0:
dependencies:
mime-db: 1.54.0
ms@2.1.2: {}
ms@2.1.3: {}
negotiator@1.0.0: {}
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
once@1.4.0:
dependencies:
wrappy: 1.0.2
parseurl@1.3.3: {}
path-to-regexp@8.2.0: {}
pkce-challenge@4.1.0: {}
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
ipaddr.js: 1.9.1
proxy-from-env@1.1.0: {}
qs@6.13.0:
dependencies:
side-channel: 1.1.0
qs@6.14.0:
dependencies:
side-channel: 1.1.0
range-parser@1.2.1: {}
raw-body@3.0.0:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
iconv-lite: 0.6.3
unpipe: 1.0.0
router@2.1.0:
dependencies:
is-promise: 4.0.0
parseurl: 1.3.3
path-to-regexp: 8.2.0
safe-buffer@5.2.1: {}
safer-buffer@2.1.2: {}
send@1.1.0:
dependencies:
debug: 4.3.6
destroy: 1.2.0
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
fresh: 0.5.2
http-errors: 2.0.0
mime-types: 2.1.35
ms: 2.1.3
on-finished: 2.4.1
range-parser: 1.2.1
statuses: 2.0.1
transitivePeerDependencies:
- supports-color
serve-static@2.1.0:
dependencies:
encodeurl: 2.0.0
escape-html: 1.0.3
parseurl: 1.3.3
send: 1.1.0
transitivePeerDependencies:
- supports-color
setprototypeof@1.2.0: {}
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-map@1.0.1:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-weakmap@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-map: 1.0.1
side-channel@1.1.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-list: 1.0.0
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
statuses@2.0.1: {}
toidentifier@1.0.1: {}
type-is@2.0.0:
dependencies:
content-type: 1.0.5
media-typer: 1.1.0
mime-types: 3.0.0
typescript@5.8.2: {}
undici-types@6.20.0: {}
unpipe@1.0.0: {}
utils-merge@1.0.1: {}
vary@1.1.2: {}
wrappy@1.0.2: {}
zod-to-json-schema@3.24.5(zod@3.24.2):
dependencies:
zod: 3.24.2
zod@3.24.2: {}
+16
View File
@@ -0,0 +1,16 @@
export const LOCAL_API_BASE = 'http://127.0.0.1:50325';
export const API_ENDPOINTS = {
START_BROWSER: '/api/v1/browser/start',
CLOSE_BROWSER: '/api/v1/browser/stop',
CREATE_BROWSER: '/api/v1/user/create',
GET_BROWSER_LIST: '/api/v1/user/list',
GET_GROUP_LIST: '/api/v1/group/list',
GET_APPLICATION_LIST: '/api/v1/application/list',
UPDATE_BROWSER: '/api/v1/user/update',
DELETE_BROWSER: '/api/v1/user/delete',
GET_OPENED_BROWSER: '/api/v1/browser/local-active',
CREATE_GROUP: '/api/v1/group/create',
UPDATE_GROUP: '/api/v1/group/update',
MOVE_BROWSER: '/api/v1/user/regroup'
} as const;
+15
View File
@@ -0,0 +1,15 @@
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import type { GetApplicationListParams } from '../types/application.js';
export const applicationHandlers = {
async getApplicationList({ size }: GetApplicationListParams) {
const params = new URLSearchParams();
if (size) {
params.set('page_size', size.toString());
}
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_APPLICATION_LIST}`, { params });
return `Application list: ${JSON.stringify(response.data.data.list, null, 2)}`;
}
};
+120
View File
@@ -0,0 +1,120 @@
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import { buildRequestBody } from '../utils/requestBuilder.js';
import type {
OpenBrowserParams,
CloseBrowserParams,
CreateBrowserParams,
UpdateBrowserParams,
DeleteBrowserParams,
GetBrowserListParams,
MoveBrowserParams
} from '../types/browser.js';
export const browserHandlers = {
async openBrowser({ serialNumber, userId }: OpenBrowserParams) {
const params = new URLSearchParams();
if (serialNumber) {
params.set('serial_number', serialNumber);
}
if (userId) {
params.set('user_id', userId);
}
params.set('open_tabs', '0');
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.START_BROWSER}`, { params });
if (response.data.code === 0) {
return `Browser opened successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join('\n')}`;
}
throw new Error(`Failed to open browser: ${response.data.message}`);
},
async closeBrowser({ userId }: CloseBrowserParams) {
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.CLOSE_BROWSER}`, {
params: { user_id: userId }
});
return 'Browser closed successfully';
},
async createBrowser(params: CreateBrowserParams) {
const requestBody = buildRequestBody(params);
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.CREATE_BROWSER}`, requestBody);
if (response.data.code === 0) {
return `Browser created successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join('\n')}`;
}
throw new Error(`Failed to create browser: ${response.data.message}`);
},
async updateBrowser(params: UpdateBrowserParams) {
const requestBody = buildRequestBody({
...params,
userId: undefined
});
requestBody.user_id = params.userId;
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.UPDATE_BROWSER}`, requestBody);
if (response.data.code === 0) {
return `Browser updated successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join('\n')}`;
}
throw new Error(`Failed to update browser: ${response.data.message}`);
},
async deleteBrowser({ userIds }: DeleteBrowserParams) {
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.DELETE_BROWSER}`, {
user_ids: userIds
});
if (response.data.code === 0) {
return `Browsers deleted successfully: ${userIds.join(', ')}`;
}
throw new Error(`Failed to delete browsers: ${response.data.message}`);
},
async getBrowserList(params: GetBrowserListParams) {
const { groupId, size, id, serialNumber, sort, order } = params;
const urlParams = new URLSearchParams();
if (size) {
urlParams.set('page_size', size.toString());
}
if (id) {
urlParams.set('user_id', id);
}
if (groupId) {
urlParams.set('group_id', groupId);
}
if (serialNumber) {
urlParams.set('serial_number', serialNumber);
}
if (sort) {
urlParams.set('user_sort', JSON.stringify({
[sort]: order || 'asc',
}));
}
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_BROWSER_LIST}`, { params: urlParams });
return `Browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
},
async getOpenedBrowser() {
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_OPENED_BROWSER}`);
if (response.data.code === 0) {
return `Opened browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
}
throw new Error(`Failed to get opened browsers: ${response.data.message}`);
},
async moveBrowser({ groupId, userIds }: MoveBrowserParams) {
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.MOVE_BROWSER}`, {
group_id: groupId,
user_ids: userIds
});
if (response.data.code === 0) {
return `Browsers moved successfully to group ${groupId}: ${userIds.join(', ')}`;
}
throw new Error(`Failed to move browsers: ${response.data.message}`);
}
};
+57
View File
@@ -0,0 +1,57 @@
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import type {
CreateGroupParams,
UpdateGroupParams,
GetGroupListParams
} from '../types/group.js';
export const groupHandlers = {
async createGroup({ groupName, remark }: CreateGroupParams) {
const requestBody: Record<string, string> = {
group_name: groupName
};
if (remark !== undefined) {
requestBody.remark = remark;
}
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.CREATE_GROUP}`, requestBody);
if (response.data.code === 0) {
return `Group created successfully with name: ${groupName}${remark ? `, remark: ${remark}` : ''}`;
}
throw new Error(`Failed to create group: ${response.data.message}`);
},
async updateGroup({ groupId, groupName, remark }: UpdateGroupParams) {
const requestBody: Record<string, any> = {
group_id: groupId,
group_name: groupName
};
if (remark !== undefined) {
requestBody.remark = remark;
}
const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.UPDATE_GROUP}`, requestBody);
if (response.data.code === 0) {
return `Group updated successfully with id: ${groupId}, name: ${groupName}${remark !== undefined ? `, remark: ${remark === null ? '(cleared)' : remark}` : ''}`;
}
throw new Error(`Failed to update group: ${response.data.message}`);
},
async getGroupList({ name, size }: GetGroupListParams) {
const params = new URLSearchParams();
if (name) {
params.set('group_name', name);
}
if (size) {
params.set('page_size', size.toString());
}
const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_GROUP_LIST}`, { params });
return `Group list: ${JSON.stringify(response.data.data.list, null, 2)}`;
}
};
+27
View File
@@ -0,0 +1,27 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { registerTools } from './utils/toolRegister.js';
// Create server instance
const server = new McpServer({
name: 'adspower-local-api',
version: '1.0.0',
capabilities: {
resources: {},
tools: {},
},
});
// Register all tools
registerTools(server);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('AdsPower Local Api MCP Server running on stdio');
}
main().catch((error) => {
console.error('Fatal error in main():', error);
process.exit(1);
});
+3
View File
@@ -0,0 +1,3 @@
export interface GetApplicationListParams {
size?: number;
}
+89
View File
@@ -0,0 +1,89 @@
import { z } from 'zod';
import { schemas } from './schemas.js';
// 代理配置的 Schema
export const userProxyConfigSchema = z.object({
proxy_soft: z.enum([
'brightdata', 'brightauto', 'oxylabsauto', '922S5auto',
'ipideeauto', 'ipfoxyauto', '922S5auth', 'kookauto',
'ssh', 'other', 'no_proxy'
]).describe('The proxy soft of the browser'),
proxy_type: z.enum(['http', 'https', 'socks5', 'no_proxy']).optional(),
proxy_host: z.string().optional(),
proxy_port: z.string().optional(),
proxy_user: z.string().optional(),
proxy_password: z.string().optional(),
proxy_url: z.string().optional(),
global_config: z.enum(['0', '1']).optional()
}).describe('The user proxy config of the browser');
// 浏览器内核配置的 Schema
export const browserKernelConfigSchema = z.object({
version: z.union([
z.literal("92"), z.literal("99"), z.literal("102"),
z.literal("105"), z.literal("108"), z.literal("110"),
z.literal("113"), z.literal("116"), z.literal("120"),
z.literal("126"), z.literal("130"), z.literal("134"),
z.literal("ua_auto")
]).optional(),
type: z.enum(['chrome', 'firefox']).optional()
}).optional();
// 随机 UA 配置的 Schema
export const randomUaConfigSchema = z.object({
ua_version: z.array(z.string()).optional(),
ua_system_version: z.array(
z.enum([
'Android 9', 'Android 10', 'Android 11', 'Android 12', 'Android 13',
'iOS 14', 'iOS 15',
'Windows 7', 'Windows 8', 'Windows 10', 'Windows 11',
'Mac OS X 10', 'Mac OS X 11', 'Mac OS X 12', 'Mac OS X 13',
'Linux'
])
).optional()
}).optional();
// 指纹配置的 Schema
export const fingerprintConfigSchema = z.object({
automatic_timezone: z.enum(['0', '1']).optional(),
timezone: z.string().optional(),
language: z.array(z.string()).optional(),
flash: z.string().optional(),
fonts: z.array(z.string()).optional(),
webrtc: z.enum(['disabled', 'forward', 'proxy', 'local']).optional(),
browser_kernel_config: browserKernelConfigSchema,
random_ua: randomUaConfigSchema,
tls_switch: z.enum(['0', '1']).optional(),
tls: z.string().optional()
}).optional();
// 创建浏览器的参数 Schema
export const createBrowserParamsSchema = z.object({
domainName: z.string().optional(),
openUrls: z.array(z.string()).optional(),
cookie: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
system: z.string().optional(),
groupId: z.string(),
name: z.string().optional(),
country: z.string().optional(),
sysAppCateId: z.string().optional(),
userProxyConfig: userProxyConfigSchema,
fingerprintConfig: fingerprintConfigSchema,
storageStrategy: z.number().optional()
});
// 更新浏览器的参数 Schema
export const updateBrowserParamsSchema = createBrowserParamsSchema.extend({
userId: z.string().describe('The user id of the browser to update'),
});
// 从已有的 schema 中导出类型
export type CreateBrowserParams = z.infer<typeof schemas.createBrowserSchema>;
export type UpdateBrowserParams = z.infer<typeof schemas.updateBrowserSchema>;
export type OpenBrowserParams = z.infer<typeof schemas.openBrowserSchema>;
export type CloseBrowserParams = z.infer<typeof schemas.closeBrowserSchema>;
export type DeleteBrowserParams = z.infer<typeof schemas.deleteBrowserSchema>;
export type GetBrowserListParams = z.infer<typeof schemas.getBrowserListSchema>;
export type MoveBrowserParams = z.infer<typeof schemas.moveBrowserSchema>;
+15
View File
@@ -0,0 +1,15 @@
export interface CreateGroupParams {
groupName: string;
remark?: string;
}
export interface UpdateGroupParams {
groupId: string;
groupName: string;
remark?: string | null;
}
export interface GetGroupListParams {
name?: string;
size?: number;
}
+20
View File
@@ -0,0 +1,20 @@
export function wrapHandler(handler: Function) {
return async (params: any) => {
try {
const result = await handler(params);
return {
content: [{
type: 'text',
text: result
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: error instanceof Error ? error.message : String(error)
}]
};
}
};
}
+167
View File
@@ -0,0 +1,167 @@
import { z } from 'zod';
// Proxy Config Schema
const userProxyConfigSchema = z.object({
proxy_soft: z.enum([
'brightdata', 'brightauto', 'oxylabsauto', '922S5auto',
'ipideeauto', 'ipfoxyauto', '922S5auth', 'kookauto',
'ssh', 'other', 'no_proxy'
]).describe('The proxy soft of the browser'),
proxy_type: z.enum(['http', 'https', 'socks5', 'no_proxy']).optional(),
proxy_host: z.string().optional(),
proxy_port: z.string().optional(),
proxy_user: z.string().optional(),
proxy_password: z.string().optional(),
proxy_url: z.string().optional(),
global_config: z.enum(['0', '1']).optional()
}).describe('The user proxy config of the browser');
// Browser Kernel Config Schema
const browserKernelConfigSchema = z.object({
version: z.union([
z.literal("92"), z.literal("99"), z.literal("102"),
z.literal("105"), z.literal("108"), z.literal("110"),
z.literal("113"), z.literal("116"), z.literal("120"),
z.literal("126"), z.literal("130"), z.literal("134"),
z.literal("ua_auto")
]).optional(),
type: z.enum(['chrome', 'firefox']).optional()
}).optional();
// Random UA Config Schema
const randomUaConfigSchema = z.object({
ua_version: z.array(z.string()).optional(),
ua_system_version: z.array(
z.enum([
'Android 9', 'Android 10', 'Android 11', 'Android 12', 'Android 13',
'iOS 14', 'iOS 15',
'Windows 7', 'Windows 8', 'Windows 10', 'Windows 11',
'Mac OS X 10', 'Mac OS X 11', 'Mac OS X 12', 'Mac OS X 13',
'Linux'
])
).optional()
}).optional();
// Fingerprint Config Schema
const fingerprintConfigSchema = z.object({
automatic_timezone: z.enum(['0', '1']).optional(),
timezone: z.string().optional(),
language: z.array(z.string()).optional(),
flash: z.string().optional(),
fonts: z.array(z.string()).optional(),
webrtc: z.enum(['disabled', 'forward', 'proxy', 'local']).optional(),
browser_kernel_config: browserKernelConfigSchema,
random_ua: randomUaConfigSchema,
tls_switch: z.enum(['0', '1']).optional(),
tls: z.string().optional()
}).optional();
export const schemas = {
// Browser Related Schema
createBrowserSchema: z.object({
domainName: z.string().optional(),
openUrls: z.array(z.string()).optional(),
cookie: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
system: z.string().optional(),
groupId: z.string(),
name: z.string().optional(),
country: z.string().optional(),
sysAppCateId: z.string().optional(),
userProxyConfig: userProxyConfigSchema,
fingerprintConfig: fingerprintConfigSchema,
storageStrategy: z.number().optional()
}),
updateBrowserSchema: z.object({
domainName: z.string().optional(),
openUrls: z.array(z.string()).optional(),
cookie: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
system: z.string().optional(),
groupId: z.string(),
name: z.string().optional(),
country: z.string().optional(),
sysAppCateId: z.string().optional(),
userProxyConfig: userProxyConfigSchema,
fingerprintConfig: fingerprintConfigSchema,
storageStrategy: z.number().optional(),
userId: z.string().describe('The user id of the browser to update')
}),
openBrowserSchema: z.object({
serialNumber: z.string().optional().describe('The serial number of the browser to open'),
userId: z.string().optional().describe('The browser id of the browser to open')
}).strict(),
closeBrowserSchema: z.object({
userId: z.string().describe('The browser id of the browser to stop')
}).strict(),
deleteBrowserSchema: z.object({
userIds: z.array(z.string()).describe('The user ids of the browsers to delete')
}).strict(),
getBrowserListSchema: z.object({
groupId: z.string().optional().describe('The group id of the browser'),
size: z.number().optional().describe('The size of the page'),
id: z.string().optional().describe('The id of the browser'),
serialNumber: z.string().optional().describe('The serial number of the browser'),
sort: z.enum(['serial_number', 'last_open_time', 'created_time']).optional()
.describe('The sort of the browser'),
order: z.enum(['asc', 'desc']).optional()
.describe('The order of the browser')
}).strict(),
moveBrowserSchema: z.object({
groupId: z.string().describe('The target group id'),
userIds: z.array(z.string()).describe('The browser ids to move')
}).strict(),
// Group Related Schema
createGroupSchema: z.object({
groupName: z.string().describe('The name of the group to create'),
remark: z.string().optional().describe('The remark of the group')
}).strict(),
updateGroupSchema: z.object({
groupId: z.string().describe('The id of the group to update'),
groupName: z.string().describe('The new name of the group'),
remark: z.string().nullable().optional().describe('The new remark of the group')
}).strict(),
getGroupListSchema: z.object({
name: z.string().optional().describe('The name of the group'),
size: z.number().optional().describe('The size of the page')
}).strict(),
// Application Related Schema
getApplicationListSchema: z.object({
size: z.number().optional().describe('The size of the page')
}).strict(),
// Empty Schema
emptySchema: z.object({}).strict()
};
export type {
CreateBrowserParams,
UpdateBrowserParams,
OpenBrowserParams,
CloseBrowserParams,
DeleteBrowserParams,
GetBrowserListParams,
MoveBrowserParams
} from './browser.js';
export type {
CreateGroupParams,
UpdateGroupParams,
GetGroupListParams
} from './group.js';
export type {
GetApplicationListParams
} from './application.js';
+22
View File
@@ -0,0 +1,22 @@
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
export function wrapHandler(handler: Function) {
return async (params: any): Promise<CallToolResult> => {
try {
const result = await handler(params);
return {
content: [{
type: 'text' as const,
text: result
}]
};
} catch (error) {
return {
content: [{
type: 'text' as const,
text: error instanceof Error ? error.message : String(error)
}]
};
}
};
}
+64
View File
@@ -0,0 +1,64 @@
import { CreateBrowserParams, UpdateBrowserParams } from '../types/browser.js';
export function buildRequestBody(params: CreateBrowserParams | UpdateBrowserParams): Record<string, any> {
const requestBody: Record<string, any> = {};
const basicFields: Record<string, string> = {
domainName: 'domain_name',
openUrls: 'open_urls',
cookie: 'cookie',
username: 'username',
password: 'password',
system: 'system',
groupId: 'group_id',
name: 'name',
country: 'country',
sysAppCateId: 'sys_app_cate_id',
userId: 'user_id'
};
Object.entries(basicFields).forEach(([paramKey, key]) => {
const value = params[paramKey as keyof typeof params];
if (value !== undefined) {
requestBody[key] = value;
}
});
if (params.userProxyConfig) {
const proxyConfig = buildNestedConfig(params.userProxyConfig);
if (Object.keys(proxyConfig).length > 0) {
requestBody.user_proxy_config = proxyConfig;
}
}
if (params.fingerprintConfig) {
const fpConfig = buildNestedConfig(params.fingerprintConfig);
if (Object.keys(fpConfig).length > 0) {
requestBody.fingerprint_config = fpConfig;
}
}
if (params.storageStrategy !== undefined) {
requestBody.storage_strategy = params.storageStrategy;
}
return requestBody;
}
function buildNestedConfig(config: Record<string, any>): Record<string, any> {
const result: Record<string, any> = {};
Object.entries(config).forEach(([key, value]) => {
if (value !== undefined) {
if (typeof value === 'object' && value !== null) {
const nestedConfig = buildNestedConfig(value);
if (Object.keys(nestedConfig).length > 0) {
result[key] = nestedConfig;
}
} else {
result[key] = value;
}
}
});
return result;
}
+47
View File
@@ -0,0 +1,47 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { browserHandlers } from '../handlers/browser.js';
import { groupHandlers } from '../handlers/group.js';
import { applicationHandlers } from '../handlers/application.js';
import { schemas } from '../types/schemas.js';
import { wrapHandler } from './handlerWrapper.js';
export function registerTools(server: McpServer) {
// Browser tools
server.tool('open-browser', 'Open the browser', schemas.openBrowserSchema.shape,
wrapHandler(browserHandlers.openBrowser));
server.tool('close-browser', 'Close the browser', schemas.closeBrowserSchema.shape,
wrapHandler(browserHandlers.closeBrowser));
server.tool('create-browser', 'Create a browser', schemas.createBrowserSchema.shape,
wrapHandler(browserHandlers.createBrowser));
server.tool('update-browser', 'Update the browser', schemas.updateBrowserSchema.shape,
wrapHandler(browserHandlers.updateBrowser));
server.tool('delete-browser', 'Delete the browser', schemas.deleteBrowserSchema.shape,
wrapHandler(browserHandlers.deleteBrowser));
server.tool('get-browser-list', 'Get the list of browsers', schemas.getBrowserListSchema.shape,
wrapHandler(browserHandlers.getBrowserList));
server.tool('get-opened-browser', 'Get the list of opened browsers', schemas.emptySchema.shape,
wrapHandler(browserHandlers.getOpenedBrowser));
server.tool('move-browser', 'Move browsers to a group', schemas.moveBrowserSchema.shape,
wrapHandler(browserHandlers.moveBrowser));
// Group tools
server.tool('create-group', 'Create a browser group', schemas.createGroupSchema.shape,
wrapHandler(groupHandlers.createGroup));
server.tool('update-group', 'Update the browser group', schemas.updateGroupSchema.shape,
wrapHandler(groupHandlers.updateGroup));
server.tool('get-group-list', 'Get the list of groups', schemas.getGroupListSchema.shape,
wrapHandler(groupHandlers.getGroupList));
// Application tools
server.tool('get-application-list', 'Get the list of applications', schemas.getApplicationListSchema.shape,
wrapHandler(applicationHandlers.getApplicationList));
}
+15
View File
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}