ghostdrive1's picture
Upload folder using huggingface_hub
116524e verified
|
Raw
History Blame Contribute Delete
11.8 kB

Feature Specification: ACE MCP Server (Optional)

Feature Branch: 002-ace-mcp-server
Created: 2026-03-02
Status: Draft
Input: User description: "extend ACE to also work as an MCP server (optional but powerful)"

Summary

Add an optional MCP server mode for ACE using the ace architecture. The server exposes ACE capabilities as MCP tools so external MCP clients (IDEs, copilots, orchestrators) can call ACE for inference and learning.

The feature is opt-in via optional dependency extras and a dedicated CLI entrypoint. Existing ACE APIs and integrations remain unchanged when MCP is not enabled.

Scope

In Scope (MVP)

  • MCP server over stdio transport.
  • Tool endpoints for ask/learn/skillbook operations.
  • Per-session ACE runner lifecycle with in-memory state.
  • Input/output validation with Pydantic models.
  • Structured error mapping to MCP tool errors.
  • Unit + integration tests for handler behavior and transport startup.
  • Docs and runnable example client.

Out of Scope (Post-MVP)

  • HTTP/SSE MCP transport.
  • Distributed or persistent multi-process session stores.
  • AuthN/AuthZ and multi-tenant isolation beyond local process boundaries.
  • Rich observability dashboards (basic logs only in MVP).

Design Constraints

  • Implement in ace integration layer, not in pipeline/ or ace/core/ for MVP.
  • Preserve backward compatibility: no breaking changes to existing runners.
  • Keep MCP dependency optional (no mandatory install-time dependency).
  • Use existing ACE runner constructors (from_model, from_roles) and skillbook persistence APIs.

User Scenarios & Testing

User Story 1 — Ask Through MCP (P1)

A client calls ace.ask through MCP and gets an answer from a session-scoped ACE instance.

Independent test: start server, call ace.ask, assert valid answer payload and session state initialization.

User Story 2 — Learn Through MCP (P1)

A client calls ace.learn.sample and ace.learn.feedback; ACE updates the skillbook for that session.

Independent test: call learning tools, then ace.skillbook.get, assert strategy count changed.

User Story 3 — Persist/Restore Skillbook (P2)

A client saves skillbook to disk and later reloads it into the same/new session.

Independent test: save then load and assert stable strategy IDs/count.

User Story 4 — Safe Optionality (P1)

Projects without MCP extras continue functioning exactly as before.

Independent test: import and use non-MCP modules without MCP installed.

Functional Requirements

  • FR-001: System MUST provide a CLI entrypoint to run ACE as an MCP server over stdio.
  • FR-002: System MUST expose MCP tools: ace.ask, ace.learn.sample, ace.learn.feedback, ace.skillbook.get, ace.skillbook.save, ace.skillbook.load.
  • FR-003: System MUST validate every tool request and response via typed schemas.
  • FR-004: System MUST isolate state by session_id.
  • FR-005: System MUST lazily initialize session runners with model/provider config.
  • FR-006: System MUST support disabling mutating tools (save/load and learn tools) in safe mode.
  • FR-007: System MUST map internal exceptions to stable MCP error codes/messages.
  • FR-008: System MUST cap request sizes (max samples per call, max payload size) to prevent runaway execution.
  • FR-009: System MUST remain fully optional via mcp extra dependency.
  • FR-010: System MUST include handler-level success tests for each tool and server startup/registration smoke tests when the mcp extra is installed.

Non-Functional Requirements

  • NFR-001: Tool roundtrip latency for ace.ask should be < 2s p50 excluding model latency.
  • NFR-002: Session operations must be thread-safe within a process.
  • NFR-003: Server startup failures must emit actionable install/config error text.
  • NFR-004: Existing test suite behavior remains unchanged when MCP extras are absent.

Tool Contract Source of Truth

Canonical tool schemas are defined in: specs/002-ace-mcp-server/contracts/tool-schemas.md.

Exact Module Tree (Implementation)

ace/
  integrations/
    mcp/
      __init__.py
      server.py                 # create_server(), main(), startup wiring
      registry.py               # session registry + lifecycle (TTL, lazy init)
      config.py                 # MCPServerConfig, limits, safe-mode flags
      errors.py                 # domain errors + MCP error mapping
      models.py                 # Pydantic request/response schemas
      handlers.py               # tool handler implementations
      adapters.py               # maps handlers <-> MCP SDK tool registration

tests/
  test_ace_mcp_models.py      # schema validation and serialization
  test_ace_mcp_registry.py    # session lifecycle and locking
  test_ace_mcp_handlers.py    # tool behavior with mocked runner
  test_ace_mcp_server.py      # server startup + tool registration smoke

docs/
  integrations/
    mcp.md                      # install, run, tool catalog, examples

examples/
  ace/
    mcp_client_demo.py          # minimal MCP client invoking ace.ask

Package and CLI Changes

  • pyproject.toml
    • Add optional dependency group:
      • mcp = ["mcp>=<pinned_version>"] (or official Python MCP SDK package used by maintainers)
    • Add script entrypoint:
      • ace-mcp = "ace.integrations.mcp.server:main"

Runtime Architecture

  1. MCP server starts and registers tool definitions from models.py.
  2. Incoming request is validated into typed request model.
  3. registry.py returns/create session runner (ACELiteLLM by default).
  4. handlers.py executes operation against runner.
  5. Response serialized to typed output model.
  6. Exceptions mapped through errors.py into stable MCP error responses.

Session Model

  • Key: session_id: str.
  • Value: session object containing runner, creation time, last access time, lock.
  • Concurrency: per-session lock around mutating operations.
  • Expiry: configurable TTL cleanup (lazy sweep on access in MVP).

