decodingtrust-agent-sdk 0.1.0__py3-none-any.whl

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 (374) hide show
  1. agent/__init__.py +30 -0
  2. agent/claudesdk/__init__.py +8 -0
  3. agent/claudesdk/example.py +221 -0
  4. agent/claudesdk/src/__init__.py +8 -0
  5. agent/claudesdk/src/agent.py +400 -0
  6. agent/claudesdk/src/mcp_proxy.py +409 -0
  7. agent/claudesdk/src/utils.py +420 -0
  8. agent/googleadk/__init__.py +15 -0
  9. agent/googleadk/example.py +237 -0
  10. agent/googleadk/src/__init__.py +12 -0
  11. agent/googleadk/src/agent.py +401 -0
  12. agent/googleadk/src/mcp_wrapper.py +163 -0
  13. agent/googleadk/src/utils.py +602 -0
  14. agent/langchain/__init__.py +8 -0
  15. agent/langchain/example.py +213 -0
  16. agent/langchain/src/__init__.py +8 -0
  17. agent/langchain/src/agent.py +645 -0
  18. agent/langchain/src/utils.py +433 -0
  19. agent/openaisdk/__init__.py +17 -0
  20. agent/openaisdk/example.py +228 -0
  21. agent/openaisdk/src/__init__.py +12 -0
  22. agent/openaisdk/src/agent.py +491 -0
  23. agent/openaisdk/src/agent_wrapper.py +143 -0
  24. agent/openaisdk/src/mcp_wrapper.py +395 -0
  25. agent/openaisdk/src/utils.py +493 -0
  26. agent/openclaw/__init__.py +10 -0
  27. agent/openclaw/example.py +251 -0
  28. agent/openclaw/src/__init__.py +14 -0
  29. agent/openclaw/src/agent.py +930 -0
  30. agent/openclaw/src/helpers/__init__.py +1 -0
  31. agent/openclaw/src/helpers/auth_helpers.py +55 -0
  32. agent/openclaw/src/mcp_proxy.py +564 -0
  33. agent/openclaw/src/plugin_generator.py +231 -0
  34. agent/openclaw/src/utils.py +341 -0
  35. agent/pocketflow/__init__.py +18 -0
  36. agent/pocketflow/example.py +221 -0
  37. agent/pocketflow/prompts/react_agent.py +46 -0
  38. agent/pocketflow/src/__init__.py +6 -0
  39. agent/pocketflow/src/agent.py +507 -0
  40. agent/pocketflow/src/agent_wrapper.py +159 -0
  41. agent/pocketflow/src/async_helper.py +92 -0
  42. agent/pocketflow/src/mcp_react_agent.py +279 -0
  43. agent/pocketflow/src/native_agent.py +74 -0
  44. agent/pocketflow/src/nodes.py +467 -0
  45. benchmark/__init__.py +0 -0
  46. benchmark/browser/benign.jsonl +34 -0
  47. benchmark/browser/direct.jsonl +85 -0
  48. benchmark/browser/indirect.jsonl +82 -0
  49. benchmark/code/benign.jsonl +0 -0
  50. benchmark/code/direct.jsonl +121 -0
  51. benchmark/code/indirect.jsonl +165 -0
  52. benchmark/crm/benign.jsonl +165 -0
  53. benchmark/crm/direct.jsonl +90 -0
  54. benchmark/crm/indirect.jsonl +150 -0
  55. benchmark/customer-service/benign.jsonl +160 -0
  56. benchmark/customer-service/direct.jsonl +100 -0
  57. benchmark/customer-service/indirect.jsonl +101 -0
  58. benchmark/finance/benign.jsonl +0 -0
  59. benchmark/finance/direct.jsonl +200 -0
  60. benchmark/finance/indirect.jsonl +200 -0
  61. benchmark/legal/benign.jsonl +0 -0
  62. benchmark/legal/direct.jsonl +200 -0
  63. benchmark/legal/indirect.jsonl +200 -0
  64. benchmark/macos/benign.jsonl +30 -0
  65. benchmark/macos/direct.jsonl +50 -0
  66. benchmark/macos/indirect.jsonl +50 -0
  67. benchmark/medical/benign.jsonl +642 -0
  68. benchmark/medical/direct.jsonl +229 -0
  69. benchmark/medical/indirect.jsonl +222 -0
  70. benchmark/os-filesystem/benign.jsonl +200 -0
  71. benchmark/os-filesystem/direct.jsonl +200 -0
  72. benchmark/os-filesystem/indirect.jsonl +200 -0
  73. benchmark/research/benign.jsonl +0 -0
  74. benchmark/research/direct.jsonl +119 -0
  75. benchmark/research/indirect.jsonl +125 -0
  76. benchmark/telecom/benign.jsonl +120 -0
  77. benchmark/telecom/direct.jsonl +161 -0
  78. benchmark/telecom/indirect.jsonl +166 -0
  79. benchmark/travel/benign.jsonl +130 -0
  80. benchmark/travel/direct.jsonl +105 -0
  81. benchmark/travel/indirect.jsonl +120 -0
  82. benchmark/windows/benign.jsonl +100 -0
  83. benchmark/windows/direct.jsonl +140 -0
  84. benchmark/windows/indirect.jsonl +107 -0
  85. benchmark/workflow/benign.jsonl +335 -0
  86. benchmark/workflow/direct.jsonl +78 -0
  87. benchmark/workflow/indirect.jsonl +107 -0
  88. cli/__init__.py +5 -0
  89. cli/main.py +182 -0
  90. cli/scaffold.py +334 -0
  91. decodingtrust_agent_sdk-0.1.0.dist-info/METADATA +642 -0
  92. decodingtrust_agent_sdk-0.1.0.dist-info/RECORD +374 -0
  93. decodingtrust_agent_sdk-0.1.0.dist-info/WHEEL +5 -0
  94. decodingtrust_agent_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  95. decodingtrust_agent_sdk-0.1.0.dist-info/licenses/LICENSE +201 -0
  96. decodingtrust_agent_sdk-0.1.0.dist-info/top_level.txt +6 -0
  97. dt_arena/config/env.yaml +515 -0
  98. dt_arena/config/injection_mcp.yaml +430 -0
  99. dt_arena/config/mcp.yaml +642 -0
  100. dt_arena/envs/arxiv/docker-compose-hub.yml +31 -0
  101. dt_arena/envs/arxiv/docker-compose.yml +36 -0
  102. dt_arena/envs/atlassian/docker/docker-compose.dev.yml +65 -0
  103. dt_arena/envs/atlassian/docker/docker-compose.yml +53 -0
  104. dt_arena/envs/atlassian/docker-compose-hub.yml +57 -0
  105. dt_arena/envs/atlassian/docker-compose.yml +72 -0
  106. dt_arena/envs/bigquery/docker-compose.yml +20 -0
  107. dt_arena/envs/booking/docker-compose.yml +59 -0
  108. dt_arena/envs/calendar/docker-compose-hub.yml +30 -0
  109. dt_arena/envs/calendar/docker-compose.yml +42 -0
  110. dt_arena/envs/custom-website/docker-compose.yml +6 -0
  111. dt_arena/envs/customer_service/docker-compose.yml +59 -0
  112. dt_arena/envs/databricks/docker-compose-hub.yml +47 -0
  113. dt_arena/envs/databricks/docker-compose.yml +51 -0
  114. dt_arena/envs/ecommerce/docker-compose.yml +6 -0
  115. dt_arena/envs/ers/docker-compose.yml +36 -0
  116. dt_arena/envs/ers/hrms/docker/docker-compose.yml +31 -0
  117. dt_arena/envs/finance/docker-compose.yml +23 -0
  118. dt_arena/envs/github/docker/docker-compose-hub.yml +50 -0
  119. dt_arena/envs/github/docker/docker-compose.yml +50 -0
  120. dt_arena/envs/gmail/docker-compose-hub.yml +51 -0
  121. dt_arena/envs/gmail/docker-compose.yml +65 -0
  122. dt_arena/envs/google-form/docker-compose-hub.yml +33 -0
  123. dt_arena/envs/google-form/docker-compose.yml +41 -0
  124. dt_arena/envs/googledocs/docker-compose-hub.yml +61 -0
  125. dt_arena/envs/googledocs/docker-compose.yml +78 -0
  126. dt_arena/envs/hospital/docker-compose-hub.yml +25 -0
  127. dt_arena/envs/hospital/docker-compose.yml +27 -0
  128. dt_arena/envs/legal/docker-compose.yml +22 -0
  129. dt_arena/envs/linkedin/docker-compose.yml +63 -0
  130. dt_arena/envs/macos/docker-compose.yml +79 -0
  131. dt_arena/envs/os-filesystem/docker-compose-hub.yml +16 -0
  132. dt_arena/envs/os-filesystem/docker-compose.yml +20 -0
  133. dt_arena/envs/paypal/docker-compose-hub.yml +48 -0
  134. dt_arena/envs/paypal/docker-compose.yml +63 -0
  135. dt_arena/envs/research/docker-compose-hub.yml +13 -0
  136. dt_arena/envs/research/docker-compose.yml +24 -0
  137. dt_arena/envs/salesforce_crm/docker-compose-hub.yaml +45 -0
  138. dt_arena/envs/salesforce_crm/docker-compose.yaml +49 -0
  139. dt_arena/envs/slack/docker-compose-hub.yml +28 -0
  140. dt_arena/envs/slack/docker-compose.yml +41 -0
  141. dt_arena/envs/snowflake/docker-compose-hub.yml +41 -0
  142. dt_arena/envs/snowflake/docker-compose.yml +44 -0
  143. dt_arena/envs/telecom/docker-compose-hub.yml +16 -0
  144. dt_arena/envs/telecom/docker-compose.yml +17 -0
  145. dt_arena/envs/telegram/docker-compose-hub.yml +57 -0
  146. dt_arena/envs/telegram/docker-compose.yml +62 -0
  147. dt_arena/envs/terminal/docker-compose-hub.yml +12 -0
  148. dt_arena/envs/terminal/docker-compose.yml +26 -0
  149. dt_arena/envs/travel/docker-compose-hub.yml +19 -0
  150. dt_arena/envs/travel/docker-compose.yml +19 -0
  151. dt_arena/envs/whatsapp/docker-compose-hub.yml +61 -0
  152. dt_arena/envs/whatsapp/docker-compose.yml +78 -0
  153. dt_arena/envs/windows/docker-compose.yml +71 -0
  154. dt_arena/envs/zoom/docker-compose-hub.yml +27 -0
  155. dt_arena/envs/zoom/docker-compose.yml +40 -0
  156. dt_arena/injection_mcp_server/atlassian/env_injection.py +134 -0
  157. dt_arena/injection_mcp_server/calendar/env_injection.py +217 -0
  158. dt_arena/injection_mcp_server/custom_website/env_injection.py +97 -0
  159. dt_arena/injection_mcp_server/customer_service/env_injection.py +659 -0
  160. dt_arena/injection_mcp_server/databricks/env_injection.py +255 -0
  161. dt_arena/injection_mcp_server/ecommerce/env_injection.py +110 -0
  162. dt_arena/injection_mcp_server/finance/env_injection.py +85 -0
  163. dt_arena/injection_mcp_server/github/env_injection.py +206 -0
  164. dt_arena/injection_mcp_server/gmail/env_injection.py +211 -0
  165. dt_arena/injection_mcp_server/google_form/env_injection.py +186 -0
  166. dt_arena/injection_mcp_server/googledocs/env_injection.py +44 -0
  167. dt_arena/injection_mcp_server/hospital/env_injection.py +43 -0
  168. dt_arena/injection_mcp_server/legal/env_injection.py +229 -0
  169. dt_arena/injection_mcp_server/macos/env_injection.py +272 -0
  170. dt_arena/injection_mcp_server/os-filesystem/env_injection.py +341 -0
  171. dt_arena/injection_mcp_server/paypal/env_injection.py +268 -0
  172. dt_arena/injection_mcp_server/research/env_injection.py +616 -0
  173. dt_arena/injection_mcp_server/salesforce/env_injection.py +514 -0
  174. dt_arena/injection_mcp_server/slack/env_injection.py +265 -0
  175. dt_arena/injection_mcp_server/snowflake/env_injection.py +230 -0
  176. dt_arena/injection_mcp_server/telecom/env_injection.py +503 -0
  177. dt_arena/injection_mcp_server/telegram/env_injection.py +171 -0
  178. dt_arena/injection_mcp_server/terminal/env_injection.py +523 -0
  179. dt_arena/injection_mcp_server/travel/env_injection.py +173 -0
  180. dt_arena/injection_mcp_server/whatsapp/env_injection.py +185 -0
  181. dt_arena/injection_mcp_server/windows/env_injection.py +943 -0
  182. dt_arena/injection_mcp_server/zoom/env_injection.py +216 -0
  183. dt_arena/mcp_server/atlassian/main.py +1554 -0
  184. dt_arena/mcp_server/atlassian/test_server.py +66 -0
  185. dt_arena/mcp_server/bigquery/main.py +333 -0
  186. dt_arena/mcp_server/booking/main.py +310 -0
  187. dt_arena/mcp_server/browser/main.py +1741 -0
  188. dt_arena/mcp_server/calendar/example_multi_user.py +162 -0
  189. dt_arena/mcp_server/calendar/main.py +792 -0
  190. dt_arena/mcp_server/calendar/test_mcp.py +135 -0
  191. dt_arena/mcp_server/customer_service/main.py +1063 -0
  192. dt_arena/mcp_server/databricks/main.py +566 -0
  193. dt_arena/mcp_server/databricks/probe.py +102 -0
  194. dt_arena/mcp_server/ers/main.py +845 -0
  195. dt_arena/mcp_server/finance/__init__.py +87 -0
  196. dt_arena/mcp_server/finance/core/__init__.py +12 -0
  197. dt_arena/mcp_server/finance/core/data_loader.py +558 -0
  198. dt_arena/mcp_server/finance/core/portfolio.py +565 -0
  199. dt_arena/mcp_server/finance/evaluation/__init__.py +20 -0
  200. dt_arena/mcp_server/finance/evaluation/evaluator.py +217 -0
  201. dt_arena/mcp_server/finance/evaluation/logger.py +137 -0
  202. dt_arena/mcp_server/finance/injection/__init__.py +66 -0
  203. dt_arena/mcp_server/finance/injection/config.py +176 -0
  204. dt_arena/mcp_server/finance/injection/content.py +755 -0
  205. dt_arena/mcp_server/finance/injection/html.py +409 -0
  206. dt_arena/mcp_server/finance/injection/locations.py +167 -0
  207. dt_arena/mcp_server/finance/injection/methods.py +193 -0
  208. dt_arena/mcp_server/finance/injection/presets.py +1023 -0
  209. dt_arena/mcp_server/finance/main.py +361 -0
  210. dt_arena/mcp_server/finance/run_mcp.py +21 -0
  211. dt_arena/mcp_server/finance/run_web.py +26 -0
  212. dt_arena/mcp_server/finance/server/__init__.py +41 -0
  213. dt_arena/mcp_server/finance/server/extractor.py +1453 -0
  214. dt_arena/mcp_server/finance/server/extractor_minimal.py +292 -0
  215. dt_arena/mcp_server/finance/server/extractor_simple.py +1164 -0
  216. dt_arena/mcp_server/finance/server/injection_mcp.py +865 -0
  217. dt_arena/mcp_server/finance/server/mcp.py +451 -0
  218. dt_arena/mcp_server/finance/server/tools/__init__.py +23 -0
  219. dt_arena/mcp_server/finance/server/tools/account.py +88 -0
  220. dt_arena/mcp_server/finance/server/tools/browsing.py +328 -0
  221. dt_arena/mcp_server/finance/server/tools/social.py +73 -0
  222. dt_arena/mcp_server/finance/server/tools/trading.py +242 -0
  223. dt_arena/mcp_server/finance/server/tools/utility.py +49 -0
  224. dt_arena/mcp_server/finance/server/web.py +2139 -0
  225. dt_arena/mcp_server/finance/tasks/benchmark/__init__.py +28 -0
  226. dt_arena/mcp_server/finance/tasks/benchmark/attack_pool.py +3026 -0
  227. dt_arena/mcp_server/finance/tasks/benchmark/attack_runner.py +1315 -0
  228. dt_arena/mcp_server/finance/tasks/benchmark/finra_requirements.py +1335 -0
  229. dt_arena/mcp_server/finance/tasks/benchmark/finra_tasks.py +3665 -0
  230. dt_arena/mcp_server/finance/tasks/benchmark/malicious_tasks.py +2673 -0
  231. dt_arena/mcp_server/finance/tasks/redteam_suite/run_redteam_suite.py +1713 -0
  232. dt_arena/mcp_server/finance/test_mcp_tools.py +476 -0
  233. dt_arena/mcp_server/github/main.py +441 -0
  234. dt_arena/mcp_server/gmail/main.py +1004 -0
  235. dt_arena/mcp_server/google_form/main.py +141 -0
  236. dt_arena/mcp_server/googledocs/main.py +458 -0
  237. dt_arena/mcp_server/hospital/mcp_server.py +458 -0
  238. dt_arena/mcp_server/legal/__init__.py +9 -0
  239. dt_arena/mcp_server/legal/core/__init__.py +14 -0
  240. dt_arena/mcp_server/legal/core/courtlistener_store.py +762 -0
  241. dt_arena/mcp_server/legal/core/data_loader.py +266 -0
  242. dt_arena/mcp_server/legal/core/document_store.py +197 -0
  243. dt_arena/mcp_server/legal/core/matter_manager.py +466 -0
  244. dt_arena/mcp_server/legal/main.py +89 -0
  245. dt_arena/mcp_server/legal/scripts/collect_data.py +988 -0
  246. dt_arena/mcp_server/legal/server/__init__.py +14 -0
  247. dt_arena/mcp_server/legal/server/mcp.py +2330 -0
  248. dt_arena/mcp_server/macos/client_test.py +270 -0
  249. dt_arena/mcp_server/macos/mcp_server.py +285 -0
  250. dt_arena/mcp_server/os-filesystem/main.py +1380 -0
  251. dt_arena/mcp_server/paypal/main.py +501 -0
  252. dt_arena/mcp_server/research/main.py +777 -0
  253. dt_arena/mcp_server/salesforce/main.py +2006 -0
  254. dt_arena/mcp_server/slack/main.py +318 -0
  255. dt_arena/mcp_server/snowflake/main.py +612 -0
  256. dt_arena/mcp_server/snowflake/probe.py +183 -0
  257. dt_arena/mcp_server/telecom/mcp_client.py +423 -0
  258. dt_arena/mcp_server/telecom/mcp_server.py +1059 -0
  259. dt_arena/mcp_server/telegram/main.py +338 -0
  260. dt_arena/mcp_server/terminal/main.py +163 -0
  261. dt_arena/mcp_server/travel/client_test.py +16 -0
  262. dt_arena/mcp_server/travel/mcp_server.py +404 -0
  263. dt_arena/mcp_server/whatsapp/main.py +318 -0
  264. dt_arena/mcp_server/windows/client_test.py +270 -0
  265. dt_arena/mcp_server/windows/mcp_server.py +218 -0
  266. dt_arena/mcp_server/zoom/main.py +466 -0
  267. dt_arena/src/__init__.py +0 -0
  268. dt_arena/src/hooks/__init__.py +0 -0
  269. dt_arena/src/hooks/audit_log.py +30 -0
  270. dt_arena/src/hooks/hooks.json +3 -0
  271. dt_arena/src/run_benign.py +142 -0
  272. dt_arena/src/types/__init__.py +0 -0
  273. dt_arena/src/types/agent.py +441 -0
  274. dt_arena/src/types/attacks.py +2 -0
  275. dt_arena/src/types/environment.py +2 -0
  276. dt_arena/src/types/hooks.py +174 -0
  277. dt_arena/src/types/judge.py +52 -0
  278. dt_arena/src/types/red_teaming_trajectory.py +385 -0
  279. dt_arena/src/types/task.py +260 -0
  280. dt_arena/src/types/trajectory.py +315 -0
  281. dt_arena/utils/__init__.py +1 -0
  282. dt_arena/utils/atlassian/__init__.py +27 -0
  283. dt_arena/utils/atlassian/helpers.py +520 -0
  284. dt_arena/utils/bigquery/__init__.py +1 -0
  285. dt_arena/utils/bigquery/helpers.py +246 -0
  286. dt_arena/utils/calendar/__init__.py +1 -0
  287. dt_arena/utils/calendar/helpers.py +87 -0
  288. dt_arena/utils/customer_service/__init__.py +17 -0
  289. dt_arena/utils/customer_service/cs_env_client.py +940 -0
  290. dt_arena/utils/customer_service/helpers.py +339 -0
  291. dt_arena/utils/customer_service/judges/__init__.py +20 -0
  292. dt_arena/utils/customer_service/judges/abusive_comms.py +149 -0
  293. dt_arena/utils/customer_service/judges/bulk_destructive.py +202 -0
  294. dt_arena/utils/customer_service/judges/cross_customer.py +481 -0
  295. dt_arena/utils/customer_service/judges/email_exfiltration.py +320 -0
  296. dt_arena/utils/customer_service/judges/financial_fraud.py +221 -0
  297. dt_arena/utils/customer_service/judges/llm_utils.py +264 -0
  298. dt_arena/utils/customer_service/judges/pii_disclosure.py +837 -0
  299. dt_arena/utils/customer_service/judges/policy_misrep.py +44 -0
  300. dt_arena/utils/customer_service/judges/text_utils.py +21 -0
  301. dt_arena/utils/databricks/__init__.py +2 -0
  302. dt_arena/utils/databricks/helpers.py +210 -0
  303. dt_arena/utils/finance/__init__.py +0 -0
  304. dt_arena/utils/finance/helpers.py +263 -0
  305. dt_arena/utils/github/__init__.py +1 -0
  306. dt_arena/utils/github/helpers.py +249 -0
  307. dt_arena/utils/gmail/__init__.py +1 -0
  308. dt_arena/utils/gmail/helpers.py +344 -0
  309. dt_arena/utils/google_form/__init__.py +2 -0
  310. dt_arena/utils/google_form/helpers.py +133 -0
  311. dt_arena/utils/legal/__init__.py +0 -0
  312. dt_arena/utils/legal/helpers.py +228 -0
  313. dt_arena/utils/macos/__init__.py +0 -0
  314. dt_arena/utils/macos/env_setup.py +215 -0
  315. dt_arena/utils/macos/helpers.py +61 -0
  316. dt_arena/utils/os_filesystem/__init__.py +1 -0
  317. dt_arena/utils/os_filesystem/helpers.py +366 -0
  318. dt_arena/utils/paypal/__init__.py +1 -0
  319. dt_arena/utils/paypal/helpers.py +178 -0
  320. dt_arena/utils/port_allocator.py +266 -0
  321. dt_arena/utils/research/__init__.py +0 -0
  322. dt_arena/utils/research/helpers.py +251 -0
  323. dt_arena/utils/salesforce/__init__.py +1 -0
  324. dt_arena/utils/salesforce/helpers.py +719 -0
  325. dt_arena/utils/slack/__init__.py +1 -0
  326. dt_arena/utils/slack/helpers.py +176 -0
  327. dt_arena/utils/snowflake/__init__.py +1 -0
  328. dt_arena/utils/snowflake/helpers.py +166 -0
  329. dt_arena/utils/telecom/__init__.py +1 -0
  330. dt_arena/utils/telecom/helpers.py +760 -0
  331. dt_arena/utils/telegram/__init__.py +0 -0
  332. dt_arena/utils/telegram/helpers.py +174 -0
  333. dt_arena/utils/terminal/__init__.py +0 -0
  334. dt_arena/utils/terminal/helpers.py +20 -0
  335. dt_arena/utils/travel/__init__.py +0 -0
  336. dt_arena/utils/travel/env_client.py +537 -0
  337. dt_arena/utils/travel/llm_judge.py +137 -0
  338. dt_arena/utils/travel/prompts.py +64 -0
  339. dt_arena/utils/utils/__init__.py +122 -0
  340. dt_arena/utils/whatsapp/__init__.py +0 -0
  341. dt_arena/utils/whatsapp/helpers.py +226 -0
  342. dt_arena/utils/windows/__init__.py +0 -0
  343. dt_arena/utils/windows/env_reset.py +224 -0
  344. dt_arena/utils/windows/env_setup.py +280 -0
  345. dt_arena/utils/windows/exfil_helpers.py +170 -0
  346. dt_arena/utils/windows/helpers.py +74 -0
  347. dt_arena/utils/zoom/__init__.py +1 -0
  348. dt_arena/utils/zoom/helpers.py +70 -0
  349. eval/__init__.py +1 -0
  350. eval/evaluation.py +426 -0
  351. eval/task_runner.py +449 -0
  352. utils/__init__.py +148 -0
  353. utils/agent_helpers.py +308 -0
  354. utils/agent_wrapper.py +189 -0
  355. utils/compose_utils.py +135 -0
  356. utils/config.py +77 -0
  357. utils/env_helpers.py +104 -0
  358. utils/eval_stats.py +88 -0
  359. utils/injection_helpers.py +429 -0
  360. utils/injection_mcp_helpers.py +152 -0
  361. utils/judge_helpers.py +181 -0
  362. utils/judge_utils.py +472 -0
  363. utils/llm.py +196 -0
  364. utils/logging.py +45 -0
  365. utils/mcp_helpers.py +232 -0
  366. utils/mcp_manager.py +235 -0
  367. utils/memory_guard.py +18 -0
  368. utils/red_teaming_sandbox.py +476 -0
  369. utils/reset_helpers.py +318 -0
  370. utils/resource_manager.py +370 -0
  371. utils/skill_helpers.py +447 -0
  372. utils/task_executor.py +904 -0
  373. utils/task_helpers.py +270 -0
  374. utils/template_helpers.py +179 -0
