The decision
An outside assistant, connected over MCP, gets direct access to selected tools through the existing tool registry, the one place where every tool runs. The assistant decides how to combine them, without HYVIRAL’s internal manager and specialist agents planning the workflow a second time.
The app and MCP share per-tool credit rates and one account credit pool. The bridge still has to do the session, confirmation and accounting work the app runtime normally performs; that maintenance cost is the price of sharing execution with a different orchestrator.
From the source
MCP core specification. The execution boundary is a hard rule:
The MCP module calls
ToolRegistryService.execute()and onlyToolRegistryService.execute(). Never a tool handler directly. Never a REST controller. Never a service that debits on its own.
Who owns what:
| Responsibility | Owner |
|---|---|
| Workflow planning | Connecting agent |
| Transport | TypeScript MCP SDK with a NestJS adapter |
| MCP exposure | Curated tool allowlist and capability scopes |
| Synchronous execution | Existing registry, inside an established session |
| Usage accounting | Bridge work required when bypassing the app runtime |
Bridge implementation. The synchronous path builds the session and calls registry execution:
const session = await this.sessions.build(auth, {
conversationId,
confirmedSpend,
mcpCallId: callId,
});
const started = Date.now();
let result: ToolResult;
try {
result = await AgentPlatformSession.run(session, () =>
this.registry.execute(name, parsed.data, {
planTier: this.tierOf(auth),
// The closed `ConversationChannel` union has no 'mcp' member. The
// SESSION says 'mcp' (which is what `isUnattendedChannel` reads); the
// context says 'web' — the same split voice uses.
channel: 'web',
}),
);
Bridge implementation. The accounting the bridge has to restore:
// ── charge (D3 — identical rates) ──────────────────────────────────────
// MCP skips the runtime, which is what accumulates `tokenUsage` and calls
// `chargeTurn` in-app. Without this every LLM-backed read tool is free
// forever: `draft_content`, `web_search`, `analyze_thumbnail` and
// `get_intel_digest` all burn real provider money at `creditCost: 0`.
const usage = result.tokenUsage;
What this shows
The synchronous path carries an authenticated session into shared execution and owns the accounting obligation that reuse would otherwise drop. Long-running work takes the existing background-job path, outside this excerpt.