fix(mcp): hoist sse/http imports, annotate auto-detection heuristic, restore field comments
This commit is contained in:
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
🐈 **nanobot** is an **ultra-lightweight** personal AI assistant inspired by [OpenClaw](https://github.com/openclaw/openclaw)
|
🐈 **nanobot** is an **ultra-lightweight** personal AI assistant inspired by [OpenClaw](https://github.com/openclaw/openclaw)
|
||||||
|
|
||||||
⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines.
|
⚡️ Delivers core agent functionality with **99% fewer lines of code** than OpenClaw, making it more customizable and understandable.
|
||||||
|
|
||||||
📏 Real-time line count: **3,935 lines** (run `bash core_agent_lines.sh` to verify anytime)
|
📏 Real-time line count: run `bash core_agent_lines.sh` to verify anytime
|
||||||
|
|
||||||
## 📢 News
|
## 📢 News
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ async def connect_mcp_servers(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Connect to configured MCP servers and register their tools."""
|
"""Connect to configured MCP servers and register their tools."""
|
||||||
from mcp import ClientSession, StdioServerParameters
|
from mcp import ClientSession, StdioServerParameters
|
||||||
|
from mcp.client.sse import sse_client
|
||||||
from mcp.client.stdio import stdio_client
|
from mcp.client.stdio import stdio_client
|
||||||
|
from mcp.client.streamable_http import streamable_http_client
|
||||||
|
|
||||||
for name, cfg in mcp_servers.items():
|
for name, cfg in mcp_servers.items():
|
||||||
try:
|
try:
|
||||||
@@ -67,6 +69,7 @@ async def connect_mcp_servers(
|
|||||||
if cfg.command:
|
if cfg.command:
|
||||||
transport_type = "stdio"
|
transport_type = "stdio"
|
||||||
elif cfg.url:
|
elif cfg.url:
|
||||||
|
# Convention: URLs ending with /sse use SSE transport; others use streamableHttp
|
||||||
transport_type = (
|
transport_type = (
|
||||||
"sse" if cfg.url.rstrip("/").endswith("/sse") else "streamableHttp"
|
"sse" if cfg.url.rstrip("/").endswith("/sse") else "streamableHttp"
|
||||||
)
|
)
|
||||||
@@ -80,8 +83,6 @@ async def connect_mcp_servers(
|
|||||||
)
|
)
|
||||||
read, write = await stack.enter_async_context(stdio_client(params))
|
read, write = await stack.enter_async_context(stdio_client(params))
|
||||||
elif transport_type == "sse":
|
elif transport_type == "sse":
|
||||||
from mcp.client.sse import sse_client
|
|
||||||
|
|
||||||
def httpx_client_factory(
|
def httpx_client_factory(
|
||||||
headers: dict[str, str] | None = None,
|
headers: dict[str, str] | None = None,
|
||||||
timeout: httpx.Timeout | None = None,
|
timeout: httpx.Timeout | None = None,
|
||||||
@@ -99,7 +100,6 @@ async def connect_mcp_servers(
|
|||||||
sse_client(cfg.url, httpx_client_factory=httpx_client_factory)
|
sse_client(cfg.url, httpx_client_factory=httpx_client_factory)
|
||||||
)
|
)
|
||||||
elif transport_type == "streamableHttp":
|
elif transport_type == "streamableHttp":
|
||||||
from mcp.client.streamable_http import streamable_http_client
|
|
||||||
# Always provide an explicit httpx client so MCP HTTP transport does not
|
# Always provide an explicit httpx client so MCP HTTP transport does not
|
||||||
# inherit httpx's default 5s timeout and preempt the higher-level tool timeout.
|
# inherit httpx's default 5s timeout and preempt the higher-level tool timeout.
|
||||||
http_client = await stack.enter_async_context(
|
http_client = await stack.enter_async_context(
|
||||||
|
|||||||
@@ -329,13 +329,13 @@ class ExecToolConfig(Base):
|
|||||||
class MCPServerConfig(Base):
|
class MCPServerConfig(Base):
|
||||||
"""MCP server connection configuration (stdio or HTTP)."""
|
"""MCP server connection configuration (stdio or HTTP)."""
|
||||||
|
|
||||||
type: Literal["stdio", "sse", "streamableHttp"] | None = None
|
type: Literal["stdio", "sse", "streamableHttp"] | None = None # auto-detected if omitted
|
||||||
command: str = ""
|
command: str = "" # Stdio: command to run (e.g. "npx")
|
||||||
args: list[str] = Field(default_factory=list)
|
args: list[str] = Field(default_factory=list) # Stdio: command arguments
|
||||||
env: dict[str, str] = Field(default_factory=dict)
|
env: dict[str, str] = Field(default_factory=dict) # Stdio: extra env vars
|
||||||
url: str = ""
|
url: str = "" # HTTP/SSE: endpoint URL
|
||||||
headers: dict[str, str] = Field(default_factory=dict)
|
headers: dict[str, str] = Field(default_factory=dict) # HTTP/SSE: custom headers
|
||||||
tool_timeout: int = 30
|
tool_timeout: int = 30 # seconds before a tool call is cancelled
|
||||||
|
|
||||||
|
|
||||||
class ToolsConfig(Base):
|
class ToolsConfig(Base):
|
||||||
|
|||||||
Reference in New Issue
Block a user