calculator-server.vala 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. * Calculator MCP Server Example
  3. *
  4. * This example demonstrates how to create an MCP server that provides
  5. * mathematical calculation tools. It shows how to implement and register
  6. * multiple tools with different capabilities.
  7. *
  8. * Compile with:
  9. * valac --pkg mcp-vala --pkg json-glib-1.0 --pkg gee-0.8 --pkg posix calculator-server.vala -o calculator-server
  10. */
  11. using Mcp;
  12. using Posix;
  13. /**
  14. * Calculator server that provides mathematical tools.
  15. */
  16. public class CalculatorServer : GLib.Object {
  17. private Mcp.Core.Server server;
  18. /**
  19. * Creates a new CalculatorServer.
  20. */
  21. public CalculatorServer () {
  22. // Create server information
  23. var server_info = new Mcp.Types.Protocol.ServerInfo (
  24. "calculator-server",
  25. "1.0.0"
  26. );
  27. server_info.description = "MCP server providing mathematical calculation tools";
  28. // Create server capabilities with tools enabled
  29. var capabilities = new Mcp.Types.Protocol.ServerCapabilities ();
  30. capabilities.logging = true;
  31. capabilities.tools = new Mcp.Types.Protocol.ToolsCapabilities ();
  32. // Create server
  33. server = new Mcp.Core.Server (server_info, capabilities);
  34. // Register calculation tools
  35. setup_tools ();
  36. }
  37. /**
  38. * Sets up mathematical calculation tools.
  39. */
  40. private void setup_tools () {
  41. // Register basic calculator tool
  42. var basic_calculator = new BasicCalculatorTool ();
  43. try {
  44. server.tool_manager.register_executor ("basic_calculator", basic_calculator);
  45. } catch (Error e) {
  46. // Error handling
  47. }
  48. // Register advanced calculator tool
  49. var advanced_calculator = new AdvancedCalculatorTool ();
  50. try {
  51. server.tool_manager.register_executor ("advanced_calculator", advanced_calculator);
  52. } catch (Error e) {
  53. // Error handling
  54. }
  55. // Register unit converter tool
  56. var unit_converter = new UnitConverterTool ();
  57. try {
  58. server.tool_manager.register_executor ("unit_converter", unit_converter);
  59. } catch (Error e) {
  60. // Error handling
  61. }
  62. }
  63. /**
  64. * Runs the server.
  65. *
  66. * @return Exit code
  67. */
  68. public async int run () {
  69. try {
  70. // Start the server
  71. bool started = yield server.start ();
  72. if (!started) {
  73. return 1;
  74. }
  75. // Calculator server started successfully
  76. // Available tools: basic_calculator, advanced_calculator, unit_converter
  77. // Waiting for MCP client connections...
  78. // Run the main loop
  79. var main_loop = new MainLoop ();
  80. // Connect shutdown signal
  81. server.shutdown.connect (() => {
  82. main_loop.quit ();
  83. });
  84. main_loop.run ();
  85. return 0;
  86. } catch (Error e) {
  87. return 1;
  88. }
  89. }
  90. }
  91. /**
  92. * Basic calculator tool for simple arithmetic operations.
  93. */
  94. public class BasicCalculatorTool : Mcp.Tools.BaseExecutor {
  95. /**
  96. * Creates a new BasicCalculatorTool.
  97. */
  98. public BasicCalculatorTool () {
  99. // Create tool definition using Variant
  100. var builder = new VariantBuilder (new VariantType ("a{sv}"));
  101. // Add schema properties
  102. builder.add ("{sv}", "type", new Variant.string ("object"));
  103. builder.add ("{sv}", "description", new Variant.string ("Perform basic arithmetic operations"));
  104. var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
  105. // Operation property
  106. var op_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  107. op_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
  108. op_prop_builder.add ("{sv}", "description", new Variant.string ("Arithmetic operation to perform"));
  109. var enum_array_builder = new VariantBuilder (new VariantType ("as"));
  110. enum_array_builder.add ("s", "add");
  111. enum_array_builder.add ("s", "subtract");
  112. enum_array_builder.add ("s", "multiply");
  113. enum_array_builder.add ("s", "divide");
  114. enum_array_builder.add ("s", "power");
  115. enum_array_builder.add ("s", "modulo");
  116. op_prop_builder.add ("{sv}", "enum", enum_array_builder.end ());
  117. properties_builder.add ("{sv}", "operation", op_prop_builder.end ());
  118. // Operand 1 property
  119. var operand1_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  120. operand1_prop_builder.add ("{sv}", "type", new Variant.string ("number"));
  121. operand1_prop_builder.add ("{sv}", "description", new Variant.string ("First operand"));
  122. properties_builder.add ("{sv}", "operand1", operand1_prop_builder.end ());
  123. // Operand 2 property
  124. var operand2_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  125. operand2_prop_builder.add ("{sv}", "type", new Variant.string ("number"));
  126. operand2_prop_builder.add ("{sv}", "description", new Variant.string ("Second operand"));
  127. properties_builder.add ("{sv}", "operand2", operand2_prop_builder.end ());
  128. builder.add ("{sv}", "properties", properties_builder.end ());
  129. var required_array_builder = new VariantBuilder (new VariantType ("as"));
  130. required_array_builder.add ("s", "operation");
  131. required_array_builder.add ("s", "operand1");
  132. required_array_builder.add ("s", "operand2");
  133. builder.add ("{sv}", "required", required_array_builder.end ());
  134. var input_schema = builder.end ();
  135. var definition = new Mcp.Tools.Types.ToolDefinition ("basic_calculator", input_schema);
  136. definition.title = "Basic Calculator";
  137. definition.description = "Perform basic arithmetic operations (add, subtract, multiply, divide, power, modulo)";
  138. base (definition);
  139. }
  140. /**
  141. * {@inheritDoc}
  142. */
  143. protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
  144. string operation = get_string_arg (arguments, "operation");
  145. double operand1 = get_double_arg (arguments, "operand1");
  146. double operand2 = get_double_arg (arguments, "operand2");
  147. double result = 0.0;
  148. switch (operation) {
  149. case "add":
  150. result = operand1 + operand2;
  151. break;
  152. case "subtract":
  153. result = operand1 - operand2;
  154. break;
  155. case "multiply":
  156. result = operand1 * operand2;
  157. break;
  158. case "divide":
  159. if (operand2 == 0) {
  160. throw new Mcp.Core.McpError.INVALID_PARAMS ("Division by zero is not allowed");
  161. }
  162. result = operand1 / operand2;
  163. break;
  164. case "power":
  165. result = Math.pow (operand1, operand2);
  166. break;
  167. case "modulo":
  168. if (operand2 == 0) {
  169. throw new Mcp.Core.McpError.INVALID_PARAMS ("Modulo by zero is not allowed");
  170. }
  171. result = (int)operand1 % (int)operand2;
  172. break;
  173. default:
  174. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown operation: %s".printf (operation));
  175. }
  176. // Create structured result using Variant
  177. var structured_data_builder = new VariantBuilder (new VariantType ("a{sv}"));
  178. structured_data_builder.add ("{sv}", "result", new Variant.double (result));
  179. structured_data_builder.add ("{sv}", "operation", new Variant.string (operation));
  180. structured_data_builder.add ("{sv}", "operand1", new Variant.double (operand1));
  181. structured_data_builder.add ("{sv}", "operand2", new Variant.double (operand2));
  182. structured_data_builder.add ("{sv}", "expression", new Variant.string ("%.2f %s %.2f = %.2f".printf (operand1, operation, operand2, result)));
  183. var structured_data = structured_data_builder.end ();
  184. return create_structured_result ("Calculation result: %.2f".printf (result), structured_data);
  185. }
  186. }
  187. /**
  188. * Advanced calculator tool for complex mathematical operations.
  189. */
  190. public class AdvancedCalculatorTool : Mcp.Tools.BaseExecutor {
  191. /**
  192. * Creates a new AdvancedCalculatorTool.
  193. */
  194. public AdvancedCalculatorTool () {
  195. // Create tool definition using Variant
  196. var builder = new VariantBuilder (new VariantType ("a{sv}"));
  197. // Add schema properties
  198. builder.add ("{sv}", "type", new Variant.string ("object"));
  199. builder.add ("{sv}", "description", new Variant.string ("Perform advanced mathematical operations"));
  200. var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
  201. // Function property
  202. var func_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  203. func_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
  204. func_prop_builder.add ("{sv}", "description", new Variant.string ("Mathematical function to apply"));
  205. var enum_array_builder = new VariantBuilder (new VariantType ("as"));
  206. enum_array_builder.add ("s", "sin");
  207. enum_array_builder.add ("s", "cos");
  208. enum_array_builder.add ("s", "tan");
  209. enum_array_builder.add ("s", "log");
  210. enum_array_builder.add ("s", "ln");
  211. enum_array_builder.add ("s", "sqrt");
  212. enum_array_builder.add ("s", "abs");
  213. enum_array_builder.add ("s", "ceil");
  214. enum_array_builder.add ("s", "floor");
  215. enum_array_builder.add ("s", "round");
  216. enum_array_builder.add ("s", "exp");
  217. func_prop_builder.add ("{sv}", "enum", enum_array_builder.end ());
  218. properties_builder.add ("{sv}", "function", func_prop_builder.end ());
  219. // Value property
  220. var value_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  221. value_prop_builder.add ("{sv}", "type", new Variant.string ("number"));
  222. value_prop_builder.add ("{sv}", "description", new Variant.string ("Value to apply the function to"));
  223. properties_builder.add ("{sv}", "value", value_prop_builder.end ());
  224. // Degrees property (for trigonometric functions)
  225. var degrees_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  226. degrees_prop_builder.add ("{sv}", "type", new Variant.string ("boolean"));
  227. degrees_prop_builder.add ("{sv}", "description", new Variant.string ("Whether to use degrees instead of radians (for trigonometric functions)"));
  228. degrees_prop_builder.add ("{sv}", "default", new Variant.boolean (false));
  229. properties_builder.add ("{sv}", "degrees", degrees_prop_builder.end ());
  230. builder.add ("{sv}", "properties", properties_builder.end ());
  231. var required_array_builder = new VariantBuilder (new VariantType ("as"));
  232. required_array_builder.add ("s", "function");
  233. required_array_builder.add ("s", "value");
  234. builder.add ("{sv}", "required", required_array_builder.end ());
  235. var input_schema = builder.end ();
  236. var definition = new Mcp.Tools.Types.ToolDefinition ("advanced_calculator", input_schema);
  237. definition.title = "Advanced Calculator";
  238. definition.description = "Perform advanced mathematical operations (trigonometric, logarithmic, etc.)";
  239. base (definition);
  240. }
  241. /**
  242. * {@inheritDoc}
  243. */
  244. protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
  245. string function = get_string_arg (arguments, "function");
  246. double value = get_double_arg (arguments, "value");
  247. bool degrees = arguments.lookup_value ("degrees", null) != null ? arguments.lookup_value ("degrees", new VariantType ("b")).get_boolean () : false;
  248. double result = 0.0;
  249. // Convert to radians if degrees are specified for trigonometric functions
  250. double radians = degrees ? value * Math.PI / 180.0 : value;
  251. switch (function) {
  252. case "sin":
  253. result = Math.sin (radians);
  254. break;
  255. case "cos":
  256. result = Math.cos (radians);
  257. break;
  258. case "tan":
  259. result = Math.tan (radians);
  260. break;
  261. case "log":
  262. if (value <= 0) {
  263. throw new Mcp.Core.McpError.INVALID_PARAMS ("Logarithm is only defined for positive numbers");
  264. }
  265. result = Math.log10 (value);
  266. break;
  267. case "ln":
  268. if (value <= 0) {
  269. throw new Mcp.Core.McpError.INVALID_PARAMS ("Natural logarithm is only defined for positive numbers");
  270. }
  271. result = Math.log (value);
  272. break;
  273. case "sqrt":
  274. if (value < 0) {
  275. throw new Mcp.Core.McpError.INVALID_PARAMS ("Square root is not defined for negative numbers");
  276. }
  277. result = Math.sqrt (value);
  278. break;
  279. case "abs":
  280. result = Math.fabs (value);
  281. break;
  282. case "ceil":
  283. result = Math.ceil (value);
  284. break;
  285. case "floor":
  286. result = Math.floor (value);
  287. break;
  288. case "round":
  289. result = Math.round (value);
  290. break;
  291. case "exp":
  292. result = Math.exp (value);
  293. break;
  294. default:
  295. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown function: %s".printf (function));
  296. }
  297. // Create structured result using Variant
  298. var structured_data_builder = new VariantBuilder (new VariantType ("a{sv}"));
  299. structured_data_builder.add ("{sv}", "result", new Variant.double (result));
  300. structured_data_builder.add ("{sv}", "function", new Variant.string (function));
  301. structured_data_builder.add ("{sv}", "input", new Variant.double (value));
  302. if (degrees && (function == "sin" || function == "cos" || function == "tan")) {
  303. structured_data_builder.add ("{sv}", "degrees", new Variant.boolean (true));
  304. structured_data_builder.add ("{sv}", "expression", new Variant.string ("%s(%.2f°) = %.6f".printf (function, value, result)));
  305. } else {
  306. structured_data_builder.add ("{sv}", "expression", new Variant.string ("%s(%.2f) = %.6f".printf (function, value, result)));
  307. }
  308. var structured_data = structured_data_builder.end ();
  309. return create_structured_result ("Advanced calculation result: %.6f".printf (result), structured_data);
  310. }
  311. }
  312. /**
  313. * Unit converter tool for converting between different units.
  314. */
  315. public class UnitConverterTool : Mcp.Tools.BaseExecutor {
  316. /**
  317. * Creates a new UnitConverterTool.
  318. */
  319. public UnitConverterTool () {
  320. // Create tool definition using Variant
  321. var builder = new VariantBuilder (new VariantType ("a{sv}"));
  322. // Add schema properties
  323. builder.add ("{sv}", "type", new Variant.string ("object"));
  324. builder.add ("{sv}", "description", new Variant.string ("Convert between different units of measurement"));
  325. var properties_builder = new VariantBuilder (new VariantType ("a{sv}"));
  326. // Conversion type property
  327. var type_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  328. type_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
  329. type_prop_builder.add ("{sv}", "description", new Variant.string ("Type of conversion"));
  330. var enum_array_builder = new VariantBuilder (new VariantType ("as"));
  331. enum_array_builder.add ("s", "temperature");
  332. enum_array_builder.add ("s", "length");
  333. enum_array_builder.add ("s", "weight");
  334. enum_array_builder.add ("s", "volume");
  335. enum_array_builder.add ("s", "data");
  336. type_prop_builder.add ("{sv}", "enum", enum_array_builder.end ());
  337. properties_builder.add ("{sv}", "type", type_prop_builder.end ());
  338. // From unit property
  339. var from_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  340. from_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
  341. from_prop_builder.add ("{sv}", "description", new Variant.string ("Source unit"));
  342. properties_builder.add ("{sv}", "from", from_prop_builder.end ());
  343. // To unit property
  344. var to_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  345. to_prop_builder.add ("{sv}", "type", new Variant.string ("string"));
  346. to_prop_builder.add ("{sv}", "description", new Variant.string ("Target unit"));
  347. properties_builder.add ("{sv}", "to", to_prop_builder.end ());
  348. // Value property
  349. var value_prop_builder = new VariantBuilder (new VariantType ("a{sv}"));
  350. value_prop_builder.add ("{sv}", "type", new Variant.string ("number"));
  351. value_prop_builder.add ("{sv}", "description", new Variant.string ("Value to convert"));
  352. properties_builder.add ("{sv}", "value", value_prop_builder.end ());
  353. builder.add ("{sv}", "properties", properties_builder.end ());
  354. var required_array_builder = new VariantBuilder (new VariantType ("as"));
  355. required_array_builder.add ("s", "type");
  356. required_array_builder.add ("s", "from");
  357. required_array_builder.add ("s", "to");
  358. required_array_builder.add ("s", "value");
  359. builder.add ("{sv}", "required", required_array_builder.end ());
  360. var input_schema = builder.end ();
  361. var definition = new Mcp.Tools.Types.ToolDefinition ("unit_converter", input_schema);
  362. definition.title = "Unit Converter";
  363. definition.description = "Convert between different units of measurement (temperature, length, weight, volume, data)";
  364. base (definition);
  365. }
  366. /**
  367. * {@inheritDoc}
  368. */
  369. protected override async Mcp.Tools.Types.CallToolResult do_execute (GLib.Variant arguments) throws Error {
  370. string conversion_type = get_string_arg (arguments, "type");
  371. string from_unit = get_string_arg (arguments, "from");
  372. string to_unit = get_string_arg (arguments, "to");
  373. double value = get_double_arg (arguments, "value");
  374. double result = 0.0;
  375. try {
  376. switch (conversion_type) {
  377. case "temperature":
  378. result = convert_temperature (value, from_unit, to_unit);
  379. break;
  380. case "length":
  381. result = convert_length (value, from_unit, to_unit);
  382. break;
  383. case "weight":
  384. result = convert_weight (value, from_unit, to_unit);
  385. break;
  386. case "volume":
  387. result = convert_volume (value, from_unit, to_unit);
  388. break;
  389. case "data":
  390. result = convert_data (value, from_unit, to_unit);
  391. break;
  392. default:
  393. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown conversion type: %s".printf (conversion_type));
  394. }
  395. } catch (Error e) {
  396. throw new Mcp.Core.McpError.INVALID_PARAMS ("Conversion error: %s".printf (e.message));
  397. }
  398. // Create structured result using Variant
  399. var structured_data_builder = new VariantBuilder (new VariantType ("a{sv}"));
  400. structured_data_builder.add ("{sv}", "result", new Variant.double (result));
  401. structured_data_builder.add ("{sv}", "conversion_type", new Variant.string (conversion_type));
  402. structured_data_builder.add ("{sv}", "from_unit", new Variant.string (from_unit));
  403. structured_data_builder.add ("{sv}", "to_unit", new Variant.string (to_unit));
  404. structured_data_builder.add ("{sv}", "input_value", new Variant.double (value));
  405. structured_data_builder.add ("{sv}", "expression", new Variant.string ("%.2f %s = %.2f %s".printf (value, from_unit, result, to_unit)));
  406. var structured_data = structured_data_builder.end ();
  407. return create_structured_result ("Conversion result: %.2f %s".printf (result, to_unit), structured_data);
  408. }
  409. /**
  410. * Converts temperature between different units.
  411. */
  412. private double convert_temperature (double value, string from, string to) throws Error {
  413. // First convert to Celsius
  414. double celsius;
  415. switch (from.down ()) {
  416. case "c":
  417. case "celsius":
  418. celsius = value;
  419. break;
  420. case "f":
  421. case "fahrenheit":
  422. celsius = (value - 32) * 5 / 9;
  423. break;
  424. case "k":
  425. case "kelvin":
  426. celsius = value - 273.15;
  427. break;
  428. default:
  429. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown temperature unit: %s".printf (from));
  430. }
  431. // Then convert from Celsius to target unit
  432. switch (to.down ()) {
  433. case "c":
  434. case "celsius":
  435. return celsius;
  436. case "f":
  437. case "fahrenheit":
  438. return celsius * 9 / 5 + 32;
  439. case "k":
  440. case "kelvin":
  441. return celsius + 273.15;
  442. default:
  443. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown temperature unit: %s".printf (to));
  444. }
  445. }
  446. /**
  447. * Converts length between different units.
  448. */
  449. private double convert_length (double value, string from, string to) throws Error {
  450. // Convert to meters first
  451. double meters;
  452. switch (from.down ()) {
  453. case "m":
  454. case "meter":
  455. case "meters":
  456. meters = value;
  457. break;
  458. case "cm":
  459. case "centimeter":
  460. case "centimeters":
  461. meters = value / 100;
  462. break;
  463. case "km":
  464. case "kilometer":
  465. case "kilometers":
  466. meters = value * 1000;
  467. break;
  468. case "ft":
  469. case "foot":
  470. case "feet":
  471. meters = value * 0.3048;
  472. break;
  473. case "in":
  474. case "inch":
  475. case "inches":
  476. meters = value * 0.0254;
  477. break;
  478. case "mi":
  479. case "mile":
  480. case "miles":
  481. meters = value * 1609.34;
  482. break;
  483. default:
  484. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown length unit: %s".printf (from));
  485. }
  486. // Convert from meters to target unit
  487. switch (to.down ()) {
  488. case "m":
  489. case "meter":
  490. case "meters":
  491. return meters;
  492. case "cm":
  493. case "centimeter":
  494. case "centimeters":
  495. return meters * 100;
  496. case "km":
  497. case "kilometer":
  498. case "kilometers":
  499. return meters / 1000;
  500. case "ft":
  501. case "foot":
  502. case "feet":
  503. return meters / 0.3048;
  504. case "in":
  505. case "inch":
  506. case "inches":
  507. return meters / 0.0254;
  508. case "mi":
  509. case "mile":
  510. case "miles":
  511. return meters / 1609.34;
  512. default:
  513. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown length unit: %s".printf (to));
  514. }
  515. }
  516. /**
  517. * Converts weight between different units.
  518. */
  519. private double convert_weight (double value, string from, string to) throws Error {
  520. // Convert to kilograms first
  521. double kilograms;
  522. switch (from.down ()) {
  523. case "kg":
  524. case "kilogram":
  525. case "kilograms":
  526. kilograms = value;
  527. break;
  528. case "g":
  529. case "gram":
  530. case "grams":
  531. kilograms = value / 1000;
  532. break;
  533. case "lb":
  534. case "pound":
  535. case "pounds":
  536. kilograms = value * 0.453592;
  537. break;
  538. case "oz":
  539. case "ounce":
  540. case "ounces":
  541. kilograms = value * 0.0283495;
  542. break;
  543. default:
  544. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown weight unit: %s".printf (from));
  545. }
  546. // Convert from kilograms to target unit
  547. switch (to.down ()) {
  548. case "kg":
  549. case "kilogram":
  550. case "kilograms":
  551. return kilograms;
  552. case "g":
  553. case "gram":
  554. case "grams":
  555. return kilograms * 1000;
  556. case "lb":
  557. case "pound":
  558. case "pounds":
  559. return kilograms / 0.453592;
  560. case "oz":
  561. case "ounce":
  562. case "ounces":
  563. return kilograms / 0.0283495;
  564. default:
  565. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown weight unit: %s".printf (to));
  566. }
  567. }
  568. /**
  569. * Converts volume between different units.
  570. */
  571. private double convert_volume (double value, string from, string to) throws Error {
  572. // Convert to liters first
  573. double liters;
  574. switch (from.down ()) {
  575. case "l":
  576. case "liter":
  577. case "liters":
  578. liters = value;
  579. break;
  580. case "ml":
  581. case "milliliter":
  582. case "milliliters":
  583. liters = value / 1000;
  584. break;
  585. case "gal":
  586. case "gallon":
  587. case "gallons":
  588. liters = value * 3.78541;
  589. break;
  590. case "qt":
  591. case "quart":
  592. case "quarts":
  593. liters = value * 0.946353;
  594. break;
  595. case "pt":
  596. case "pint":
  597. case "pints":
  598. liters = value * 0.473176;
  599. break;
  600. case "cup":
  601. case "cups":
  602. liters = value * 0.236588;
  603. break;
  604. default:
  605. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown volume unit: %s".printf (from));
  606. }
  607. // Convert from liters to target unit
  608. switch (to.down ()) {
  609. case "l":
  610. case "liter":
  611. case "liters":
  612. return liters;
  613. case "ml":
  614. case "milliliter":
  615. case "milliliters":
  616. return liters * 1000;
  617. case "gal":
  618. case "gallon":
  619. case "gallons":
  620. return liters / 3.78541;
  621. case "qt":
  622. case "quart":
  623. case "quarts":
  624. return liters / 0.946353;
  625. case "pt":
  626. case "pint":
  627. case "pints":
  628. return liters / 0.473176;
  629. case "cup":
  630. case "cups":
  631. return liters / 0.236588;
  632. default:
  633. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown volume unit: %s".printf (to));
  634. }
  635. }
  636. /**
  637. * Converts data storage between different units.
  638. */
  639. private double convert_data (double value, string from, string to) throws Error {
  640. // Convert to bytes first
  641. double bytes;
  642. switch (from.down ()) {
  643. case "b":
  644. case "byte":
  645. case "bytes":
  646. bytes = value;
  647. break;
  648. case "kb":
  649. case "kilobyte":
  650. case "kilobytes":
  651. bytes = value * 1024;
  652. break;
  653. case "mb":
  654. case "megabyte":
  655. case "megabytes":
  656. bytes = value * 1024 * 1024;
  657. break;
  658. case "gb":
  659. case "gigabyte":
  660. case "gigabytes":
  661. bytes = value * 1024 * 1024 * 1024;
  662. break;
  663. case "tb":
  664. case "terabyte":
  665. case "terabytes":
  666. bytes = value * 1024.0 * 1024.0 * 1024.0 * 1024.0;
  667. break;
  668. default:
  669. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown data unit: %s".printf (from));
  670. }
  671. // Convert from bytes to target unit
  672. switch (to.down ()) {
  673. case "b":
  674. case "byte":
  675. case "bytes":
  676. return bytes;
  677. case "kb":
  678. case "kilobyte":
  679. case "kilobytes":
  680. return bytes / 1024;
  681. case "mb":
  682. case "megabyte":
  683. case "megabytes":
  684. return bytes / (1024 * 1024);
  685. case "gb":
  686. case "gigabyte":
  687. case "gigabytes":
  688. return bytes / (1024 * 1024 * 1024);
  689. case "tb":
  690. case "terabyte":
  691. case "terabytes":
  692. return bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0);
  693. default:
  694. throw new Mcp.Core.McpError.INVALID_PARAMS ("Unknown data unit: %s".printf (to));
  695. }
  696. }
  697. }
  698. /**
  699. * Main function.
  700. *
  701. * @param args Command line arguments
  702. * @return Exit code
  703. */
  704. public static int main (string[] args) {
  705. // Create and run the server
  706. var server = new CalculatorServer ();
  707. // Handle Ctrl+C to gracefully shutdown
  708. // For now, we'll skip signal handling to get the build working
  709. var loop = new MainLoop ();
  710. // Run the server
  711. server.run.begin ((obj, res) => {
  712. loop.quit ();
  713. });
  714. // Keep the main loop running
  715. loop.run ();
  716. return 0;
  717. }