Connection lost
Trying to reconnect…
Server didn't respond
Recovering…
Compare
Custom MCP server vs emisar
Building your own MCP server is a reasonable thing to do — and for a narrow surface, the right one. This is the honest version of what changes between the afternoon you ship the prototype and the quarter you spend making it safe to point an agent at production.
The prototype is the easy 20%
Wiring up tools/list
and a handler that shells out is genuinely a few hours' work. If that's the whole job —
one team, one target that's already an API, your existing auth and audit already cover it
— build the adapter and move on; emisar would be overkill. The work that doesn't show up
in the demo is everything between the model's request and a safe, attributable execution
on a real host. That part is never done: every new host, pack, client, and edge
case reopens the list, and it's your pager.
server.tool("pg_kill", async ({ pid }) => {
return ssh.exec(
`psql -c "…terminate_backend(${pid})"`)
})
// then everything you still own:
// validate pid · redact secrets
// risk gate → human approval
// audit: who · what · why
// reconnect · orphans · per-user scope
// OAuth + transport per client
id: postgres.terminate_backend
kind: exec
risk: high # → policy gates it
args:
- name: pid
type: integer
required: true
execution:
command:
binary: psql
argv: ["-tAc", "SELECT
pg_terminate_backend({{ args.pid }})"]
Both run the same query — but the left drops an unvalidated
${pid}
straight into a SQL string, one slip from injection; the right declares
pid
an integer the runner re-validates before psql
ever sees it. That gap, plus the other 80% — redaction, approval, audit, reconnect — is
what emisar ships once, for every host, pack, and client you add.
What you'd build and own
A capable team can build every row of this. The column on the left isn't "what custom servers lack" — it's the code you write, test, and carry. The column on the right is what emisar ships so you don't.
Argument validation
You build it
Reject undeclared args, coerce types, enforce bounds — and do it on the host, since the model's output is untrusted
emisar
Typed YAML schemas the runner re-validates before exec; argv arrays, never a shell string
Tool integrity
You build it
Your deploy pipeline is the only thing stopping a changed handler
emisar
Content-addressed packs; a changed SHA-256 blocks dispatch until an admin re-trusts
Host transport
You build it
Credentials and routing you design and secure
emisar
Outbound-only runners, single-use enrollment, revocable per-runner tokens — nothing listens on the host
Policy & approval
You build it
Conditional logic in code plus a homemade approval queue
emisar
Risk-tier defaults + per-action overrides, human approval, and standing grants that expire
Per-user access
You build it
Hand-rolled, and easy to get subtly wrong
emisar
Per-member runner scopes in UI, API, and dispatch; keys inherit the creator's scope at call time
Multi-client access
You build it
Auth and transport work per client (Claude, ChatGPT, Cursor, CLIs)
emisar
OAuth 2.1 remote MCP plus a stdio bridge, one catalog behind both
Output safety
You build it
Your redaction regexes, your output caps, your bug if one leaks
emisar
20+ built-in patterns plus your own, masked on the host before egress; output bytes clamped
Audit
You build it
Logs you design, store, and have to prove weren't edited
emisar
Hash-chained host journal (emisar audit verify), searchable cloud audit, NDJSON SIEM export
Failure modes
You build it
Reconnect, orphaned runs, leaked child processes — yours to handle
emisar
Run-state reconciled on reconnect; children reaped on disconnect; orphans marked, not lost
None of these are hard in isolation. They're a product because they have to hold together, forever, across every host and client you add.
What emisar costs you
Not buying the boring 80% isn't free either. The honest tradeoffs:
- It's a vendor in your path. The control plane is hosted by us; there's no supported self-hosted or air-gapped deployment today (the source is available for evaluation, not production self-hosting). Your runner stays on your host, dials out, and keeps its own tamper-evident journal — and a host-side admission list lets an operator veto any action even if our cloud is wrong — but the dispatch decision still rides through our service.
- It's opinionated. Actions are YAML packs, the policy model is risk-tiers-plus-overrides, the transport is MCP. If your workflow doesn't fit that shape, a server you control will fit it better than one you bend to.
- It's finite on purpose. emisar exists to let an agent run a reviewed catalog, not arbitrary commands. If you want the model to do anything it can think of, that's raw SSH — and we wrote that comparison too.
- It's another bill, and another vendor in your path. Team is $20 per runner per month, and you're putting a young product on part of your ops path. We try to earn it with the on-host guarantees above — and the runner stays useful even if our cloud is unreachable.
Build it yourself when
The surface is narrow, one team owns it, the target is already an API sitting behind your existing authorization and audit, and you don't expect to add hosts or clients. A small MCP adapter is exactly enough, and a second system would only be in the way.
Reach for emisar when
Tools reach real hosts, more than one agent or client needs access, security wants a reviewable action contract, operators want one approval and audit surface across the fleet, and you'd rather not own the failure modes above for the life of the project.
Skip building — and securing — your own MCP server.
emisar is the policy engine, approvals, audit trail, and runner trust you'd otherwise build and maintain yourself. Connect a runner and you're done.
Three runners. Seven-day audit. No credit card.