140 lines
5.6 KiB
Python
140 lines
5.6 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Annotated, Any
|
|
|
|
from pydantic import Field
|
|
|
|
SafeResult = Callable[[Callable[[], dict[str, Any]]], dict[str, Any]]
|
|
SafeRawResult = Callable[[bool, Callable[[], dict[str, Any]]], dict[str, Any]]
|
|
|
|
|
|
def register_core_tools(server: Any, service: Any, safe_result: SafeResult, *, enable_config_tools: bool) -> None:
|
|
@server.tool()
|
|
def crm_health() -> dict[str, Any]:
|
|
"""Check NocoBase CLI reachability and the configured CRM collection mapping."""
|
|
return safe_result(service.crm_health)
|
|
|
|
@server.tool()
|
|
def crm_schema(
|
|
include_fields: Annotated[
|
|
bool,
|
|
Field(description="When true, try to include NocoBase collection and field metadata."),
|
|
] = False,
|
|
) -> dict[str, Any]:
|
|
"""Return the configured CRM collection and field mapping for this MCP server."""
|
|
return safe_result(lambda: service.crm_schema(include_fields=include_fields))
|
|
|
|
@server.tool()
|
|
def crm_overview(
|
|
date_from: Annotated[
|
|
str | None,
|
|
Field(
|
|
description="Optional lower bound for follow-up date, in YYYY-MM-DD or an accepted NocoBase date shortcut."
|
|
),
|
|
] = None,
|
|
date_to: Annotated[
|
|
str | None,
|
|
Field(
|
|
description="Optional upper bound for follow-up date, in YYYY-MM-DD or an accepted NocoBase date shortcut."
|
|
),
|
|
] = None,
|
|
owner: Annotated[
|
|
str | None,
|
|
Field(description="Optional user to filter customer ownership and follow-up participation."),
|
|
] = None,
|
|
) -> dict[str, Any]:
|
|
"""Return CRM totals, common customer distributions, and recent follow-ups."""
|
|
return safe_result(lambda: service.crm_overview(date_from=date_from, date_to=date_to, owner=owner))
|
|
|
|
@server.tool()
|
|
def crm_filter_options(
|
|
owner_query: Annotated[
|
|
str | None,
|
|
Field(description="Optional owner search text. Returns matching user candidates for owner filters."),
|
|
] = None,
|
|
) -> dict[str, Any]:
|
|
"""Return available customer filter values and optional owner candidates."""
|
|
return safe_result(lambda: service.crm_filter_options(owner_query=owner_query))
|
|
|
|
@server.tool()
|
|
def resolve_owner(
|
|
query: Annotated[str, Field(description="Owner username, nickname, email, or English name to resolve.")],
|
|
) -> dict[str, Any]:
|
|
"""Return candidate NocoBase users for an owner filter before querying CRM data."""
|
|
return safe_result(lambda: service.resolve_owner(query))
|
|
|
|
@server.tool()
|
|
def list_teams(
|
|
query: Annotated[str | None, Field(description="Optional team name search.")] = None,
|
|
include_members: Annotated[bool, Field(description="Include resolved team members.")] = False,
|
|
formal_members_only: Annotated[
|
|
bool,
|
|
Field(description="When including members, keep only formal employees."),
|
|
] = True,
|
|
limit: Annotated[int, Field(description="Maximum teams to return.")] = 20,
|
|
offset: Annotated[int, Field(description="Zero-based result offset.")] = 0,
|
|
) -> dict[str, Any]:
|
|
"""List configured CRM teams and optionally their formal members."""
|
|
return safe_result(
|
|
lambda: service.list_teams(
|
|
query,
|
|
include_members=include_members,
|
|
formal_members_only=formal_members_only,
|
|
limit=limit,
|
|
offset=offset,
|
|
)
|
|
)
|
|
|
|
@server.tool()
|
|
def resolve_team(
|
|
query: Annotated[str, Field(description="Team name to resolve.")],
|
|
) -> dict[str, Any]:
|
|
"""Resolve a team name before using it as a CRM filter."""
|
|
return safe_result(lambda: service.resolve_team(query))
|
|
|
|
@server.tool()
|
|
def get_team(
|
|
team_id: Annotated[Any, Field(description="NocoBase team ID.")],
|
|
include_members: Annotated[bool, Field(description="Include team members.")] = True,
|
|
formal_members_only: Annotated[
|
|
bool,
|
|
Field(description="Return only formal employees when members are included."),
|
|
] = True,
|
|
) -> dict[str, Any]:
|
|
"""Get one CRM team, its managers, and optionally its members."""
|
|
return safe_result(
|
|
lambda: service.get_team(
|
|
team_id,
|
|
include_members=include_members,
|
|
formal_members_only=formal_members_only,
|
|
)
|
|
)
|
|
|
|
@server.tool()
|
|
def team_crm_overview(
|
|
team: Annotated[str, Field(description="Exact or uniquely matching CRM team name.")],
|
|
date_from: Annotated[str | None, Field(description="Optional lower follow-up date bound.")] = None,
|
|
date_to: Annotated[str | None, Field(description="Optional upper follow-up date bound.")] = None,
|
|
include_member_breakdown: Annotated[
|
|
bool,
|
|
Field(description="Include per-member customer ownership and follow-up contribution."),
|
|
] = True,
|
|
) -> dict[str, Any]:
|
|
"""Return team totals and member contributions using formal CRM team membership."""
|
|
return safe_result(
|
|
lambda: service.team_crm_overview(
|
|
team,
|
|
date_from=date_from,
|
|
date_to=date_to,
|
|
include_member_breakdown=include_member_breakdown,
|
|
)
|
|
)
|
|
|
|
if enable_config_tools:
|
|
|
|
@server.tool()
|
|
def crm_config_template() -> dict[str, Any]:
|
|
"""Infer a config.json template from collection field metadata without reading business records."""
|
|
return safe_result(service.crm_config_template)
|