pub struct ServerState {
pub inner: Arc<Mutex<Inner>>,
pub enable_trading: bool,
pub allow_real_trading: bool,
pub key_store: Arc<KeyStore>,
pub authed_key: Option<Arc<KeyRecord>>,
pub trade_pwd_account: Option<String>,
pub counters: Arc<RuntimeCounters>,
pub push_subscribers: Arc<Mutex<HashMap<String, PushSubscriber>>>,
}Expand description
MCP server 运行时状态
Fields§
§inner: Arc<Mutex<Inner>>Inner 共享可变状态(gateway 地址 + 懒加载的 [FutuClient])
enable_trading: bool是否启用交易写工具(place/modify/cancel)。默认 false。旧开关,仅当
key_store.is_configured() == false 时生效。
allow_real_trading: bool是否允许对 real 环境下单。默认 false。旧开关,同上。
key_store: Arc<KeyStore>keys.json 加载的 KeyStore。is_configured() 为 true 时走 scope 授权模式。
authed_key: Option<Arc<KeyRecord>>调用方传入的 API Key 对应的记录;None 表示未提供 key。
trade_pwd_account: Option<String>交易密码所属登录账号。用于 futu_unlock_trade 从账号级 keychain
trade-password.<login-account> 读取密码;None 时走 legacy/global/env 兼容路径。
counters: Arc<RuntimeCounters>限额运行时(日累计计数器)
push_subscribers: Arc<Mutex<HashMap<String, PushSubscriber>>>v1.4.38 Phase 5: MCP push 订阅者注册表(session_uuid → subscriber)。
futu_sub_acc_push 工具在 HTTP 模式下调用时注册当前 session,daemon
push 到 MCP 后按 acc_id filter 向注册的 peer 发
notify_logging_message(server-initiated notification)。
Implementations§
Source§impl ServerState
impl ServerState
Sourcepub fn new(gateway: String) -> Self
pub fn new(gateway: String) -> Self
创建默认 state:enable_trading=false / allow_real_trading=false /
空 [KeyStore] / 无 authed_key。使用 with_* 链式方法注入额外能力。
Sourcepub async fn register_push_subscriber_with_owner(
&self,
peer: Peer<RoleServer>,
acc_ids: HashSet<u64>,
bearer_token: Option<String>,
owner_key_id_override: Option<String>,
) -> String
pub async fn register_push_subscriber_with_owner( &self, peer: Peer<RoleServer>, acc_ids: HashSet<u64>, bearer_token: Option<String>, owner_key_id_override: Option<String>, ) -> String
v1.4.38 Phase 5: 注册当前 session 接收指定 acc_id 的 push。返回 session UUID(调用方存着,后续可 unregister)。
v1.4.38: 已 wire 到 futu_sub_acc_push tool。tool 被调用时拿到
RequestContext.peer,acc_ids 从工具 args 解析,注册完成后
state.rs 的 push drain loop 会按 acc_ids filter 转 notify 给该 peer。
v1.4.103 (codex 50 F5 / 53 F2 / 58 F3 — B7) + (codex 50 F6 / 53 F4 — B8):
注册当前 session 接收指定 acc_id 的 push。
owner_key_id_override 由 caller 传入 (例如从 HTTP Bearer 解析得到 key id);
若 None → fall back 到 bearer_token 解析 → fall back 到 startup authed_key.id.
allowed_acc_ids_snapshot 同样 fall back 链: bearer → startup.
Sourcepub async fn unregister_push_subscriber_with_owner_check(
&self,
session_id: &str,
caller_key_id: Option<&str>,
) -> Result<bool, String>
pub async fn unregister_push_subscriber_with_owner_check( &self, session_id: &str, caller_key_id: Option<&str>, ) -> Result<bool, String>
v1.4.103 (codex 50 F6 / 53 F4 — B8): unsub session ownership check.
行为:
- 无 caller_key_id (legacy / stdio): 退化为旧行为 (任何 caller 可 unsub).
- 有 caller_key_id + subscriber.owner_key_id 匹配: 删除, 返 Ok(true).
- 有 caller_key_id + subscriber.owner_key_id 不匹配: 拒绝, 返 Err(reason) — 防其他 caller 拿可见 session_id 强制 unsub.
- session_id 不存在: 返 Ok(false) (idempotent, 不报错).
- subscriber.owner_key_id = None (legacy 注册): 退化为旧行为 — 任何 caller 可 unsub (向后兼容).
Sourcepub async fn push_subscribers_summary(
&self,
caller_allowed_acc_ids: Option<&HashSet<u64>>,
) -> Vec<(String, HashSet<u64>, u64)>
pub async fn push_subscribers_summary( &self, caller_allowed_acc_ids: Option<&HashSet<u64>>, ) -> Vec<(String, HashSet<u64>, u64)>
v1.4.58 Phase A: 列出所有 push 订阅 summary(tool diagnostic 用)。
返 Vec<(session_id, acc_ids, age_secs)>。
MED-NEW-3 修(2nd review):加 caller_allowed_acc_ids 参数做
scope-mode 多租过滤。当 caller 的 key 有 allowed_acc_ids 白名单时,
只返 subscription 的 acc_ids 与 caller 白名单有交集的条目。
避免 agent A(acc_ids=[100, 200])通过本 tool 看到 agent B 订阅的
acc_id=[300, 400]。
caller_allowed_acc_ids=None / empty → 不过滤(legacy mode / no-scope key)。
rmcp 版本兼容:rmcp 1.4.0 Peer<RoleServer> 不实装 PartialEq,
无法按 peer 身份直接过滤。若未来 rmcp 加 PartialEq,可切到更精确的
per-session-owner 过滤(当前只能靠 acc_id 权限交集近似)。
Sourcepub fn with_trading(
self,
enable_trading: bool,
allow_real_trading: bool,
) -> Self
pub fn with_trading( self, enable_trading: bool, allow_real_trading: bool, ) -> Self
启用交易写工具(构造器式链式设置)
Sourcepub fn with_key_store(self, store: Arc<KeyStore>) -> Self
pub fn with_key_store(self, store: Arc<KeyStore>) -> Self
设置 KeyStore(新授权模式)
Sourcepub fn with_authed_key(self, key: Option<Arc<KeyRecord>>) -> Self
pub fn with_authed_key(self, key: Option<Arc<KeyRecord>>) -> Self
设置已通过验证的 API Key 记录
Sourcepub fn with_trade_pwd_account(self, account: Option<String>) -> Self
pub fn with_trade_pwd_account(self, account: Option<String>) -> Self
设置交易密码所属登录账号(MCP 只连 gateway,本身无法可靠推断 daemon 的 login account;由 CLI/env/config 显式注入)。
Sourcepub fn is_scope_mode(&self) -> bool
pub fn is_scope_mode(&self) -> bool
是否启用了 scope 授权模式
Trait Implementations§
Source§impl Clone for ServerState
impl Clone for ServerState
Source§fn clone(&self) -> ServerState
fn clone(&self) -> ServerState
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ServerState
impl !RefUnwindSafe for ServerState
impl Send for ServerState
impl Sync for ServerState
impl Unpin for ServerState
impl UnsafeUnpin for ServerState
impl !UnwindSafe for ServerState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more