apps/docs/skills/mcp-tool-integration/SKILL.md
Connect agents to MCP servers using stdio or HTTP transport, with automatic Docker lifecycle management and transport auto-detection.
npx skillsauth add tylerjrbuell/reactive-agents-ts mcp-tool-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Produce a builder with MCP servers correctly configured — right transport, Docker lifecycle, and auth — so the agent can discover and call MCP tools transparently.
import { ReactiveAgents } from "@reactive-agents/runtime";
const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.withReasoning({ defaultStrategy: "adaptive" })
.withMCP([
{
name: "github",
command: "docker",
args: [
"run", "--rm", "-i",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server",
],
env: { GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_TOKEN ?? "" },
},
{
name: "filesystem",
command: "docker",
args: [
"run", "--rm", "-i",
"-v", `${process.cwd()}:/workspace`,
"mcp/filesystem", "/workspace",
],
// transport auto-inferred as "stdio" (command present, no endpoint)
},
])
.build();
.withMCP() implicitly enables the tools layer — .withTools() is not required before it.
Pattern A — stdio MCP (GitHub MCP, filesystem MCP): reads JSON-RPC from stdin
.withMCP({
name: "github",
command: "docker",
args: ["run", "--rm", "-i", "ghcr.io/github/github-mcp-server"],
env: { GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_TOKEN ?? "" },
// transport: inferred as "stdio" — "-i" keeps stdin open for JSON-RPC
})
Pattern B — HTTP-only MCP (context7, etc.): starts HTTP server, ignores stdin
.withMCP({
name: "context7",
command: "docker",
args: ["run", "--rm", "-p", "3000:3000", "ghcr.io/upstash/context7-mcp"],
// Framework auto-detects HTTP URL printed to stderr → switches to port-mapped HTTP
// Do NOT hardcode transport here — let auto-detection handle it
})
When a stdio Docker container prints an HTTP URL to stderr, the MCP client races the stdio connection against HTTP URL detection. HTTP wins → client switches to port-mapped HTTP mode automatically.
Two container phases are created:
rax-probe-<name>-<pid> — initial stdio probe attemptrax-mcp-<name>-<pid> — port-mapped HTTP managed container (if HTTP detected)PID-based naming prevents conflicts when multiple agents run concurrently.
// Auto-inferred rules:
// command present, no endpoint → "stdio"
// endpoint ends with /mcp → "streamable-http"
// endpoint (other path) → "sse"
// Only set transport explicitly when overriding detection:
.withMCP({ name: "my-server", endpoint: "http://localhost:3000/api", transport: "sse" })
// Local process
.withMCP({ name: "my-mcp", command: "node", args: ["./my-mcp-server.js"] })
// npx
.withMCP({ name: "fs", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"] })
// Remote Streamable HTTP
.withMCP({ name: "remote", endpoint: "https://mcp.example.com/mcp" })
// Remote SSE with auth header
.withMCP({ name: "secure", endpoint: "https://mcp.example.com/sse", headers: { Authorization: `Bearer ${process.env.API_KEY}` } })
The framework owns container lifecycle:
docker run starts the container when the agent is builtdocker rm -f <containerName> stops itCritical: docker rm -f is the only reliable way to stop MCP Docker containers. Killing the docker run process leaves the container alive in the Docker daemon.
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| name | string | Yes | Unique identifier for this server |
| command | string | For stdio | Executable ("docker", "node", "npx", etc.) |
| args | string[] | For stdio | Command arguments |
| env | Record<string, string> | No | Environment variables merged over process.env |
| cwd | string | No | Working directory for the subprocess |
| endpoint | string | For HTTP | URL of the MCP HTTP endpoint |
| headers | Record<string, string> | No | HTTP auth headers for remote endpoints |
| transport | "stdio"\|"streamable-http"\|"sse" | No | Auto-inferred if omitted |
subprocess.kill() does not stop Docker containers — only docker rm -f workstransport: "streamable-http" for HTTP-only Docker servers — let auto-detection handle itenv values must be strings — use process.env.VAR ?? "" pattern, never pass undefined-i in the docker args to keep stdin open; HTTP Pattern B requires -p PORT:PORT for host accessdevelopment
Orient to the Reactive Agents framework, understand the builder API shape, and select the right capability skills for your task.
testing
Enable output verification (hallucination detection, semantic entropy, self-consistency), add post-run verification steps, and run LLM-scored evals across 5 quality dimensions.
data-ai
Configure per-provider behavior, understand streaming quirks, and use the 7-hook adapter system for optimal performance across LLM providers.
data-ai
Configure the 4-layer memory system with SQLite/FTS5/vec storage for persistent agent knowledge that survives sessions.