分析当前 MCP 实现是否提供 tools search 功能,目前功能较多,未来每个 tools 将会有更多更详细的说明。类似于 longbridge cli 一样 -h 是看到基础摘要的说明。而 - #53
Open
endless-bot wants to merge 86 commits into
Open
分析当前 MCP 实现是否提供 tools search 功能,目前功能较多,未来每个 tools 将会有更多更详细的说明。类似于 longbridge cli 一样 -h 是看到基础摘要的说明。而 #53endless-bot wants to merge 86 commits into
endless-bot wants to merge 86 commits into
Conversation
## Summary - Add a 5-second force-exit fallback in `shutdown_signal()` so SSE/streaming connections that linger indefinitely don't block port reuse when restarting the server - Reduce graceful shutdown timeout from 10s to 5s to align with the force-exit window ## Test plan - [ ] Start the server and connect an SSE client - [ ] Send SIGINT — verify the server exits within 5 seconds even with an active SSE connection - [ ] Verify a new instance can bind to the same port immediately after 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary - Add `GET /mcp/tools.json` endpoint (no auth required) that returns all registered MCP tool names and descriptions as JSON - Expose `tool_router` with `pub(crate)` visibility via `#[tool_router(vis = "pub(crate)")]` - Add `tools::list_tools()` public helper backed by `ToolRouter::list_all()` - Log tool count and URL on server startup ## Test plan - [ ] Start server and verify startup log shows `tools available count=N url=.../mcp/tools.json` - [ ] `curl http://localhost:8000/mcp/tools.json` returns JSON with `tools` array containing name/description for each tool 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Config always enables overnight trading - Remove LONGBRIDGE_LANGUAGE (determined by Accept-Language header) - Remove LONGBRIDGE_ENABLE_OVERNIGHT (always on) - Remove RUST_LOG from README
- McpContext bundles token + language, methods create_config/create_http_client - Language from Accept-Language header sets SDK Config.language - enable_overnight always on - Single struct param makes future extensions backward-compatible
…emium, statement_list, and security_list - financial_report: add required `kind` param (IS/BS/CF/ALL, default ALL) - valuation: add required `indicator` (default pe) and `range` (default 1) params - ah_premium: add `AhPremiumParam` with `period` and `count`; map to `line_type`/`line_num` - statement_list: replace broken HTTP endpoint with SDK AssetContext.statements() - security_list: clarify that `category` must be "Overnight" in param doc and tool description
- broker_holding: add period param (rct_1/rct_5/rct_20/rct_60, default rct_1) - profit_analysis: merge summary + sublist into single response, matching terminal behavior
…trade_sessions, calendar category, alert frequency, and statement sections
…put (#25) Follow-up to #24 — audit of the 13 typed output schemas against the SDK source caught **6 places** where the declared shape didn't match what `tool_json` actually emits, plus one `account_channel` nullability fix. ## Bugs fixed | Schema | Before (in #24) | After (this PR) | Why | |---|---|---|---| | `StockPositionsResponse` | `channels: [...]` | `list: [...]` | SDK uses `#[serde(rename = "list")]` | | `FundPositionsResponse` | `channels: [...]` | `list: [...]` | same | | `StockPositionChannel` | `positions: [...]` | `stock_info: [...]` | SDK uses `#[serde(rename = "stock_info")]` | | `FundPositionChannel` | `positions: [...]` | `fund_info: [...]` | SDK uses `#[serde(rename = "fund_info")]` | | `StockPositionChannel.account_channel` `FundPositionChannel.account_channel` | `String` | `Option<String>` | `to_tool_json` overwrites this field to `null` for privacy regardless of upstream value | | `MarketTemperatureResponse.updated_at` | — | `timestamp` | The SDK field name is `timestamp`; `alias = "updated_at"` only takes effect on **deserialize**, not serialize | | `HistoryMarketTemperatureResponse.records` | `records: [...]` | `list: [...]` | SDK uses `#[serde(rename = "list")]` | ## Audit method Cross-referenced each declared schema against: 1. The SDK type source (`longbridge::trade::types::*`, `longbridge::quote::types::*`, etc.) — pulled directly from `~/.cargo/git/checkouts/openapi-*/rust/src/` 2. The `serde_utils::*` custom serializers (decimals stringify, enums via `collect_str`, RFC3339 timestamps, `Option` nullability rules) 3. The local `to_tool_json` transform (snake_case + `_at`-i64-to-RFC3339 + `counter_id` → `symbol` rename + `aaid` / `account_channel` → `null`) ## Verified clean (no changes needed) - `OrderIdResponse` (`{order_id}`) - `StatementUrlResponse` (`{url}`) - `EstimateMaxQtyResponse` (`{cash_max_qty, margin_max_qty}`) - `MarginRatioResponse` (`{im_factor, mm_factor, fm_factor}`) - `DepthResponse` (`{bids, asks}` with `{position, price, volume, order_num}` per level) - `BrokersResponse` (`{bid_brokers, ask_brokers}`) - `CapitalDistributionResponse` (`{timestamp, capital_in, capital_out}`) - `TradingDaysResponse` (`{trading_days, half_trading_days}`) - `OrderDetailResponse` (25 documented fields; commission/fee tail covered by JSON Schema's default `additionalProperties: true`) ## Test plan - [x] `cargo +nightly fmt` clean - [x] `cargo build` clean - [x] `cargo clippy --all-features --all-targets` — 0 warnings - [x] `cargo test` — 48 passed - [x] Live `GET /mcp/tools.json` confirms each fixed schema now emits the corrected field names (`list`, `stock_info`, `fund_info`, `timestamp`) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary - Reorder `FinanceCalendarParam` fields: `category` first (primary selector), then date range, then optional `market` - Expand `category` field doc with plain-language descriptions for each value: - `report` — earnings reports (includes financial statements) - `dividend` — dividend announcements - `split` — stock splits **and** reverse splits (share consolidations) - `ipo` — upcoming IPO listings - `macrodata` — macro economic data releases (CPI, NFP, rate decisions, etc.) - `closed` — market closure days - Remove deprecated `financial` from category list (it's included automatically under `report`) - Clarify `market` is optional and list all supported codes: HK, US, CN, SG, JP, UK, DE, AU - Update tool-level description in `mod.rs` to reflect the same information 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… server version from Cargo.pkg (#28) Closes longbridge/developers#953. ## Root cause v0.1.11 added `outputSchema` declarations to 13 tools but never updated the tool response format. MCP spec §tool-result states: > A tool that declares an `outputSchema` **MUST** return `structuredContent` in its response. `tool_result()` was returning only `content: [{ type: "text", text: "..." }]` with `structuredContent` absent. Clients that validate this requirement — including Claude Code — raised: ``` Tool stock_positions has an output schema but did not return structured content ``` A second unrelated issue was also found during the audit: `initialize` responses always reported `serverInfo.version = "0.1.6"` because the `#[tool_handler]` macro had a hardcoded `version = "0.1.6"` attribute that was never bumped. ## What changed (`src/tools/mod.rs` only, 9 lines) ### Fix 1 — populate `structured_content` on every tool response ```rust // before fn tool_result(json: String) -> CallToolResult { CallToolResult::success(vec![Content::text(json)]) } // after fn tool_result(json: String) -> CallToolResult { let structured = serde_json::from_str::<serde_json::Value>(&json).ok(); let mut result = CallToolResult::success(vec![Content::text(json)]); result.structured_content = structured; result } ``` Text content is preserved (backwards-compatible). `structuredContent` is now always populated for every tool that goes through `tool_result()`, so the invariant holds for all 13 tools with `outputSchema` and any future ones. ### Fix 2 — remove hardcoded server version ```rust // before #[tool_handler(name = "longbridge-mcp", version = "0.1.6", instructions = "...")] // after #[tool_handler(name = "longbridge-mcp", instructions = "...")] ``` When `name` is present but `version` is absent the rmcp macro falls through to its built-in `env!("CARGO_PKG_VERSION")` path, so `serverInfo.version` in `initialize` responses now automatically matches `Cargo.toml`. ## Test plan - [x] `cargo +nightly fmt` clean - [x] `cargo build` clean - [x] `cargo clippy --all-features --all-targets` — 0 warnings - [x] `cargo test` — 48 passed - [x] Live comparison: local returns `structuredContent`, prod does not - [x] `serverInfo.version` in `initialize` now shows `0.1.11` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub username changed from `wuxsoft` to `hogan-yuan`. Updates `glama.json` so the new username has admin access to the Glama listing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Glama's build system invokes servers via `mcp-proxy --` which expects a
**stdio** MCP process. Since `longbridge-mcp` is an HTTP server, this
script bridges the gap:
1. Starts the HTTP server in the background
2. Waits up to 10 s for `/health` to respond
3. `exec`s `mcp-proxy http://localhost:8000/mcp` — replacing itself with
an stdio↔HTTP proxy
Data flow inside Glama's container:
```
Glama scanner → [stdio] → outer mcp-proxy -- glama-start.sh
└→ [stdio] → inner mcp-proxy (exec'd)
└→ [HTTP] → longbridge-mcp :8000
```
**Glama config update needed:**
CMD arguments: `["/app/scripts/glama-start.sh"]`
Build steps: add `chmod +x /app/scripts/glama-start.sh` at the end
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## What Adds a `--stdio` transport mode so Glama's build system can scan the server's tool definitions without needing a real OAuth token. ``` # New flag — does not affect the existing HTTP server in any way longbridge-mcp --stdio ``` When `--stdio` is passed the binary: 1. Listens for MCP JSON-RPC messages on **stdin** 2. Responds on **stdout** (logs go to **stderr**, keeping stdout clean) 3. Holds the server alive via `RunningService::waiting()` until stdin closes `tools/list` works fully without credentials. `tools/call` returns auth errors for any upstream calls that require a Longbridge token — which is expected and acceptable for a directory scanner. ## Why Glama's build system wraps every server with `mcp-proxy --`, which expects a **stdio** MCP process. Our server is an HTTP server, so the wrapper always timed out or errored. This flag bridges that gap with minimal code (~20 lines in `main.rs`). ## What doesn't change The existing HTTP server path is completely untouched — no behaviour change when running without `--stdio`. ## Files changed | File | Change | |---|---| | `src/main.rs` | `--stdio` flag → rmcp `AsyncRwTransport` over stdin/stdout; logs explicitly routed to stderr | | `Cargo.toml` | enable rmcp `transport-io` feature | | `scripts/glama-start.sh` | simplified: `exec longbridge-mcp --stdio` | ## Test plan - [x] `cargo build` clean - [x] `cargo clippy --all-features --all-targets` — 0 warnings - [x] `cargo test` — 48 passed - [x] HTTP mode: `--bind 0.0.0.0:8001` starts normally, `/health` 200, `/mcp/tools.json` 109 tools - [x] stdio mode: `initialize` + `tools/list` returns 109 tools with title / annotations / outputSchema all present; stdout is pure JSON-RPC, logs on stderr 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ls (#34) ## Summary - **Search**: `news_search`, `topic_search` — search news articles and community topics by keyword - **Fundamental**: `financial_statement`, `financial_report_latest`, `valuation_rank`, `analyst_estimates`, `institution_rating_history`, `institution_rating_industry_rank` - **Trade / Asset**: `short_margin`, `holding_period`, `trade_info` - **ATM**: `bank_cards`, `withdrawals`, `deposits` - **IPO**: `ipo_subscriptions`, `ipo_calendar`, `ipo_listed`, `ipo_detail`, `ipo_orders`, `ipo_order_detail`, `ipo_profit_loss` Ports 20 new tools from [longbridge-terminal PR #185](longbridge/longbridge-terminal#185). New sub-modules `atm.rs`, `ipo.rs`, and `search.rs` added; `fundamental.rs` and `trade.rs` extended. ## Test plan - [ ] `cargo build` passes - [ ] `cargo clippy --all-features --all-targets` zero warnings 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary - **version**: bump `Cargo.toml` and `server.json` to `0.2.1` - **calendar**: switch `finance_calendar` to `http_get_tool_unix` — converts `list[].infos[].datetime` from unix to ISO 8601 - **ipo**: convert `ipo_calendar` `timestamp` field to ISO 8601 - **portfolio**: add `start_time` to `profit_analysis` unix path conversion (was missing alongside `end_time`) - **mod**: fix `static_info` description (`name` → `name_cn, name_en`) and `depth` description (`bid/ask` → `asks/bids`) ## Test plan - [x] `cargo build` passes - [x] Full 128-tool test suite: PASS 95 / WARN 2 / SKIP 31 / FAIL 0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
## Summary Ref longbridge/developers#982 - 删除 `AnalystEstimatesParam` struct - 删除 `fundamental::analyst_estimates` 函数 - 删除对应的 MCP tool `analyst_estimates` ## Test plan - [ ] 确认编译无错误 - [ ] 确认其他 MCP tools 功能不受影响 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…, fix registry link - locales: remove analyst_estimates from zh-CN and zh-HK (tool removed in #37) - README/server.json: 110 → 127 tools, add IPO/Search/ATM categories - README: fix MCP Registry badge href (404 → /versions endpoint) - server.json: update localizedDescriptions and toolCategories Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…olation (#38) ## Summary - Switch MCP server to stateless mode to fix session-not-found errors on multi-instance deployments - Fix `structuredContent` type violation that caused Cursor to reject array tool responses ## Fix 1 — Stateless mode (`src/auth/mod.rs`) **Root cause**: The server is designed for stateless multi-instance deployment, but was using `stateful_mode: true` (the rmcp default) with an in-memory `LocalSessionManager`. Under a load balancer, sessions created on Instance A are unknown to Instance B, triggering a failure chain in Cursor: 1. POST with cached `Mcp-Session-Id` → **404 Session not found** (session lives on another instance) 2. Cursor falls back to legacy SSE V1 protocol (GET without session ID) → **400 Session ID is required** Claude Code and Codex are unaffected because they re-initialize on every connection rather than caching session IDs. **Fix**: Replace `LocalSessionManager` with `NeverSessionManager` and set `stateful_mode(false)`. The `Mcp-Session-Id` header is completely ignored in stateless mode; each POST is handled independently with no session state. ## Fix 2 — `structuredContent` type (`src/tools/mod.rs`) **Root cause**: `tool_result` unconditionally assigned the parsed JSON value to `structured_content`. Tools returning `Vec<T>` (e.g. `quote`, `static_info`, `trades`, `candlesticks`, `participants`) serialize to a JSON array. The MCP spec requires `structuredContent` to be a JSON **object** (record); Cursor validates this strictly and rejects array values with: ``` Invalid input: expected record, received array ``` **Fix**: Added `.filter(serde_json::Value::is_object)` so `structured_content` is only set for JSON object responses. Array responses leave it as `None`, which is valid per spec. The fix is centralized in `tool_result` and covers all tools. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
) ## Summary - Add `extra_headers: Vec<(String, String)>` to `McpContext` to carry all incoming request headers - In `create_http_client()`, chain `.header()` calls to attach extra headers to every upstream REST request - In `extract_context()`, collect all headers from the MCP request (skipping non-UTF-8 values) - Add a `tracing::debug!` log line to verify forwarded headers during development ## Notes - `longbridge::Config` in the current dependency version (`485cf02`) has no `header()` method, so WebSocket-based SDK clients (`QuoteContext`, `TradeContext`) do not yet receive the extra headers — only `HttpClient`-based REST calls are affected - The MCP `Accept: application/json, text/event-stream` header will be forwarded to upstream; if upstream returns 406, filtering out the `accept` header is the minimal fix needed ## Test plan - [ ] Start server with `RUST_LOG=longbridge_mcp=debug` - [ ] Send a request with a custom header (`X-My-Custom: hello`) plus `Accept: application/json, text/event-stream` - [ ] Confirm the debug log shows the custom header in the forwarded list 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary - Bump `Cargo.toml` and `server.json` (version + OCI identifier) to `0.2.3` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
## Summary `mcp-publisher publish` rejects descriptions > 100 characters. Removes "real-time " (10 chars) to bring it within limit (104 → 94 chars). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…er_id lookup (#44) ## Summary - Replaces the runtime-initialized `OnceLock<HashSet>` with a compile-time `phf::Set` generated by `build.rs` via `phf_codegen`, eliminating startup initialization cost - Merges ETF, IX, and WT counter_id lists (25k+ entries) into a single `SPECIAL_COUNTER_IDS` set embedded in the binary - Unifies `symbol_to_counter_id` to resolve all special types (ETF/IX/WT) via set lookup, adds leading-dot handling for US index symbols and leading-zero stripping for numeric codes - Keeps `index_symbol_to_counter_id` as a compatibility alias delegating to `symbol_to_counter_id` ## Test plan - [ ] `cargo test` passes (54 tests including new `ix_hk_via_set`, `ix_us_leading_dot`, `wt_hk_via_set`, `index_alias`) - [ ] `SPY.US` → `ETF/US/SPY`, `HSI.HK` → `IX/HK/HSI`, `10005.HK` → `WT/HK/10005`, `TSLA.US` → `ST/US/TSLA` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary Implements 6 new tools from `docs/stock-detail-mcp-prompt.md`: | Tool | Path | |------|------| | `business_segments` | `GET /v1/quote/fundamentals/business-segments` | | `business_segments_history` | `GET /v1/quote/fundamentals/business-segments/history` | | `institutional_views` | `GET /v1/quote/ratings/institutional` | | `industry_rank` | `GET /v1/quote/industry/rank` | | `industry_peers` | `GET /v1/quote/industries/peers` | | `financial_report_snapshot` | `GET /v1/quote/financials/earnings-snapshot` | ### Details - `counter.rs`: added `bk_symbol_to_counter` / `bk_counter_to_symbol` for `IN00xxx.US ↔ BK/US/IN00xxx` conversion - `industry_rank`: recursively converts BK `counter_id` fields to `symbol` in response - `locales`: zh-CN and zh-HK entries added for all 6 tools - `cargo test locales_match_live_tool_schema` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
#47) ## Summary Improves all 133 tool `description` strings to raise Glama `quality_grade` from B to A. ### Changes - Every "Get X" description now lists key return fields with example values - Parameter doc comments clarified with format examples (e.g. `"AAPL.US"`, `"YYYYMMDD"`) - Enum parameter values documented with defaults ### Verification - `cargo build` ✅ - `cargo clippy --all-features --all-targets -- -D warnings` ✅ (0 warnings) - `cargo test locales_match_live_tool_schema` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Adds LobeHub MCP badge linking to https://lobehub.com/mcp/longbridge-longbridge-mcp 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary Improves all 133 Chinese tool descriptions in zh-CN and zh-HK locale files. - Average description length: **36 → 90 chars** - Added return field names in Chinese (最新价, 成交量, 除权日, etc.) - Added parameter examples and constraints - zh-HK uses consistent Traditional Chinese (繁體) ## Verification - `cargo test locales_match_live_tool_schema` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
## Summary - `today_executions` and `history_executions` now include a `side` field (Buy/Sell) by concurrently fetching the corresponding orders and joining by `order_id` - `order_detail` already serializes the full SDK struct, so `history` (execution records) is automatically included in the response ## Test plan - [ ] `today_executions` — verify `side` field appears in the result - [ ] `history_executions` — verify `side` field appears in the result - [ ] `order_detail` — verify `history` array is present with status/time/price/quantity/msg 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…json (#51) ## Summary ### New files - **`data/tools_app_id.json`** — Maps each MCP tool to its `id` in `open_api_entries.json`. 111/133 tools matched; 22 WebSocket-only QuoteContext tools have no HTTP endpoint (app_id: null) - **`data/scopes.json`** — Moved from root to `data/` ### Changes - **`/mcp/tools.json`** HTTP endpoint now includes `app_id` per tool (null for WebSocket-only tools) - **`src/auth/mod.rs`** — Merges `app_id` from `data/tools_app_id.json` into the tools.json response at startup - **`data/scopes.json`** — Added `General` scope (id=0) containing 95 tools not covered by scopes 4/6/10/11 ### Scope breakdown | id | name | tools | |----|------|-------| | 0 | General | 95 | | 4 | Watchlist | 5 | | 6 | Account & Positions | 16 | | 10 | Trade Order Lookup | 9 | | 11 | Trade Execution | 8 | ### Note `app_id` is only returned by the `/mcp/tools.json` HTTP endpoint. The MCP protocol `tools/list` response does **not** include `app_id` (verified). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
## Summary - `calc_indexes` tool was returning raw unscaled Greek values that differ from what the Longbridge app displays - Apply the same normalization as `longbridge-terminal` CLI before returning results: - **theta**: raw value is annualized (×252) → divide by 252 for per-trading-day value - **vega**: raw value is scaled by 100 → divide by 100 for per-1%-IV-change value - **rho**: raw value is scaled by 100 → divide by 100 for per-1%-rate-change value ## Test plan - [ ] Start MCP server locally and call `calc_indexes` with `theta`, `vega`, `rho` fields - [ ] Verify returned values match the Longbridge app display (same as `longbridge calc-index` CLI output) Fixes longbridge/developers#1014 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…的说明。类似于 longbridge cli 一样 -h 是看到基础摘要的说明。而 Generated by Endless task #7. Co-authored-by: Huacnlee Li Huashun <huacnlee@longbridge-inc.com>
hogan-yuan
force-pushed
the
main
branch
2 times, most recently
from
July 6, 2026 02:22
8284189 to
c33ad40
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Auto-generated by Endless task #7.
Initiated by: Huacnlee Li Huashun
背景
longbridge-mcp 目前暴露 133 个 MCP tools,AI client 每次使用前需通过
tools/list获取全量列表才能找到目标工具。当工具数量持续增长时,上下文消耗显著增加,且没有任何机制支持按关键词过滤或分层查阅。MCP 标准本身只定义了
tools/list(全量列出)和tools/call(调用),没有内置搜索或分级帮助能力。业界通行做法是将工具发现能力实现为元工具(meta-tools),作为 MCP tools 本身暴露给 AI agent。本次改动参照 longbridge CLI 的
-h(摘要)/--help(详情)分层帮助设计,为 MCP server 引入完整的工具发现与搜索机制。摘要
src/tools/meta.rs,实现三个无需鉴权的元工具src/tools/mod.rs注册三个新工具到#[tool_router]implserver.json中的 toolCount(133→136)和分类统计list_tools()静态注册信息,无任何外部 I/O,无需 Bearer token,实现最简now工具模式(sync 逻辑 + async 包装),不引入新外部依赖cargo build— 无编译错误cargo clippy --all-features --all-targets— 零 warningcargo test—locales_match_live_tool_schema测试验证 locale 完整性tools_list({})返回 136 个工具摘要,tools_search({"query":"order"})返回订单相关工具,tools_describe({"name":"depth"})返回完整参数文档修改
src/tools/meta.rstools_list、tools_search、tools_describe三个函数的实现src/tools/mod.rsmod meta;声明;在#[tool_router]impl 中注册三个新工具方法locales/zh-CN/tools.jsontools_list、tools_search、tools_describe的简体中文翻译条目locales/zh-HK/tools.jsontools_list、tools_search、tools_describe的繁体中文翻译条目server.jsontoolCount133→136,utility分类计数 1→4,三处本地化描述更新关键决策
元工具不调用 extract_context:三个新工具只访问本地工具注册信息,不需要 Bearer token。这是有意为之——工具发现本身是公开信息,要求认证会增加 AI agent 的使用摩擦。
通过现有
list_tools()获取注册信息:未引入新的全局状态或缓存,list_tools()本身已经高效(Lazy<Vec<Tool>>),重复调用无开销。description 截断到 ~120 字符(词边界):
tools_list作为-h等价物返回摘要,过长描述会破坏可读性。完整描述通过tools_search/tools_describe获取。