ARCP runtime that fronts an MCP server. Inbound tool.invoke
envelopes translate to MCP call_tool; the bridge emits the ARCP
job lifecycle back to the calling client.
You either (a) ditch your ARCP-native session/lease/observability story and run MCP straight, losing the runtime layer; or (b) embed MCP into one specific agent that knows how to call it directly, which doesn't compose with the rest of your stack. Wrap one, re-wrap the other.
Per RFC §20:
| MCP | ARCP |
|---|---|
| tool schema | capability (arcpx.mcp.tool.<name>.v1) |
| tool call | job (tool.invoke → job.completed) |
| resource | stream of kind: event (delegated) |
The bridge advertises the upstream server's tools as namespaced capability extensions at session open. Clients that need a specific MCP tool refuse the session if it's not advertised — same shape as any other ARCP capability negotiation.
$mcp = McpClientSession::stdio(upstreamParams());
$mcp->initialize();
$extensions = advertiseFromMcp($mcp); // MCP tool list -> arcpx.mcp.tool.*.v1
foreach ($inbound as $env) {
if ($env->payload instanceof ToolInvoke) {
handleInvoke($send, $mcp, $env);
}
}callViaMcp translates MCP errors into canonical ARCP error codes
(FAILED_PRECONDITION for result.isError, INTERNAL for
unexpected exceptions at the boundary).
- MCP compatibility — RFC §20 (the whole point).
tool.invoke/job.accepted/job.started/job.completed/job.failedlifecycle — §6.3, §10.- Capability extensions for advertised tools — §7, §21.
- Canonical error mapping — §18.2.
main.php— the bridge.handleInvokeis the file. Runtime wiring (transport, session manager) is symmetric withArcp\Runtime\ARCPRuntimeand elided.upstream.php— MCP server invocation + stubMcpClientSession. No first-class MCP PHP SDK exists yet; vendor a bridge.
- Front multiple MCP servers from one ARCP runtime; namespace each
set of tools under
arcpx.mcp.<server>.tool.<name>.v1. - Bridge MCP resources to ARCP streams of
kind: eventso ARCP observers can subscribe to MCP resource changes. - Layer ARCP leases on top: gate
tool.invokefor any side-effecting MCP tool throughpermission.requestbefore forwarding to MCP.