FGP: Making AI Agent Tools 19x Faster
MCP stdio spawns a new process for every tool call. FGP replaces that with persistent daemons over UNIX sockets, cutting latency from seconds to milliseconds.
The Problem: Death by Cold Start
AI agents make sequential tool calls. Each call should feel instant. Instead, MCP stdio adds ~2.3 seconds of cold-start overhead per call.
For a simple 4-step workflow (navigate → snapshot → click → snapshot), that's 11+ seconds of waiting. The agent feels sluggish. Users lose trust.
The math is brutal:
| Agent Workflow | Tool Calls | MCP Overhead | Time Lost |
|---|---|---|---|
| Check email | 2 | 4.6s | 4.6s |
| Browse + fill form | 5 | 11.5s | 11.4s |
| Full productivity check | 10 | 23s | 22.9s |
| Complex agent task | 20 | 46s | 45.8s |
The problem isn't the tools themselves—it's the protocol overhead.
The Insight: Keep It Warm
MCP stdio spawns a fresh process for each tool invocation. This gives you isolation but kills latency.
The insight: most agent tools don't need per-call isolation. A browser session should stay warm. A Gmail connection should stay authenticated. A database connection should stay pooled.
FGP flips the model:
MCP stdio (cold): Agent → spawn process → load deps → connect → execute → return → die
FGP daemon (warm): Agent → send message → execute → return (process stays alive)
Architecture
FGP uses persistent daemons connected via UNIX sockets:
┌─────────────────────────────────────────────────────────┐
│ AI Agent / Claude │
├─────────────────────────────────────────────────────────┤
│ FGP UNIX Sockets │
│ ~/.fgp/services/{browser,gmail,calendar,github}/ │
├──────────┬──────────┬──────────┬──────────┬────────────┤
│ Browser │ Gmail │ Calendar │ GitHub │ ... │
│ Daemon │ Daemon │ Daemon │ Daemon │ │
│ (Rust) │ (PyO3) │ (PyO3) │ (Rust) │ │
├──────────┴──────────┴──────────┴──────────┴────────────┤
│ Chrome │ Google APIs │ gh CLI │
└─────────────────────────────────────────────────────────┘
Key design decisions:
- UNIX sockets — Zero network overhead, file-based permissions, no TCP handshake
- NDJSON protocol — Human-readable, streaming-friendly, easy to debug
- Per-service daemons — Independent scaling, fault isolation, simple upgrades
- Rust core — Sub-millisecond protocol overhead, ~10MB memory per daemon
Benchmark Results
Browser Automation (vs Playwright MCP)
The browser daemon connects to Chrome via DevTools Protocol and keeps the connection warm:
| Operation | FGP Browser | Playwright MCP | Speedup |
|---|---|---|---|
| Navigate | 8ms | 2,328ms | 292x |
| Snapshot | 9ms | 2,484ms | 276x |
| Screenshot | 30ms | 1,635ms | 54x |
Multi-Step Workflow
The real test: a 4-step workflow (navigate → snapshot → click → snapshot):
| Tool | Total Time | vs MCP |
|---|---|---|
| FGP Browser | 585ms | 19x faster |
| Vercel agent-browser | 733ms | 15x faster |
| Playwright MCP | 11,211ms | baseline |
API Daemons
All methods tested at 100% success rate:
Gmail Daemon (PyO3 + Google API):
| Method | Mean | Payload |
|---|---|---|
| inbox | 881ms | 2.4KB |
| search | 748ms | 2.4KB |
| thread | 116ms | 795B |
Calendar Daemon (PyO3 + Google API):
| Method | Mean | Payload |
|---|---|---|
| today | 315ms | 48B |
| upcoming | 241ms | 444B |
| search | 177ms | 46B |
| free_slots | 198ms | 65B |
GitHub Daemon (Native Rust + gh CLI):
| Method | Mean | Payload |
|---|---|---|
| repos | 569ms | 2.8KB |
| notifications | 521ms | 9.8KB |
| issues | 390ms | 75B |
Key insight: Latency is dominated by external API calls (~100-900ms), not FGP overhead (~5-10ms). For MCP, add ~2.3s cold-start to every call.
The Protocol
All daemons speak the same NDJSON-over-UNIX-socket protocol:
Request:
{"id": "uuid", "v": 1, "method": "browser.navigate", "params": {"url": "..."}}
Response:
{"id": "uuid", "ok": true, "result": {...}, "meta": {"server_ms": 8.2}}
Built-in methods every daemon supports:
health— Check daemon healthmethods— List available methodsstop— Graceful shutdown
Building New Daemons
The SDK makes it easy to add new services:
use fgp_daemon::{FgpServer, FgpService};
struct MyService { /* state */ }
impl FgpService for MyService {
fn name(&self) -> &str { "my-service" }
fn version(&self) -> &str { "1.0.0" }
fn dispatch(&self, method: &str, params: Value) -> Result<Value> {
match method {
"my-service.hello" => Ok(json!({"message": "Hello!"})),
_ => bail!("Unknown method"),
}
}
}
fn main() {
let server = FgpServer::new(MyService::new(), "~/.fgp/services/my-service/daemon.sock")?;
server.serve()?;
}
Why This Matters
Agent tooling is at an inflection point. LLMs can orchestrate complex workflows, but latency breaks the illusion.
When tools feel instant:
- Users trust the agent
- Agents can make more calls without timeout pressure
- Complex workflows become practical
FGP isn't about raw speed—it's about moving from "noticeable delay" to "instant response" in the user perception tier.
Status
| Component | Status | Performance |
|---|---|---|
| browser | Production | 8ms navigate, 9ms snapshot |
| gmail | Beta | 116ms thread, 881ms inbox |
| calendar | Beta | 177ms search, 233ms avg |
| github | Beta | 390ms issues, 474ms avg |
| daemon SDK | Stable | Core library |
| cli | WIP | Daemon management |
Takeaways
- Cold-start overhead compounds — Each tool call paying 2.3s adds up fast in agent workflows
- Daemons beat processes for high-frequency, stateful tools
- UNIX sockets are underrated — Zero network overhead, file-based security, simple debugging
- The "real work" is often fast — It's the protocol overhead that kills UX
- User perception tiers matter — Moving from 2s to 10ms isn't just "faster," it's a different experience class
You might also like
iMessage Gateway CLI
The fastest iMessage integration for Claude Code. CLI + daemon design avoids MCP overhead for "instant" UX.
SEC EDGAR Agent
AI-native platform for financial research providing LLM-ready SEC filing data with semantic search, RAG chat, and structured table extraction.
AI Life Planner
A personal operating system: projects, tasks, notes, and integrations—driven through an agent-first CLI.
Interested in working together?
Get in touch →