Skip to content

feat: add optional Python gRPC server and proto-derived MCP tools #14

Description

@antoinetoussaint-byte

Summary

Add optional, first-class gRPC server support to the generated Python FastAPI service and optionally expose selected FastAPI operations and gRPC RPCs as MCP tools.

Today this agent:

  • serves a FastAPI REST application;
  • generates Python gRPC client stubs for declared service dependencies during Builder.Sync;
  • does not create or run a service-owned gRPC server.

A service-owned grpc.aio listener would let protobuf be the canonical typed contract and make deterministic proto-to-MCP generation possible while keeping the existing FastAPI application.

Proposed configuration

grpc-server:
  enabled: true
  proto: proto/api.proto

mcp:
  enabled: true
  path: /mcp

  rest:
    mode: annotated # none | annotated | all

  grpc:
    mode: selected # none | selected | all
    methods:
      - api.CatalogService/Search
      - api.CatalogService/GetItem

The exact YAML shape can change, but the following behavior is required:

  • both gRPC and MCP are disabled by default;
  • enabling gRPC does not require enabling MCP;
  • MCP can expose all unary RPCs or an explicit allowlist;
  • streaming RPCs are skipped with a clear diagnostic until MCP task/stream semantics are deliberately supported;
  • FastAPI operations can be selected by OpenAPI operationId and/or an x-mcp extension;
  • configuration validation fails on unknown or duplicate RPC selectors.

A future shared protobuf option may carry tool names, descriptions, and MCP annotations, but this repository's service configuration must remain the final exposure allowlist.

Repository work

Optional Python gRPC server

  • Add settings and creation questions for the optional gRPC server.
  • Scaffold proto/api.proto and Buf generation configuration when enabled.
  • Generate Python protobuf and gRPC code during Sync.
  • Run grpc.aio.Server alongside Uvicorn, with coordinated startup and graceful shutdown.
  • Provide a user-owned implementation seam separate from generator-owned files.
  • Create/load a Codefly gRPC endpoint in Builder and Runtime.
  • Wire native, container, and Kubernetes port mappings.
  • Add gRPC health service support.
  • Preserve the existing REST-only behavior and generated layout when disabled.

FastAPI itself remains the ASGI/REST listener. The gRPC server uses a separate internal port in the same service process.

Proto-derived MCP tools

Mount the official MCP Python SDK 2.x Streamable HTTP ASGI application under the existing FastAPI listener, normally at /mcp.

At Sync time, generate a registry from protobuf descriptors containing:

  • full RPC path;
  • service and method names;
  • input and output message descriptors;
  • dependency/self endpoint identity;
  • configured tool name and behavioral annotations.

At runtime:

  • convert MCP arguments into protobuf messages with google.protobuf.json_format;
  • invoke grpc.aio unary RPCs;
  • return structured protobuf responses as MCP structured content;
  • derive JSON Schema from protobuf descriptors, including nested messages, enums, repeated fields, maps, oneofs, and presence;
  • preserve gRPC status details as model-readable MCP tool errors;
  • avoid generating one bespoke Python wrapper function per RPC.

The same machinery may expose generated dependency gRPC clients, but service-owned RPCs are the first required path.

OpenAPI-derived MCP tools

For the FastAPI surface:

  • discover operations from app.openapi() after routers/plugins are registered;
  • default to annotated-only exposure;
  • support mode none, annotated, or all;
  • use operationId as the stable selector;
  • permit x-mcp metadata for name, description, read-only, destructive, and idempotent hints;
  • do not expose the MCP mount itself as a REST tool;
  • preserve FastAPI dependency/authentication behavior when dispatching a selected operation.

Do not call route functions directly if that bypasses FastAPI dependencies, middleware, validation, or authorization.

Security

  • MCP remains off by default.
  • Enabling MCP must not automatically make the REST endpoint public.
  • Mounted MCP requests must pass an explicit authentication/authorization boundary; per-route FastAPI dependencies do not automatically protect a mounted ASGI sub-application.
  • Configure the MCP SDK Host/Origin allowlist for deployed hostnames, or explicitly rely on a trusted reverse proxy that enforces those checks.
  • Treat MCP tool annotations as hints, not authorization policy.
  • Add CORS support for MCP protocol headers without weakening existing origin policy.

Envoy / ingress requirements

These are integration prerequisites, not implementation owned by this repository.

For the gRPC listener, Envoy must:

  • use HTTP/2 upstream;
  • preserve gRPC content type, trailers, deadlines, and status;
  • route the declared Codefly gRPC endpoint port;
  • use gRPC-aware health checks where applicable.

For the MCP path on the FastAPI listener, Envoy must:

  • forward POST and, for compatible protocol revisions, GET and DELETE at /mcp;
  • forward OPTIONS for browser CORS;
  • preserve Authorization, Origin, Accept, Content-Type, Last-Event-ID, Mcp-Protocol-Version, Mcp-Session-Id, Mcp-Method, and Mcp-Name headers;
  • return/expose Mcp-Session-Id where used;
  • disable response buffering for SSE/streaming compatibility;
  • allow appropriately long request/idle timeouts;
  • enforce a reasonable JSON request-body limit;
  • avoid path rewriting or slash normalization that changes the MCP endpoint;
  • either provide session affinity for legacy sessionful MCP clients or use the stateless 2026 protocol path.

The first version does not require a new MCP port or Codefly endpoint type because Streamable HTTP is mounted on the existing FastAPI HTTP endpoint. If discovery must distinguish MCP from ordinary REST, that contract belongs in core and should be tracked separately.

External prerequisites

Track outside this repository as needed:

  • any shared protobuf MCP annotation definition;
  • reusable protobuf-to-JSON-Schema support;
  • Codefly core endpoint/discovery changes if MCP needs a distinct semantic endpoint;
  • Envoy/gateway routing and header policy;
  • CLI/UI support for discovering the service MCP URL.

This issue must not implement those external components.

Acceptance criteria

  • Existing generated REST-only services are unchanged by default.
  • A newly generated service can optionally start both FastAPI and grpc.aio listeners.
  • Native, container, and deployment modes advertise and reach both enabled listeners.
  • Sync deterministically regenerates protobuf artifacts and the MCP registry.
  • MCP tools/list exposes exactly the configured REST operations and unary RPCs.
  • MCP tools/call successfully round-trips nested protobuf input/output through a real grpc.aio test server.
  • Unknown selectors and unsupported streaming selections fail with actionable errors.
  • Authentication is covered by integration tests; mounting MCP cannot bypass the intended boundary.
  • Shutdown releases both HTTP and gRPC listeners.
  • Tests cover MCP through the mounted ASGI endpoint and through an Envoy-equivalent proxy configuration where that harness exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions