fd-daas-mcp 0.1.0__tar.gz
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.
- fd_daas_mcp-0.1.0/LICENSE +21 -0
- fd_daas_mcp-0.1.0/PKG-INFO +201 -0
- fd_daas_mcp-0.1.0/README.md +142 -0
- fd_daas_mcp-0.1.0/pyproject.toml +94 -0
- fd_daas_mcp-0.1.0/setup.cfg +4 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/__init__.py +13 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/cli.py +151 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/alert_database.py +429 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/alert_tools.py +149 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/engine.py +204 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/expressions.py +266 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/messaging.py +37 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/__init__.py +18 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/base.py +45 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/dingtalk.py +61 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/discord.py +32 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/feishu.py +60 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/registry.py +67 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/slack.py +31 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/telegram.py +51 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/twitter.py +128 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/notifiers/wecowork.py +44 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/selfcheck.py +281 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/alerts/server.py +216 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/composite_database.py +434 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/composite_tools.py +350 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/seed_example.py +51 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/selfcheck.py +144 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/selfcheck_ui_tool.py +64 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/server.py +115 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/composite/ui_tools.py +130 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/agent_runner.py +121 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/database.py +32 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/main.py +6 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/registry.py +33 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/scheduler.py +140 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/server.py +375 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/tasks/__init__.py +23 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/tasks/fetch_via_leader.py +81 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/cron/tasks.py +23 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/README.md +90 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/backfill_massive.py +188 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/collection_writer.py +316 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/daas_database.py +290 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/daas_tools.py +490 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/entity_collection_sync.py +209 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/entity_collection_tools.py +278 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/entity_rule_script.py +134 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/entity_sync.py +534 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/entity_tools.py +146 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/fetch_data_cli.py +74 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/indicator_collection_tools.py +253 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/indicator_tools.py +187 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/migrate_process_cron.py +111 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/pipeline_tools.py +864 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/process_api.py +264 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/process_database.py +626 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/process_tools.py +394 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/register_us_leaders_cron.py +111 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/registry_service.py +2229 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/rule_engine.py +458 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/rule_tools.py +389 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/seed_external_mcps.py +705 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/seed_massive_endpoints.py +671 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/seed_pipeline_from_mapping.py +210 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/seed_us_leaders_indicators.py +110 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck.py +276 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_collection_writer.py +162 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_entity_collection_script.py +344 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_entity_collections.py +390 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_indicator_scores.py +402 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_massive_endpoints.py +203 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_pipeline.py +324 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_process.py +271 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/selfcheck_scores.py +228 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/server.py +318 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/daas/sources/__init__.py +1 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/backfill_dashboards.py +130 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/dashboard_database.py +344 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/dashboards/build_us_leaders_dashboard.py +395 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/dashboards/daas.md +6 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/dashboards/fetch_pool_indicators.py +95 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/dashboards/screen_us_top300.py +143 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/selfcheck_dashboards.py +103 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/dashboard/server.py +282 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/README.md +147 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/__init__.py +1 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/data_crew.py +237 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/database.py +125 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/gateway_database.py +240 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/gateway_tools.py +401 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/leader_crew.py +243 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/leader_database.py +140 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/leader_tools.py +671 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/migrate_registry.py +228 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/registry_service.py +129 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/seed_massive_upstream.py +94 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/seed_specialist_agents.py +135 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/seed_upstreams.py +168 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/selfcheck_gateway.py +189 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/selfcheck_tiers.py +144 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/selfcheck_workflow.py +298 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/server.py +166 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/specialist_agents.py +555 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/tests/test_datasource.py +267 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/workflow_database.py +621 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/leader/workflow_tools.py +681 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/pdf/embedding_client.py +196 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/pdf/pdf_database.py +332 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/pdf/pdf_tools.py +445 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/pdf/selfcheck.py +142 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/pdf/server.py +79 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/research/research_database.py +86 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/research/research_report.py +139 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/research/research_tools.py +639 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/mcp/research/server.py +49 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/models.py +1935 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/registry.py +341 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/selfcheck.py +154 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp/server.py +49 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/PKG-INFO +201 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/SOURCES.txt +141 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/dependency_links.txt +1 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/entry_points.txt +3 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/requires.txt +37 -0
- fd_daas_mcp-0.1.0/src/fd_daas_mcp.egg-info/top_level.txt +1 -0
- fd_daas_mcp-0.1.0/tests/test_alert_tools.py +211 -0
- fd_daas_mcp-0.1.0/tests/test_cli.py +99 -0
- fd_daas_mcp-0.1.0/tests/test_composite_tools.py +128 -0
- fd_daas_mcp-0.1.0/tests/test_core_group_tools.py +80 -0
- fd_daas_mcp-0.1.0/tests/test_cron_tools.py +206 -0
- fd_daas_mcp-0.1.0/tests/test_dashboard_tools.py +134 -0
- fd_daas_mcp-0.1.0/tests/test_entity_collection_sync.py +136 -0
- fd_daas_mcp-0.1.0/tests/test_indicator_collection_sync.py +112 -0
- fd_daas_mcp-0.1.0/tests/test_leader_tools.py +165 -0
- fd_daas_mcp-0.1.0/tests/test_pdf_optional.py +82 -0
- fd_daas_mcp-0.1.0/tests/test_registration_report.py +65 -0
- fd_daas_mcp-0.1.0/tests/test_registry.py +77 -0
- fd_daas_mcp-0.1.0/tests/test_research_tools.py +434 -0
- fd_daas_mcp-0.1.0/tests/test_rule_engine.py +182 -0
- fd_daas_mcp-0.1.0/tests/test_rule_tools.py +191 -0
- fd_daas_mcp-0.1.0/tests/test_run_indicator_eviction.py +87 -0
- fd_daas_mcp-0.1.0/tests/test_selfcheck.py +31 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FindDataOfficial
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fd-daas-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Consolidated DAAS MCP server + CLI - hosts the alerts, cron, composite, daas, dashboard, leader, pdf, and research tool groups (~187 tools) behind one stdio FastMCP server and one Click CLI. Both consume fd_daas_mcp/registry.py so the server and CLI surfaces cannot drift.
|
|
5
|
+
Author: FindDataOfficial
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/FindDataOfficial/fd-daas-mcp
|
|
8
|
+
Project-URL: Documentation, https://finddataofficial.github.io/fd-daas-mcp/
|
|
9
|
+
Project-URL: Repository, https://github.com/FindDataOfficial/fd-daas-mcp
|
|
10
|
+
Project-URL: Issues, https://github.com/FindDataOfficial/fd-daas-mcp/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/FindDataOfficial/fd-daas-mcp/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: mcp,model-context-protocol,fastmcp,data,finance,indicators,dashboards
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Database
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: fastmcp>=3.4.2
|
|
29
|
+
Requires-Dist: click>=8.0
|
|
30
|
+
Requires-Dist: pandas>=1.0
|
|
31
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
32
|
+
Requires-Dist: python-dotenv>=1.0
|
|
33
|
+
Requires-Dist: apscheduler>=3.11.2
|
|
34
|
+
Provides-Extra: crew
|
|
35
|
+
Requires-Dist: crewai; extra == "crew"
|
|
36
|
+
Requires-Dist: litellm; extra == "crew"
|
|
37
|
+
Provides-Extra: akshare
|
|
38
|
+
Requires-Dist: akshare>=1.13; extra == "akshare"
|
|
39
|
+
Provides-Extra: es
|
|
40
|
+
Requires-Dist: elasticsearch>=8.0; extra == "es"
|
|
41
|
+
Provides-Extra: pdf
|
|
42
|
+
Requires-Dist: sentence-transformers; extra == "pdf"
|
|
43
|
+
Requires-Dist: sqlite-vec; extra == "pdf"
|
|
44
|
+
Requires-Dist: pdfplumber; extra == "pdf"
|
|
45
|
+
Requires-Dist: pypdf; extra == "pdf"
|
|
46
|
+
Provides-Extra: position
|
|
47
|
+
Requires-Dist: lxml; extra == "position"
|
|
48
|
+
Requires-Dist: cssselect; extra == "position"
|
|
49
|
+
Requires-Dist: jsonpath-ng; extra == "position"
|
|
50
|
+
Provides-Extra: repl
|
|
51
|
+
Requires-Dist: prompt_toolkit>=3.0; extra == "repl"
|
|
52
|
+
Provides-Extra: dev
|
|
53
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
54
|
+
Requires-Dist: mkdocs>=1.6; extra == "dev"
|
|
55
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "dev"
|
|
56
|
+
Requires-Dist: mkdocs-static-i18n>=1.2; extra == "dev"
|
|
57
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
58
|
+
Dynamic: license-file
|
|
59
|
+
|
|
60
|
+
# fd-daas-mcp
|
|
61
|
+
|
|
62
|
+
[](https://pypi.org/project/fd-daas-mcp/)
|
|
63
|
+
[](https://pypi.org/project/fd-daas-mcp/)
|
|
64
|
+
[](LICENSE)
|
|
65
|
+
[](https://finddataofficial.github.io/fd-daas-mcp/)
|
|
66
|
+
|
|
67
|
+
A single MCP server + CLI for skill-driven data access across financial,
|
|
68
|
+
economic, and statistical sources. Browse thousands of indicators, build entity
|
|
69
|
+
& indicator collections, run research workflows, and share dashboards - all
|
|
70
|
+
behind one stdio server with **181 tools across 8 groups** (187 with the
|
|
71
|
+
optional `pdf` extra).
|
|
72
|
+
|
|
73
|
+
`fd-daas-mcp` is the engine behind the [DAAS](https://github.com/FindDataOfficial)
|
|
74
|
+
skill-driven data-fetch workflow. Point any MCP client (Claude Code, etc.) at
|
|
75
|
+
it and the tools show up as `<group>_<tool>` calls - e.g. `daas_list_sources`,
|
|
76
|
+
`alerts_create_alert_rule`, `research_create`.
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install fd-daas-mcp
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Optional extras (all lazy-loaded - a missing extra degrades to a per-feature
|
|
85
|
+
error, never a startup crash):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install "fd-daas-mcp[pdf]" # local PDF/text vector search (sqlite-vec)
|
|
89
|
+
pip install "fd-daas-mcp[crew]" # CrewAI router for the leader group
|
|
90
|
+
pip install "fd-daas-mcp[akshare]" # live A-share OHLCV/fundamentals
|
|
91
|
+
pip install "fd-daas-mcp[position]" # CSS/xpath/json-path rule extraction
|
|
92
|
+
pip install "fd-daas-mcp[repl]" # REPL history/autocomplete
|
|
93
|
+
pip install "fd-daas-mcp[dev]" # pytest + mkdocs for contributors
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 60-second quickstart
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 1. Install
|
|
100
|
+
pip install fd-daas-mcp
|
|
101
|
+
|
|
102
|
+
# 2. Point your MCP client at it. For Claude Code, add to your .mcp.json:
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
// .mcp.json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"fd-daas-mcp": {
|
|
110
|
+
"command": "fd-daas-mcp-server",
|
|
111
|
+
"args": []
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# 3. Set a database URL (the schema auto-creates on first startup via
|
|
119
|
+
# Base.metadata.create_all - no manual init step):
|
|
120
|
+
export DAAS_DATABASE_URL=sqlite:///daas.db
|
|
121
|
+
|
|
122
|
+
# 4. Or use the CLI directly:
|
|
123
|
+
fd-daas-mcp --help # see every group + tool
|
|
124
|
+
fd-daas-mcp daas list_sources # invoke a tool: <group> <tool> [key=value ...]
|
|
125
|
+
fd-daas-mcp # drop into the REPL (needs [repl] extra)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
On server startup the schema auto-creates and you'll see the registration
|
|
129
|
+
report:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
registry: 181 tools across 8 sources (failed=0, skipped_optional=1)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
(181 tools with the default install; 187 with the `pdf` extra installed. The
|
|
136
|
+
`pdf` group is optional and skipped when `sqlite-vec` is absent.)
|
|
137
|
+
|
|
138
|
+
## Tool groups
|
|
139
|
+
|
|
140
|
+
| Group | Surface prefix | What it does |
|
|
141
|
+
|-------------|------------------|-----------------------------------------------------------------------|
|
|
142
|
+
| `daas` | `daas_*` | Datasource/function/column catalog, entities, indicators, collections, rules, pipelines |
|
|
143
|
+
| `alerts` | `alerts_*` | Rule-based alerting over indicator series (Feishu/Discord/Slack/Telegram/DingTalk/WeCom/Twitter) |
|
|
144
|
+
| `cron` | `cron_*` | Scheduled task execution + history |
|
|
145
|
+
| `composite` | `composite_*` | Compose + chain tools across upstream MCPs |
|
|
146
|
+
| `dashboard` | `dashboard_*` | Standalone-HTML dashboard registry + query |
|
|
147
|
+
| `leader` | `leader_*` | CrewAI DataCrew router, specialist agents, workflows, snapshots |
|
|
148
|
+
| `pdf` | `pdf_*` | Local PDF/text semantic vector search (optional - needs `sqlite-vec`) |
|
|
149
|
+
| `research` | `research_*` | Persisted research bundles + generated markdown reports |
|
|
150
|
+
|
|
151
|
+
The CLI tree mirrors this: `fd-daas-mcp <group> <tool>`. Both server and CLI
|
|
152
|
+
are generated from the same `registry.build()`, so they cannot drift.
|
|
153
|
+
|
|
154
|
+
## Skills
|
|
155
|
+
|
|
156
|
+
The `skills/` directory (in the repo, not the wheel) contains 15 Claude Code
|
|
157
|
+
skills that turn the raw tools into guided workflows - data fetch, research
|
|
158
|
+
orchestration, dashboard building, rule authoring, and more. To use them:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git clone https://github.com/FindDataOfficial/fd-daas-mcp.git
|
|
162
|
+
# Then point Claude Code at skills/ in the clone (or symlink into ~/.claude/skills/).
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) and the [docs site](https://finddataofficial.github.io/fd-daas-mcp/) for details.
|
|
166
|
+
|
|
167
|
+
## Architecture
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
src/fd_daas_mcp/ # the installable package
|
|
171
|
+
server.py # FastMCP app - registers every tool as <group>_<tool>
|
|
172
|
+
cli.py # Click CLI - auto-generated from registry.build()
|
|
173
|
+
registry.py # AST-harvests tools from each mcp/<group>/ (per-group sys.modules isolation)
|
|
174
|
+
selfcheck.py # offline invariants (run_invariants())
|
|
175
|
+
models.py # vendored SQLAlchemy schema (Base + ORM for every domain)
|
|
176
|
+
mcp/ # tool-group source (shipped as package data)
|
|
177
|
+
alerts/ cron/ composite/ daas/ dashboard/ leader/ pdf/ research/
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The registry loads each group's `server.py` and harvests `@app.tool`-decorated
|
|
181
|
+
functions (inline groups) or the `*_tools.py` modules they import (non-inline
|
|
182
|
+
groups), with per-group `sys.modules` isolation so leaf modules like
|
|
183
|
+
`database.py` don't collide across groups. The `cron` group is loaded with
|
|
184
|
+
`suppress=True` to neutralize APScheduler's import-time thread while keeping
|
|
185
|
+
its idempotent DDL.
|
|
186
|
+
|
|
187
|
+
## Development
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
git clone https://github.com/FindDataOfficial/fd-daas-mcp.git
|
|
191
|
+
cd fd-daas-mcp
|
|
192
|
+
uv sync --extra dev # editable install + dev deps (pytest, mkdocs, twine)
|
|
193
|
+
uv run pytest # offline test suite
|
|
194
|
+
uv run python -m fd_daas_mcp.selfcheck
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
[MIT](LICENSE) - © FindDataOfficial.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# fd-daas-mcp
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/fd-daas-mcp/)
|
|
4
|
+
[](https://pypi.org/project/fd-daas-mcp/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://finddataofficial.github.io/fd-daas-mcp/)
|
|
7
|
+
|
|
8
|
+
A single MCP server + CLI for skill-driven data access across financial,
|
|
9
|
+
economic, and statistical sources. Browse thousands of indicators, build entity
|
|
10
|
+
& indicator collections, run research workflows, and share dashboards - all
|
|
11
|
+
behind one stdio server with **181 tools across 8 groups** (187 with the
|
|
12
|
+
optional `pdf` extra).
|
|
13
|
+
|
|
14
|
+
`fd-daas-mcp` is the engine behind the [DAAS](https://github.com/FindDataOfficial)
|
|
15
|
+
skill-driven data-fetch workflow. Point any MCP client (Claude Code, etc.) at
|
|
16
|
+
it and the tools show up as `<group>_<tool>` calls - e.g. `daas_list_sources`,
|
|
17
|
+
`alerts_create_alert_rule`, `research_create`.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install fd-daas-mcp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Optional extras (all lazy-loaded - a missing extra degrades to a per-feature
|
|
26
|
+
error, never a startup crash):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install "fd-daas-mcp[pdf]" # local PDF/text vector search (sqlite-vec)
|
|
30
|
+
pip install "fd-daas-mcp[crew]" # CrewAI router for the leader group
|
|
31
|
+
pip install "fd-daas-mcp[akshare]" # live A-share OHLCV/fundamentals
|
|
32
|
+
pip install "fd-daas-mcp[position]" # CSS/xpath/json-path rule extraction
|
|
33
|
+
pip install "fd-daas-mcp[repl]" # REPL history/autocomplete
|
|
34
|
+
pip install "fd-daas-mcp[dev]" # pytest + mkdocs for contributors
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 60-second quickstart
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 1. Install
|
|
41
|
+
pip install fd-daas-mcp
|
|
42
|
+
|
|
43
|
+
# 2. Point your MCP client at it. For Claude Code, add to your .mcp.json:
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```jsonc
|
|
47
|
+
// .mcp.json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"fd-daas-mcp": {
|
|
51
|
+
"command": "fd-daas-mcp-server",
|
|
52
|
+
"args": []
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 3. Set a database URL (the schema auto-creates on first startup via
|
|
60
|
+
# Base.metadata.create_all - no manual init step):
|
|
61
|
+
export DAAS_DATABASE_URL=sqlite:///daas.db
|
|
62
|
+
|
|
63
|
+
# 4. Or use the CLI directly:
|
|
64
|
+
fd-daas-mcp --help # see every group + tool
|
|
65
|
+
fd-daas-mcp daas list_sources # invoke a tool: <group> <tool> [key=value ...]
|
|
66
|
+
fd-daas-mcp # drop into the REPL (needs [repl] extra)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
On server startup the schema auto-creates and you'll see the registration
|
|
70
|
+
report:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
registry: 181 tools across 8 sources (failed=0, skipped_optional=1)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
(181 tools with the default install; 187 with the `pdf` extra installed. The
|
|
77
|
+
`pdf` group is optional and skipped when `sqlite-vec` is absent.)
|
|
78
|
+
|
|
79
|
+
## Tool groups
|
|
80
|
+
|
|
81
|
+
| Group | Surface prefix | What it does |
|
|
82
|
+
|-------------|------------------|-----------------------------------------------------------------------|
|
|
83
|
+
| `daas` | `daas_*` | Datasource/function/column catalog, entities, indicators, collections, rules, pipelines |
|
|
84
|
+
| `alerts` | `alerts_*` | Rule-based alerting over indicator series (Feishu/Discord/Slack/Telegram/DingTalk/WeCom/Twitter) |
|
|
85
|
+
| `cron` | `cron_*` | Scheduled task execution + history |
|
|
86
|
+
| `composite` | `composite_*` | Compose + chain tools across upstream MCPs |
|
|
87
|
+
| `dashboard` | `dashboard_*` | Standalone-HTML dashboard registry + query |
|
|
88
|
+
| `leader` | `leader_*` | CrewAI DataCrew router, specialist agents, workflows, snapshots |
|
|
89
|
+
| `pdf` | `pdf_*` | Local PDF/text semantic vector search (optional - needs `sqlite-vec`) |
|
|
90
|
+
| `research` | `research_*` | Persisted research bundles + generated markdown reports |
|
|
91
|
+
|
|
92
|
+
The CLI tree mirrors this: `fd-daas-mcp <group> <tool>`. Both server and CLI
|
|
93
|
+
are generated from the same `registry.build()`, so they cannot drift.
|
|
94
|
+
|
|
95
|
+
## Skills
|
|
96
|
+
|
|
97
|
+
The `skills/` directory (in the repo, not the wheel) contains 15 Claude Code
|
|
98
|
+
skills that turn the raw tools into guided workflows - data fetch, research
|
|
99
|
+
orchestration, dashboard building, rule authoring, and more. To use them:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/FindDataOfficial/fd-daas-mcp.git
|
|
103
|
+
# Then point Claude Code at skills/ in the clone (or symlink into ~/.claude/skills/).
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) and the [docs site](https://finddataofficial.github.io/fd-daas-mcp/) for details.
|
|
107
|
+
|
|
108
|
+
## Architecture
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
src/fd_daas_mcp/ # the installable package
|
|
112
|
+
server.py # FastMCP app - registers every tool as <group>_<tool>
|
|
113
|
+
cli.py # Click CLI - auto-generated from registry.build()
|
|
114
|
+
registry.py # AST-harvests tools from each mcp/<group>/ (per-group sys.modules isolation)
|
|
115
|
+
selfcheck.py # offline invariants (run_invariants())
|
|
116
|
+
models.py # vendored SQLAlchemy schema (Base + ORM for every domain)
|
|
117
|
+
mcp/ # tool-group source (shipped as package data)
|
|
118
|
+
alerts/ cron/ composite/ daas/ dashboard/ leader/ pdf/ research/
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The registry loads each group's `server.py` and harvests `@app.tool`-decorated
|
|
122
|
+
functions (inline groups) or the `*_tools.py` modules they import (non-inline
|
|
123
|
+
groups), with per-group `sys.modules` isolation so leaf modules like
|
|
124
|
+
`database.py` don't collide across groups. The `cron` group is loaded with
|
|
125
|
+
`suppress=True` to neutralize APScheduler's import-time thread while keeping
|
|
126
|
+
its idempotent DDL.
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/FindDataOfficial/fd-daas-mcp.git
|
|
132
|
+
cd fd-daas-mcp
|
|
133
|
+
uv sync --extra dev # editable install + dev deps (pytest, mkdocs, twine)
|
|
134
|
+
uv run pytest # offline test suite
|
|
135
|
+
uv run python -m fd_daas_mcp.selfcheck
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
[MIT](LICENSE) - © FindDataOfficial.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fd-daas-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Consolidated DAAS MCP server + CLI - hosts the alerts, cron, composite, daas, dashboard, leader, pdf, and research tool groups (~187 tools) behind one stdio FastMCP server and one Click CLI. Both consume fd_daas_mcp/registry.py so the server and CLI surfaces cannot drift."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "FindDataOfficial" }]
|
|
9
|
+
keywords = ["mcp", "model-context-protocol", "fastmcp", "data", "finance", "indicators", "dashboards"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Environment :: Console",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Database",
|
|
21
|
+
"Topic :: Office/Business :: Financial",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"fastmcp>=3.4.2",
|
|
26
|
+
"click>=8.0",
|
|
27
|
+
"pandas>=1.0",
|
|
28
|
+
"sqlalchemy>=2.0",
|
|
29
|
+
"python-dotenv>=1.0",
|
|
30
|
+
"apscheduler>=3.11.2",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/FindDataOfficial/fd-daas-mcp"
|
|
35
|
+
Documentation = "https://finddataofficial.github.io/fd-daas-mcp/"
|
|
36
|
+
Repository = "https://github.com/FindDataOfficial/fd-daas-mcp"
|
|
37
|
+
Issues = "https://github.com/FindDataOfficial/fd-daas-mcp/issues"
|
|
38
|
+
Changelog = "https://github.com/FindDataOfficial/fd-daas-mcp/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
# CrewAI powers leader's DataCrew router (ask_data_crew) + specialist agents.
|
|
42
|
+
# Falls back to a deterministic direct router when absent.
|
|
43
|
+
crew = ["crewai", "litellm"]
|
|
44
|
+
# akshare is imported lazily by daas source modules; install for live A-share fetches.
|
|
45
|
+
akshare = ["akshare>=1.13"]
|
|
46
|
+
# elasticsearch powers cnreport ES store/search tools.
|
|
47
|
+
es = ["elasticsearch>=8.0"]
|
|
48
|
+
# Local PDF/text vector search: sentence-transformers (embeddings) + sqlite-vec
|
|
49
|
+
# (vec0 ANN index) + pdfplumber/pypdf (text extraction). Loaded as an optional
|
|
50
|
+
# `pdf` tool group gated on `sqlite_vec` (see registry.py). No API key, no egress.
|
|
51
|
+
pdf = ["sentence-transformers", "sqlite-vec", "pdfplumber", "pypdf"]
|
|
52
|
+
# Position rules: CSS/xpath (lxml+cssselect) + json-path (jsonpath-ng) extraction.
|
|
53
|
+
# regex needs no extra dep. Lazy-imported by rule_engine._eval_position, so a
|
|
54
|
+
# missing install degrades to a per-rule error, never a server-startup crash.
|
|
55
|
+
position = ["lxml", "cssselect", "jsonpath-ng"]
|
|
56
|
+
# REPL history/autocomplete.
|
|
57
|
+
repl = ["prompt_toolkit>=3.0"]
|
|
58
|
+
dev = [
|
|
59
|
+
"pytest>=8.0",
|
|
60
|
+
"mkdocs>=1.6",
|
|
61
|
+
"mkdocs-material>=9.5",
|
|
62
|
+
"mkdocs-static-i18n>=1.2",
|
|
63
|
+
"twine>=5.0",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[project.scripts]
|
|
67
|
+
fd-daas-mcp = "fd_daas_mcp.cli:cli"
|
|
68
|
+
fd-daas-mcp-server = "fd_daas_mcp.server:main"
|
|
69
|
+
|
|
70
|
+
[tool.setuptools.packages.find]
|
|
71
|
+
where = ["src"]
|
|
72
|
+
include = ["fd_daas_mcp*"]
|
|
73
|
+
|
|
74
|
+
[tool.setuptools.package-data]
|
|
75
|
+
fd_daas_mcp = [
|
|
76
|
+
"mcp/**/*.py",
|
|
77
|
+
"mcp/**/*.md",
|
|
78
|
+
"mcp/**/*.json",
|
|
79
|
+
"mcp/**/*.yaml",
|
|
80
|
+
"mcp/**/*.yml",
|
|
81
|
+
"mcp/**/*.txt",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
testpaths = ["tests"]
|
|
86
|
+
pythonpath = ["src"]
|
|
87
|
+
# The .venv leaks micromamba site-packages whose logfire pytest plugin crashes
|
|
88
|
+
# on import (opentelemetry._tail_sampling). `-p no:X` is a no-op when the plugin
|
|
89
|
+
# isn't registered, so this is safe in a clean venv too.
|
|
90
|
+
addopts = "-p no:logfire -p no:pytest_logfire"
|
|
91
|
+
|
|
92
|
+
[build-system]
|
|
93
|
+
requires = ["setuptools>=68.0"]
|
|
94
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""fd-daas-mcp - the single consolidated MCP server for the DAAS platform.
|
|
2
|
+
|
|
3
|
+
This is the only MCP in the project. Tool logic is hosted in-package at
|
|
4
|
+
``fd-daas-mcp/<group>-mcp/`` (moved, not rewritten, from the former ``mcp/``
|
|
5
|
+
source dirs). The :mod:`registry` imports each group's tool functions with
|
|
6
|
+
per-group ``sys.modules`` isolation and re-exposes them under a collision-free
|
|
7
|
+
``<group>_<tool>`` namespace on one FastMCP server (and one Click CLI).
|
|
8
|
+
|
|
9
|
+
Groups (core always-on unless the extra is absent): alerts, cron, composite,
|
|
10
|
+
daas, dashboard, leader, pdf, cnreport, massive, scrapling, firecrawl.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Click CLI for fd-daas-mcp - auto-generated from the same registry as the server.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
fd-daas-mcp <group> <tool> [key=value ...] [--json]
|
|
5
|
+
fd-daas-mcp # REPL mode (needs [repl] extra for history)
|
|
6
|
+
fd-daas-mcp --help # authoritative live surface (no drift)
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import inspect
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import click
|
|
18
|
+
|
|
19
|
+
from fd_daas_mcp import registry
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _parse_value(v: str) -> Any:
|
|
23
|
+
try:
|
|
24
|
+
return json.loads(v)
|
|
25
|
+
except (json.JSONDecodeError, ValueError):
|
|
26
|
+
return v
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _print(result: Any, as_json: bool) -> None:
|
|
30
|
+
if isinstance(result, (dict, list)) or as_json:
|
|
31
|
+
try:
|
|
32
|
+
click.echo(json.dumps(result, default=str, ensure_ascii=False, indent=2))
|
|
33
|
+
return
|
|
34
|
+
except (TypeError, ValueError):
|
|
35
|
+
pass
|
|
36
|
+
click.echo(str(result))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _make_command(name: str, func: Any) -> click.Command:
|
|
40
|
+
sig = inspect.signature(func)
|
|
41
|
+
params = list(sig.parameters.values())
|
|
42
|
+
help_text = ""
|
|
43
|
+
if func.__doc__:
|
|
44
|
+
help_text = func.__doc__.strip().split("\n\n", 1)[0][:200]
|
|
45
|
+
|
|
46
|
+
@click.command(name=name, help=help_text or name)
|
|
47
|
+
@click.argument("kv", nargs=-1)
|
|
48
|
+
@click.option("--json", "as_json", is_flag=True, help="Print raw JSON output")
|
|
49
|
+
def _cmd(kv, as_json):
|
|
50
|
+
kwargs: dict[str, Any] = {}
|
|
51
|
+
for pair in kv:
|
|
52
|
+
if "=" not in pair:
|
|
53
|
+
click.echo(f"error: argument {pair!r} is not key=value", err=True)
|
|
54
|
+
sys.exit(2)
|
|
55
|
+
k, v = pair.split("=", 1)
|
|
56
|
+
kwargs[k] = _parse_value(v)
|
|
57
|
+
for p in params:
|
|
58
|
+
if p.name not in kwargs and p.default is inspect.Parameter.empty:
|
|
59
|
+
click.echo(f"error: missing required parameter {p.name}", err=True)
|
|
60
|
+
sys.exit(2)
|
|
61
|
+
try:
|
|
62
|
+
if inspect.iscoroutinefunction(func):
|
|
63
|
+
result = asyncio.run(func(**kwargs))
|
|
64
|
+
else:
|
|
65
|
+
result = func(**kwargs)
|
|
66
|
+
except SystemExit:
|
|
67
|
+
raise
|
|
68
|
+
except Exception as e: # noqa: BLE001
|
|
69
|
+
click.echo(f"error: {type(e).__name__}: {e}", err=True)
|
|
70
|
+
sys.exit(1)
|
|
71
|
+
_print(result, as_json)
|
|
72
|
+
|
|
73
|
+
return _cmd
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@click.group(invoke_without_command=True)
|
|
77
|
+
@click.pass_context
|
|
78
|
+
def cli(ctx: click.Context) -> None:
|
|
79
|
+
"""fd-daas-mcp - the consolidated DAAS MCP CLI. Run with no subcommand for REPL."""
|
|
80
|
+
if ctx.invoked_subcommand is None:
|
|
81
|
+
_repl()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _repl() -> None:
|
|
85
|
+
session = None
|
|
86
|
+
try:
|
|
87
|
+
from prompt_toolkit import PromptSession
|
|
88
|
+
from prompt_toolkit.history import FileHistory
|
|
89
|
+
|
|
90
|
+
hist = Path.home() / ".cache" / "fd-daas-mcp" / "history"
|
|
91
|
+
hist.parent.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
session = PromptSession(history=FileHistory(str(hist)))
|
|
93
|
+
except ImportError:
|
|
94
|
+
pass
|
|
95
|
+
click.echo("fd-daas-mcp REPL. Ctrl-D to exit. `--help` lists groups/tools.")
|
|
96
|
+
while True:
|
|
97
|
+
try:
|
|
98
|
+
line = (session.prompt("fd-daas-mcp> ") if session else input("fd-daas-mcp> ")).strip()
|
|
99
|
+
except (EOFError, KeyboardInterrupt):
|
|
100
|
+
click.echo("")
|
|
101
|
+
break
|
|
102
|
+
if not line:
|
|
103
|
+
continue
|
|
104
|
+
try:
|
|
105
|
+
cli.main(line.split(), standalone_mode=False)
|
|
106
|
+
except click.exceptions.UsageError as e:
|
|
107
|
+
click.echo(str(e), err=True)
|
|
108
|
+
except SystemExit:
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
for _group, _name, _func in registry.build():
|
|
113
|
+
if _group not in cli.commands:
|
|
114
|
+
_grp = click.Group(name=_group, help=f"{_group} group")
|
|
115
|
+
cli.add_command(_grp)
|
|
116
|
+
cli.commands[_group].add_command(_make_command(_name, _func))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _pdf_branch(argv: list[str]) -> int:
|
|
120
|
+
"""In-process cron branches --pdf-ingest / --pdf-search for the optional
|
|
121
|
+
pdf group (mirror daas-mcp/server.py's --run-rule). Reachable as:
|
|
122
|
+
``python -m fd_daas_mcp.cli --pdf-ingest <path|url>`` /
|
|
123
|
+
``--pdf-search "<query>"``. Returns a structured error when the [pdf]
|
|
124
|
+
extra is absent."""
|
|
125
|
+
_pdf_dir = Path(__file__).resolve().parents[2] / "pdf-mcp"
|
|
126
|
+
if str(_pdf_dir) not in sys.path:
|
|
127
|
+
sys.path.insert(0, str(_pdf_dir))
|
|
128
|
+
try:
|
|
129
|
+
from pdf_tools import cli_ingest, cli_search # type: ignore
|
|
130
|
+
except Exception as e: # noqa: BLE001
|
|
131
|
+
click.echo(json.dumps({"error": f"pdf extra not installed: {e}. uv sync --extra pdf"}))
|
|
132
|
+
return 1
|
|
133
|
+
if "--pdf-ingest" in argv:
|
|
134
|
+
i = argv.index("--pdf-ingest")
|
|
135
|
+
if i + 1 >= len(argv):
|
|
136
|
+
click.echo(json.dumps({"error": "--pdf-ingest requires a <path|url> argument"}))
|
|
137
|
+
return 2
|
|
138
|
+
return cli_ingest(argv[i + 1])
|
|
139
|
+
if "--pdf-search" in argv:
|
|
140
|
+
i = argv.index("--pdf-search")
|
|
141
|
+
if i + 1 >= len(argv):
|
|
142
|
+
click.echo(json.dumps({"error": "--pdf-search requires a <query> argument"}))
|
|
143
|
+
return 2
|
|
144
|
+
return cli_search(argv[i + 1])
|
|
145
|
+
return 0
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
if "--pdf-ingest" in sys.argv or "--pdf-search" in sys.argv:
|
|
150
|
+
sys.exit(_pdf_branch(sys.argv[1:]))
|
|
151
|
+
cli()
|