1
0

mcp_server.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import json
  2. import os
  3. from mcp.server.fastmcp import FastMCP
  4. _here = os.path.dirname(__file__)
  5. with open(os.path.join(_here, "config.json")) as f:
  6. _config = json.load(f)
  7. SERVICES = _config['services']
  8. SALES_TAX = _config['global']['taxes']['sales']
  9. mcp = FastMCP("room-price-calc")
  10. def _dollar(v: float) -> str:
  11. return "{:.2f}".format(round(v, 2))
  12. def _details_fmt(details: dict) -> dict:
  13. return {k.replace('_', ' ').title(): _dollar(v) for k, v in details.items()}
  14. def _resolve_service(service: str):
  15. svc = SERVICES.get(service.lower().strip())
  16. if svc is None:
  17. keys = ', '.join(SERVICES.keys())
  18. raise ValueError(f"Unknown service '{service}'. Valid keys: {keys}")
  19. return svc
  20. def _n2l(svc, net, det):
  21. comm_rate = svc.get('fees', {}).get('commission', 0)
  22. wrong_rate = svc.get('taxes', {}).get('wrong', SALES_TAX)
  23. list_ = net / (1 - comm_rate - SALES_TAX + wrong_rate)
  24. if 'fees' in svc and 'commission' in svc['fees']:
  25. det['commission'] = list_ * comm_rate
  26. if 'taxes' in svc and 'wrong' in svc['taxes']:
  27. det['wrong_tax'] = list_ * wrong_rate
  28. det['sales_tax'] = list_ * SALES_TAX
  29. det['wrong_tax_loss'] = det['sales_tax'] - det['wrong_tax']
  30. return round(list_, 2)
  31. def _l2n(svc, list_, det):
  32. net = list_
  33. if 'fees' in svc and 'commission' in svc['fees']:
  34. det['commission'] = net * svc['fees']['commission']
  35. if 'taxes' in svc and 'wrong' in svc['taxes']:
  36. det['sales_tax'] = net * SALES_TAX
  37. det['wrong_tax'] = net * svc['taxes']['wrong']
  38. det['wrong_tax_loss'] = det['sales_tax'] - det['wrong_tax']
  39. for k in ['commission', 'wrong_tax_loss']:
  40. if k in det:
  41. net -= det[k]
  42. return round(net, 2)
  43. def _l2r(svc, list_, det):
  44. retail = list_
  45. if 'fees' in svc and 'client_fee' in svc['fees']:
  46. det['client_fee'] = retail * svc['fees']['client_fee']
  47. retail += det['client_fee']
  48. if 'taxes' in svc and 'wrong' in svc['taxes']:
  49. det['wrong_tax'] = retail * svc['taxes']['wrong']
  50. retail += det['wrong_tax']
  51. else:
  52. det['sales_tax'] = retail * SALES_TAX
  53. retail += det['sales_tax']
  54. if 'taxes' in svc and 'flat_tax' in svc['taxes']:
  55. det['service_tax'] = svc['taxes']['flat_tax']
  56. retail += det['service_tax']
  57. return round(retail, 2)
  58. def _r2l(svc, retail, det):
  59. list_ = retail
  60. if 'taxes' in svc and 'flat_tax' in svc['taxes']:
  61. det['service_tax'] = svc['taxes']['flat_tax']
  62. list_ -= det['service_tax']
  63. if 'taxes' in svc and 'wrong' in svc['taxes']:
  64. det['wrong_tax'] = list_ - (list_ / (1 + svc['taxes']['wrong']))
  65. list_ -= det['wrong_tax']
  66. else:
  67. det['sales_tax'] = list_ - (list_ / (1 + SALES_TAX))
  68. list_ -= det['sales_tax']
  69. if 'fees' in svc and 'client_fee' in svc['fees']:
  70. det['client_fee'] = list_ - (list_ / (1 + svc['fees']['client_fee']))
  71. list_ -= det['client_fee']
  72. return round(list_, 2)
  73. def _result(service_key, **amounts) -> dict:
  74. det = {k: _dollar(v) for k, v in amounts.items() if k != 'details'}
  75. return {'service': service_key, **det}
  76. @mcp.tool()
  77. def list_services() -> list:
  78. """List all available booking services with their keys and display names."""
  79. return [{'key': k, 'name': v['name']} for k, v in SERVICES.items()]
  80. @mcp.tool()
  81. def net_to_list(service: str, amount: float) -> dict:
  82. """Convert a net (owner payout) amount to the list (booking) price for a service.
  83. Args:
  84. service: Service key (e.g. 'airbnb', 'booking')
  85. amount: Net amount in dollars
  86. """
  87. svc = _resolve_service(service)
  88. det = {}
  89. list_ = _n2l(svc, amount, det)
  90. return {'service': service, 'net': _dollar(amount), 'list': _dollar(list_), 'details': _details_fmt(det)}
  91. @mcp.tool()
  92. def list_to_net(service: str, amount: float) -> dict:
  93. """Convert a list (booking) price to the net (owner payout) amount for a service.
  94. Args:
  95. service: Service key (e.g. 'airbnb', 'booking')
  96. amount: List price in dollars
  97. """
  98. svc = _resolve_service(service)
  99. det = {}
  100. net = _l2n(svc, amount, det)
  101. return {'service': service, 'list': _dollar(amount), 'net': _dollar(net), 'details': _details_fmt(det)}
  102. @mcp.tool()
  103. def list_to_retail(service: str, amount: float) -> dict:
  104. """Convert a list (booking) price to the retail (guest-facing) price for a service.
  105. Args:
  106. service: Service key (e.g. 'airbnb', 'booking')
  107. amount: List price in dollars
  108. """
  109. svc = _resolve_service(service)
  110. det = {}
  111. retail = _l2r(svc, amount, det)
  112. return {'service': service, 'list': _dollar(amount), 'retail': _dollar(retail), 'details': _details_fmt(det)}
  113. @mcp.tool()
  114. def retail_to_list(service: str, amount: float) -> dict:
  115. """Convert a retail (guest-facing) price to the list (booking) price for a service.
  116. Args:
  117. service: Service key (e.g. 'airbnb', 'booking')
  118. amount: Retail price in dollars
  119. """
  120. svc = _resolve_service(service)
  121. det = {}
  122. list_ = _r2l(svc, amount, det)
  123. return {'service': service, 'retail': _dollar(amount), 'list': _dollar(list_), 'details': _details_fmt(det)}
  124. @mcp.tool()
  125. def net_to_retail(service: str, amount: float) -> dict:
  126. """Convert a net (owner payout) amount to the retail (guest-facing) price for a service.
  127. Args:
  128. service: Service key (e.g. 'airbnb', 'booking')
  129. amount: Net amount in dollars
  130. """
  131. svc = _resolve_service(service)
  132. det = {}
  133. list_ = _n2l(svc, amount, det)
  134. det2 = {}
  135. retail = _l2r(svc, list_, det2)
  136. det.update(det2)
  137. return {'service': service, 'net': _dollar(amount), 'list': _dollar(list_), 'retail': _dollar(retail), 'details': _details_fmt(det)}
  138. @mcp.tool()
  139. def retail_to_net(service: str, amount: float) -> dict:
  140. """Convert a retail (guest-facing) price to the net (owner payout) amount for a service.
  141. Args:
  142. service: Service key (e.g. 'airbnb', 'booking')
  143. amount: Retail price in dollars
  144. """
  145. svc = _resolve_service(service)
  146. det = {}
  147. list_ = _r2l(svc, amount, det)
  148. det2 = {}
  149. net = _l2n(svc, list_, det2)
  150. det.update(det2)
  151. return {'service': service, 'retail': _dollar(amount), 'list': _dollar(list_), 'net': _dollar(net), 'details': _details_fmt(det)}
  152. if __name__ == "__main__":
  153. mcp.run()