ACE MCP Server¶
ACE (Agentic Context Engine) provides an optional MCP server that exposes ACE as a tool provider over the Model Context Protocol. Orchestration frameworks, IDEs (Cursor, Windsurf, Claude Code), and other MCP clients can connect to the server and use ACE skills at runtime.
The integration is fully opt-in. Installing ACE without the mcp extra does not pull in the MCP SDK, and attempting to start ace-mcp without that extra will fail with an install hint instead of breaking normal ACE imports.
Installation¶
Running the Server¶
Start the server using the provided CLI entrypoint:
By default it communicates over stdio, making it ready for integration as a local tool provider in any MCP-compatible client.
Example with a specific model:
Configuration¶
All settings are read from environment variables with the ACE_MCP_ prefix:
| Variable | Default | Description |
|---|---|---|
ACE_MCP_DEFAULT_MODEL |
gpt-4o-mini |
LiteLLM model identifier used when creating new sessions. Any LiteLLM-supported model works (e.g. bedrock/..., anthropic/..., openai/...). |
ACE_MCP_SAFE_MODE |
false |
When true, blocks ace.learn.sample, ace.learn.feedback, ace.skillbook.save, and ace.skillbook.load. Read-only tools (ace.ask, ace.skillbook.get) remain available. |
ACE_MCP_ALLOW_SAVE_LOAD |
true |
When false, blocks ace.skillbook.save and ace.skillbook.load independently of safe mode. |
ACE_MCP_MAX_SAMPLES_PER_CALL |
25 |
Maximum number of samples accepted in a single ace.learn.sample call. |
ACE_MCP_MAX_PROMPT_CHARS |
100000 |
Maximum total characters across question + context fields. |
ACE_MCP_SESSION_TTL_SECONDS |
3600 |
Idle time (seconds) before a session is garbage-collected. |
ACE_MCP_LEARN_TIMEOUT_SECONDS |
300 |
Maximum seconds for a single ace.learn.sample or ace.learn.feedback call before returning ACE_MCP_TIMEOUT. |
ACE_MCP_SKILLBOOK_ROOT |
unset | If set, ace.skillbook.save and ace.skillbook.load reject paths outside this directory. |
ACE_MCP_LOG_LEVEL |
INFO |
Server log level (DEBUG, INFO, WARNING, ERROR). Logs go to stderr. |
Tools¶
ace.ask¶
Ask a question using the current skillbook. Does not mutate the skillbook.
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier for state isolation. |
question |
string | yes | The question to answer. |
context |
string | no | Additional context for the question. |
session_config |
object | no | Override model, temperature, max_tokens for this session. |
Returns: answer, skill_count.
ace.learn.sample¶
Provide sample question/answer pairs for ACE to learn from. Runs the full ACE pipeline (Agent, Evaluate, Reflect, Update, Apply).
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier. |
samples |
array | yes | List of {question, context?, ground_truth?, metadata?} items (1–25). |
epochs |
int | no | Number of learning passes (default: 1, max: 20). |
session_config |
object | no | Override model settings. |
Returns: processed, failed, skill_count_before, skill_count_after, new_skill_count.
Blocked by: ACE_MCP_SAFE_MODE=true.
ace.learn.feedback¶
Provide feedback on a previous answer. If a prior ace.ask exists for the session, learns directly from that interaction. Otherwise, builds a trace from the provided fields and learns from it.
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier. |
question |
string | yes | The original question. |
answer |
string | yes | The answer being evaluated. |
feedback |
string | yes | Feedback about answer quality. |
context |
string | no | Original context. |
ground_truth |
string | no | The correct answer. |
session_config |
object | no | Override model settings. |
Returns: learned (always true on success — the learning path executed), skill_count_before, skill_count_after, new_skill_count.
Blocked by: ACE_MCP_SAFE_MODE=true.
ace.skillbook.get¶
Retrieve skills and statistics from the active skillbook.
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier. |
limit |
int | no | Max skills to return (default: 20, max: 200). |
include_invalid |
bool | no | Include invalidated skills (default: false). |
Returns: stats, skills[] (each with id, content, topic, helpful, harmful, neutral).
ace.skillbook.save¶
Save the session's skillbook to a file on disk.
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier. |
path |
string | yes | File path to save to. |
Returns: path (resolved absolute path), saved_skill_count.
Blocked by: ACE_MCP_SAFE_MODE=true (ACE_MCP_FORBIDDEN_IN_SAFE_MODE) or ACE_MCP_ALLOW_SAVE_LOAD=false (ACE_MCP_SAVE_LOAD_DISABLED). The path is resolved to a canonical absolute path before validation and file I/O. Must be under ACE_MCP_SKILLBOOK_ROOT if configured.
ace.skillbook.load¶
Load a skillbook from disk into the session, replacing the current one.
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session identifier. |
path |
string | yes | File path to load from. |
Returns: path (resolved absolute path), skill_count.
Blocked by: ACE_MCP_SAFE_MODE=true (ACE_MCP_FORBIDDEN_IN_SAFE_MODE) or ACE_MCP_ALLOW_SAVE_LOAD=false (ACE_MCP_SAVE_LOAD_DISABLED). The path is resolved to a canonical absolute path before validation and file I/O. Must be under ACE_MCP_SKILLBOOK_ROOT if configured.
Session Model¶
All state is isolated by session_id. Each session holds its own ACELiteLLM runner with an independent skillbook. Pass the same session_id across calls to persist context within server memory.
Sessions are garbage-collected after ACE_MCP_SESSION_TTL_SECONDS of inactivity. Per-session locks ensure concurrent requests to the same session are serialised.
Any tool that accepts session_config can override the model, temperature, and max_tokens for that session's runner on first creation. Once a session exists, session_config on subsequent calls is used only if it creates a new session.
Architecture¶
The MCP server does not use custom pipeline steps. It is a thin async layer over ACELiteLLM:
MCP Client (stdio)
→ MCP SDK (handles JSON-RPC framing)
→ adapters.py (tool registration, schema generation, error mapping)
→ handlers.py (validation, session management, safety guards)
→ ACELiteLLM (sync runner — bridged via asyncio.to_thread)
→ Pipeline (internal — handles step execution, async_boundary, background learning)
The handlers use asyncio.to_thread() to call the sync ACELiteLLM methods from the async MCP event loop. This is the standard Python pattern for bridging async callers to sync APIs. The pipeline engine handles all internal async concerns (step-level to_thread, async_boundary for background learning) transparently.
Testing with the MCP Inspector¶
The MCP Inspector provides a web UI for testing MCP servers interactively:
Set ACE_MCP_DEFAULT_MODEL in the Inspector's environment variables panel before connecting.
File Layout¶
ace_next/integrations/mcp/
__init__.py ← Package marker
server.py ← Server creation and CLI entrypoint
config.py ← MCPServerConfig (pydantic-settings, env vars)
registry.py ← SessionRegistry (session lifecycle, TTL sweep)
handlers.py ← MCPHandlers (validation, safety, delegation to ACELiteLLM)
adapters.py ← MCP SDK glue (tool registration, schema inlining, error mapping)
models.py ← Pydantic request/response models for all six tools
errors.py ← ACEMCPError hierarchy and MCP error mapping