diff --git a/README.md b/README.md index f491965..7bcf0a5 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,18 @@ BlockVectra provides two Streamable HTTP MCP endpoints. Use `https://docs.blockv https://docs.blockvectra.com/mcp ``` +### Read documentation from a Python agent + +Python 3.11+ can connect directly with the [official MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk). With [uv](https://docs.astral.sh/uv/) installed, run this from the cloned repository: + +```bash +uv run examples/mcp_docs.py +``` + +The example pins `mcp==2.3.0` in its script metadata, lists the two documentation tools, then reads the English `quickstart` page. It prints JSON containing the tool names, page path, language and complete Markdown text, so an agent can consume the result. It uses the documentation-only endpoint: no BlockVectra key, wallet, model API or chain RPC is involved. Errors exit non-zero; the example has a 40-second overall deadline. Dependency installation occurs before that deadline. + +The separate standard-library RPC example above still needs no third-party Python packages. + ### 1. Claude Code Configuration #### Keyless Documentation MCP diff --git a/README.zh.md b/README.zh.md index 0402cda..21da4b3 100644 --- a/README.zh.md +++ b/README.zh.md @@ -331,6 +331,18 @@ BlockVectra 提供两个基于 Streamable HTTP 的 MCP 入口:文档专用入 https://docs.blockvectra.com/mcp ``` +### 从 Python Agent 读取文档 + +Python 3.11+ 可通过[官方 MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)直接连接。安装 [uv](https://docs.astral.sh/uv/) 后,在克隆的仓库中执行: + +```bash +uv run examples/mcp_docs.py +``` + +示例在脚本元数据中固定 `mcp==2.3.0`,先列出两个文档工具,再读取英文 `quickstart` 页。输出 JSON 包含工具名、页面路径、语言和完整 Markdown,Agent 可直接消费。它只连接文档专用入口,不需要 BlockVectra key、钱包或模型 API,也不调用链上 RPC。出错时非零退出;示例运行总时限为 40 秒,依赖安装不包含在该时限内。 + +前面的独立标准库 RPC 示例仍无需第三方 Python 包。 + ### 1. Claude Code 配置 #### 免 Key 文档服务 diff --git a/examples/mcp_docs.py b/examples/mcp_docs.py new file mode 100644 index 0000000..18df29e --- /dev/null +++ b/examples/mcp_docs.py @@ -0,0 +1,48 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = ["mcp==2.3.0"] +# /// +"""Read BlockVectra documentation with the official Python MCP SDK.""" + +import asyncio +import json +import os + +import httpx2 +from mcp import ClientSession +from mcp.client.streamable_http import streamable_http_client + +ENDPOINT = "https://docs.blockvectra.com/mcp/docs" + + +async def read_quickstart(http_client: httpx2.AsyncClient) -> dict: + async with streamable_http_client(ENDPOINT, http_client=http_client) as (read, write): + async with ClientSession(read, write, read_timeout_seconds=15) as session: + await session.initialize() + available = await session.list_tools() + names = sorted(tool.name for tool in available.tools) + if names != ["read_doc", "search_docs"]: + raise RuntimeError("The endpoint did not expose the two documentation tools.") + result = await session.call_tool("read_doc", {"path": "quickstart", "lang": "en"}) + payload = result.model_dump(mode="json", by_alias=True) + if payload.get("isError", False): + raise RuntimeError("read_doc returned a tool error.") + texts = [item["text"] for item in payload.get("content", []) if item.get("type") == "text"] + if not texts or not any(text.strip() for text in texts): + raise RuntimeError("read_doc returned no documentation text.") + return {"tools": names, "path": "quickstart", "lang": "en", "text": "\n".join(texts)} + + +async def main() -> None: + user_agent = "BlockVectraDocsPython/1" + if os.environ.get("BLOCKVECTRA_INTERNAL_QA") == "1": + user_agent += " BlockVectraQA/1" + async with httpx2.AsyncClient( + timeout=15, follow_redirects=False, headers={"User-Agent": user_agent} + ) as http_client: + result = await read_quickstart(http_client) + print(json.dumps(result, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + asyncio.run(asyncio.wait_for(main(), timeout=40))