← Back to Blog

Local vs Remote: The Trust Boundary That Matters

·9 min read

pyRPC v0.14.0 ships two MCP servers. One runs on your machine as a stdio subprocess. The other runs on pyRPC infrastructure and serves documentation over HTTP. They are not interchangeable. They are not two flavors of the same thing. They are two servers separated by a trust boundary, and the distinction matters for security, compliance, and agent behavior.

The local server

pyrpc mcp spawns a subprocess inside your client. The subprocess imports your Python backend module in your interpreter, walks your live registry, and returns metadata from your environment. No network calls. No telemetry. No data leaves your machine.

The agent sees your actual routers, your actual schemas, your actual types. Not a generated snapshot, not a documentation approximation, the real thing. This is what makes check_call meaningful: it validates against your real validation logic, including custom validators, pydantic models, and runtime constraints that no schema file can capture.

The remote server

The documentation MCP lives at mcp.pyrpc.com/mcp. It serves pyRPC documentation, adapter guides, and procedure reference material. It is read-only, requires no authentication, and carries zero access to any user’s codebase.

Launch it with npx @pyrpc/mcp mcp. The agent gets up-to-date documentation without leaving the IDE, and the server gets nothing in return but the query.

The trust boundary

  +---------------------------------------------------+
  |  YOUR MACHINE                                     |
  |                                                   |
  |  AI Client (Claude Code / Cursor / VS Code)       |
  |    |                                              |
  |    |-- stdio subprocess                           |
  |    |                                              |
  |    v                                              |
  |  Local MCP Server                                 |
  |    imports YOUR backend module                     |
  |    walks YOUR registry                             |
  |    validates YOUR types                            |
  |    writes YOUR codegen output                      |
  |                                                   |
  |  [zero network egress]                             |
  |                                                   |
  +---------------------------------------------------+
  |  NETWORK BOUNDARY                                 |
  +---------------------------------------------------+
  |                                                   |
  |  Remote MCP Server (mcp.pyrpc.com/mcp)            |
  |    hosted on pyRPC infrastructure                 |
  |    read-only documentation                         |
  |    no authentication required                      |
  |    no access to any user code                      |
  |    managed infrastructure, managed updates         |
  |                                                   |
  +---------------------------------------------------+

Why the distinction matters

For security teams, the question is not “does this tool do something dangerous?” but “where does this tool execute, and what can it see?” The local server executes in your environment with your permissions. It can see your database models, your authentication logic, your internal API surface. That visibility is the point, and it is also the risk.

The remote server executes in pyRPC’s environment with pyRPC’s permissions. It can see documentation URLs and adapter names. The blast radius is bounded by design.

Enterprise compliance frameworks ask about data residency, network egress, and credential exposure. The local server has zero network egress and zero credential exposure because it runs on the developer’s machine. The remote server has no user data because it never touches user code. Both answers are clean, but for different reasons.

How agents handle both simultaneously

A typical agent workflow uses both servers in the same session. The agent calls introspect_project on the local server to understand the user’s actual API. It calls the remote server to look up how pyRPC’s FastAPI adapter handles middleware. It calls check_call locally to validate the payload. It calls run_codegen to regenerate the client.

The agent does not need to reason about which server to use for which task. The tool names are self-describing: introspect_project is obviously local, search_docs is obviously remote. The boundary is implicit in the tool semantics, not a decision the agent must make.

Claude Desktop and remote server refusal

Claude Desktop, by default, refuses to connect to remote MCP servers that require authentication. This is by design, not a bug. The threat model is sound: a remote server with access to user data and write permissions is a lateral movement vector. pyRPC’s remote server avoids this entirely because it requires no authentication and has no write permissions. It serves documentation. That is all.

For clients that enforce stricter policies, the local server is always available as the default. The remote server is a convenience, not a requirement. Projects that cannot accept remote connections for compliance reasons use the local server exclusively and lose nothing.

The no procedure execution guarantee

Neither server executes procedures. The local server validates arguments against real types but never calls your functions. The remote server does not have access to your functions. There is no tool that triggers a database write, a network call, or any other side effect of your backend.

This is not a policy decision that could change in v0.15.0. It is architectural: the MCP server imports your module to read metadata, not to invoke handlers. Adding execution would require a fundamentally different server design, and we have no plans to build one. The boundary is structural, not aspirational.

Why this split and not one server

Supabase ships one server because one API and one credential reach everything. Prisma ships two because local schema operations and remote database management serve different audiences in different execution environments. Neon collapsed to one because their entire product is cloud-hosted.

pyRPC follows the Prisma pattern because the split is forced by the problem. Introspection must import your routers in your interpreter; no hosted service can do that. Documentation gains nothing from being local; bundled docs go stale between releases. The boundary is not a choice. It is the shape of the problem.