@@ -0,0 +1,1059 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Telecom MCP Server
4
+ Model Context Protocol (MCP) server for comprehensive telecom operations.
5
+ Provides tools for managing customers, accounts, bills, orders, tickets, SMS, emails, outages, and calendar events.
6
+ Interacts with the telecom Flask server via HTTP requests.
7
+ """
8
+ import os
9
+ import sys
10
+ import requests
11
+ from typing import Any, Dict
12
+
13
+ from fastmcp import FastMCP
14
+
15
+
16
+ # Telecom server configuration
17
+ timeout = 30
18
+ TELECOM_HOST = os.getenv("TELECOM_HOST", "localhost")
19
+ TELECOM_PORT = os.getenv("TELECOM_PORT", "10301")
20
+
21
+ # Create FastMCP server instance
22
+ mcp = FastMCP("Telecom Server")
23
+
24
+
25
+ def send_request(endpoint: str, params: dict = None) -> dict:
26
+ """Send GET request to telecom server."""
27
+ url = f"http://{TELECOM_HOST}:{TELECOM_PORT}/{endpoint}"
28
+ resp = requests.get(url, params=params, timeout=timeout)
29
+ return resp.json()
30
+
31
+
32
+ def send_post_request(endpoint: str, data: dict) -> dict:
33
+ """Send POST request to telecom server."""
34
+ url = f"http://{TELECOM_HOST}:{TELECOM_PORT}/{endpoint}"
35
+ resp = requests.post(url, json=data, timeout=timeout)
36
+ return resp.json()
37
+
38
+
39
+ # ============================================================================
40
+ # CUSTOMER TOOLS
41
+ # ============================================================================
42
+
43
+ @mcp.tool(name="query_customer")
44
+ def query_customer(customer_id: str) -> dict:
45
+ """
46
+ Query customer information by customer ID.
47
+
48
+ Args:
49
+ customer_id: The customer ID to query
50
+
51
+ Returns:
52
+ Dictionary with customer information or error message
53
+ """
54
+ return send_request("query_customer", params={"id": customer_id})
55
+
56
+
57
+ @mcp.tool(name="add_customer")
58
+ def add_customer(data: Dict[str, Any]) -> dict:
59
+ """
60
+ Add a new customer record.
61
+
62
+ Args:
63
+ data: Dictionary with customer record fields. Required fields typically include:
64
+ - id (str): Customer ID (unique identifier)
65
+ - name (str): Customer name
66
+ - email (str): Customer email address
67
+ - phone (str): Customer phone number
68
+ - address (str): Customer address
69
+ - city (str): City
70
+ - state (str): State
71
+ - zip_code (str): ZIP code
72
+ - country (str): Country
73
+ - status (str): Customer status (e.g., "active", "inactive")
74
+ Additional fields may be required based on the CSV schema.
75
+
76
+ Returns:
77
+ Dictionary with success or error message
78
+
79
+ Example:
80
+ add_customer({
81
+ "id": "CUST001",
82
+ "name": "John Doe",
83
+ "email": "john@example.com",
84
+ "phone": "555-1234",
85
+ "address": "123 Main St",
86
+ "city": "San Francisco",
87
+ "state": "CA",
88
+ "zip_code": "94102",
89
+ "country": "USA",
90
+ "status": "active"
91
+ })
92
+ """
93
+ return send_post_request("add_customer", data)
94
+
95
+
96
+ @mcp.tool(name="remove_customer")
97
+ def remove_customer(customer_id: str) -> dict:
98
+ """
99
+ Remove a customer record by customer ID.
100
+
101
+ Args:
102
+ customer_id: The customer ID to remove
103
+
104
+ Returns:
105
+ Dictionary with success or error message
106
+ """
107
+ return send_post_request("remove_customer", {"id": customer_id})
108
+
109
+
110
+ @mcp.tool(name="update_customer")
111
+ def update_customer(
112
+ customer_id: str,
113
+ field: str = None,
114
+ value: Any = None,
115
+ updates: dict = None
116
+ ) -> dict:
117
+ """
118
+ Update a customer record by customer ID.
119
+
120
+ Args:
121
+ customer_id: The customer ID to update
122
+ field: Single field name to update (use with value)
123
+ value: Value to set for the field
124
+ updates: Dictionary of field:value pairs to update
125
+
126
+ Returns:
127
+ Dictionary with success or error message
128
+ """
129
+ data = {"id": customer_id}
130
+ if updates:
131
+ data["updates"] = updates
132
+ elif field:
133
+ data["field"] = field
134
+ data["value"] = value
135
+ return send_post_request("update_customer", data)
136
+
137
+
138
+ # ============================================================================
139
+ # ACCOUNT TOOLS
140
+ # ============================================================================
141
+
142
+ @mcp.tool(name="query_account")
143
+ def query_account(customer_id: str) -> dict:
144
+ """
145
+ Query account information by customer ID.
146
+
147
+ Args:
148
+ customer_id: The customer ID to query account for
149
+
150
+ Returns:
151
+ Dictionary with account information or error message
152
+ """
153
+ return send_request("query_account", params={"customer_id": customer_id})
154
+
155
+
156
+ @mcp.tool(name="add_account")
157
+ def add_account(data: Dict[str, Any]) -> dict:
158
+ """
159
+ Add a new account record.
160
+
161
+ Args:
162
+ data: Dictionary with account record fields. Required fields typically include:
163
+ - customer_id (str): Customer ID (foreign key, required)
164
+ - account_number (str): Account number
165
+ - account_type (str): Type of account (e.g., "mobile", "internet", "landline")
166
+ - plan (str): Service plan name
167
+ - status (str): Account status (e.g., "active", "suspended", "cancelled")
168
+ - activation_date (str): Account activation date
169
+ - balance (str/float): Current account balance
170
+ Additional fields may be required based on the CSV schema.
171
+
172
+ Returns:
173
+ Dictionary with success or error message
174
+
175
+ Example:
176
+ add_account({
177
+ "customer_id": "CUST001",
178
+ "account_number": "ACC123456",
179
+ "account_type": "mobile",
180
+ "plan": "Premium",
181
+ "status": "active",
182
+ "activation_date": "2024-01-15",
183
+ "balance": "0.00"
184
+ })
185
+ """
186
+ return send_post_request("add_account", data)
187
+
188
+
189
+ @mcp.tool(name="remove_account")
190
+ def remove_account(customer_id: str) -> dict:
191
+ """
192
+ Remove an account record by customer ID.
193
+
194
+ Args:
195
+ customer_id: The customer ID whose account to remove
196
+
197
+ Returns:
198
+ Dictionary with success or error message
199
+ """
200
+ return send_post_request("remove_account", {"customer_id": customer_id})
201
+
202
+
203
+ @mcp.tool(name="update_account")
204
+ def update_account(
205
+ customer_id: str,
206
+ field: str = None,
207
+ value: Any = None,
208
+ updates: dict = None
209
+ ) -> dict:
210
+ """
211
+ Update an account record by customer ID.
212
+
213
+ Args:
214
+ customer_id: The customer ID whose account to update
215
+ field: Single field name to update (use with value)
216
+ value: Value to set for the field
217
+ updates: Dictionary of field:value pairs to update
218
+
219
+ Returns:
220
+ Dictionary with success or error message
221
+ """
222
+ data = {"customer_id": customer_id}
223
+ if updates:
224
+ data["updates"] = updates
225
+ elif field:
226
+ data["field"] = field
227
+ data["value"] = value
228
+ return send_post_request("update_account", data)
229
+
230
+
231
+ # ============================================================================
232
+ # BILL TOOLS
233
+ # ============================================================================
234
+
235
+ @mcp.tool(name="query_bill")
236
+ def query_bill(customer_id: str) -> dict:
237
+ """
238
+ Query bill information by customer ID.
239
+
240
+ Args:
241
+ customer_id: The customer ID to query bills for
242
+
243
+ Returns:
244
+ Dictionary with bill information or error message
245
+ """
246
+ return send_request("query_bill", params={"customer_id": customer_id})
247
+
248
+
249
+ @mcp.tool(name="add_bill")
250
+ def add_bill(data: Dict[str, Any]) -> dict:
251
+ """
252
+ Add a new bill record.
253
+
254
+ Args:
255
+ data: Dictionary with bill record fields. Required fields typically include:
256
+ - customer_id (str): Customer ID (foreign key, required)
257
+ - bill_id (str): Bill ID (unique identifier)
258
+ - bill_date (str): Bill date
259
+ - due_date (str): Due date
260
+ - amount (str/float): Bill amount
261
+ - status (str): Payment status (e.g., "paid", "unpaid", "overdue")
262
+ - service_period (str): Service period covered by the bill
263
+ Additional fields may be required based on the CSV schema.
264
+
265
+ Returns:
266
+ Dictionary with success or error message
267
+
268
+ Example:
269
+ add_bill({
270
+ "customer_id": "CUST001",
271
+ "bill_id": "BILL001",
272
+ "bill_date": "2024-01-01",
273
+ "due_date": "2024-01-31",
274
+ "amount": "99.99",
275
+ "status": "unpaid",
276
+ "service_period": "2024-01"
277
+ })
278
+ """
279
+ return send_post_request("add_bill", data)
280
+
281
+
282
+ @mcp.tool(name="remove_bill")
283
+ def remove_bill(customer_id: str) -> dict:
284
+ """
285
+ Remove a bill record by customer ID.
286
+
287
+ Args:
288
+ customer_id: The customer ID whose bill to remove
289
+
290
+ Returns:
291
+ Dictionary with success or error message
292
+ """
293
+ return send_post_request("remove_bill", {"customer_id": customer_id})
294
+
295
+
296
+ @mcp.tool(name="update_bill")
297
+ def update_bill(
298
+ customer_id: str,
299
+ field: str = None,
300
+ value: Any = None,
301
+ updates: dict = None
302
+ ) -> dict:
303
+ """
304
+ Update a bill record by customer ID.
305
+
306
+ Args:
307
+ customer_id: The customer ID whose bill to update
308
+ field: Single field name to update (use with value)
309
+ value: Value to set for the field
310
+ updates: Dictionary of field:value pairs to update
311
+
312
+ Returns:
313
+ Dictionary with success or error message
314
+ """
315
+ data = {"customer_id": customer_id}
316
+ if updates:
317
+ data["updates"] = updates
318
+ elif field:
319
+ data["field"] = field
320
+ data["value"] = value
321
+ return send_post_request("update_bill", data)
322
+
323
+
324
+ # ============================================================================
325
+ # CALENDAR EVENT TOOLS
326
+ # ============================================================================
327
+
328
+ @mcp.tool(name="query_calendar_event")
329
+ def query_calendar_event(event_id: str) -> dict:
330
+ """
331
+ Query calendar event information by event ID.
332
+
333
+ Args:
334
+ event_id: The calendar event ID to query
335
+
336
+ Returns:
337
+ Dictionary with calendar event information or error message
338
+ """
339
+ return send_request("query_calendar_event", params={"id": event_id})
340
+
341
+
342
+ @mcp.tool(name="add_calendar_event")
343
+ def add_calendar_event(data: Dict[str, Any]) -> dict:
344
+ """
345
+ Add a new calendar event record.
346
+
347
+ Args:
348
+ data: Dictionary with calendar event record fields. Required fields typically include:
349
+ - id (str): Event ID (unique identifier)
350
+ - title (str): Event title
351
+ - description (str): Event description
352
+ - start_date (str): Event start date/time
353
+ - end_date (str): Event end date/time
354
+ - location (str): Event location
355
+ - attendees (str): Comma-separated list of attendees
356
+ - event_type (str): Type of event (e.g., "meeting", "appointment", "call")
357
+ Additional fields may be required based on the CSV schema.
358
+
359
+ Returns:
360
+ Dictionary with success or error message
361
+
362
+ Example:
363
+ add_calendar_event({
364
+ "id": "EVT001",
365
+ "title": "Customer Meeting",
366
+ "description": "Discuss service upgrade",
367
+ "start_date": "2024-02-01 10:00:00",
368
+ "end_date": "2024-02-01 11:00:00",
369
+ "location": "Office",
370
+ "attendees": "john@example.com,jane@example.com",
371
+ "event_type": "meeting"
372
+ })
373
+ """
374
+ return send_post_request("add_calendar_event", data)
375
+
376
+
377
+ @mcp.tool(name="remove_calendar_event")
378
+ def remove_calendar_event(event_id: str) -> dict:
379
+ """
380
+ Remove a calendar event record by event ID.
381
+
382
+ Args:
383
+ event_id: The calendar event ID to remove
384
+
385
+ Returns:
386
+ Dictionary with success or error message
387
+ """
388
+ return send_post_request("remove_calendar_event", {"id": event_id})
389
+
390
+
391
+ @mcp.tool(name="update_calendar_event")
392
+ def update_calendar_event(
393
+ event_id: str,
394
+ field: str = None,
395
+ value: Any = None,
396
+ updates: dict = None
397
+ ) -> dict:
398
+ """
399
+ Update a calendar event record by event ID.
400
+
401
+ Args:
402
+ event_id: The calendar event ID to update
403
+ field: Single field name to update (use with value)
404
+ value: Value to set for the field
405
+ updates: Dictionary of field:value pairs to update
406
+
407
+ Returns:
408
+ Dictionary with success or error message
409
+ """
410
+ data = {"id": event_id}
411
+ if updates:
412
+ data["updates"] = updates
413
+ elif field:
414
+ data["field"] = field
415
+ data["value"] = value
416
+ return send_post_request("update_calendar_event", data)
417
+
418
+
419
+ # ============================================================================
420
+ # EMAIL TOOLS
421
+ # ============================================================================
422
+
423
+ @mcp.tool(name="query_email")
424
+ def query_email(email_id: str) -> dict:
425
+ """
426
+ Query email information by email ID.
427
+
428
+ Args:
429
+ email_id: The email ID to query
430
+
431
+ Returns:
432
+ Dictionary with email information or error message
433
+ """
434
+ return send_request("query_email", params={"id": email_id})
435
+
436
+
437
+ @mcp.tool(name="add_email")
438
+ def add_email(data: Dict[str, Any]) -> dict:
439
+ """
440
+ Add a new email record.
441
+
442
+ Args:
443
+ data: Dictionary with email record fields. Required fields typically include:
444
+ - id (str): Email ID (unique identifier)
445
+ - from_address (str): Sender email address
446
+ - to_address (str): Recipient email address(es)
447
+ - subject (str): Email subject
448
+ - body (str): Email body/content
449
+ - date (str): Email date/time
450
+ - status (str): Email status (e.g., "sent", "received", "draft")
451
+ - customer_id (str): Associated customer ID (if applicable)
452
+ Additional fields may be required based on the CSV schema.
453
+
454
+ Returns:
455
+ Dictionary with success or error message
456
+
457
+ Example:
458
+ add_email({
459
+ "id": "EMAIL001",
460
+ "from_address": "support@telecom.com",
461
+ "to_address": "customer@example.com",
462
+ "subject": "Service Update",
463
+ "body": "Your service has been updated.",
464
+ "date": "2024-01-15 14:30:00",
465
+ "status": "sent",
466
+ "customer_id": "CUST001"
467
+ })
468
+ """
469
+ return send_post_request("add_email", data)
470
+
471
+
472
+ @mcp.tool(name="remove_email")
473
+ def remove_email(email_id: str) -> dict:
474
+ """
475
+ Remove an email record by email ID.
476
+
477
+ Args:
478
+ email_id: The email ID to remove
479
+
480
+ Returns:
481
+ Dictionary with success or error message
482
+ """
483
+ return send_post_request("remove_email", {"id": email_id})
484
+
485
+
486
+ @mcp.tool(name="update_email")
487
+ def update_email(
488
+ email_id: str,
489
+ field: str = None,
490
+ value: Any = None,
491
+ updates: dict = None
492
+ ) -> dict:
493
+ """
494
+ Update an email record by email ID.
495
+
496
+ Args:
497
+ email_id: The email ID to update
498
+ field: Single field name to update (use with value)
499
+ value: Value to set for the field
500
+ updates: Dictionary of field:value pairs to update
501
+
502
+ Returns:
503
+ Dictionary with success or error message
504
+ """
505
+ data = {"id": email_id}
506
+ if updates:
507
+ data["updates"] = updates
508
+ elif field:
509
+ data["field"] = field
510
+ data["value"] = value
511
+ return send_post_request("update_email", data)
512
+
513
+
514
+ # ============================================================================
515
+ # ORDER TOOLS
516
+ # ============================================================================
517
+
518
+ @mcp.tool(name="query_order")
519
+ def query_order(order_id: str) -> dict:
520
+ """
521
+ Query order information by order ID.
522
+
523
+ Args:
524
+ order_id: The order ID to query
525
+
526
+ Returns:
527
+ Dictionary with order information or error message
528
+ """
529
+ return send_request("query_order", params={"order_id": order_id})
530
+
531
+
532
+ @mcp.tool(name="add_order")
533
+ def add_order(data: Dict[str, Any]) -> dict:
534
+ """
535
+ Add a new order record.
536
+
537
+ Args:
538
+ data: Dictionary with order record fields. Required fields typically include:
539
+ - order_id (str): Order ID (unique identifier)
540
+ - customer_id (str): Customer ID (foreign key)
541
+ - order_date (str): Order date
542
+ - product (str): Product/service ordered
543
+ - quantity (str/int): Quantity ordered
544
+ - price (str/float): Order price
545
+ - status (str): Order status (e.g., "pending", "completed", "cancelled")
546
+ - delivery_date (str): Expected delivery date
547
+ Additional fields may be required based on the CSV schema.
548
+
549
+ Returns:
550
+ Dictionary with success or error message
551
+
552
+ Example:
553
+ add_order({
554
+ "order_id": "ORD001",
555
+ "customer_id": "CUST001",
556
+ "order_date": "2024-01-15",
557
+ "product": "Premium Plan",
558
+ "quantity": "1",
559
+ "price": "99.99",
560
+ "status": "pending",
561
+ "delivery_date": "2024-01-20"
562
+ })
563
+ """
564
+ return send_post_request("add_order", data)
565
+
566
+
567
+ @mcp.tool(name="remove_order")
568
+ def remove_order(order_id: str) -> dict:
569
+ """
570
+ Remove an order record by order ID.
571
+
572
+ Args:
573
+ order_id: The order ID to remove
574
+
575
+ Returns:
576
+ Dictionary with success or error message
577
+ """
578
+ return send_post_request("remove_order", {"order_id": order_id})
579
+
580
+
581
+ @mcp.tool(name="update_order")
582
+ def update_order(
583
+ order_id: str,
584
+ field: str = None,
585
+ value: Any = None,
586
+ updates: dict = None
587
+ ) -> dict:
588
+ """
589
+ Update an order record by order ID.
590
+
591
+ Args:
592
+ order_id: The order ID to update
593
+ field: Single field name to update (use with value)
594
+ value: Value to set for the field
595
+ updates: Dictionary of field:value pairs to update
596
+
597
+ Returns:
598
+ Dictionary with success or error message
599
+ """
600
+ data = {"order_id": order_id}
601
+ if updates:
602
+ data["updates"] = updates
603
+ elif field:
604
+ data["field"] = field
605
+ data["value"] = value
606
+ return send_post_request("update_order", data)
607
+
608
+
609
+ # ============================================================================
610
+ # OUTAGE TOOLS
611
+ # ============================================================================
612
+
613
+ @mcp.tool(name="query_outage")
614
+ def query_outage(area: str) -> dict:
615
+ """
616
+ Query outage information by area.
617
+
618
+ Args:
619
+ area: The area to query outages for
620
+
621
+ Returns:
622
+ Dictionary with outage information or error message
623
+ """
624
+ return send_request("query_outage", params={"area": area})
625
+
626
+
627
+ @mcp.tool(name="add_outage")
628
+ def add_outage(data: Dict[str, Any]) -> dict:
629
+ """
630
+ Add a new outage record.
631
+
632
+ Args:
633
+ data: Dictionary with outage record fields. Required fields typically include:
634
+ - area (str): Affected area (unique identifier)
635
+ - start_time (str): Outage start time
636
+ - end_time (str): Outage end time (if resolved)
637
+ - status (str): Outage status (e.g., "active", "resolved", "scheduled")
638
+ - description (str): Outage description
639
+ - affected_customers (str/int): Number of affected customers
640
+ - severity (str): Severity level (e.g., "low", "medium", "high", "critical")
641
+ Additional fields may be required based on the CSV schema.
642
+
643
+ Returns:
644
+ Dictionary with success or error message
645
+
646
+ Example:
647
+ add_outage({
648
+ "area": "Downtown",
649
+ "start_time": "2024-01-15 10:00:00",
650
+ "end_time": "2024-01-15 12:00:00",
651
+ "status": "resolved",
652
+ "description": "Power outage affecting service",
653
+ "affected_customers": "150",
654
+ "severity": "high"
655
+ })
656
+ """
657
+ return send_post_request("add_outage", data)
658
+
659
+
660
+ @mcp.tool(name="remove_outage")
661
+ def remove_outage(area: str) -> dict:
662
+ """
663
+ Remove an outage record by area.
664
+
665
+ Args:
666
+ area: The area whose outage to remove
667
+
668
+ Returns:
669
+ Dictionary with success or error message
670
+ """
671
+ return send_post_request("remove_outage", {"area": area})
672
+
673
+
674
+ @mcp.tool(name="update_outage")
675
+ def update_outage(
676
+ area: str,
677
+ field: str = None,
678
+ value: Any = None,
679
+ updates: dict = None
680
+ ) -> dict:
681
+ """
682
+ Update an outage record by area.
683
+
684
+ Args:
685
+ area: The area whose outage to update
686
+ field: Single field name to update (use with value)
687
+ value: Value to set for the field
688
+ updates: Dictionary of field:value pairs to update
689
+
690
+ Returns:
691
+ Dictionary with success or error message
692
+ """
693
+ data = {"area": area}
694
+ if updates:
695
+ data["updates"] = updates
696
+ elif field:
697
+ data["field"] = field
698
+ data["value"] = value
699
+ return send_post_request("update_outage", data)
700
+
701
+
702
+ # ============================================================================
703
+ # SMS TOOLS
704
+ # ============================================================================
705
+
706
+ @mcp.tool(name="query_sms")
707
+ def query_sms(sms_id: str) -> dict:
708
+ """
709
+ Query SMS log information by SMS ID.
710
+
711
+ Args:
712
+ sms_id: The SMS ID to query
713
+
714
+ Returns:
715
+ Dictionary with SMS information or error message
716
+ """
717
+ return send_request("query_sms", params={"id": sms_id})
718
+
719
+
720
+ @mcp.tool(name="add_sms")
721
+ def add_sms(data: Dict[str, Any]) -> dict:
722
+ """
723
+ Add a new SMS log record.
724
+
725
+ Args:
726
+ data: Dictionary with SMS record fields. Required fields typically include:
727
+ - id (str): SMS ID (unique identifier)
728
+ - from_number (str): Sender phone number
729
+ - to_number (str): Recipient phone number
730
+ - message (str): SMS message content
731
+ - date (str): SMS date/time
732
+ - status (str): SMS status (e.g., "sent", "received", "delivered", "failed")
733
+ - customer_id (str): Associated customer ID (if applicable)
734
+ Additional fields may be required based on the CSV schema.
735
+
736
+ Returns:
737
+ Dictionary with success or error message
738
+
739
+ Example:
740
+ add_sms({
741
+ "id": "SMS001",
742
+ "from_number": "+15551234567",
743
+ "to_number": "+15559876543",
744
+ "message": "Your service has been activated.",
745
+ "date": "2024-01-15 14:30:00",
746
+ "status": "sent",
747
+ "customer_id": "CUST001"
748
+ })
749
+ """
750
+ return send_post_request("add_sms", data)
751
+
752
+
753
+ @mcp.tool(name="remove_sms")
754
+ def remove_sms(sms_id: str) -> dict:
755
+ """
756
+ Remove an SMS log record by SMS ID.
757
+
758
+ Args:
759
+ sms_id: The SMS ID to remove
760
+
761
+ Returns:
762
+ Dictionary with success or error message
763
+ """
764
+ return send_post_request("remove_sms", {"id": sms_id})
765
+
766
+
767
+ @mcp.tool(name="update_sms")
768
+ def update_sms(
769
+ sms_id: str,
770
+ field: str = None,
771
+ value: Any = None,
772
+ updates: dict = None
773
+ ) -> dict:
774
+ """
775
+ Update an SMS log record by SMS ID.
776
+
777
+ Args:
778
+ sms_id: The SMS ID to update
779
+ field: Single field name to update (use with value)
780
+ value: Value to set for the field
781
+ updates: Dictionary of field:value pairs to update
782
+
783
+ Returns:
784
+ Dictionary with success or error message
785
+ """
786
+ data = {"id": sms_id}
787
+ if updates:
788
+ data["updates"] = updates
789
+ elif field:
790
+ data["field"] = field
791
+ data["value"] = value
792
+ return send_post_request("update_sms", data)
793
+
794
+
795
+ # ============================================================================
796
+ # TICKET TOOLS
797
+ # ============================================================================
798
+
799
+ @mcp.tool(name="query_ticket")
800
+ def query_ticket(ticket_id: str) -> dict:
801
+ """
802
+ Query ticket information by ticket ID.
803
+
804
+ Args:
805
+ ticket_id: The ticket ID to query
806
+
807
+ Returns:
808
+ Dictionary with ticket information or error message
809
+ """
810
+ return send_request("query_ticket", params={"id": ticket_id})
811
+
812
+
813
+ @mcp.tool(name="add_ticket")
814
+ def add_ticket(data: Dict[str, Any]) -> dict:
815
+ """
816
+ Add a new ticket record.
817
+
818
+ Args:
819
+ data: Dictionary with ticket record fields. Required fields typically include:
820
+ - id (str): Ticket ID (unique identifier)
821
+ - customer_id (str): Customer ID (foreign key)
822
+ - subject (str): Ticket subject
823
+ - description (str): Ticket description/issue details
824
+ - status (str): Ticket status (e.g., "open", "in_progress", "resolved", "closed")
825
+ - priority (str): Priority level (e.g., "low", "medium", "high", "urgent")
826
+ - created_date (str): Ticket creation date/time
827
+ - assigned_to (str): Agent/user assigned to the ticket
828
+ - resolution (str): Resolution details (if resolved)
829
+ Additional fields may be required based on the CSV schema.
830
+
831
+ Returns:
832
+ Dictionary with success or error message
833
+
834
+ Example:
835
+ add_ticket({
836
+ "id": "TKT001",
837
+ "customer_id": "CUST001",
838
+ "subject": "Service interruption",
839
+ "description": "Customer experiencing service outage",
840
+ "status": "open",
841
+ "priority": "high",
842
+ "created_date": "2024-01-15 10:00:00",
843
+ "assigned_to": "agent1",
844
+ "resolution": ""
845
+ })
846
+ """
847
+ return send_post_request("add_ticket", data)
848
+
849
+
850
+ @mcp.tool(name="remove_ticket")
851
+ def remove_ticket(ticket_id: str) -> dict:
852
+ """
853
+ Remove a ticket record by ticket ID.
854
+
855
+ Args:
856
+ ticket_id: The ticket ID to remove
857
+
858
+ Returns:
859
+ Dictionary with success or error message
860
+ """
861
+ return send_post_request("remove_ticket", {"id": ticket_id})
862
+
863
+
864
+ @mcp.tool(name="update_ticket")
865
+ def update_ticket(
866
+ ticket_id: str,
867
+ field: str = None,
868
+ value: Any = None,
869
+ updates: dict = None
870
+ ) -> dict:
871
+ """
872
+ Update a ticket record by ticket ID.
873
+
874
+ Args:
875
+ ticket_id: The ticket ID to update
876
+ field: Single field name to update (use with value)
877
+ value: Value to set for the field
878
+ updates: Dictionary of field:value pairs to update
879
+
880
+ Returns:
881
+ Dictionary with success or error message
882
+ """
883
+ data = {"id": ticket_id}
884
+ if updates:
885
+ data["updates"] = updates
886
+ elif field:
887
+ data["field"] = field
888
+ data["value"] = value
889
+ return send_post_request("update_ticket", data)
890
+
891
+
892
+ # ============================================================================
893
+ # FORUM TOOLS
894
+ # ============================================================================
895
+
896
+ @mcp.tool(name="query_forum_thread")
897
+ def query_forum_thread(thread_id: str) -> dict:
898
+ """
899
+ Query a forum thread by its thread ID.
900
+
901
+ Args:
902
+ thread_id: The forum thread ID (e.g., "FTHR001")
903
+
904
+ Returns:
905
+ Dictionary with thread information: id, title, topic, created_at_iso, status, author_id, author_type
906
+ """
907
+ return send_request("query_forum_thread", params={"id": thread_id})
908
+
909
+
910
+ @mcp.tool(name="query_forum_posts_by_thread")
911
+ def query_forum_posts_by_thread(thread_id: str) -> dict:
912
+ """
913
+ List all posts in a forum thread, sorted by creation time.
914
+
915
+ Args:
916
+ thread_id: The forum thread ID whose posts to retrieve (e.g., "FTHR001")
917
+
918
+ Returns:
919
+ Dictionary with list of posts: id, thread_id, author_id, author_type, content, created_at_iso
920
+ """
921
+ return send_request("query_forum_posts_by_thread", params={"thread_id": thread_id})
922
+
923
+
924
+ @mcp.tool(name="query_forum_post")
925
+ def query_forum_post(post_id: str) -> dict:
926
+ """
927
+ Query a single forum post by its post ID.
928
+
929
+ Args:
930
+ post_id: The forum post ID (e.g., "FPOST001")
931
+
932
+ Returns:
933
+ Dictionary with post information: id, thread_id, author_id, author_type, content, created_at_iso
934
+ """
935
+ return send_request("query_forum_post", params={"id": post_id})
936
+
937
+
938
+ # ============================================================================
939
+ # CUSTOMER-BASED LOOKUP TOOLS
940
+ # ============================================================================
941
+
942
+ @mcp.tool(name="query_tickets_by_customer")
943
+ def query_tickets_by_customer(customer_id: str) -> dict:
944
+ """
945
+ List all support tickets for a customer, sorted by creation date (newest first).
946
+
947
+ Args:
948
+ customer_id: The customer ID to look up tickets for
949
+
950
+ Returns:
951
+ Dictionary with list of tickets: id, customer_id, issue, created_at_iso, status
952
+ """
953
+ return send_request("query_tickets_by_customer", params={"customer_id": customer_id})
954
+
955
+
956
+ @mcp.tool(name="query_calendar_events_by_customer")
957
+ def query_calendar_events_by_customer(customer_id: str) -> dict:
958
+ """
959
+ List all calendar events for a customer, sorted by start time.
960
+
961
+ Args:
962
+ customer_id: The customer ID to look up calendar events for
963
+
964
+ Returns:
965
+ Dictionary with list of events: id, customer_id, start_time_iso, end_time_iso, title, description
966
+ """
967
+ return send_request("query_calendar_events_by_customer", params={"customer_id": customer_id})
968
+
969
+
970
+ @mcp.tool(name="query_sms_by_customer")
971
+ def query_sms_by_customer(customer_id: str) -> dict:
972
+ """
973
+ List all SMS records for a customer, sorted by sent time (newest first).
974
+
975
+ Args:
976
+ customer_id: The customer ID to look up SMS records for
977
+
978
+ Returns:
979
+ Dictionary with list of SMS: id, customer_id, body, sent_at_iso
980
+ """
981
+ return send_request("query_sms_by_customer", params={"customer_id": customer_id})
982
+
983
+
984
+ @mcp.tool(name="query_emails_by_customer")
985
+ def query_emails_by_customer(customer_id: str) -> dict:
986
+ """
987
+ List all email records for a customer, sorted by sent time (newest first).
988
+
989
+ Args:
990
+ customer_id: The customer ID to look up email records for
991
+
992
+ Returns:
993
+ Dictionary with list of emails: id, customer_id, subject, body, sent_at_iso
994
+ """
995
+ return send_request("query_emails_by_customer", params={"customer_id": customer_id})
996
+
997
+
998
+ # ============================================================================
999
+ # UTILITY TOOLS
1000
+ # ============================================================================
1001
+
1002
+ @mcp.tool(name="reload_all_tables")
1003
+ def reload_all_tables() -> dict:
1004
+ """
1005
+ Reload all CSV tables from disk.
1006
+ This refreshes the in-memory data from the CSV files.
1007
+
1008
+ Returns:
1009
+ Dictionary with success or error message
1010
+ """
1011
+ return send_post_request("reload_all", {})
1012
+
1013
+
1014
+ def main():
1015
+ """Main entry point for the MCP server."""
1016
+ print("Starting Telecom MCP server...", file=sys.stderr)
1017
+ print("=" * 60, file=sys.stderr)
1018
+ print("Available Tools:", file=sys.stderr)
1019
+ print(" Customers: query_customer, add_customer, remove_customer, update_customer", file=sys.stderr)
1020
+ print(" Accounts: query_account, add_account, remove_account, update_account", file=sys.stderr)
1021
+ print(" Bills: query_bill, add_bill, remove_bill, update_bill", file=sys.stderr)
1022
+ print(" Calendar Events: query_calendar_event, add_calendar_event, remove_calendar_event, update_calendar_event", file=sys.stderr)
1023
+ print(" Calendar Events (by customer): query_calendar_events_by_customer", file=sys.stderr)
1024
+ print(" Emails: query_email, add_email, remove_email, update_email", file=sys.stderr)
1025
+ print(" Emails (by customer): query_emails_by_customer", file=sys.stderr)
1026
+ print(" Forum: query_forum_thread, query_forum_posts_by_thread, query_forum_post, add_forum_thread, add_forum_post", file=sys.stderr)
1027
+ print(" Orders: query_order, add_order, remove_order, update_order", file=sys.stderr)
1028
+ print(" Outages: query_outage, add_outage, remove_outage, update_outage", file=sys.stderr)
1029
+ print(" SMS: query_sms, add_sms, remove_sms, update_sms", file=sys.stderr)
1030
+ print(" SMS (by customer): query_sms_by_customer", file=sys.stderr)
1031
+ print(" Tickets: query_ticket, add_ticket, remove_ticket, update_ticket", file=sys.stderr)
1032
+ print(" Tickets (by customer): query_tickets_by_customer", file=sys.stderr)
1033
+ print(" Utility: reload_all_tables", file=sys.stderr)
1034
+ print("=" * 60, file=sys.stderr)
1035
+ print(f"Backend Telecom server: http://{TELECOM_HOST}:{TELECOM_PORT}", file=sys.stderr)
1036
+
1037
+ # Support both stdio and HTTP transport
1038
+ transport = os.getenv("TELECOM_MCP_TRANSPORT", "stdio")
1039
+ TELECOM_MCP_HOST = os.getenv("TELECOM_MCP_HOST", "localhost")
1040
+ TELECOM_MCP_PORT = os.getenv("TELECOM_MCP_PORT", "12345")
1041
+
1042
+ if transport == "http":
1043
+ print(f"MCP server (HTTP): http://{TELECOM_MCP_HOST}:{TELECOM_MCP_PORT}", file=sys.stderr)
1044
+ print("MCP server is running and accepting HTTP connections", file=sys.stderr)
1045
+ else:
1046
+ print(f"MCP server (stdio): Port {TELECOM_MCP_PORT} configured (not used in stdio mode)", file=sys.stderr)
1047
+ print("MCP server is waiting for MCP client connections via stdio", file=sys.stderr)
1048
+
1049
+ print("=" * 60, file=sys.stderr)
1050
+ sys.stderr.flush()
1051
+
1052
+ if transport == "http":
1053
+ mcp.run(transport="http", port=int(TELECOM_MCP_PORT))
1054
+ else:
1055
+ mcp.run(transport="stdio")
1056
+
1057
+
1058
+ if __name__ == "__main__":
1059
+ main()