Configuration Model

MCPServerConfig fields (MVP):

  • default_model: str = "gpt-4o-mini"
  • safe_mode: bool = false
  • max_samples_per_call: int = 25
  • max_prompt_chars: int = 100_000
  • session_ttl_seconds: int = 3600
  • allow_save_load: bool = true
  • learn_timeout_seconds: int = 300
  • skillbook_root: str | None = null
  • log_level: str = "INFO"

Environment variable mapping (MVP):

  • ACE_MCP_DEFAULT_MODEL
  • ACE_MCP_SAFE_MODE
  • ACE_MCP_MAX_SAMPLES_PER_CALL
  • ACE_MCP_MAX_PROMPT_CHARS
  • ACE_MCP_SESSION_TTL_SECONDS
  • ACE_MCP_ALLOW_SAVE_LOAD
  • ACE_MCP_LEARN_TIMEOUT_SECONDS
  • ACE_MCP_SKILLBOOK_ROOT

Error Taxonomy

  • ACE_MCP_VALIDATION_ERROR
  • ACE_MCP_SESSION_NOT_FOUND
  • ACE_MCP_FORBIDDEN_IN_SAFE_MODE — mutating tool called with safe_mode=true
  • ACE_MCP_SAVE_LOAD_DISABLED — save/load tool called with allow_save_load=false (independent of safe mode)
  • ACE_MCP_PROVIDER_ERROR
  • ACE_MCP_TIMEOUT
  • ACE_MCP_INTERNAL_ERROR

Each error must include:

  • code (stable string)
  • message (human-readable)
  • details (optional structured dict)

Design Notes

ace.ask response

The applied_skill_ids field was removed from the ace.ask response. The underlying ACELiteLLM.ask() does not track which skills were applied during generation, so the field was always empty. Removed to avoid a misleading contract.

ace.learn.feedback response

The learned field reports True when the feedback handler successfully executed the learning path (either direct feedback or trace-based fallback), regardless of whether new skills were created. This avoids false negatives when the reflector modifies existing skills without adding new ones.

ace.learn.feedback fallback trace

When no prior ask() exists for the session, the handler builds a synthetic trace. The context field maps to context (not reasoning) in the trace dict, since context is background information and reasoning is the agent's chain of thought.

MCP learning limitations

Learning through MCP (ace.learn.sample) does not provide a task environment. The pipeline's EvaluateStep uses ground_truth comparison only. Environment-based evaluation is not available through MCP in the MVP.

Learn timeout

ace.learn.sample and ace.learn.feedback wrap their runner calls in asyncio.wait_for with learn_timeout_seconds (default 300s). When the timeout fires, the handler raises ACE_MCP_TIMEOUT instead of ACE_MCP_INTERNAL_ERROR.

Prompt limit fields

The per-tool fields included in the max_prompt_chars check:

  • ace.ask: question + context
  • ace.learn.sample: question + context per sample (0-indexed in error messages)
  • ace.learn.feedback: question + context + answer + feedback + ground_truth

Save/load path resolution

ace.skillbook.save and ace.skillbook.load resolve the user-provided path to an absolute canonical path (via Path.resolve()) before validation and before passing it to the runner. The response echoes the resolved path, not the raw input. This eliminates TOCTOU races with symlinks or .. path components.

Security & Safety

  • Safe mode blocks mutating operations by policy.
  • Path validation for save/load (reject paths outside ACE_MCP_SKILLBOOK_ROOT when set). Validation operates on the resolved canonical path.
  • Request size limits enforced before runner call.
  • No secret values logged in payload dumps.

Testing Plan

Unit

  • models.py: required fields, type coercion, limits.
  • registry.py: session create/get/delete, TTL expiry, lock semantics.
  • handlers.py: tool success paths + mapped failures.

Integration

  • Boot server with MCP SDK test harness when the mcp extra is installed.
  • Validate tool registration/startup via smoke tests and cover tool success paths at the handler layer.
  • Validate safe mode blocks expected tools.

Regression

  • Run existing ace tests ensuring no MCP dependency required unless explicitly installed.

Delivery Plan (PR Sequence)

  1. PR-1: skeleton package + config + models + tests.
  2. PR-2: session registry + handlers for ace.ask and ace.skillbook.get.
  3. PR-3: learning + save/load handlers, error mapping, limits.
  4. PR-4: server bootstrap + CLI entrypoint + integration tests.
  5. PR-5: docs + example client + changelog entry.

Acceptance Criteria

  • All implemented FR/NFR remain consistent with the optional dependency boundary.
  • Tool schemas match contract doc exactly.
  • ace-mcp starts successfully and serves all MVP tools.
  • Existing non-MCP workflows are unaffected.

Ready for Merge Checklist

  • Module tree implemented under ace/integrations/mcp/
  • Tool schemas implemented and contract-aligned (ace.ask, ace.learn.sample, ace.learn.feedback, ace.skillbook.get/save/load)
  • Optional dependency and CLI entrypoint wired (mcp extra, ace-mcp)
  • Safe mode policy enforced for mutating tools
  • Request-size limits enforced (max_prompt_chars, max_samples_per_call)
  • Optional root-bound path validation enforced for save/load (ACE_MCP_SKILLBOOK_ROOT)
  • MCP-focused tests passing (test_ace_mcp_models/registry/handlers/server)
  • Optional dependency boundary enforced with actionable install errors
  • Docs + example client updated (docs/integrations/mcp.md, examples/ace/mcp_client_demo.py)
  • Changelog updated for this feature