query_goods_info.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. class QueryGoodsInfoTool:
  2. name = 'query_goods_info'
  3. route_path = '/mcp/tools/queryGoodsInfo'
  4. def __init__(self, api_client=None):
  5. self.api_client = api_client
  6. def metadata(self):
  7. return {
  8. 'name': self.name,
  9. 'description': (
  10. '使用场景:用户明确要查已审核商品资料时使用,可按 SKU 或中文品名查询,'
  11. '返回与后台编码查询页相同的列表字段,包括起运国、目的国、属性、'
  12. '报关编码、清关编码和税率。SKU 与中文品名至少提供一个;'
  13. '用户没说明是 SKU 还是中文品名时必须先询问,确认前不得调用。'
  14. '不得根据号码格式猜测,不得跨字段或跨工具试查。'
  15. '同一 SKU 按起运国和目的国会返回多行。'
  16. '禁止使用:不查未审核商品,不导出文件,不修改商品或清关资料。'
  17. ),
  18. 'input_schema': {
  19. 'type': 'object',
  20. 'properties': {
  21. 'sku': {
  22. 'type': 'string',
  23. 'minLength': 1,
  24. 'maxLength': 2000,
  25. 'description': (
  26. 'SKU。仅当用户明确说明是 SKU 时使用。'
  27. '多个 SKU 用逗号或换行分隔,最多 50 个,每个最多 100 个字符。'
  28. ),
  29. },
  30. 'cn_name': {
  31. 'type': 'string',
  32. 'minLength': 1,
  33. 'maxLength': 100,
  34. 'description': (
  35. '中文品名。仅当用户明确说明是中文品名时使用,按包含关系查询。'
  36. ),
  37. },
  38. 'page': {
  39. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  40. 'default': 1,
  41. },
  42. 'limit': {
  43. 'type': 'integer', 'minimum': 1, 'maximum': 100,
  44. 'default': 20,
  45. },
  46. },
  47. 'additionalProperties': False,
  48. },
  49. }
  50. def call(
  51. self,
  52. sku='',
  53. cn_name='',
  54. page=1,
  55. limit=20,
  56. request_id='rq_query_goods_info',
  57. **_ignored,
  58. ):
  59. if self.api_client is None:
  60. raise RuntimeError('api client is required for query_goods_info')
  61. payload = {
  62. 'page': self._bounded_integer(page, 'page'),
  63. 'limit': self._bounded_integer(limit, 'limit'),
  64. }
  65. sku = self._text(sku, 'sku', 2000)
  66. cn_name = self._text(cn_name, 'cn_name', 100)
  67. if sku:
  68. payload['sku'] = sku
  69. if cn_name:
  70. payload['cn_name'] = cn_name
  71. if 'sku' not in payload and 'cn_name' not in payload:
  72. raise ValueError('sku or cn_name is required')
  73. return self.api_client.call_tool(
  74. self.name, self.route_path, payload, request_id
  75. )
  76. @staticmethod
  77. def _text(value, field, max_length):
  78. if value in (None, ''):
  79. return ''
  80. if not isinstance(value, str):
  81. raise ValueError(field + ' must be a string')
  82. value = value.strip()
  83. if len(value) > max_length:
  84. raise ValueError(field + ' is too long')
  85. return value
  86. @staticmethod
  87. def _bounded_integer(value, field):
  88. if isinstance(value, bool) or not isinstance(value, int) or value < 1 or value > 100:
  89. raise ValueError(field + ' is invalid')
  90. return value