@josephyan/qingflow-app-user-mcp 0.2.0-beta.48 → 0.2.0-beta.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.49
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.49 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -984,14 +984,26 @@ class AiBuilderFacade:
|
|
|
984
984
|
candidate_key = str(item.get("app_key") or "").strip()
|
|
985
985
|
if not candidate_key:
|
|
986
986
|
continue
|
|
987
|
+
tag_ids = _coerce_int_list(item.get("tag_ids"))
|
|
987
988
|
tag_id = _coerce_positive_int(item.get("tag_id"))
|
|
988
|
-
if
|
|
989
|
-
|
|
989
|
+
if tag_id is not None and tag_id not in tag_ids:
|
|
990
|
+
tag_ids.append(tag_id)
|
|
991
|
+
if package_tag_id is not None and package_tag_id > 0:
|
|
992
|
+
try:
|
|
993
|
+
base = self.apps.app_get_base(profile=profile, app_key=candidate_key, include_raw=True)
|
|
994
|
+
except (QingflowApiError, RuntimeError):
|
|
995
|
+
continue
|
|
996
|
+
result = base.get("result") if isinstance(base.get("result"), dict) else {}
|
|
997
|
+
resolved_tag_ids = _coerce_int_list(result.get("tagIds"))
|
|
998
|
+
if resolved_tag_ids:
|
|
999
|
+
tag_ids = resolved_tag_ids
|
|
1000
|
+
if package_tag_id not in tag_ids:
|
|
1001
|
+
continue
|
|
990
1002
|
matches.append(
|
|
991
1003
|
{
|
|
992
1004
|
"app_key": candidate_key,
|
|
993
1005
|
"app_name": title,
|
|
994
|
-
"tag_ids":
|
|
1006
|
+
"tag_ids": tag_ids,
|
|
995
1007
|
}
|
|
996
1008
|
)
|
|
997
1009
|
if not matches:
|
|
@@ -5,6 +5,7 @@ import re
|
|
|
5
5
|
import time
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from datetime import UTC, datetime
|
|
8
|
+
from decimal import Decimal, InvalidOperation
|
|
8
9
|
from typing import Any, cast
|
|
9
10
|
|
|
10
11
|
from mcp.server.fastmcp import FastMCP
|
|
@@ -4265,6 +4266,8 @@ class RecordTools(ToolBase):
|
|
|
4265
4266
|
return [_attachment_value(value) for value in _expand_values(raw_values)]
|
|
4266
4267
|
if field.que_type in RELATION_QUE_TYPES:
|
|
4267
4268
|
return [_relation_value(value) for value in _expand_values(raw_values)]
|
|
4269
|
+
if field.que_type == 8:
|
|
4270
|
+
return [{"value": _normalize_amount_value_for_write(field, raw_values[0])}]
|
|
4268
4271
|
return [{"value": _stringify_json(raw_values[0])}]
|
|
4269
4272
|
|
|
4270
4273
|
def _normalize_subtable_rows(
|
|
@@ -6370,6 +6373,71 @@ def _coerce_amount(value: JSONValue) -> float | None:
|
|
|
6370
6373
|
return None
|
|
6371
6374
|
|
|
6372
6375
|
|
|
6376
|
+
def _normalize_amount_value_for_write(field: FormField, value: JSONValue) -> str:
|
|
6377
|
+
if isinstance(value, bool) or value is None:
|
|
6378
|
+
raise RecordInputError(
|
|
6379
|
+
message=f"field '{field.que_title}' requires a numeric amount",
|
|
6380
|
+
error_code="INVALID_AMOUNT_VALUE",
|
|
6381
|
+
fix_hint="Pass a numeric value or numeric string for the amount field.",
|
|
6382
|
+
details={"field": _field_ref_payload(field), "received_value": value},
|
|
6383
|
+
)
|
|
6384
|
+
if isinstance(value, int):
|
|
6385
|
+
return str(value)
|
|
6386
|
+
if isinstance(value, float):
|
|
6387
|
+
decimal_value = Decimal(str(value))
|
|
6388
|
+
elif isinstance(value, str):
|
|
6389
|
+
text = value.strip()
|
|
6390
|
+
if not text:
|
|
6391
|
+
raise RecordInputError(
|
|
6392
|
+
message=f"field '{field.que_title}' requires a numeric amount",
|
|
6393
|
+
error_code="INVALID_AMOUNT_VALUE",
|
|
6394
|
+
fix_hint="Pass a numeric value or numeric string for the amount field.",
|
|
6395
|
+
details={"field": _field_ref_payload(field), "received_value": value},
|
|
6396
|
+
)
|
|
6397
|
+
negative = False
|
|
6398
|
+
if text.startswith("(") and text.endswith(")"):
|
|
6399
|
+
negative = True
|
|
6400
|
+
text = text[1:-1].strip()
|
|
6401
|
+
for symbol in ("¥", "¥", "$"):
|
|
6402
|
+
text = text.replace(symbol, "")
|
|
6403
|
+
text = text.replace(",", "").replace(" ", "")
|
|
6404
|
+
if negative and text and not text.startswith("-"):
|
|
6405
|
+
text = f"-{text}"
|
|
6406
|
+
try:
|
|
6407
|
+
decimal_value = Decimal(text)
|
|
6408
|
+
except InvalidOperation as exc:
|
|
6409
|
+
raise RecordInputError(
|
|
6410
|
+
message=f"field '{field.que_title}' requires a numeric amount",
|
|
6411
|
+
error_code="INVALID_AMOUNT_VALUE",
|
|
6412
|
+
fix_hint="Pass a numeric value or numeric string for the amount field.",
|
|
6413
|
+
details={"field": _field_ref_payload(field), "received_value": value},
|
|
6414
|
+
) from exc
|
|
6415
|
+
else:
|
|
6416
|
+
raise RecordInputError(
|
|
6417
|
+
message=f"field '{field.que_title}' requires a numeric amount",
|
|
6418
|
+
error_code="INVALID_AMOUNT_VALUE",
|
|
6419
|
+
fix_hint="Pass a numeric value or numeric string for the amount field.",
|
|
6420
|
+
details={"field": _field_ref_payload(field), "received_value": value},
|
|
6421
|
+
)
|
|
6422
|
+
|
|
6423
|
+
allow_decimal = bool((field.raw or {}).get("canDecimal"))
|
|
6424
|
+
if not allow_decimal:
|
|
6425
|
+
integral_value = decimal_value.to_integral_value()
|
|
6426
|
+
if decimal_value != integral_value:
|
|
6427
|
+
raise RecordInputError(
|
|
6428
|
+
message=f"field '{field.que_title}' requires an integer amount",
|
|
6429
|
+
error_code="INVALID_AMOUNT_VALUE",
|
|
6430
|
+
fix_hint="Pass an integer value for this amount field, or remove the decimal part.",
|
|
6431
|
+
details={"field": _field_ref_payload(field), "received_value": value},
|
|
6432
|
+
)
|
|
6433
|
+
return format(integral_value, "f").split(".")[0]
|
|
6434
|
+
|
|
6435
|
+
normalized = format(decimal_value, "f")
|
|
6436
|
+
if "." in normalized:
|
|
6437
|
+
normalized = normalized.rstrip("0").rstrip(".")
|
|
6438
|
+
return normalized or "0"
|
|
6439
|
+
|
|
6440
|
+
|
|
6373
6441
|
def _to_time_bucket(value: JSONValue, bucket: str) -> str:
|
|
6374
6442
|
text = _stringify_json(value).strip()
|
|
6375
6443
|
if not text:
|