mcpmake 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/README.md +691 -0
  2. package/bin/mcpmake.mjs +2 -0
  3. package/dist/analyzer/auth-detector.d.ts +12 -0
  4. package/dist/analyzer/auth-detector.js +142 -0
  5. package/dist/analyzer/dom-parser.d.ts +10 -0
  6. package/dist/analyzer/dom-parser.js +259 -0
  7. package/dist/analyzer/goal-crawler.d.ts +25 -0
  8. package/dist/analyzer/goal-crawler.js +177 -0
  9. package/dist/analyzer/hybrid-detector.d.ts +28 -0
  10. package/dist/analyzer/hybrid-detector.js +96 -0
  11. package/dist/analyzer/index.d.ts +12 -0
  12. package/dist/analyzer/index.js +8 -0
  13. package/dist/analyzer/screenshot-capture.d.ts +29 -0
  14. package/dist/analyzer/screenshot-capture.js +42 -0
  15. package/dist/analyzer/selector-builder.d.ts +19 -0
  16. package/dist/analyzer/selector-builder.js +199 -0
  17. package/dist/analyzer/semantic-analyzer.d.ts +13 -0
  18. package/dist/analyzer/semantic-analyzer.js +145 -0
  19. package/dist/analyzer/site-crawler.d.ts +38 -0
  20. package/dist/analyzer/site-crawler.js +235 -0
  21. package/dist/cloud/billing/billing-engine.d.ts +44 -0
  22. package/dist/cloud/billing/billing-engine.js +81 -0
  23. package/dist/cloud/billing/credit-store.d.ts +64 -0
  24. package/dist/cloud/billing/credit-store.js +168 -0
  25. package/dist/cloud/billing/index.d.ts +4 -0
  26. package/dist/cloud/billing/index.js +2 -0
  27. package/dist/cloud/billing/usage-store.d.ts +42 -0
  28. package/dist/cloud/billing/usage-store.js +85 -0
  29. package/dist/cloud/billing/usage-tracker.d.ts +38 -0
  30. package/dist/cloud/billing/usage-tracker.js +95 -0
  31. package/dist/cloud/build-pipeline.d.ts +39 -0
  32. package/dist/cloud/build-pipeline.js +310 -0
  33. package/dist/cloud/build-queue.d.ts +30 -0
  34. package/dist/cloud/build-queue.js +70 -0
  35. package/dist/cloud/caddy-manager.d.ts +18 -0
  36. package/dist/cloud/caddy-manager.js +97 -0
  37. package/dist/cloud/container-backend.d.ts +62 -0
  38. package/dist/cloud/container-backend.js +59 -0
  39. package/dist/cloud/container-manager.d.ts +64 -0
  40. package/dist/cloud/container-manager.js +301 -0
  41. package/dist/cloud/crypto.d.ts +27 -0
  42. package/dist/cloud/crypto.js +63 -0
  43. package/dist/cloud/db/index.d.ts +27 -0
  44. package/dist/cloud/db/index.js +53 -0
  45. package/dist/cloud/db/migrations.d.ts +12 -0
  46. package/dist/cloud/db/migrations.js +329 -0
  47. package/dist/cloud/db/pg-store.d.ts +45 -0
  48. package/dist/cloud/db/pg-store.js +336 -0
  49. package/dist/cloud/failure-tracker.d.ts +51 -0
  50. package/dist/cloud/failure-tracker.js +102 -0
  51. package/dist/cloud/idle-monitor.d.ts +30 -0
  52. package/dist/cloud/idle-monitor.js +70 -0
  53. package/dist/cloud/mailer.d.ts +21 -0
  54. package/dist/cloud/mailer.js +193 -0
  55. package/dist/cloud/mcp-proxy.d.ts +58 -0
  56. package/dist/cloud/mcp-proxy.js +203 -0
  57. package/dist/cloud/metric-samples.d.ts +43 -0
  58. package/dist/cloud/metric-samples.js +85 -0
  59. package/dist/cloud/metrics.d.ts +26 -0
  60. package/dist/cloud/metrics.js +59 -0
  61. package/dist/cloud/multipart.d.ts +26 -0
  62. package/dist/cloud/multipart.js +132 -0
  63. package/dist/cloud/observability.d.ts +27 -0
  64. package/dist/cloud/observability.js +98 -0
  65. package/dist/cloud/rate-limiter.d.ts +31 -0
  66. package/dist/cloud/rate-limiter.js +58 -0
  67. package/dist/cloud/request-security.d.ts +5 -0
  68. package/dist/cloud/request-security.js +74 -0
  69. package/dist/cloud/resource-monitor.d.ts +69 -0
  70. package/dist/cloud/resource-monitor.js +130 -0
  71. package/dist/cloud/secret-store.d.ts +38 -0
  72. package/dist/cloud/secret-store.js +103 -0
  73. package/dist/cloud/security.d.ts +26 -0
  74. package/dist/cloud/security.js +142 -0
  75. package/dist/cloud/server.d.ts +21 -0
  76. package/dist/cloud/server.js +1079 -0
  77. package/dist/cloud/shared-state.d.ts +72 -0
  78. package/dist/cloud/shared-state.js +159 -0
  79. package/dist/cloud/ssrf.d.ts +43 -0
  80. package/dist/cloud/ssrf.js +150 -0
  81. package/dist/cloud/store.d.ts +41 -0
  82. package/dist/cloud/store.js +75 -0
  83. package/dist/cloud/stripe.d.ts +78 -0
  84. package/dist/cloud/stripe.js +317 -0
  85. package/dist/cloud/telemetry-store.d.ts +53 -0
  86. package/dist/cloud/telemetry-store.js +108 -0
  87. package/dist/cloud/web/auth.d.ts +225 -0
  88. package/dist/cloud/web/auth.js +555 -0
  89. package/dist/cloud/web/charts.d.ts +70 -0
  90. package/dist/cloud/web/charts.js +178 -0
  91. package/dist/cloud/web/csrf.d.ts +14 -0
  92. package/dist/cloud/web/csrf.js +22 -0
  93. package/dist/cloud/web/docs.d.ts +40 -0
  94. package/dist/cloud/web/docs.js +174 -0
  95. package/dist/cloud/web/router.d.ts +25 -0
  96. package/dist/cloud/web/router.js +1921 -0
  97. package/dist/cloud/web/static/alpine.min.js +5 -0
  98. package/dist/cloud/web/static/favicon.svg +4 -0
  99. package/dist/cloud/web/static/htmx-sse.js +290 -0
  100. package/dist/cloud/web/static/htmx.min.js +1 -0
  101. package/dist/cloud/web/static/style.css +2683 -0
  102. package/dist/cloud/web/static-server.d.ts +13 -0
  103. package/dist/cloud/web/static-server.js +73 -0
  104. package/dist/cloud/web/template-engine.d.ts +27 -0
  105. package/dist/cloud/web/template-engine.js +146 -0
  106. package/dist/cloud/web/templates/layouts/admin.hbs +57 -0
  107. package/dist/cloud/web/templates/layouts/auth.hbs +138 -0
  108. package/dist/cloud/web/templates/layouts/base.hbs +16 -0
  109. package/dist/cloud/web/templates/layouts/dashboard.hbs +39 -0
  110. package/dist/cloud/web/templates/layouts/landing.hbs +82 -0
  111. package/dist/cloud/web/templates/pages/admin/overview.hbs +123 -0
  112. package/dist/cloud/web/templates/pages/admin/servers.hbs +129 -0
  113. package/dist/cloud/web/templates/pages/admin/telemetry.hbs +39 -0
  114. package/dist/cloud/web/templates/pages/admin/user-edit.hbs +91 -0
  115. package/dist/cloud/web/templates/pages/admin/users.hbs +179 -0
  116. package/dist/cloud/web/templates/pages/auth/forgot-password.hbs +25 -0
  117. package/dist/cloud/web/templates/pages/auth/login.hbs +33 -0
  118. package/dist/cloud/web/templates/pages/auth/register.hbs +32 -0
  119. package/dist/cloud/web/templates/pages/auth/reset-password.hbs +34 -0
  120. package/dist/cloud/web/templates/pages/dashboard/billing.hbs +140 -0
  121. package/dist/cloud/web/templates/pages/dashboard/create.hbs +173 -0
  122. package/dist/cloud/web/templates/pages/dashboard/index.hbs +8 -0
  123. package/dist/cloud/web/templates/pages/dashboard/server-detail.hbs +280 -0
  124. package/dist/cloud/web/templates/pages/dashboard/server-logs.hbs +35 -0
  125. package/dist/cloud/web/templates/pages/dashboard/server-metrics.hbs +63 -0
  126. package/dist/cloud/web/templates/pages/dashboard/servers-partial.hbs +21 -0
  127. package/dist/cloud/web/templates/pages/dashboard/servers.hbs +44 -0
  128. package/dist/cloud/web/templates/pages/docs/show.hbs +16 -0
  129. package/dist/cloud/web/templates/pages/errors/404.hbs +9 -0
  130. package/dist/cloud/web/templates/pages/errors/500.hbs +8 -0
  131. package/dist/cloud/web/templates/pages/landing/index.hbs +223 -0
  132. package/dist/cloud/web/templates/pages/legal/privacy.hbs +71 -0
  133. package/dist/cloud/web/templates/pages/legal/terms.hbs +73 -0
  134. package/dist/cloud/web/templates/partials/admin-stats.hbs +52 -0
  135. package/dist/cloud/web/templates/partials/flash-message.hbs +6 -0
  136. package/dist/cloud/web/templates/partials/pricing-table.hbs +103 -0
  137. package/dist/cloud/web/templates/partials/server-card.hbs +19 -0
  138. package/dist/cloud/web/templates/partials/status-badge.hbs +1 -0
  139. package/dist/commands/bundle.d.ts +18 -0
  140. package/dist/commands/bundle.js +82 -0
  141. package/dist/commands/ci.d.ts +25 -0
  142. package/dist/commands/ci.js +149 -0
  143. package/dist/commands/deploy.d.ts +24 -0
  144. package/dist/commands/deploy.js +145 -0
  145. package/dist/commands/diff.d.ts +18 -0
  146. package/dist/commands/diff.js +185 -0
  147. package/dist/commands/from/describe.d.ts +65 -0
  148. package/dist/commands/from/describe.js +173 -0
  149. package/dist/commands/from/har.d.ts +81 -0
  150. package/dist/commands/from/har.js +255 -0
  151. package/dist/commands/from/openapi.d.ts +105 -0
  152. package/dist/commands/from/openapi.js +302 -0
  153. package/dist/commands/from/postman.d.ts +51 -0
  154. package/dist/commands/from/postman.js +146 -0
  155. package/dist/commands/from/target-support.d.ts +11 -0
  156. package/dist/commands/from/target-support.js +33 -0
  157. package/dist/commands/from/url.d.ts +75 -0
  158. package/dist/commands/from/url.js +244 -0
  159. package/dist/commands/from/website.d.ts +75 -0
  160. package/dist/commands/from/website.js +284 -0
  161. package/dist/commands/lint.d.ts +24 -0
  162. package/dist/commands/lint.js +184 -0
  163. package/dist/commands/merge.d.ts +18 -0
  164. package/dist/commands/merge.js +161 -0
  165. package/dist/commands/publish.d.ts +27 -0
  166. package/dist/commands/publish.js +334 -0
  167. package/dist/commands/rescan.d.ts +40 -0
  168. package/dist/commands/rescan.js +255 -0
  169. package/dist/commands/update.d.ts +14 -0
  170. package/dist/commands/update.js +87 -0
  171. package/dist/commands/verify.d.ts +14 -0
  172. package/dist/commands/verify.js +71 -0
  173. package/dist/config/configurable-command.d.ts +13 -0
  174. package/dist/config/configurable-command.js +70 -0
  175. package/dist/config/mcpmake-config.d.ts +68 -0
  176. package/dist/config/mcpmake-config.js +207 -0
  177. package/dist/docs/cli.md +400 -0
  178. package/dist/docs/mcp-2026-07-28-migration.md +78 -0
  179. package/dist/docs/migrate-from-stainless.md +94 -0
  180. package/dist/docs/quickstart.md +166 -0
  181. package/dist/docs/show-hn.md +26 -0
  182. package/dist/docs/website-servers.md +169 -0
  183. package/dist/emitter/code-writer.d.ts +8 -0
  184. package/dist/emitter/code-writer.js +25 -0
  185. package/dist/emitter/index.d.ts +32 -0
  186. package/dist/emitter/index.js +280 -0
  187. package/dist/emitter/mcpb-bundler.d.ts +31 -0
  188. package/dist/emitter/mcpb-bundler.js +172 -0
  189. package/dist/emitter/project-scaffolder.d.ts +4 -0
  190. package/dist/emitter/project-scaffolder.js +89 -0
  191. package/dist/emitter/python-template-loader.d.ts +4 -0
  192. package/dist/emitter/python-template-loader.js +30 -0
  193. package/dist/emitter/python-templates/dockerfile.hbs +14 -0
  194. package/dist/emitter/python-templates/env.example.hbs +6 -0
  195. package/dist/emitter/python-templates/requirements.txt.hbs +4 -0
  196. package/dist/emitter/python-templates/server.py.hbs +77 -0
  197. package/dist/emitter/site-scaffolder.d.ts +13 -0
  198. package/dist/emitter/site-scaffolder.js +70 -0
  199. package/dist/emitter/site-template-loader.d.ts +5 -0
  200. package/dist/emitter/site-template-loader.js +47 -0
  201. package/dist/emitter/site-templates/browser-manager.ts.hbs +233 -0
  202. package/dist/emitter/site-templates/config.ts.hbs +28 -0
  203. package/dist/emitter/site-templates/dockerfile.hbs +31 -0
  204. package/dist/emitter/site-templates/env.example.hbs +19 -0
  205. package/dist/emitter/site-templates/package.json.hbs +26 -0
  206. package/dist/emitter/site-templates/server-main-http.ts.hbs +108 -0
  207. package/dist/emitter/site-templates/server-main.ts.hbs +23 -0
  208. package/dist/emitter/site-templates/tool-handler-action.ts.hbs +86 -0
  209. package/dist/emitter/site-templates/tool-handler-form.ts.hbs +116 -0
  210. package/dist/emitter/site-templates/tool-handler-lifecycle.ts.hbs +146 -0
  211. package/dist/emitter/site-templates/tool-index.ts.hbs +11 -0
  212. package/dist/emitter/template-loader.d.ts +1 -0
  213. package/dist/emitter/template-loader.js +27 -0
  214. package/dist/emitter/templates/auth-provider.ts.hbs +57 -0
  215. package/dist/emitter/templates/config.ts.hbs +63 -0
  216. package/dist/emitter/templates/discovery.ts.hbs +301 -0
  217. package/dist/emitter/templates/dockerfile.hbs +34 -0
  218. package/dist/emitter/templates/env.example.hbs +28 -0
  219. package/dist/emitter/templates/gitignore.hbs +5 -0
  220. package/dist/emitter/templates/http-executor.ts.hbs +117 -0
  221. package/dist/emitter/templates/oauth.ts.hbs +188 -0
  222. package/dist/emitter/templates/package.json.hbs +25 -0
  223. package/dist/emitter/templates/prompts.ts.hbs +22 -0
  224. package/dist/emitter/templates/readme.md.hbs +123 -0
  225. package/dist/emitter/templates/resources.ts.hbs +63 -0
  226. package/dist/emitter/templates/server-main-http.ts.hbs +407 -0
  227. package/dist/emitter/templates/server-main.ts.hbs +40 -0
  228. package/dist/emitter/templates/task-handlers.ts.hbs +189 -0
  229. package/dist/emitter/templates/task-manager.ts.hbs +139 -0
  230. package/dist/emitter/templates/task-sse.ts.hbs +105 -0
  231. package/dist/emitter/templates/tool-handler.ts.hbs +124 -0
  232. package/dist/emitter/templates/tool-index.ts.hbs +11 -0
  233. package/dist/emitter/templates/tool-test.ts.hbs +57 -0
  234. package/dist/emitter/templates/trace.ts.hbs +79 -0
  235. package/dist/emitter/templates/tsconfig.json.hbs +16 -0
  236. package/dist/emitter/templates/types.ts.hbs +5 -0
  237. package/dist/emitter/worker-template-loader.d.ts +5 -0
  238. package/dist/emitter/worker-template-loader.js +33 -0
  239. package/dist/emitter/worker-templates/config.ts.hbs +54 -0
  240. package/dist/emitter/worker-templates/dev-vars.example.hbs +10 -0
  241. package/dist/emitter/worker-templates/gitignore.hbs +6 -0
  242. package/dist/emitter/worker-templates/package.json.hbs +24 -0
  243. package/dist/emitter/worker-templates/readme.md.hbs +53 -0
  244. package/dist/emitter/worker-templates/server.test.ts.hbs +20 -0
  245. package/dist/emitter/worker-templates/tool-handler.ts.hbs +85 -0
  246. package/dist/emitter/worker-templates/tool-index.ts.hbs +28 -0
  247. package/dist/emitter/worker-templates/tsconfig.json.hbs +17 -0
  248. package/dist/emitter/worker-templates/worker.ts.hbs +242 -0
  249. package/dist/emitter/worker-templates/wrangler.toml.hbs +19 -0
  250. package/dist/generator/spec-generator.d.ts +6 -0
  251. package/dist/generator/spec-generator.js +50 -0
  252. package/dist/index.d.ts +1 -0
  253. package/dist/index.js +64 -0
  254. package/dist/parser/har-filter.d.ts +8 -0
  255. package/dist/parser/har-filter.js +71 -0
  256. package/dist/parser/har-loader.d.ts +2 -0
  257. package/dist/parser/har-loader.js +14 -0
  258. package/dist/parser/har-normalizer.d.ts +20 -0
  259. package/dist/parser/har-normalizer.js +78 -0
  260. package/dist/parser/index.d.ts +10 -0
  261. package/dist/parser/index.js +6 -0
  262. package/dist/parser/openapi-loader.d.ts +6 -0
  263. package/dist/parser/openapi-loader.js +308 -0
  264. package/dist/parser/operation-extractor.d.ts +13 -0
  265. package/dist/parser/operation-extractor.js +155 -0
  266. package/dist/parser/overlay-loader.d.ts +10 -0
  267. package/dist/parser/overlay-loader.js +184 -0
  268. package/dist/parser/postman-loader.d.ts +9 -0
  269. package/dist/parser/postman-loader.js +106 -0
  270. package/dist/parser/schema-converter.d.ts +12 -0
  271. package/dist/parser/schema-converter.js +117 -0
  272. package/dist/plugins/adapter.d.ts +40 -0
  273. package/dist/plugins/adapter.js +15 -0
  274. package/dist/plugins/loader.d.ts +25 -0
  275. package/dist/plugins/loader.js +58 -0
  276. package/dist/pricing.d.ts +55 -0
  277. package/dist/pricing.js +133 -0
  278. package/dist/providers/index.d.ts +15 -0
  279. package/dist/providers/index.js +56 -0
  280. package/dist/recorder/browser-recorder.d.ts +22 -0
  281. package/dist/recorder/browser-recorder.js +205 -0
  282. package/dist/registry/official-registry.d.ts +90 -0
  283. package/dist/registry/official-registry.js +129 -0
  284. package/dist/rescan/diff-engine.d.ts +5 -0
  285. package/dist/rescan/diff-engine.js +312 -0
  286. package/dist/rescan/index.d.ts +3 -0
  287. package/dist/rescan/index.js +2 -0
  288. package/dist/rescan/rescan-runner.d.ts +42 -0
  289. package/dist/rescan/rescan-runner.js +69 -0
  290. package/dist/rescan/rescan-scheduler.d.ts +41 -0
  291. package/dist/rescan/rescan-scheduler.js +179 -0
  292. package/dist/site-transformer/browser-tools.d.ts +10 -0
  293. package/dist/site-transformer/browser-tools.js +59 -0
  294. package/dist/site-transformer/index.d.ts +2 -0
  295. package/dist/site-transformer/index.js +2 -0
  296. package/dist/site-transformer/selector-healer.d.ts +8 -0
  297. package/dist/site-transformer/selector-healer.js +106 -0
  298. package/dist/site-transformer/tool-generator.d.ts +13 -0
  299. package/dist/site-transformer/tool-generator.js +245 -0
  300. package/dist/transformer/auth-detector.d.ts +13 -0
  301. package/dist/transformer/auth-detector.js +90 -0
  302. package/dist/transformer/catalog-builder.d.ts +18 -0
  303. package/dist/transformer/catalog-builder.js +56 -0
  304. package/dist/transformer/client-compat.d.ts +6 -0
  305. package/dist/transformer/client-compat.js +44 -0
  306. package/dist/transformer/har-clusterer.d.ts +9 -0
  307. package/dist/transformer/har-clusterer.js +27 -0
  308. package/dist/transformer/har-dedup.d.ts +10 -0
  309. package/dist/transformer/har-dedup.js +81 -0
  310. package/dist/transformer/har-schema-inferrer.d.ts +15 -0
  311. package/dist/transformer/har-schema-inferrer.js +90 -0
  312. package/dist/transformer/har-to-operations.d.ts +13 -0
  313. package/dist/transformer/har-to-operations.js +192 -0
  314. package/dist/transformer/index.d.ts +8 -0
  315. package/dist/transformer/index.js +6 -0
  316. package/dist/transformer/llm-namer.d.ts +6 -0
  317. package/dist/transformer/llm-namer.js +59 -0
  318. package/dist/transformer/naming.d.ts +4 -0
  319. package/dist/transformer/naming.js +30 -0
  320. package/dist/transformer/operation-filter.d.ts +13 -0
  321. package/dist/transformer/operation-filter.js +52 -0
  322. package/dist/transformer/resource-builder.d.ts +12 -0
  323. package/dist/transformer/resource-builder.js +80 -0
  324. package/dist/transformer/schema-merger.d.ts +14 -0
  325. package/dist/transformer/schema-merger.js +65 -0
  326. package/dist/transformer/tool-builder.d.ts +3 -0
  327. package/dist/transformer/tool-builder.js +114 -0
  328. package/dist/types/index.d.ts +131 -0
  329. package/dist/types/index.js +1 -0
  330. package/dist/types/site.d.ts +284 -0
  331. package/dist/types/site.js +8 -0
  332. package/dist/utils/fail.d.ts +48 -0
  333. package/dist/utils/fail.js +204 -0
  334. package/dist/utils/fs.d.ts +5 -0
  335. package/dist/utils/fs.js +28 -0
  336. package/dist/utils/interactive.d.ts +6 -0
  337. package/dist/utils/interactive.js +30 -0
  338. package/dist/utils/logger.d.ts +1 -0
  339. package/dist/utils/logger.js +2 -0
  340. package/dist/utils/sanitize.d.ts +28 -0
  341. package/dist/utils/sanitize.js +44 -0
  342. package/dist/utils/watcher.d.ts +11 -0
  343. package/dist/utils/watcher.js +36 -0
  344. package/package.json +65 -0
