@langwatch/mcp-server 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +7 -0
- package/.npmignore +41 -0
- package/CHANGELOG.md +280 -200
- package/CONTRIBUTING.md +10 -0
- package/README.md +82 -52
- package/dist/add-dashboard-widget-4ZC5UN73.js +50 -0
- package/dist/add-dashboard-widget-ACC6QYBG.js +49 -0
- package/dist/archive-project-KWFM3I5Z.js +19 -0
- package/dist/{archive-project-4EQGLBJJ.js → archive-project-SPVHXK6A.js} +4 -4
- package/dist/archive-run-plan-65QN3XRX.js +16 -0
- package/dist/archive-run-plan-Z4SYE6BP.js +15 -0
- package/dist/{archive-scenario-W6BXYDZ3.js → archive-scenario-A6QV5LOW.js} +4 -4
- package/dist/archive-scenario-FXEYQNEH.js +19 -0
- package/dist/archive-test-suite-5ADQ3KPQ.js +15 -0
- package/dist/archive-test-suite-NKZDZY3D.js +16 -0
- package/dist/assign-prompt-tag-5IUZXJ2T.js +23 -0
- package/dist/{assign-prompt-tag-VLXUWEKU.js → assign-prompt-tag-HBZLBIFD.js} +8 -4
- package/dist/{chunk-CDYQOY5U.js → chunk-3OCG3QPU.js} +7 -10
- package/dist/chunk-3YLN3ATJ.js +241 -0
- package/dist/chunk-5FNCQRCX.js +91 -0
- package/dist/chunk-6YZUOD34.js +55 -0
- package/dist/{chunk-WVI5CJ6S.js → chunk-7AQLPVFL.js} +2 -2
- package/dist/chunk-7VNSRCXO.js +129 -0
- package/dist/{chunk-7RHG56OH.js → chunk-B4J3PJLX.js} +11 -10
- package/dist/{chunk-ZXKLPC2E.js → chunk-BIIKE3EI.js} +1 -1
- package/dist/{chunk-37SMPMQS.js → chunk-DMM3JQ42.js} +7 -2
- package/dist/{chunk-NUFPTHKU.js → chunk-FOKVY3BK.js} +1 -1
- package/dist/{chunk-WT4PO4A3.js → chunk-H6WGMG2T.js} +10 -7
- package/dist/{chunk-TOXJQDIZ.js → chunk-HGELNIVY.js} +135 -51
- package/dist/{chunk-UJPXFA26.js → chunk-HHMNZAPD.js} +101 -74
- package/dist/{chunk-J42FWRJ2.js → chunk-I7ATIZED.js} +7 -7
- package/dist/{chunk-AQJO2EI5.js → chunk-ILZDO25L.js} +7 -10
- package/dist/{chunk-4QC7SA2L.js → chunk-J7PQKBLD.js} +884 -559
- package/dist/{chunk-YX3A3CFM.js → chunk-JRJPH75H.js} +7 -13
- package/dist/chunk-K2I7Z3LZ.js +28 -0
- package/dist/{chunk-5CCZFUXS.js → chunk-NKMTIHIJ.js} +6 -9
- package/dist/chunk-O7EMWEVJ.js +44 -0
- package/dist/chunk-PTDR56Z3.js +37 -0
- package/dist/chunk-RABYBFX5.js +43 -0
- package/dist/chunk-SUPUUC4W.js +64 -0
- package/dist/{chunk-SFB4MU6H.js → chunk-SXFC3FNH.js} +4 -4
- package/dist/chunk-U24EACC4.js +67 -0
- package/dist/chunk-UNJM3BIL.js +21 -0
- package/dist/{chunk-ZWIL4EFL.js → chunk-UTJCWXPZ.js} +4 -4
- package/dist/chunk-UWLE5T2F.js +312 -0
- package/dist/chunk-VMWJD732.js +57 -0
- package/dist/chunk-XUIJYNRJ.js +15 -0
- package/dist/chunk-Y34DHR5K.js +67 -0
- package/dist/chunk-YCARO42Z.js +516 -0
- package/dist/config-EAKW6F26.js +16 -0
- package/dist/config.cjs +109 -0
- package/dist/config.js +5 -4
- package/dist/{create-agent-7XHO6UIS.js → create-agent-AYZ3LB3V.js} +4 -4
- package/dist/create-agent-S5ZBCEFT.js +23 -0
- package/dist/create-annotation-LHNCLHYP.js +29 -0
- package/dist/{create-annotation-YQXRQC6A.js → create-annotation-VUSXULQK.js} +10 -5
- package/dist/{create-api-key-YUS36KBU.js → create-api-key-NNYKARMG.js} +5 -7
- package/dist/create-api-key-T4KSNPKB.js +24 -0
- package/dist/create-dashboard-DHVFMEU4.js +18 -0
- package/dist/{create-dashboard-4Z5JO5LB.js → create-dashboard-WTKKS5Z6.js} +4 -4
- package/dist/{create-dataset-E6NMSVX7.js → create-dataset-2MC4SD4O.js} +6 -6
- package/dist/create-dataset-LUP5PVDM.js +22 -0
- package/dist/create-dataset-records-NSKBZP3G.js +20 -0
- package/dist/{create-dataset-records-SKHPRD2K.js → create-dataset-records-W4GLN2FV.js} +5 -7
- package/dist/{create-evaluator-JXF5PF33.js → create-evaluator-643G6LXL.js} +4 -4
- package/dist/create-evaluator-HMTYO5SS.js +27 -0
- package/dist/create-mcp-server.cjs +9513 -0
- package/dist/create-mcp-server.js +2647 -5
- package/dist/create-project-6N7PIYRY.js +44 -0
- package/dist/{create-project-CS2CB57Y.js → create-project-KAIC46UY.js} +4 -4
- package/dist/{create-prompt-F5RMX3L3.js → create-prompt-E67LXIYT.js} +5 -7
- package/dist/create-prompt-PKJ7EDRR.js +37 -0
- package/dist/create-prompt-tag-4YO3FSJ3.js +17 -0
- package/dist/{create-prompt-tag-GMRWTEFR.js → create-prompt-tag-OPQUEXWB.js} +3 -3
- package/dist/create-scenario-5PJBMAXO.js +33 -0
- package/dist/{create-scenario-JDR2VB2H.js → create-scenario-UEM77OE7.js} +11 -4
- package/dist/create-test-suite-4IPXVSFQ.js +37 -0
- package/dist/create-test-suite-SZEPVXSE.js +36 -0
- package/dist/create-trigger-5HZSCRAN.js +49 -0
- package/dist/create-trigger-PRELMT6J.js +48 -0
- package/dist/delete-agent-JUIZWAXG.js +18 -0
- package/dist/{delete-agent-O3EEH4S5.js → delete-agent-QMEK3XHK.js} +4 -4
- package/dist/delete-annotation-HY3O2OGR.js +17 -0
- package/dist/{delete-annotation-XP6FQM7A.js → delete-annotation-VKIQWUYW.js} +4 -4
- package/dist/delete-dashboard-76N66XXL.js +18 -0
- package/dist/{delete-dashboard-RFUNYCNP.js → delete-dashboard-JVIVHNJM.js} +4 -4
- package/dist/delete-dataset-HQCR66MG.js +18 -0
- package/dist/{delete-dataset-3MJFRDLP.js → delete-dataset-WKRUW4FP.js} +5 -7
- package/dist/{delete-dataset-records-WPMU5GL5.js → delete-dataset-records-C2IQFFVQ.js} +5 -7
- package/dist/delete-dataset-records-SDUHQLLM.js +19 -0
- package/dist/delete-evaluator-4SNSCLEE.js +16 -0
- package/dist/delete-evaluator-QP3QHTLN.js +15 -0
- package/dist/delete-prompt-tag-NZ4JQMYG.js +17 -0
- package/dist/{delete-prompt-tag-KNMZVSPB.js → delete-prompt-tag-YYQ4VMAD.js} +3 -3
- package/dist/{delete-workflow-3NUXO46U.js → delete-workflow-5J46T73T.js} +4 -4
- package/dist/delete-workflow-JSWABL5F.js +17 -0
- package/dist/discover-evaluator-schema-UHWA5HVL.js +120 -0
- package/dist/discover-evaluator-schema-XKCLLCB3.js +118 -0
- package/dist/discover-scenario-schema-NOJY6S7E.js +137 -0
- package/dist/discover-scenario-schema-OOFIQKOG.js +139 -0
- package/dist/{discover-schema-L6QDPON3.js → discover-schema-55YJBFGQ.js} +181 -186
- package/dist/discover-schema-A33SLMXW.js +442 -0
- package/dist/get-agent-LJQX7OF4.js +69 -0
- package/dist/get-agent-OTIYUFZA.js +70 -0
- package/dist/get-analytics-DCS72353.js +80 -0
- package/dist/get-analytics-IQZKJHLW.js +79 -0
- package/dist/get-dashboard-5NYJEIX2.js +29 -0
- package/dist/{get-dashboard-KHBEGZGL.js → get-dashboard-QMTYDQAZ.js} +4 -4
- package/dist/get-dataset-ALSP7RTX.js +64 -0
- package/dist/get-dataset-X4B5JDG2.js +63 -0
- package/dist/{get-evaluator-ADMKVWYZ.js → get-evaluator-ISMC4LLI.js} +4 -4
- package/dist/get-evaluator-XEUZGZCH.js +47 -0
- package/dist/{get-project-RAK7URQJ.js → get-project-5VKROSDH.js} +4 -4
- package/dist/get-project-RM6FRCBK.js +26 -0
- package/dist/get-prompt-OWXJZHQQ.js +95 -0
- package/dist/get-prompt-W52DY36E.js +94 -0
- package/dist/get-run-plan-BE3M2AUX.js +59 -0
- package/dist/get-run-plan-RUXQ6PAX.js +58 -0
- package/dist/get-scenario-RNM7BAX2.js +37 -0
- package/dist/{get-scenario-ZTAJJL5T.js → get-scenario-YM4ODWW6.js} +8 -4
- package/dist/get-simulation-run-6GIATQE5.js +69 -0
- package/dist/{get-simulation-run-T2ZQWYH2.js → get-simulation-run-LCFSMPGQ.js} +33 -20
- package/dist/get-test-suite-GC2O7YH6.js +49 -0
- package/dist/get-test-suite-P5LJ6VLF.js +48 -0
- package/dist/get-trace-KBRVV4NN.js +45 -0
- package/dist/{get-trace-K7U234Q4.js → get-trace-SEF3FMR5.js} +11 -13
- package/dist/get-workflow-7PVED7JE.js +25 -0
- package/dist/{get-workflow-L5L2PSK3.js → get-workflow-YXULW4GC.js} +4 -4
- package/dist/{http-security-EU3CHTY7.js → http-security-DNLBNQZL.js} +2 -2
- package/dist/{http-server-YXHFPPGA.js → http-server-IR4QOS43.js} +4071 -342
- package/dist/index.js +60221 -38077
- package/dist/langwatch-api-annotations-6SA4OB4C.js +17 -0
- package/dist/{langwatch-api-annotations-FDAS6NQ7.js → langwatch-api-annotations-TBHLCQ5R.js} +4 -4
- package/dist/langwatch-api-dashboards-6EO2VVZW.js +17 -0
- package/dist/{langwatch-api-dashboards-JTVCS7ZJ.js → langwatch-api-dashboards-NHU5BZD7.js} +4 -4
- package/dist/langwatch-api-monitors-CBF3FGIM.js +47 -0
- package/dist/{langwatch-api-monitors-3J7UIQME.js → langwatch-api-monitors-YNWA2M5Y.js} +11 -16
- package/dist/langwatch-api-secrets-ADTOJELP.js +56 -0
- package/dist/langwatch-api-secrets-RNFO4LF2.js +55 -0
- package/dist/langwatch-api-triggers-KQDQC6L5.js +22 -0
- package/dist/langwatch-api-triggers-QS7HDIVW.js +23 -0
- package/dist/{langwatch-api-workflows-NBJX5KOG.js → langwatch-api-workflows-OKC4FXIF.js} +4 -4
- package/dist/langwatch-api-workflows-XGJE6SR5.js +15 -0
- package/dist/list-agents-HVYWEQMI.js +43 -0
- package/dist/list-agents-RBAOCF53.js +42 -0
- package/dist/list-annotations-HJH4NBLD.js +38 -0
- package/dist/{list-annotations-ZTVP4EEL.js → list-annotations-J4UAHSUN.js} +10 -5
- package/dist/{list-api-keys-CWD4UQT5.js → list-api-keys-7UTJRZDG.js} +10 -5
- package/dist/list-api-keys-A2PMV435.js +42 -0
- package/dist/list-dashboard-boards-OPWROHMG.js +33 -0
- package/dist/list-dashboard-boards-U2GJ7GC5.js +34 -0
- package/dist/{list-dashboards-PWG6P6KR.js → list-dashboards-ROSYFLDQ.js} +4 -4
- package/dist/list-dashboards-RQ635ZU7.js +32 -0
- package/dist/{list-dataset-records-IOE7LQXS.js → list-dataset-records-M5TKA6LK.js} +14 -10
- package/dist/list-dataset-records-WFM7F33C.js +43 -0
- package/dist/{list-datasets-ZT4JYUDT.js → list-datasets-B5X4P7BQ.js} +9 -13
- package/dist/list-datasets-THUKQHPX.js +56 -0
- package/dist/{list-evaluators-SJHC7VBH.js → list-evaluators-MYH2OVCI.js} +5 -7
- package/dist/list-evaluators-NLVWF6K7.js +32 -0
- package/dist/{list-model-providers-PPD2WPD2.js → list-model-providers-3JUGP4YI.js} +4 -4
- package/dist/list-model-providers-H3XKORFO.js +35 -0
- package/dist/{list-projects-K7QAIX2I.js → list-projects-6EJ5YYEW.js} +5 -7
- package/dist/list-projects-YNNSRMLC.js +40 -0
- package/dist/{list-prompt-tags-FOO6TNHB.js → list-prompt-tags-NVFQO6WX.js} +3 -3
- package/dist/list-prompt-tags-XUQTTAH4.js +23 -0
- package/dist/{list-prompts-SC2HAUFG.js → list-prompts-HSIMMHTF.js} +4 -6
- package/dist/list-prompts-IRI6AIXO.js +30 -0
- package/dist/list-run-plans-PX2XI6EK.js +46 -0
- package/dist/list-run-plans-QALLCN2K.js +45 -0
- package/dist/list-scenarios-QZRPVHS4.js +46 -0
- package/dist/list-scenarios-SSJQEMJP.js +45 -0
- package/dist/list-simulation-runs-KNOLGMDV.js +53 -0
- package/dist/{list-simulation-runs-KF5THG5H.js → list-simulation-runs-OEADLLQR.js} +19 -9
- package/dist/list-test-suites-ANAQBLDG.js +34 -0
- package/dist/list-test-suites-N4WVLBKK.js +35 -0
- package/dist/list-trigger-fires-JV3WFYYG.js +19 -0
- package/dist/list-trigger-fires-WTW4DVIW.js +20 -0
- package/dist/list-triggers-SQNIG35Q.js +45 -0
- package/dist/list-triggers-V4Y356AK.js +46 -0
- package/dist/{list-workflows-QSJWURCK.js → list-workflows-IMSX7SXU.js} +5 -7
- package/dist/list-workflows-ZHTX5LCL.js +33 -0
- package/dist/{rename-prompt-tag-EKWU5QF3.js → rename-prompt-tag-IQI7MHOI.js} +3 -3
- package/dist/rename-prompt-tag-PA2BRIE6.js +18 -0
- package/dist/rename-test-suite-4J7UX5S2.js +21 -0
- package/dist/rename-test-suite-NNVLMLKY.js +20 -0
- package/dist/report-issue-AS34ZMJF.js +898 -0
- package/dist/report-issue-DCZFLGDO.js +899 -0
- package/dist/rerun-run-plan-TG2V4WM4.js +22 -0
- package/dist/rerun-run-plan-ZI5OY3VA.js +21 -0
- package/dist/revoke-api-key-3J3ZA4UB.js +15 -0
- package/dist/{revoke-api-key-FTRTZMOF.js → revoke-api-key-SFMEFWJC.js} +4 -4
- package/dist/run-agent-W4VJP72Z.js +75 -0
- package/dist/run-agent-YNV6ZHW4.js +74 -0
- package/dist/run-plan-6C77GWG4.js +38 -0
- package/dist/run-plan-PAARQSI4.js +39 -0
- package/dist/run-query-KJDH544C.js +47 -0
- package/dist/run-query-T4QW2Z5O.js +46 -0
- package/dist/run-test-suite-SQJELEZX.js +26 -0
- package/dist/run-test-suite-STB6NUJM.js +25 -0
- package/dist/{run-workflow-QPXC627O.js → run-workflow-D6PQNBI6.js} +4 -4
- package/dist/{run-agent-6SM4XNA7.js → run-workflow-SP32SO5M.js} +10 -11
- package/dist/search-traces-HCBGOG6R.js +170 -0
- package/dist/search-traces-HSTQ6WTQ.js +171 -0
- package/dist/{set-model-provider-3WKT63ZN.js → set-model-provider-GF7NXUJA.js} +4 -4
- package/dist/set-model-provider-KDQ7C4EZ.js +33 -0
- package/dist/{update-agent-SMAEHLXH.js → update-agent-DWG43T2P.js} +4 -4
- package/dist/update-agent-MXNOBS4H.js +20 -0
- package/dist/update-dashboard-widget-CJKJLCDY.js +71 -0
- package/dist/update-dashboard-widget-CYQDS2NR.js +70 -0
- package/dist/update-dataset-DQH3OHOU.js +22 -0
- package/dist/{update-dataset-BDUK7TUO.js → update-dataset-SQZ6T4WX.js} +6 -6
- package/dist/{update-dataset-record-4ZSDRBSW.js → update-dataset-record-3AT4IPBC.js} +4 -4
- package/dist/update-dataset-record-7PLDGTMR.js +19 -0
- package/dist/update-evaluator-4LFTKFPT.js +24 -0
- package/dist/{update-evaluator-LS6TIBY7.js → update-evaluator-IGTX6PX4.js} +4 -4
- package/dist/{update-project-LKVYXENH.js → update-project-PLJIOZS6.js} +4 -4
- package/dist/update-project-QVHSJRUP.js +24 -0
- package/dist/update-prompt-GDKRYJI3.js +140 -0
- package/dist/update-prompt-MY263DYF.js +141 -0
- package/dist/update-scenario-7KA3JDXA.js +34 -0
- package/dist/{update-scenario-NEXCAQI7.js → update-scenario-MOHRQKAQ.js} +11 -4
- package/package.json +39 -44
- package/pyproject.toml +8 -8
- package/src/config.d.ts +4 -0
- package/src/config.ts +20 -29
- package/src/create-mcp-server.ts +1021 -596
- package/src/documentation-fetch.ts +21 -20
- package/src/http-security.ts +166 -135
- package/src/http-server.ts +189 -224
- package/src/index.ts +14 -16
- package/src/langwatch-api-agents.ts +202 -21
- package/src/langwatch-api-annotations.ts +11 -12
- package/src/langwatch-api-api-keys.ts +8 -9
- package/src/langwatch-api-boards.ts +46 -0
- package/src/langwatch-api-dashboard-widgets.ts +112 -0
- package/src/langwatch-api-dashboards.ts +13 -10
- package/src/langwatch-api-datasets.ts +98 -32
- package/src/langwatch-api-evaluators.ts +13 -19
- package/src/langwatch-api-model-providers.ts +4 -4
- package/src/langwatch-api-monitors.ts +14 -18
- package/src/langwatch-api-projects.ts +27 -9
- package/src/langwatch-api-query.ts +114 -0
- package/src/langwatch-api-run-plans.ts +140 -0
- package/src/langwatch-api-scenarios.ts +17 -10
- package/src/langwatch-api-secrets.ts +31 -24
- package/src/langwatch-api-simulation-runs.ts +10 -7
- package/src/langwatch-api-test-suites.ts +116 -0
- package/src/langwatch-api-triggers.ts +96 -34
- package/src/langwatch-api-workflows.ts +9 -9
- package/src/langwatch-api.ts +143 -109
- package/src/public-http-request.ts +21 -12
- package/src/schemas/analytics-metrics.ts +3 -15
- package/src/schemas/create-dataset.ts +3 -4
- package/src/schemas/run-plan.ts +76 -0
- package/src/schemas/suite-fields.ts +132 -0
- package/src/schemas/triggers.ts +365 -0
- package/src/tools/add-dashboard-widget.ts +63 -0
- package/src/tools/archive-project.ts +2 -4
- package/src/tools/archive-run-plan.ts +10 -0
- package/src/tools/archive-scenario.ts +2 -4
- package/src/tools/archive-test-suite.ts +10 -0
- package/src/tools/assign-prompt-tag.ts +6 -2
- package/src/tools/create-agent.ts +1 -1
- package/src/tools/create-annotation.ts +7 -2
- package/src/tools/create-api-key.ts +4 -6
- package/src/tools/create-dashboard.ts +1 -1
- package/src/tools/create-dataset-records.ts +4 -8
- package/src/tools/create-dataset.ts +5 -7
- package/src/tools/create-evaluator.ts +3 -5
- package/src/tools/create-project.ts +2 -2
- package/src/tools/create-prompt-tag.ts +2 -4
- package/src/tools/create-prompt.ts +9 -18
- package/src/tools/create-scenario.ts +11 -5
- package/src/tools/create-test-suite.ts +38 -0
- package/src/tools/create-trigger.ts +55 -0
- package/src/tools/dashboard-exists.ts +25 -0
- package/src/tools/dashboard-widget-queries.ts +32 -0
- package/src/tools/delete-agent.ts +1 -1
- package/src/tools/delete-annotation.ts +1 -1
- package/src/tools/delete-dashboard.ts +1 -1
- package/src/tools/delete-dataset-records.ts +4 -8
- package/src/tools/delete-dataset.ts +3 -7
- package/src/tools/delete-evaluator.ts +4 -6
- package/src/tools/delete-prompt-tag.ts +2 -4
- package/src/tools/delete-workflow.ts +1 -1
- package/src/tools/discover-evaluator-schema.ts +34 -25
- package/src/tools/discover-scenario-schema.ts +86 -12
- package/src/tools/discover-schema.ts +149 -27
- package/src/tools/experiment-run-status.ts +2 -8
- package/src/tools/format-dataset-mutation.ts +5 -10
- package/src/tools/format-run-plan.ts +54 -0
- package/src/tools/format-scenario.ts +12 -0
- package/src/tools/format-suite-details.ts +90 -0
- package/src/tools/get-agent.ts +54 -3
- package/src/tools/get-analytics.ts +52 -46
- package/src/tools/get-dashboard.ts +1 -1
- package/src/tools/get-dataset.ts +34 -16
- package/src/tools/get-evaluator.ts +4 -11
- package/src/tools/get-experiment-results.ts +219 -186
- package/src/tools/get-project.ts +2 -4
- package/src/tools/get-prompt.ts +100 -37
- package/src/tools/get-run-plan.ts +60 -0
- package/src/tools/get-scenario.ts +6 -5
- package/src/tools/get-simulation-run.ts +32 -20
- package/src/tools/get-test-suite.ts +46 -0
- package/src/tools/get-trace.ts +16 -17
- package/src/tools/get-workflow.ts +1 -1
- package/src/tools/list-agents.ts +20 -3
- package/src/tools/list-annotations.ts +8 -5
- package/src/tools/list-api-keys.ts +7 -2
- package/src/tools/list-dashboard-boards.ts +28 -0
- package/src/tools/list-dashboards.ts +1 -1
- package/src/tools/list-dataset-records.ts +8 -6
- package/src/tools/list-datasets.ts +12 -23
- package/src/tools/list-evaluators.ts +4 -8
- package/src/tools/list-experiment-runs.ts +5 -9
- package/src/tools/list-experiments.ts +5 -11
- package/src/tools/list-model-providers.ts +3 -5
- package/src/tools/list-projects.ts +2 -4
- package/src/tools/list-prompt-tags.ts +3 -3
- package/src/tools/list-prompts.ts +4 -8
- package/src/tools/list-run-plans.ts +47 -0
- package/src/tools/list-scenarios.ts +26 -17
- package/src/tools/list-simulation-runs.ts +13 -5
- package/src/tools/list-test-suites.ts +35 -0
- package/src/tools/list-trigger-fires.ts +17 -0
- package/src/tools/list-triggers.ts +39 -0
- package/src/tools/list-workflows.ts +2 -4
- package/src/tools/rename-prompt-tag.ts +1 -1
- package/src/tools/rename-test-suite.ts +15 -0
- package/src/tools/report-issue.ts +5 -9
- package/src/tools/rerun-run-plan.ts +18 -0
- package/src/tools/revoke-api-key.ts +2 -4
- package/src/tools/run-agent.ts +65 -14
- package/src/tools/run-experiment.ts +36 -37
- package/src/tools/run-plan.ts +46 -0
- package/src/tools/run-query.ts +47 -0
- package/src/tools/run-test-suite.ts +27 -0
- package/src/tools/run-workflow.ts +2 -5
- package/src/tools/search-traces.ts +161 -47
- package/src/tools/set-model-provider.ts +4 -6
- package/src/tools/test-agent.ts +18 -0
- package/src/tools/update-agent.ts +1 -1
- package/src/tools/update-dashboard-widget.ts +97 -0
- package/src/tools/update-dataset-record.ts +1 -1
- package/src/tools/update-dataset.ts +5 -7
- package/src/tools/update-evaluator.ts +3 -5
- package/src/tools/update-project.ts +1 -1
- package/src/tools/update-prompt.ts +185 -15
- package/src/tools/update-scenario.ts +11 -5
- package/src/tools/update-test-suite.ts +40 -0
- package/src/utils/date-parsing.ts +1 -1
- package/src/utils/escape-markdown.ts +3 -8
- package/src/utils/format-evaluations.ts +6 -6
- package/src/utils/markdown-table.ts +58 -0
- package/src/utils/trace-id-shape.ts +20 -0
- package/tsconfig.app.json +24 -0
- package/tsconfig.json +19 -12
- package/uv.lock +416 -296
- package/vitest.integration.config.js +10 -0
- package/vitest.scenario.config.js +9 -0
- package/.eslintrc.cjs +0 -36
- package/dist/archive-suite-4T6BSRS7.js +0 -16
- package/dist/chunk-77BNWQ3U.js +0 -86
- package/dist/chunk-A2LEVYQ5.js +0 -217
- package/dist/chunk-TJCXFNDT.js +0 -24
- package/dist/chunk-YZLYHLLI.js +0 -48
- package/dist/config.d.ts +0 -17
- package/dist/create-mcp-server.d.ts +0 -10
- package/dist/create-suite-LZS6QIAF.js +0 -39
- package/dist/delete-evaluator-33SP2JFX.js +0 -16
- package/dist/discover-evaluator-schema-XTAD4X7D.js +0 -2191
- package/dist/discover-scenario-schema-FE64QK2D.js +0 -67
- package/dist/get-agent-Y7MWZ65F.js +0 -29
- package/dist/get-analytics-TETCSOK6.js +0 -73
- package/dist/get-dataset-RCMU5VAH.js +0 -49
- package/dist/get-prompt-OY5B7TRI.js +0 -46
- package/dist/get-suite-J7JVWO6O.js +0 -45
- package/dist/index.d.ts +0 -2
- package/dist/langwatch-api-secrets-BUBSNCNO.js +0 -41
- package/dist/langwatch-api-triggers-EDFUCJN6.js +0 -31
- package/dist/list-agents-KFHKGPXV.js +0 -33
- package/dist/list-scenarios-F2WYNRIE.js +0 -41
- package/dist/list-suites-CRY4VWW6.js +0 -43
- package/dist/report-issue-XYVAPAYJ.js +0 -412
- package/dist/run-suite-NKZCJ2IN.js +0 -30
- package/dist/search-traces-A6HFKPLJ.js +0 -79
- package/dist/update-prompt-ODCRQRN6.js +0 -25
- package/dist/update-suite-SNO3GS7T.js +0 -40
- package/src/__tests__/all-tools.integration.test.ts +0 -1626
- package/src/__tests__/config.unit.test.ts +0 -202
- package/src/__tests__/datasets.integration.test.ts +0 -620
- package/src/__tests__/datasets.unit.test.ts +0 -244
- package/src/__tests__/date-parsing.unit.test.ts +0 -78
- package/src/__tests__/discover-evaluator-schema.unit.test.ts +0 -89
- package/src/__tests__/discover-schema.unit.test.ts +0 -118
- package/src/__tests__/docker.integration.test.ts +0 -318
- package/src/__tests__/documentation-fetch-security.integration.test.ts +0 -182
- package/src/__tests__/evaluator-tools.unit.test.ts +0 -262
- package/src/__tests__/experiment-list-tools.unit.test.ts +0 -157
- package/src/__tests__/experiment-status.unit.test.ts +0 -194
- package/src/__tests__/feature-map-tool-drift.unit.test.ts +0 -93
- package/src/__tests__/get-experiment-results.unit.test.ts +0 -313
- package/src/__tests__/http-security-origin.unit.test.ts +0 -97
- package/src/__tests__/http-security-sessions.unit.test.ts +0 -209
- package/src/__tests__/http-security-verifier.unit.test.ts +0 -248
- package/src/__tests__/http-server-allocation.integration.test.ts +0 -279
- package/src/__tests__/http-server-origin.integration.test.ts +0 -169
- package/src/__tests__/http-server-session-auth.integration.test.ts +0 -341
- package/src/__tests__/http-transport.integration.test.ts +0 -395
- package/src/__tests__/integration.integration.test.ts +0 -288
- package/src/__tests__/langwatch-api.unit.test.ts +0 -661
- package/src/__tests__/model-provider-tools.unit.test.ts +0 -190
- package/src/__tests__/project-api-key-tools.unit.test.ts +0 -451
- package/src/__tests__/public-http-request-security.integration.test.ts +0 -118
- package/src/__tests__/report-issue.integration.test.ts +0 -147
- package/src/__tests__/scenario-tools.integration.test.ts +0 -286
- package/src/__tests__/scenario-tools.unit.test.ts +0 -188
- package/src/__tests__/schemas.unit.test.ts +0 -85
- package/src/__tests__/support/http-server-harness.ts +0 -138
- package/src/__tests__/tools.unit.test.ts +0 -924
- package/src/langwatch-api-suites.ts +0 -118
- package/src/schemas/filter-fields.ts +0 -119
- package/src/schemas/index.ts +0 -4
- package/src/tools/archive-suite.ts +0 -12
- package/src/tools/create-suite.ts +0 -42
- package/src/tools/get-suite.ts +0 -47
- package/src/tools/list-suites.ts +0 -43
- package/src/tools/run-suite.ts +0 -28
- package/src/tools/update-suite.ts +0 -44
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { createServer, type Server } from "node:http";
|
|
2
|
-
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
headersForRedirect,
|
|
6
|
-
requestPublicJson,
|
|
7
|
-
resolvePublicDestination,
|
|
8
|
-
} from "../public-http-request.js";
|
|
9
|
-
|
|
10
|
-
describe("public HTTP request security", () => {
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
vi.useRealTimers();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
/** @scenario Running an HTTP agent rejects unsafe destinations */
|
|
16
|
-
it.each([
|
|
17
|
-
"http://127.0.0.1/secrets",
|
|
18
|
-
"http://2130706433/secrets",
|
|
19
|
-
"http://169.254.169.254/latest/meta-data/",
|
|
20
|
-
"http://10.0.0.1/internal",
|
|
21
|
-
"http://[::1]/secrets",
|
|
22
|
-
"file:///etc/passwd",
|
|
23
|
-
"http://user:password@example.com/",
|
|
24
|
-
])("rejects unsafe destination %s", async (url) => {
|
|
25
|
-
await expect(resolvePublicDestination(url)).rejects.toThrow(/globally routable public addresses/);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("fails closed when any resolved address is not public", async () => {
|
|
29
|
-
await expect(
|
|
30
|
-
resolvePublicDestination("https://agent.example/run", async () => [
|
|
31
|
-
{ address: "93.184.216.34", family: 4 },
|
|
32
|
-
{ address: "10.0.0.4", family: 4 },
|
|
33
|
-
])
|
|
34
|
-
).rejects.toThrow(/globally routable public addresses/);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("pins a validated public destination", async () => {
|
|
38
|
-
await expect(
|
|
39
|
-
resolvePublicDestination("https://agent.example/run", async () => [{ address: "93.184.216.34", family: 4 }])
|
|
40
|
-
).resolves.toMatchObject({
|
|
41
|
-
address: "93.184.216.34",
|
|
42
|
-
family: 4,
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("bounds DNS resolution time", async () => {
|
|
47
|
-
vi.useFakeTimers();
|
|
48
|
-
const resolution = resolvePublicDestination(
|
|
49
|
-
"https://agent.example/run",
|
|
50
|
-
() => new Promise(() => undefined)
|
|
51
|
-
);
|
|
52
|
-
const rejection = expect(resolution).rejects.toThrow(
|
|
53
|
-
/destination could not be resolved/
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
await vi.advanceTimersByTimeAsync(30_000);
|
|
57
|
-
|
|
58
|
-
await rejection;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
/** @scenario HTTP agent redirects are revalidated */
|
|
62
|
-
it("rejects private redirect targets and strips cross-origin secrets", async () => {
|
|
63
|
-
await expect(
|
|
64
|
-
resolvePublicDestination("http://127.0.0.1/redirect-target")
|
|
65
|
-
).rejects.toThrow(/globally routable public addresses/);
|
|
66
|
-
|
|
67
|
-
expect(
|
|
68
|
-
headersForRedirect(
|
|
69
|
-
{
|
|
70
|
-
Authorization: "Bearer secret",
|
|
71
|
-
Cookie: "session=secret",
|
|
72
|
-
"Content-Type": "application/json",
|
|
73
|
-
"X-Api-Key": "secret",
|
|
74
|
-
"X-Request-Id": "request-1",
|
|
75
|
-
},
|
|
76
|
-
true
|
|
77
|
-
)
|
|
78
|
-
).toEqual({
|
|
79
|
-
"Content-Type": "application/json",
|
|
80
|
-
"X-Request-Id": "request-1",
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe("real HTTP request", () => {
|
|
85
|
-
let server: Server;
|
|
86
|
-
let port: number;
|
|
87
|
-
let hits = 0;
|
|
88
|
-
|
|
89
|
-
beforeAll(async () => {
|
|
90
|
-
server = createServer((_request, response) => {
|
|
91
|
-
hits += 1;
|
|
92
|
-
response.setHeader("Content-Type", "application/json");
|
|
93
|
-
response.end(JSON.stringify({ secret: true }));
|
|
94
|
-
});
|
|
95
|
-
await new Promise<void>((resolve) => {
|
|
96
|
-
server.listen(0, "127.0.0.1", resolve);
|
|
97
|
-
});
|
|
98
|
-
const address = server.address();
|
|
99
|
-
port = typeof address === "object" && address ? address.port : 0;
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
afterAll(async () => {
|
|
103
|
-
await new Promise<void>((resolve, reject) => {
|
|
104
|
-
server.close((error) => (error ? reject(error) : resolve()));
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("blocks loopback before opening a connection", async () => {
|
|
109
|
-
await expect(
|
|
110
|
-
requestPublicJson(`http://127.0.0.1:${port}/secrets`, {
|
|
111
|
-
method: "POST",
|
|
112
|
-
body: "{}",
|
|
113
|
-
})
|
|
114
|
-
).rejects.toThrow(/globally routable public addresses/);
|
|
115
|
-
expect(hits).toBe(0);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { createServer, type Server } from "node:http";
|
|
2
|
-
import type { AddressInfo } from "node:net";
|
|
3
|
-
import {
|
|
4
|
-
afterAll,
|
|
5
|
-
beforeAll,
|
|
6
|
-
beforeEach,
|
|
7
|
-
describe,
|
|
8
|
-
expect,
|
|
9
|
-
it,
|
|
10
|
-
} from "vitest";
|
|
11
|
-
import { initConfig } from "../config.js";
|
|
12
|
-
import { createMcpServer } from "../create-mcp-server.js";
|
|
13
|
-
import { handleReportIssue } from "../tools/report-issue.js";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Integration tests for the report_issue tool against a REAL local HTTP
|
|
17
|
-
* server. Corresponds to specs/mcp-server/report-issue-tool.feature.
|
|
18
|
-
*/
|
|
19
|
-
describe("report_issue", () => {
|
|
20
|
-
let server: Server;
|
|
21
|
-
let endpoint: string;
|
|
22
|
-
let received: { headers: Record<string, unknown>; body: any }[];
|
|
23
|
-
|
|
24
|
-
beforeAll(async () => {
|
|
25
|
-
server = createServer((req, res) => {
|
|
26
|
-
let data = "";
|
|
27
|
-
req.on("data", (chunk: Buffer) => (data += chunk.toString()));
|
|
28
|
-
req.on("end", () => {
|
|
29
|
-
received.push({ headers: { ...req.headers }, body: JSON.parse(data) });
|
|
30
|
-
res.writeHead(201, { "content-type": "application/json" });
|
|
31
|
-
res.end(JSON.stringify({ id: "report-mcp-1" }));
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
35
|
-
endpoint = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
afterAll(async () => {
|
|
39
|
-
await new Promise((resolve) => server.close(resolve));
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
received = [];
|
|
44
|
-
initConfig({ endpoint, apiKey: undefined });
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe("given the registered tool set", () => {
|
|
48
|
-
/** @scenario "The report tool is listed with an agent-facing description" */
|
|
49
|
-
it("lists report_issue with the agent-facing consent description", () => {
|
|
50
|
-
const server = createMcpServer();
|
|
51
|
-
const tools = (
|
|
52
|
-
server as unknown as {
|
|
53
|
-
_registeredTools: Record<string, { description?: string }>;
|
|
54
|
-
}
|
|
55
|
-
)._registeredTools;
|
|
56
|
-
expect(Object.keys(tools)).toContain("report_issue");
|
|
57
|
-
const description = tools.report_issue?.description ?? "";
|
|
58
|
-
expect(description).toMatch(/whenever you struggled/i);
|
|
59
|
-
expect(description).toMatch(/ask the user for permission first/i);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("given the user did not approve sending", () => {
|
|
64
|
-
/** @scenario "Calls without user approval are rejected with instructions" */
|
|
65
|
-
it("refuses with instructions to ask the user first", async () => {
|
|
66
|
-
await expect(
|
|
67
|
-
handleReportIssue({
|
|
68
|
-
user_approved: false,
|
|
69
|
-
title: "broken tool",
|
|
70
|
-
summary: "search_traces 500s",
|
|
71
|
-
}),
|
|
72
|
-
).rejects.toThrow(/ask the user/i);
|
|
73
|
-
expect(received).toHaveLength(0);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe("given nothing to report", () => {
|
|
78
|
-
it("asks for a summary or session content", async () => {
|
|
79
|
-
await expect(
|
|
80
|
-
handleReportIssue({ user_approved: true, title: "empty" }),
|
|
81
|
-
).rejects.toThrow(/Nothing to report/);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe("when the user approved a summary report", () => {
|
|
86
|
-
/** @scenario "Reporting an issue through MCP reaches the LangWatch backend" */
|
|
87
|
-
it("delivers it marked as coming from MCP and returns a thank-you", async () => {
|
|
88
|
-
const text = await handleReportIssue({
|
|
89
|
-
user_approved: true,
|
|
90
|
-
title: "evaluator setup confusing",
|
|
91
|
-
summary: "the evaluator wizard 404s on step 2",
|
|
92
|
-
agent: "claude-code",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
expect(received).toHaveLength(1);
|
|
96
|
-
expect(received[0]?.body.source).toBe("mcp");
|
|
97
|
-
expect(received[0]?.body.kind).toBe("summary");
|
|
98
|
-
expect(received[0]?.body.title).toBe("evaluator setup confusing");
|
|
99
|
-
expect(text).toContain("report-mcp-1");
|
|
100
|
-
expect(text.toLowerCase()).toContain("thank you");
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe("when the title itself includes a secret", () => {
|
|
105
|
-
it("redacts it before sending", async () => {
|
|
106
|
-
await handleReportIssue({
|
|
107
|
-
user_approved: true,
|
|
108
|
-
title: "X-Api-Key sk-proj-abcdefghijklmnopqrstuvwxyz123456 rejected",
|
|
109
|
-
summary: "the key was rejected",
|
|
110
|
-
});
|
|
111
|
-
expect(received[0]?.body.title).toBe("X-Api-Key [SECRET] rejected");
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe("when session content includes secrets", () => {
|
|
116
|
-
/** @scenario "Session content passed through MCP is redacted before sending" */
|
|
117
|
-
it("redacts them locally before sending", async () => {
|
|
118
|
-
await handleReportIssue({
|
|
119
|
-
user_approved: true,
|
|
120
|
-
title: "agent stuck",
|
|
121
|
-
session_content: JSON.stringify({
|
|
122
|
-
role: "user",
|
|
123
|
-
content: "my key sk-proj-abcdefghijklmnopqrstuvwxyz123456 failed",
|
|
124
|
-
}),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const wire = JSON.stringify(received[0]?.body);
|
|
128
|
-
expect(wire).not.toContain("sk-proj-abcdefghijklmnopqrstuvwxyz123456");
|
|
129
|
-
expect(received[0]?.body.sessionData).toContain("[SECRET]");
|
|
130
|
-
expect(received[0]?.body.kind).toBe("full_session");
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe("when an API key is configured", () => {
|
|
135
|
-
it("attaches it so the report links to the project", async () => {
|
|
136
|
-
initConfig({ endpoint, apiKey: "sk-lw-mcp-key-abcdef1234567890" });
|
|
137
|
-
await handleReportIssue({
|
|
138
|
-
user_approved: true,
|
|
139
|
-
title: "linked",
|
|
140
|
-
summary: "linked report",
|
|
141
|
-
});
|
|
142
|
-
expect(received[0]?.headers.authorization).toBe(
|
|
143
|
-
"Bearer sk-lw-mcp-key-abcdef1234567890",
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
});
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { createServer, type Server } from "http";
|
|
2
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
|
-
import { initConfig } from "../config.js";
|
|
4
|
-
|
|
5
|
-
// --- Canned responses for scenario API endpoints ---
|
|
6
|
-
|
|
7
|
-
const CANNED_SCENARIOS_LIST = [
|
|
8
|
-
{
|
|
9
|
-
id: "scen_abc123",
|
|
10
|
-
name: "Login Flow Happy Path",
|
|
11
|
-
situation: "User attempts to log in with valid credentials",
|
|
12
|
-
criteria: ["Responds with a welcome message", "Includes user name in greeting"],
|
|
13
|
-
labels: ["auth", "happy-path"],
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
id: "scen_def456",
|
|
17
|
-
name: "Password Reset",
|
|
18
|
-
situation: "User requests a password reset link",
|
|
19
|
-
criteria: ["Sends reset email"],
|
|
20
|
-
labels: ["auth"],
|
|
21
|
-
},
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const CANNED_SCENARIO_DETAIL = {
|
|
25
|
-
id: "scen_abc123",
|
|
26
|
-
name: "Login Flow Happy Path",
|
|
27
|
-
situation: "User attempts to log in with valid credentials",
|
|
28
|
-
criteria: ["Responds with a welcome message", "Includes user name in greeting"],
|
|
29
|
-
labels: ["auth", "happy-path"],
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const CANNED_SCENARIO_CREATED = {
|
|
33
|
-
id: "scen_new789",
|
|
34
|
-
name: "Login Flow Happy Path",
|
|
35
|
-
situation: "User attempts to log in with valid creds",
|
|
36
|
-
criteria: ["Responds with a welcome message", "Includes user name in greeting"],
|
|
37
|
-
labels: ["auth", "happy-path"],
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const CANNED_SCENARIO_UPDATED = {
|
|
41
|
-
id: "scen_abc123",
|
|
42
|
-
name: "Login Flow - Valid Credentials",
|
|
43
|
-
situation: "User logs in with correct email and pass",
|
|
44
|
-
criteria: [
|
|
45
|
-
"Responds with welcome message",
|
|
46
|
-
"Sets session cookie",
|
|
47
|
-
"Redirects to dashboard",
|
|
48
|
-
],
|
|
49
|
-
labels: ["auth", "happy-path"],
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const CANNED_SCENARIO_ARCHIVED = {
|
|
53
|
-
id: "scen_abc123",
|
|
54
|
-
archived: true,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// --- Mock HTTP Server ---
|
|
58
|
-
|
|
59
|
-
function createMockServer(): Server {
|
|
60
|
-
return createServer((req, res) => {
|
|
61
|
-
const authToken = req.headers["x-auth-token"];
|
|
62
|
-
if (authToken !== "test-integration-key") {
|
|
63
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
64
|
-
res.end(JSON.stringify({ message: "Invalid auth token." }));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let body = "";
|
|
69
|
-
req.on("data", (chunk: string) => (body += chunk));
|
|
70
|
-
req.on("end", () => {
|
|
71
|
-
const url = req.url ?? "";
|
|
72
|
-
res.setHeader("Content-Type", "application/json");
|
|
73
|
-
|
|
74
|
-
// GET /api/scenarios - list all scenarios
|
|
75
|
-
if (url === "/api/scenarios" && req.method === "GET") {
|
|
76
|
-
res.writeHead(200);
|
|
77
|
-
res.end(JSON.stringify(CANNED_SCENARIOS_LIST));
|
|
78
|
-
}
|
|
79
|
-
// GET /api/scenarios/:id - get scenario detail
|
|
80
|
-
else if (
|
|
81
|
-
url.match(/^\/api\/scenarios\/scen_abc123(\?|$)/) &&
|
|
82
|
-
req.method === "GET"
|
|
83
|
-
) {
|
|
84
|
-
res.writeHead(200);
|
|
85
|
-
res.end(JSON.stringify(CANNED_SCENARIO_DETAIL));
|
|
86
|
-
}
|
|
87
|
-
// GET /api/scenarios/:id - not found
|
|
88
|
-
else if (
|
|
89
|
-
url.match(/^\/api\/scenarios\/scen_nonexistent(\?|$)/) &&
|
|
90
|
-
req.method === "GET"
|
|
91
|
-
) {
|
|
92
|
-
res.writeHead(404);
|
|
93
|
-
res.end(JSON.stringify({ message: "Scenario not found" }));
|
|
94
|
-
}
|
|
95
|
-
// POST /api/scenarios - create scenario
|
|
96
|
-
else if (url === "/api/scenarios" && req.method === "POST") {
|
|
97
|
-
const parsed = JSON.parse(body);
|
|
98
|
-
if (!parsed.name) {
|
|
99
|
-
res.writeHead(400);
|
|
100
|
-
res.end(JSON.stringify({ message: "Validation error: name is required" }));
|
|
101
|
-
} else {
|
|
102
|
-
res.writeHead(201);
|
|
103
|
-
res.end(JSON.stringify(CANNED_SCENARIO_CREATED));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// PUT /api/scenarios/:id - update scenario
|
|
107
|
-
else if (
|
|
108
|
-
url.match(/^\/api\/scenarios\/scen_abc123$/) &&
|
|
109
|
-
req.method === "PUT"
|
|
110
|
-
) {
|
|
111
|
-
res.writeHead(200);
|
|
112
|
-
res.end(JSON.stringify(CANNED_SCENARIO_UPDATED));
|
|
113
|
-
}
|
|
114
|
-
// PUT /api/scenarios/:id - not found
|
|
115
|
-
else if (
|
|
116
|
-
url.match(/^\/api\/scenarios\/scen_nonexistent$/) &&
|
|
117
|
-
req.method === "PUT"
|
|
118
|
-
) {
|
|
119
|
-
res.writeHead(404);
|
|
120
|
-
res.end(JSON.stringify({ message: "Scenario not found" }));
|
|
121
|
-
}
|
|
122
|
-
// DELETE /api/scenarios/:id - archive scenario
|
|
123
|
-
else if (
|
|
124
|
-
url.match(/^\/api\/scenarios\/scen_abc123$/) &&
|
|
125
|
-
req.method === "DELETE"
|
|
126
|
-
) {
|
|
127
|
-
res.writeHead(200);
|
|
128
|
-
res.end(JSON.stringify(CANNED_SCENARIO_ARCHIVED));
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
res.writeHead(404);
|
|
132
|
-
res.end(
|
|
133
|
-
JSON.stringify({ message: `Not found: ${req.method} ${url}` })
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// --- Integration Tests ---
|
|
141
|
-
// These verify that MCP tool handlers correctly communicate with the REST API
|
|
142
|
-
// (auth, HTTP methods, status codes, error propagation).
|
|
143
|
-
// Formatting/digest logic is tested in scenario-tools.unit.test.ts.
|
|
144
|
-
|
|
145
|
-
describe("MCP scenario tools integration", () => {
|
|
146
|
-
let server: Server;
|
|
147
|
-
let port: number;
|
|
148
|
-
|
|
149
|
-
beforeAll(async () => {
|
|
150
|
-
server = createMockServer();
|
|
151
|
-
await new Promise<void>((resolve) => {
|
|
152
|
-
server.listen(0, () => {
|
|
153
|
-
const addr = server.address();
|
|
154
|
-
port = typeof addr === "object" && addr ? addr.port : 0;
|
|
155
|
-
initConfig({
|
|
156
|
-
apiKey: "test-integration-key",
|
|
157
|
-
endpoint: `http://localhost:${port}`,
|
|
158
|
-
});
|
|
159
|
-
resolve();
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
afterAll(async () => {
|
|
165
|
-
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
describe("platform_list_scenarios", () => {
|
|
169
|
-
describe("when the API returns scenarios", () => {
|
|
170
|
-
it("returns a non-empty result", async () => {
|
|
171
|
-
const { handleListScenarios } = await import(
|
|
172
|
-
"../tools/list-scenarios.js"
|
|
173
|
-
);
|
|
174
|
-
const result = await handleListScenarios({});
|
|
175
|
-
expect(result.length).toBeGreaterThan(0);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe("when format is json", () => {
|
|
180
|
-
it("returns parseable JSON matching the API response", async () => {
|
|
181
|
-
const { handleListScenarios } = await import(
|
|
182
|
-
"../tools/list-scenarios.js"
|
|
183
|
-
);
|
|
184
|
-
const result = await handleListScenarios({ format: "json" });
|
|
185
|
-
expect(JSON.parse(result)).toEqual(CANNED_SCENARIOS_LIST);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
describe("platform_get_scenario", () => {
|
|
191
|
-
describe("when the scenario exists", () => {
|
|
192
|
-
it("returns a non-empty result", async () => {
|
|
193
|
-
const { handleGetScenario } = await import(
|
|
194
|
-
"../tools/get-scenario.js"
|
|
195
|
-
);
|
|
196
|
-
const result = await handleGetScenario({ scenarioId: "scen_abc123" });
|
|
197
|
-
expect(result.length).toBeGreaterThan(0);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe("when the scenario does not exist", () => {
|
|
202
|
-
it("propagates the 404 error", async () => {
|
|
203
|
-
const { handleGetScenario } = await import(
|
|
204
|
-
"../tools/get-scenario.js"
|
|
205
|
-
);
|
|
206
|
-
await expect(
|
|
207
|
-
handleGetScenario({ scenarioId: "scen_nonexistent" })
|
|
208
|
-
).rejects.toThrow("404");
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
describe("platform_create_scenario", () => {
|
|
214
|
-
describe("when valid data is provided", () => {
|
|
215
|
-
it("returns confirmation with new scenario ID", async () => {
|
|
216
|
-
const { handleCreateScenario } = await import(
|
|
217
|
-
"../tools/create-scenario.js"
|
|
218
|
-
);
|
|
219
|
-
const result = await handleCreateScenario({
|
|
220
|
-
name: "Login Flow Happy Path",
|
|
221
|
-
situation: "User attempts to log in with valid creds",
|
|
222
|
-
criteria: ["Responds with a welcome message", "Includes user name in greeting"],
|
|
223
|
-
labels: ["auth", "happy-path"],
|
|
224
|
-
});
|
|
225
|
-
expect(result).toContain("scen_new789");
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
describe("when name is empty", () => {
|
|
230
|
-
it("propagates the validation error", async () => {
|
|
231
|
-
const { handleCreateScenario } = await import(
|
|
232
|
-
"../tools/create-scenario.js"
|
|
233
|
-
);
|
|
234
|
-
await expect(
|
|
235
|
-
handleCreateScenario({
|
|
236
|
-
name: "",
|
|
237
|
-
situation: "Some situation",
|
|
238
|
-
})
|
|
239
|
-
).rejects.toThrow();
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
describe("platform_update_scenario", () => {
|
|
245
|
-
describe("when the scenario exists", () => {
|
|
246
|
-
it("returns a non-empty result", async () => {
|
|
247
|
-
const { handleUpdateScenario } = await import(
|
|
248
|
-
"../tools/update-scenario.js"
|
|
249
|
-
);
|
|
250
|
-
const result = await handleUpdateScenario({
|
|
251
|
-
scenarioId: "scen_abc123",
|
|
252
|
-
name: "Login Flow - Valid Credentials",
|
|
253
|
-
});
|
|
254
|
-
expect(result.length).toBeGreaterThan(0);
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
describe("when the scenario does not exist", () => {
|
|
259
|
-
it("propagates the 404 error", async () => {
|
|
260
|
-
const { handleUpdateScenario } = await import(
|
|
261
|
-
"../tools/update-scenario.js"
|
|
262
|
-
);
|
|
263
|
-
await expect(
|
|
264
|
-
handleUpdateScenario({
|
|
265
|
-
scenarioId: "scen_nonexistent",
|
|
266
|
-
name: "Updated Name",
|
|
267
|
-
})
|
|
268
|
-
).rejects.toThrow("404");
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
describe("platform_archive_scenario", () => {
|
|
274
|
-
describe("when the scenario exists", () => {
|
|
275
|
-
it("returns confirmation that scenario was archived", async () => {
|
|
276
|
-
const { handleArchiveScenario } = await import(
|
|
277
|
-
"../tools/archive-scenario.js"
|
|
278
|
-
);
|
|
279
|
-
const result = await handleArchiveScenario({
|
|
280
|
-
scenarioId: "scen_abc123",
|
|
281
|
-
});
|
|
282
|
-
expect(result).toContain("archived");
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
});
|