Conversation
Add kag-solve and kag-status to `kag mcp-server` --enabled-tools so
the upstream host carries the same frozen contracts as the standalone
kag-bridge (design docs §A.1; dual-hosting keeps KAGWeb zero-change).
- kag_solve(question, use_pipeline): runs do_qa_pipeline through a
pure-memory OpenSPGReporter and returns
{answer, reference, subgraph, cost_ms, namespace} — the identical
shape kag-bridge/KAGWeb already consume.
- kag_status(): loaded config / project / llm_configured health,
errors as structured JSON, never echoes credentials.
- Config loading resets the KAGConfigMgr singleton via
initialize(config_file=...) — its all_config is cached on first
call, so calling get_config() before chdir (as the module import
chain can) returns stale empty config; the reset makes the project
dir authoritative.
Verified over stdio: kag_status returns
{bridge: ok, plugin fix project_id/namespace/llm_configured} from a
real bound project. kag-solve E2E shares the do_qa_pipeline path
already measured in M3.
…review) kag_solve now holds a module-level asyncio.Semaphore(1) around config loading and do_qa_pipeline. KAGConfigMgr/KAGConfigAccessor are process-global state - initialize() rewrites the singleton and the solver reads the same cfg dict - so concurrent solves could clobber each other's config mid-flight. Aligns with the standalone kag-bridge (§5.1 R3) which already queues solves. The reporter product chain was also confirmed: add_report_line accumulates locally into report_stream_data (no network when host_addr=None), so the subgraph the frozen contract returns is assembled correctly.
…5-B)
Completes the staged tool surface so upstream `kag mcp-server` carries
all four frozen contracts, dual-hosting with the standalone kag-bridge.
- kag_schema(): ReasonerClient.get_reason_schema -> {project_id,
namespace, spg_types}; keys are the namespace-qualified full names,
matching the bridge.
- kag_reason(dsl, params): straight POST to /public/v1/reason/run in a
thread pool (the knext ReasonTask model drops resultMessage, so the
raw response path keeps the frozen error detail); params values are
JSON-stringified so raw arrays work; rows capped at 200, error
clipped to 600.
Verified over stdio against the bound project: kag_schema lists 19
types (Person present), kag_reason returns FINISH with the workFor
edge rows -- same shape as the M3 bridge E2E.
kag_schema/kag_reason/kag_status each call _load_kag_config, which runs KAG_CONFIG.initialize() over the process-global singleton. Only kag_solve held the semaphore, so a concurrent lightweight tool could rewrite the global config mid-solve. Move all four tools' config load under the shared _solve_semaphore so every global initialize is mutually exclusive. Regression-verified kag_schema (19 types) and kag_reason (FINISH 3 rows).
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.
PR Description —
feat/mcp-frozen-contractEnglish
Title
feat(mcp): align
kag mcp-serverwith the frozen OPENKG WebUI tool contractsBackground / Motivation
OPENKG WebUI (the
kagwebrepository) integrates with KAG through an MCP tool surface and has defined and frozen four tool contracts (kag_solve/kag_schema/kag_reason/kag_status— inputSchema and return schema frozen since v1). Until now these contracts only existed in the standalonekag-bridge(FastMCP, dual transport: stdio + streamable-http).This PR aligns the same frozen contracts into the upstream
kag mcp-server, making KAG's built-in MCP server a second host (dual-hosting). OPENKG WebUI stays unchanged when switching hosts.Changes
kag/mcp/server/kag_mcp_server.py:kag-solve(ca69a671) — align the frozenkag_solvecontract:OpenSPGReporterin-memory product (host_addr=None, zero network) throughdo_qa_pipeline, returning the frozen{answer, reference, subgraph, cost_ms, namespace}.KAGConfigMgr.all_configcaches on first access, and the module-top-level import chain initializes it with an empty config in a config-less cwd;_load_kag_confignow callsKAG_CONFIG.initialize(config_file=...)to reset explicitly.kag-status(ca69a671) — config / project / LLM connectivity probe; structured errors; no credential echo.kag-schema(156ed685) —ReasonerClient.get_reason_schema→{project_id, namespace, spg_types}(keys are namespace-qualified full names).kag-reason(156ed685) — directPOST /public/v1/reason/run(in a thread pool):ReasonTaskclient model does not mapresultMessage(error details exist only in the raw response); the direct call keeps the frozen error detail.paramsvalues are JSON-stringified (raw arrays from an agent also work); rows capped at 200 with atruncatedflag; errors clipped to 600 chars.69d3a7a0/0ec71b49, review fixes) —KAGConfigAccessor/KAG_CONFIGare process-global singletons andinitialize()rewrites the singleton; all four tools now load config under a module-level_solve_semaphore(asyncio.Semaphore(1)) so every global initialization is mutually exclusive.Frozen contracts (v1, identical to the standalone kag-bridge)
kag_solvequestion,use_pipeline{answer, reference[], subgraph{...}, cost_ms, namespace}kag_schema{project_id, namespace, spg_types{fullName: {spg_type_enum}}}kag_reasondsl,params{status, header, rows(≤200), row_count, truncated, cost_ms, namespace, error?}kag_status{bridge, project, namespace, llm_configured}(structured errors, no credentials)Verification (local stdio against a live OpenSPG)
kag_status→{bridge: ok, project: 3, namespace: m0ProbeLive, llm_configured: true}kag_schema→ 19 SPG types (m0ProbeLive.Personpresent)kag_reason→workForquery FINISH, 3 rows (Zhang San → Kaiyuan University)kag_solve→ samedo_qa_pipelinepath already E2E-verified in M3Known boundaries (need upstream confirmation)
python -m kag.bin.kag_cmds mcp-server --transport stdio --enabled-tools ...showsConnection closedin this environment while directKagMcpServer(...).serve()works — likely stdout pollution from the import chain or arg wiring; this looks like a CLI-wrapper issue, worth verifying upstream.kagweb/tests/); the contract test seeds can be moved here if approved.enabled-toolsallowlist mechanism; the transport layer is untouched.Review focus
KAG_CONFIG.initialize()reset in_load_kag_config.Connection closed.中文
标题
feat(mcp):将
kag mcp-server对齐 OPENKG WebUI 冻结工具契约背景 / 动机
OPENKG WebUI(
kagweb仓库)通过 MCP 工具面与 KAG 集成,已定义并冻结了 4 个工具契约(kag_solve/kag_schema/kag_reason/kag_status,inputSchema 与返回 schema 自 v1 冻结)。此前这些契约仅存在于独立部署的kag-bridge(FastMCP,stdio + streamable-http 双 transport)。本 PR 将同一组冻结契约对齐进上游
kag mcp-server,使 KAG 自带 MCP server 成为第二宿主(双宿主);切换宿主时 OPENKG WebUI 侧零改动。变更内容
kag/mcp/server/kag_mcp_server.py:kag-solve(ca69a671)——对齐kag_solve冻结契约:OpenSPGReporter纯内存产物(host_addr=None,零网络),经do_qa_pipeline返回冻结的{answer, reference, subgraph, cost_ms, namespace}KAGConfigMgr.all_config首调即缓存,模块顶层 import 链会在无配置 cwd 抢先初始化;_load_kag_config改用KAG_CONFIG.initialize(config_file=...)显式重置kag-status(ca69a671)——配置 / 项目 / LLM 连通性健康探测,结构化错误,不回显凭据kag-schema(156ed685)——ReasonerClient.get_reason_schema→{project_id, namespace, spg_types}(key 为 namespace 全名)kag-reason(156ed685)——直调POST /public/v1/reason/run(线程池):ReasonTask客户端模型不映射resultMessage(错误详情只在原始响应),直调保留冻结的错误详情truncated标记;错误截 600 字符69d3a7a0/0ec71b49,评审修复)——KAGConfigAccessor/KAG_CONFIG是进程级全局单例,initialize()会重写该单例;四个工具的所有 config 加载统一纳入模块级_solve_semaphore(asyncio.Semaphore(1)),令全局初始化互斥冻结契约(v1,与独立 kag-bridge 完全一致)
kag_solvequestion,use_pipeline{answer, reference[], subgraph{...}, cost_ms, namespace}kag_schema{project_id, namespace, spg_types{全名: {spg_type_enum}}}kag_reasondsl,params{status, header, rows(≤200), row_count, truncated, cost_ms, namespace, error?}kag_status{bridge, project, namespace, llm_configured}(结构化错误,无凭据)验证(本地 stdio 实测,连真实 OpenSPG)
kag_status→{bridge: ok, project: 3, namespace: m0ProbeLive, llm_configured: true}kag_schema→ 19 个 SPG 类型(m0ProbeLive.Person在列)kag_reason→workFor查询 FINISH 3 rows(张三→开元大学)kag_solve→ 复用 M3 已实测的同一do_qa_pipeline路径已知边界(需上游确认)
python -m kag.bin.kag_cmds mcp-server --transport stdio --enabled-tools ...在本环境冒烟出Connection closed(直接KagMcpServer(...).serve()正常)——疑似 import 链 stdout 污染或参数接线,属 CLI 包装层问题,建议上游核验该入口kagweb/tests/);如认可,可将契约测试种子迁入本仓库enabled-tools白名单机制,未改 transport 层请 reviewer 关注
_load_kag_config的KAG_CONFIG.initialize()显式重置是否有副作用