feat(lib): bundle MCP servers from .common/lib into factory/lib/
Copies source (no node_modules, dist, .tasks, .wiki, __pycache__) for: - projects-meta-mcp v2.25.0 (TypeScript/Node) - wiki-graph v0.3.1 (TypeScript/Node) - interns-mcp v0.3.3 (Python/FastMCP) .gitignore: exclude lib build artefacts (node_modules, dist, .venv, __pycache__, *.pyc) bootstrap.ps1: add MCP build step — npm install+build for TS servers, venv+pip for Python Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
43
lib/interns-mcp/interns_mcp/client.py
Normal file
43
lib/interns-mcp/interns_mcp/client.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""OpenAI-compatible HTTP client, persistent per-endpoint."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from openai import OpenAI
|
||||
|
||||
# Bound every LLM call. Without this the SDK default (600s) lets a stalled
|
||||
# endpoint hang the worker thread that ran the tool; enough such threads exhaust
|
||||
# FastMCP's pool and wedge the whole stdio server. 90s is well above a healthy
|
||||
# deepseek-v4-flash response yet short enough to fail fast and free the thread.
|
||||
DEFAULT_REQUEST_TIMEOUT = 90.0
|
||||
|
||||
|
||||
def _resolve_timeout(endpoint_cfg: dict[str, Any]) -> float:
|
||||
"""Per-endpoint request timeout in seconds; falls back to the bounded default."""
|
||||
return float(endpoint_cfg.get("request_timeout", DEFAULT_REQUEST_TIMEOUT))
|
||||
|
||||
|
||||
def make_client(endpoint_cfg: dict[str, Any], api_key: str) -> OpenAI:
|
||||
"""Create a persistent OpenAI client for an endpoint."""
|
||||
kwargs: dict[str, Any] = {
|
||||
"base_url": endpoint_cfg["base_url"],
|
||||
"api_key": api_key,
|
||||
"timeout": _resolve_timeout(endpoint_cfg),
|
||||
}
|
||||
defaults = endpoint_cfg.get("request_defaults", {})
|
||||
if "extra_body" in defaults:
|
||||
kwargs["default_query"] = {}
|
||||
return OpenAI(**kwargs)
|
||||
|
||||
|
||||
class ClientPool:
|
||||
"""Manages persistent HTTP clients per endpoint."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._clients: dict[str, OpenAI] = {}
|
||||
|
||||
def get(self, name: str, endpoint_cfg: dict[str, Any], api_key: str) -> OpenAI:
|
||||
if name not in self._clients:
|
||||
self._clients[name] = make_client(endpoint_cfg, api_key)
|
||||
return self._clients[name]
|
||||
Reference in New Issue
Block a user