oct.mcp.server module#

Purpose#

MCP server core (Layers 1 + orchestration) for the oct-mcp server. Creates a mcp.server.fastmcp.FastMCP instance, binds it to a validated project root (Layer 1 — Gateway), and exposes the nine Phase 5A read-only tools via oct.mcp.tools.

Responsibilities#

  • Implement start_server(): resolve + validate project root, load config, instantiate all pipeline layers, register tools, run.

  • Implement the token-bucket rate limiter (Layer 1) via RateLimiter.

  • Expose _server_state for tools to access the shared pipeline instances (singleton pattern: one server = one context).

Diagnostics#

Domain: MCP Levels:

L1 — errors: startup failures, workspace binding failures L2 — lifecycle: server start/stop, workspace bound L3 — request details L4 — deep trace

Contracts#

  • start_server() raises SystemExit(1) on fatal startup errors (invalid project root, no oct command) so __main__.py can propagate a clean exit code.

  • The rate limiter is per-server-instance (not per-session), which is sufficient for the stdio Phase 5A transport where one server process handles one client session.

  • _server_state is set before FastMCP.run() is called and is available to all tool handlers during their execution.

class oct.mcp.server.RateLimiter(limit_per_minute: int = 30)[source]#

Bases: object

Simple token-bucket rate limiter (stdlib only).

One token is consumed per tool call. Tokens refill at the rate of limit_per_minute / 60 tokens per second. The bucket starts full.

Thread safety: not needed for stdio Phase 5A (single-threaded).

consume() bool[source]#

Try to consume one token. Returns False if rate limit is exceeded.

class oct.mcp.server.ServerState(project_root: Path, config: McpConfig, policy: McpPolicy, executor: ToolExecutor, redactor: Redactor, audit_logger: McpAuditLogger, rate_limiter: RateLimiter, safety: SafetyGate, metrics: McpMetrics, session_id: str = '')[source]#

Bases: object

All pipeline layer instances for one server session.

Created in start_server() and stored in the module-level _server_state singleton so tool handlers can access it without having to pass context through the MCP SDK call graph.

audit_logger: McpAuditLogger#
config: McpConfig#
executor: ToolExecutor#
metrics: McpMetrics#
policy: McpPolicy#
project_root: Path#
rate_limiter: RateLimiter#
redactor: Redactor#
safety: SafetyGate#
session_id: str = ''#
oct.mcp.server.get_server_state() ServerState[source]#

Return the current ServerState.

Raises RuntimeError if called outside a running server context (i.e. before start_server() has initialised the state).

oct.mcp.server.start_server(project_root: str | Path | None = None, profile: str | None = None, config_path: Path | None = None, transport: str = 'stdio', host: str = '127.0.0.1', port: int = 3001, metrics_port: int | None = None) None[source]#

Initialise and run the oct-mcp server.

Steps:

  1. Resolve and validate project root (Layer 1 — Gateway).

  2. Load McpConfig (with env var overrides).

  3. Apply centralised policy overrides (Phase 5C, M-C7).

  4. Override profile if --profile CLI arg was provided.

  5. Instantiate all pipeline layers.

  6. Start Prometheus metrics server (optional, Phase 5C).

  7. Create FastMCP server.

  8. Set _server_state singleton.

  9. Register 9 read-only (Phase 5A) + 11 write (Phase 5B) tools.

  10. Run the FastMCP server (stdio or SSE transport).

Parameters:
  • project_root – Project root path override (None = auto-discover).

  • profile – MCP profile override (None = use config file / env var).

  • config_path – Path to the ~/.oct-mcp/config.json config file (None = use default location).

  • transport – MCP transport: "stdio" (default) or "sse" (HTTP/Server-Sent Events for remote access).

  • host – Host to bind for SSE transport (default "127.0.0.1"). Only used when transport is "sse".

  • port – Port to bind for SSE transport (default 3001). Only used when transport is "sse".

  • metrics_port – If set, starts a Prometheus /metrics server on this port. Overrides config.metrics_port. Requires oct[metrics].