MCP Tools¶
Yaaf loads MCP tools from a config file. The path is resolved in this order:
--mcp <path>passed toask,chat,agent, orrun(or as a global option before the subcommand).YAAF_MCP_FILEfrom the process environment or.envfile..yaaf/mcp.jsonauto-discovered in the current working directory.
When none of these is set and no .yaaf/mcp.json exists, yaaf runs without MCP tools.
The file must use the VS Code MCP configuration shape unchanged, but yaaf keeps project-owned MCP config under .yaaf/mcp.json for auto-discovery and examples. For explicit non-default paths, pass a normal file path such as ./configs/docs.mcp.json.
For project-owned defaults, drop a .yaaf/mcp.json at the repository root and yaaf will pick it up automatically for both regular commands and yaaf run <script> invocations launched from that directory.
Supported Config Shape¶
Supported top-level fields:
servers: required object keyed by server id.
Supported server types:
http: JSON-RPC over HTTP POST.sse: accepted as an HTTP-style server entry;text/event-streamresponses are parsed fordata:payloads.stdio: JSON-RPC over newline-delimited stdio on Windows, macOS, and Linux builds.
Supported server fields:
urlforhttpandsseservers.headersforhttpandsseservers.commandandargsforstdioservers.envandenvFileforstdioprocess environment overrides.
Minimal HTTP server:
{
"servers": {
"docs": {
"type": "http",
"url": "http://127.0.0.1:3000/mcp"
}
}
}
Minimal stdio server:
{
"servers": {
"hello": {
"type": "stdio",
"command": "uv",
"args": ["--directory", "${workspaceFolder}/mcp-servers", "run", "python", "hello_stdio.py"]
}
}
}
For the repository fixture servers, Linux uses the same uv-based stdio setup as macOS. There are no extra Linux-only stdio fixture prerequisites beyond having uv available.
Variable Substitution¶
Yaaf expands variables recursively in string values inside each server object.
Supported variables:
${workspaceFolder}: replaced with the current workspace root using forward slashes.${env:NAME}: replaced with the process environment variable value, or an empty string if it is not set.
Example with workspace and environment variables:
{
"servers": {
"docs": {
"type": "http",
"url": "${env:DOCS_MCP_URL}",
"headers": {
"Authorization": "Bearer ${env:DOCS_MCP_TOKEN}"
}
},
"hello": {
"type": "stdio",
"command": "uv",
"args": ["--directory", "${workspaceFolder}/mcp-servers", "run", "python", "hello_stdio.py"],
"envFile": "${workspaceFolder}/.env",
"env": {
"YAAF_HELLO_MODE": "local"
}
}
}
}
envFile lines use NAME=value. Empty names, comment lines starting with #, and lines without = are ignored. Inline env values override values loaded from envFile.
Values under headers and env are redacted from doctor output, including the active MCP diagnostics added to each server report.
Tool Names¶
MCP tools are exposed as <server>.<tool>. A server named docs with a remote tool named lookup becomes docs.lookup:
yaaf doctor
yaaf doctor --format json --pretty
yaaf ask --tool docs.lookup "Look up the install steps."
yaaf chat --tool docs.lookup "What does this API do?"
yaaf agent --name react --tool docs.lookup "Summarize the docs for this feature."
doctor now performs an active initialize plus tools/list check for each configured server. In text mode it shows per-server initialize status and discovered tool names such as docs.lookup; in JSON mode each mcp.servers[] entry gains an active object with initialize and tools results.
Runtime Behavior¶
Implemented JSON-RPC lifecycle:
initializewith the latest generated supported protocol version.- Negotiated
protocolVersionvalidation. notifications/initializedafter successful initialization.- Per-server session caching.
Implemented MCP methods:
tools/list, includingnextCursorpagination.tools/call.
HTTP behavior:
- Sends
Accept: application/json, text/event-stream. - Sends
MCP-Protocol-Versionafter negotiation. - Stores and re-sends
Mcp-Session-Idwhen returned by the server. - Parses both JSON responses and SSE-style
data:response payloads.
Tool call results are normalized into yaaf's tool result shape. Text content blocks are joined with newlines, non-text content blocks are preserved as JSON text, and structuredContent is used as JSON text when there are no content blocks.
Schema Support¶
Protocol version metadata is generated from the official versioned MCP JSON schemas in modelcontextprotocol/modelcontextprotocol.
Current generated protocol versions:
2024-11-052025-03-262025-06-182025-11-25
Refresh generated schema files with:
./scripts/UpdateMcpSchemas.ps1
Generated files include one backend implementation per protocol version under libyaaf/mcp/schema/schema-<version>.cpp, plus the registry/factory used by the native client.
Fixture Servers¶
Real hello-world MCP fixture servers live in mcp-servers. They expose:
hello(name?: string): returnsHello, <name>!.repeat(text: string, count?: integer): repeats text a bounded number of times.
The optional local fixture stack also starts httpbin plus the HTTP and SSE fixtures for manual transport debugging and smoke checks:
docker compose -f docker-compose.fixture-stack.yml up
Fixture URLs exposed by that stack:
- HTTP client fixture:
http://127.0.0.1:18082 - HTTP client fixture through mitmproxy visibility:
http://host.docker.internal:18082 - HTTP:
http://127.0.0.1:39231/mcp - HTTP through mitmproxy visibility:
http://host.docker.internal:39231/mcp - SSE:
http://127.0.0.1:39232/mcp
Not Implemented Yet¶
Yaaf currently does not implement native client APIs for prompts, resources, resource subscriptions, roots, sampling, elicitation, logging level control, task APIs, progress or cancellation handling, OAuth flows, JSON-RPC batching, or long-lived SSE event streams beyond extracting response payloads from HTTP responses.
The implementation-level support matrix is maintained in libyaaf/mcp/README.md.