@@ -0,0 +1,86 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ {{#if button}}
4
+ import { getOrCreateSession, takeScreenshot, resolveSelector } from '../browser-manager.js';
5
+ {{else}}
6
+ import { getOrCreateSession, takeScreenshot } from '../browser-manager.js';
7
+ {{/if}}
8
+ import type { AppConfig } from '../config.js';
9
+
10
+ const inputSchema = {{{inputSchemaCode}}};
11
+
12
+ export function register(server: McpServer, config: AppConfig): void {
13
+ server.registerTool(
14
+ '{{name}}',
15
+ {
16
+ title: '{{jsString title}}',
17
+ description: `{{{description}}}`,
18
+ inputSchema,
19
+ {{#if annotations}}
20
+ annotations: {
21
+ {{#if annotations.readOnlyHint}}
22
+ readOnlyHint: true,
23
+ {{/if}}
24
+ {{#if annotations.destructiveHint}}
25
+ destructiveHint: true,
26
+ {{/if}}
27
+ {{#if annotations.idempotentHint}}
28
+ idempotentHint: true,
29
+ {{/if}}
30
+ },
31
+ {{/if}}
32
+ },
33
+ async (input) => {
34
+ try {
35
+ const { page, sessionId } = await getOrCreateSession(
36
+ (input as Record<string, unknown>).sessionId as string | undefined,
37
+ );
38
+
39
+ {{#if pageUrl}}
40
+ // Navigate to the page if not already there
41
+ const targetUrl = '{{jsString pageUrl}}';
42
+ if (!page.url().startsWith(targetUrl.split('?')[0])) {
43
+ await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
44
+ await page.waitForTimeout(500);
45
+ }
46
+ {{/if}}
47
+
48
+ {{#if link}}
49
+ // Navigate to link
50
+ await page.goto('{{jsString link.href}}', { waitUntil: 'domcontentloaded' });
51
+ await page.waitForTimeout(500);
52
+ {{else if button}}
53
+ // Click button
54
+ const buttonSelector = await resolveSelector(page, ['{{jsString button.selector.primary}}'{{#each button.selector.fallbacks}}, '{{jsString this}}'{{/each}}]);
55
+ await page.click(buttonSelector);
56
+ await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {});
57
+ {{/if}}
58
+
59
+ // Capture result
60
+ const pageTitle = await page.title();
61
+ const pageUrl = page.url();
62
+ const screenshot = await takeScreenshot(sessionId);
63
+
64
+ return {
65
+ content: [
66
+ {
67
+ type: 'text' as const,
68
+ text: JSON.stringify({ sessionId, pageTitle, url: pageUrl, success: true }, null, 2),
69
+ },
70
+ {
71
+ type: 'image' as const,
72
+ data: screenshot.toString('base64'),
73
+ mimeType: 'image/png',
74
+ },
75
+ ],
76
+ };
77
+ } catch (error) {
78
+ const message = error instanceof Error ? error.message : String(error);
79
+ return {
80
+ content: [{ type: 'text' as const, text: `Error: ${message}` }],
81
+ isError: true,
82
+ };
83
+ }
84
+ },
85
+ );
86
+ }
@@ -0,0 +1,116 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { getOrCreateSession, takeScreenshot, resolveSelector } from '../browser-manager.js';
4
+ import type { AppConfig } from '../config.js';
5
+
6
+ const inputSchema = {{{inputSchemaCode}}};
7
+
8
+ export function register(server: McpServer, config: AppConfig): void {
9
+ server.registerTool(
10
+ '{{name}}',
11
+ {
12
+ title: '{{jsString title}}',
13
+ description: `{{{description}}}`,
14
+ inputSchema,
15
+ {{#if annotations}}
16
+ annotations: {
17
+ {{#if annotations.readOnlyHint}}
18
+ readOnlyHint: true,
19
+ {{/if}}
20
+ {{#if annotations.destructiveHint}}
21
+ destructiveHint: true,
22
+ {{/if}}
23
+ {{#if annotations.idempotentHint}}
24
+ idempotentHint: true,
25
+ {{/if}}
26
+ },
27
+ {{/if}}
28
+ },
29
+ async (input) => {
30
+ try {
31
+ const { page, sessionId } = await getOrCreateSession(
32
+ (input as Record<string, unknown>).sessionId as string | undefined,
33
+ );
34
+
35
+ // Navigate to the page if not already there
36
+ {{#if pageUrl}}
37
+ const targetUrl = '{{jsString pageUrl}}';
38
+ if (!page.url().startsWith(targetUrl.split('?')[0])) {
39
+ await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
40
+ await page.waitForTimeout(500);
41
+ }
42
+ {{/if}}
43
+
44
+ // Fill form fields
45
+ {{#each form.fields}}
46
+ {{#unless (eq fieldType "hidden")}}
47
+ {{#if (eq fieldType "checkbox")}}
48
+ if ((input as Record<string, unknown>)['{{jsString name}}'] !== undefined) {
49
+ const checked = Boolean((input as Record<string, unknown>)['{{jsString name}}']);
50
+ const fieldSelector = await resolveSelector(page, ['{{jsString selector.primary}}'{{#each selector.fallbacks}}, '{{jsString this}}'{{/each}}]);
51
+ if (checked) {
52
+ await page.check(fieldSelector);
53
+ } else {
54
+ await page.uncheck(fieldSelector);
55
+ }
56
+ }
57
+ {{else if (eq fieldType "select")}}
58
+ if ((input as Record<string, unknown>)['{{jsString name}}'] !== undefined) {
59
+ const fieldSelector = await resolveSelector(page, ['{{jsString selector.primary}}'{{#each selector.fallbacks}}, '{{jsString this}}'{{/each}}]);
60
+ await page.selectOption(fieldSelector, String((input as Record<string, unknown>)['{{jsString name}}']));
61
+ }
62
+ {{else if (eq fieldType "radio")}}
63
+ if ((input as Record<string, unknown>)['{{jsString name}}'] !== undefined) {
64
+ const radioName = '{{jsString name}}';
65
+ const radioValue = String((input as Record<string, unknown>)['{{jsString name}}']).replace(/["\\[\]()]/g, '\\$&');
66
+ const radioNameSel = radioName.replace(/["\\]/g, '\\$&');
67
+ await page.check(`input[name="${radioNameSel}"][value="${radioValue}"]`);
68
+ }
69
+ {{else}}
70
+ if ((input as Record<string, unknown>)['{{jsString name}}'] !== undefined) {
71
+ const fieldSelector = await resolveSelector(page, ['{{jsString selector.primary}}'{{#each selector.fallbacks}}, '{{jsString this}}'{{/each}}]);
72
+ await page.fill(fieldSelector, String((input as Record<string, unknown>)['{{jsString name}}']));
73
+ }
74
+ {{/if}}
75
+ {{/unless}}
76
+ {{/each}}
77
+
78
+ // Submit the form
79
+ {{#if form.submitButton}}
80
+ const submitSelector = await resolveSelector(page, ['{{jsString form.submitButton.primary}}'{{#each form.submitButton.fallbacks}}, '{{jsString this}}'{{/each}}]);
81
+ await page.click(submitSelector);
82
+ {{else}}
83
+ await page.keyboard.press('Enter');
84
+ {{/if}}
85
+
86
+ // Wait for navigation or response
87
+ await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
88
+
89
+ // Capture result
90
+ const pageTitle = await page.title();
91
+ const pageUrl = page.url();
92
+ const screenshot = await takeScreenshot(sessionId);
93
+
94
+ return {
95
+ content: [
96
+ {
97
+ type: 'text' as const,
98
+ text: JSON.stringify({ sessionId, pageTitle, url: pageUrl, success: true }, null, 2),
99
+ },
100
+ {
101
+ type: 'image' as const,
102
+ data: screenshot.toString('base64'),
103
+ mimeType: 'image/png',
104
+ },
105
+ ],
106
+ };
107
+ } catch (error) {
108
+ const message = error instanceof Error ? error.message : String(error);
109
+ return {
110
+ content: [{ type: 'text' as const, text: `Error: ${message}` }],
111
+ isError: true,
112
+ };
113
+ }
114
+ },
115
+ );
116
+ }
@@ -0,0 +1,146 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import {
4
+ getOrCreateSession,
5
+ closeSession,
6
+ closeBrowser,
7
+ takeScreenshot as doScreenshot,
8
+ listSessions,
9
+ isBrowserRunning,
10
+ } from '../browser-manager.js';
11
+ import type { AppConfig } from '../config.js';
12
+
13
+ {{#if (eq name "start_browser")}}
14
+ const inputSchema = z.object({
15
+ sessionId: z.string().optional().describe('Reuse an existing session instead of starting a new one'),
16
+ headless: z.boolean().optional().describe('Run in headless mode (default: from server config)'),
17
+ });
18
+
19
+ export function register(server: McpServer, config: AppConfig): void {
20
+ server.registerTool(
21
+ 'start_browser',
22
+ {
23
+ title: 'Start Browser',
24
+ description: 'Launch a browser session. Returns a sessionId for subsequent tool calls.',
25
+ inputSchema,
26
+ annotations: { idempotentHint: true },
27
+ },
28
+ async (input) => {
29
+ try {
30
+ const { sessionId } = await getOrCreateSession(
31
+ (input as Record<string, unknown>).sessionId as string | undefined,
32
+ );
33
+
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text' as const,
38
+ text: JSON.stringify({
39
+ sessionId,
40
+ status: 'started',
41
+ activeSessions: listSessions().length,
42
+ }, null, 2),
43
+ },
44
+ ],
45
+ };
46
+ } catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ return {
49
+ content: [{ type: 'text' as const, text: `Error: ${message}` }],
50
+ isError: true,
51
+ };
52
+ }
53
+ },
54
+ );
55
+ }
56
+ {{/if}}
57
+
58
+ {{#if (eq name "stop_browser")}}
59
+ const inputSchema = z.object({
60
+ sessionId: z.string().optional().describe('Session to close. If omitted, closes all sessions'),
61
+ });
62
+
63
+ export function register(server: McpServer, config: AppConfig): void {
64
+ server.registerTool(
65
+ 'stop_browser',
66
+ {
67
+ title: 'Stop Browser',
68
+ description: 'Close a browser session and free resources.',
69
+ inputSchema,
70
+ annotations: { destructiveHint: true },
71
+ },
72
+ async (input) => {
73
+ try {
74
+ const sessionId = (input as Record<string, unknown>).sessionId as string | undefined;
75
+
76
+ if (sessionId) {
77
+ await closeSession(sessionId);
78
+ } else {
79
+ await closeBrowser();
80
+ }
81
+
82
+ return {
83
+ content: [
84
+ {
85
+ type: 'text' as const,
86
+ text: JSON.stringify({
87
+ status: 'stopped',
88
+ activeSessions: listSessions().length,
89
+ }, null, 2),
90
+ },
91
+ ],
92
+ };
93
+ } catch (error) {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ return {
96
+ content: [{ type: 'text' as const, text: `Error: ${message}` }],
97
+ isError: true,
98
+ };
99
+ }
100
+ },
101
+ );
102
+ }
103
+ {{/if}}
104
+
105
+ {{#if (eq name "take_screenshot")}}
106
+ const inputSchema = z.object({
107
+ sessionId: z.string().optional().describe('Session to screenshot. If omitted, uses default session'),
108
+ fullPage: z.boolean().optional().describe('Capture the full scrollable page (default: false)'),
109
+ });
110
+
111
+ export function register(server: McpServer, config: AppConfig): void {
112
+ server.registerTool(
113
+ 'take_screenshot',
114
+ {
115
+ title: 'Take Screenshot',
116
+ description: 'Capture a screenshot of the current page.',
117
+ inputSchema,
118
+ annotations: { readOnlyHint: true },
119
+ },
120
+ async (input) => {
121
+ try {
122
+ const sessionId = (input as Record<string, unknown>).sessionId as string | undefined;
123
+ const fullPage = (input as Record<string, unknown>).fullPage as boolean | undefined;
124
+
125
+ const screenshot = await doScreenshot(sessionId, fullPage ?? false);
126
+
127
+ return {
128
+ content: [
129
+ {
130
+ type: 'image' as const,
131
+ data: screenshot.toString('base64'),
132
+ mimeType: 'image/png',
133
+ },
134
+ ],
135
+ };
136
+ } catch (error) {
137
+ const message = error instanceof Error ? error.message : String(error);
138
+ return {
139
+ content: [{ type: 'text' as const, text: `Error: ${message}` }],
140
+ isError: true,
141
+ };
142
+ }
143
+ },
144
+ );
145
+ }
146
+ {{/if}}
@@ -0,0 +1,11 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { AppConfig } from '../config.js';
3
+ {{#each tools}}
4
+ import { register as register{{capitalize functionName}} } from './{{fileName}}.js';
5
+ {{/each}}
6
+
7
+ export function registerAllTools(server: McpServer, config: AppConfig): void {
8
+ {{#each tools}}
9
+ register{{capitalize functionName}}(server, config);
10
+ {{/each}}
11
+ }
@@ -0,0 +1 @@
1
+ export declare function renderTemplate(name: string, data: any): string;
@@ -0,0 +1,27 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import Handlebars from 'handlebars';
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const TEMPLATE_DIR = resolve(__dirname, 'templates');
7
+ const templateCache = new Map();
8
+ Handlebars.registerHelper('eq', function (a, b) {
9
+ return a === b;
10
+ });
11
+ Handlebars.registerHelper('capitalize', function (str) {
12
+ if (!str)
13
+ return str;
14
+ return str.charAt(0).toUpperCase() + str.slice(1);
15
+ });
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export function renderTemplate(name, data) {
18
+ if (!templateCache.has(name)) {
19
+ const templatePath = resolve(TEMPLATE_DIR, `${name}.hbs`);
20
+ if (!templatePath.startsWith(TEMPLATE_DIR + '/')) {
21
+ throw new Error(`Invalid template name: ${name}`);
22
+ }
23
+ const raw = readFileSync(templatePath, 'utf-8');
24
+ templateCache.set(name, Handlebars.compile(raw, { noEscape: true }));
25
+ }
26
+ return templateCache.get(name)(data);
27
+ }
@@ -0,0 +1,57 @@
1
+ import type { AppConfig } from './config.js';
2
+ {{#if hasOAuth}}
3
+ import { getAccessToken } from './oauth.js';
4
+ {{/if}}
5
+
6
+ {{#if hasOAuth}}
7
+ export async function getAuthHeaders(config: AppConfig): Promise<Record<string, string>> {
8
+ {{else}}
9
+ export function getAuthHeaders(config: AppConfig): Record<string, string> {
10
+ {{/if}}
11
+ const headers: Record<string, string> = {};
12
+
13
+ {{#each authSchemes}}
14
+ {{#if (eq type "apiKey")}}
15
+ {{#if (eq in "header")}}
16
+ if (config.apiKey) {
17
+ headers['{{headerName}}'] = config.apiKey;
18
+ }
19
+ {{/if}}
20
+ {{#if (eq in "query")}}
21
+ // API key sent as query parameter — handled in request URL construction
22
+ {{/if}}
23
+ {{/if}}
24
+ {{#if (eq type "http-bearer")}}
25
+ if (config.bearerToken) {
26
+ headers['Authorization'] = `Bearer ${config.bearerToken}`;
27
+ }
28
+ {{/if}}
29
+ {{#if (eq type "http-basic")}}
30
+ if (config.basicUsername && config.basicPassword) {
31
+ const encoded = Buffer.from(`${config.basicUsername}:${config.basicPassword}`).toString('base64');
32
+ headers['Authorization'] = `Basic ${encoded}`;
33
+ }
34
+ {{/if}}
35
+ {{#if (eq type "oauth2")}}
36
+ // OAuth2 — use token management with refresh
37
+ try {
38
+ const token = await getAccessToken({
39
+ clientId: config.oauth2ClientId ?? '',
40
+ clientSecret: config.oauth2ClientSecret,
41
+ authorizationUrl: config.oauth2AuthorizationUrl ?? '',
42
+ tokenUrl: config.oauth2TokenUrl ?? '',
43
+ scopes: [],
44
+ redirectUri: config.oauth2RedirectUri ?? 'http://localhost:3000/callback',
45
+ });
46
+ headers['Authorization'] = `Bearer ${token}`;
47
+ } catch {
48
+ // Fallback to pre-obtained token
49
+ if (config.oauth2Token) {
50
+ headers['Authorization'] = `Bearer ${config.oauth2Token}`;
51
+ }
52
+ }
53
+ {{/if}}
54
+ {{/each}}
55
+
56
+ return headers;
57
+ }
@@ -0,0 +1,63 @@
1
+ export interface AppConfig {
2
+ baseUrl: string;
3
+ {{#each authSchemes}}
4
+ {{#if (eq type "apiKey")}}
5
+ apiKey?: string;
6
+ {{/if}}
7
+ {{#if (eq type "http-bearer")}}
8
+ bearerToken?: string;
9
+ {{/if}}
10
+ {{#if (eq type "http-basic")}}
11
+ basicUsername?: string;
12
+ basicPassword?: string;
13
+ {{/if}}
14
+ {{#if (eq type "oauth2")}}
15
+ oauth2Token?: string;
16
+ oauth2ClientId?: string;
17
+ oauth2ClientSecret?: string;
18
+ oauth2AuthorizationUrl?: string;
19
+ oauth2TokenUrl?: string;
20
+ oauth2RedirectUri?: string;
21
+ {{/if}}
22
+ {{/each}}
23
+ maxRetries: number;
24
+ requestIntervalMs: number;
25
+ }
26
+
27
+ export function loadConfig(): AppConfig {
28
+ const baseUrl = requireEnv('BASE_URL');
29
+
30
+ return {
31
+ baseUrl: baseUrl.replace(/\/$/, ''),
32
+ {{#each authSchemes}}
33
+ {{#if (eq type "apiKey")}}
34
+ apiKey: process.env.API_KEY,
35
+ {{/if}}
36
+ {{#if (eq type "http-bearer")}}
37
+ bearerToken: process.env.BEARER_TOKEN,
38
+ {{/if}}
39
+ {{#if (eq type "http-basic")}}
40
+ basicUsername: process.env.BASIC_USERNAME,
41
+ basicPassword: process.env.BASIC_PASSWORD,
42
+ {{/if}}
43
+ {{#if (eq type "oauth2")}}
44
+ oauth2Token: process.env.OAUTH2_TOKEN,
45
+ oauth2ClientId: process.env.OAUTH2_CLIENT_ID,
46
+ oauth2ClientSecret: process.env.OAUTH2_CLIENT_SECRET,
47
+ oauth2AuthorizationUrl: process.env.OAUTH2_AUTHORIZATION_URL,
48
+ oauth2TokenUrl: process.env.OAUTH2_TOKEN_URL,
49
+ oauth2RedirectUri: process.env.OAUTH2_REDIRECT_URI,
50
+ {{/if}}
51
+ {{/each}}
52
+ maxRetries: parseInt(process.env.MAX_RETRIES ?? '3', 10),
53
+ requestIntervalMs: parseInt(process.env.REQUEST_INTERVAL_MS ?? '100', 10),
54
+ };
55
+ }
56
+
57
+ function requireEnv(name: string): string {
58
+ const value = process.env[name];
59
+ if (!value) {
60
+ throw new Error(`Missing required environment variable: ${name}`);
61
+ }
62
+ return value;
63
+ }