MockServer supports mocking gRPC services by transparently converting gRPC requests (protobuf over HTTP/2) into JSON-over-HTTP requests internally. This allows the standard expectation matching engine to handle gRPC requests using the same JSON format used for HTTP mocking.

 

How gRPC Mocking Works

When MockServer receives a gRPC request:

  1. The protobuf binary body is decoded to JSON using the loaded proto descriptors
  2. MockServer adds metadata headers to the converted request:
  3. The converted JSON request is matched against active expectations
  4. The JSON response is encoded back to protobuf binary and returned as a gRPC response

This means you can set up gRPC expectations using the same JSON format and client APIs as HTTP mocking — no special gRPC client tooling is needed.

 

Loading Proto Descriptors

MockServer needs proto descriptors to convert between protobuf binary and JSON. There are three ways to load them:

1. Pre-compiled Descriptor Files

Compile your .proto files to descriptor sets and point MockServer at the directory:

protoc --descriptor_set_out=service.dsc --include_imports service.proto

Then configure MockServer:

-Dmockserver.grpcDescriptorDirectory="/path/to/descriptors"

Or via environment variable:

MOCKSERVER_GRPC_DESCRIPTOR_DIRECTORY=/path/to/descriptors

2. Proto Source Files (Auto-compiled)

Point MockServer at a directory of .proto source files and they will be compiled at startup using protoc:

-Dmockserver.grpcProtoDirectory="/path/to/protos"

This requires protoc to be available on the system PATH. If protoc is installed elsewhere, configure its path:

-Dmockserver.grpcProtocPath="/usr/local/bin/protoc"

3. REST API Upload

Upload compiled descriptors at runtime via the REST API:

curl -v -X PUT "http://localhost:1080/mockserver/grpc/descriptors" \
  --data-binary @service.dsc
 

Docker

When running MockServer in Docker, mount your proto files or descriptors into the container:

docker run -d --rm \
  -p 1080:1080 \
  -v /local/path/to/protos:/protos \
  -e MOCKSERVER_GRPC_PROTO_DIRECTORY=/protos \
  mockserver/mockserver:latest

Replace latest with a specific version tag (e.g. mockserver/mockserver:6.1.0) to pin a known working version.

 

Creating gRPC Expectations

Given a proto file such as:

syntax = "proto3";
package com.example.grpc;

service GreetingService {
  rpc Greeting (HelloRequest) returns (HelloResponse);
  rpc ListGreetings (HelloRequest) returns (stream HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string greeting = 1;
}

You can create expectations that match on the JSON-converted request body and the gRPC metadata headers:

 

Unary RPC

curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
  "httpRequest": {
    "method": "POST",
    "path": "/com.example.grpc.GreetingService/Greeting",
    "headers": {
      "x-grpc-service": ["com.example.grpc.GreetingService"],
      "x-grpc-method": ["Greeting"]
    },
    "body": {
      "type": "JSON",
      "json": "{\"name\": \"World\"}"
    }
  },
  "httpResponse": {
    "statusCode": 200,
    "headers": {
      "grpc-status": ["0"]
    },
    "body": "{\"greeting\": \"Hello World\"}"
  }
}'
new MockServerClient("localhost", 1080)
    .when(
        request()
            .withMethod("POST")
            .withPath("/com.example.grpc.GreetingService/Greeting")
            .withHeader("x-grpc-service", "com.example.grpc.GreetingService")
            .withHeader("x-grpc-method", "Greeting")
            .withBody(json("{\"name\": \"World\"}"))
    )
    .respond(
        response()
            .withStatusCode(200)
            .withHeader("grpc-status", "0")
            .withBody("{\"greeting\": \"Hello World\"}")
    );
from mockserver import MockServerClient, HttpRequest, HttpResponse, KeyToMultiValue

client = MockServerClient("localhost", 1080)
client.when(
    HttpRequest(
        method="POST",
        path="/com.example.grpc.GreetingService/Greeting",
        headers=[
            KeyToMultiValue(name="x-grpc-service", values=["com.example.grpc.GreetingService"]),
            KeyToMultiValue(name="x-grpc-method", values=["Greeting"])
        ],
        body={"type": "JSON", "json": '{"name": "World"}'}
    )
).respond(
    HttpResponse(
        status_code=200,
        headers=[KeyToMultiValue(name="grpc-status", values=["0"])],
        body='{"greeting": "Hello World"}'
    )
)
require 'mockserver-client'
include MockServer

client = MockServer::Client.new('localhost', 1080)
client.when(
  HttpRequest.new(
    method: 'POST',
    path: '/com.example.grpc.GreetingService/Greeting',
    headers: [
      { name: 'x-grpc-service', values: ['com.example.grpc.GreetingService'] },
      { name: 'x-grpc-method', values: ['Greeting'] }
    ],
    body: { type: 'JSON', json: '{"name": "World"}' }
  )
).respond(
  HttpResponse.new(
    status_code: 200,
    headers: [{ name: 'grpc-status', values: ['0'] }],
    body: '{"greeting": "Hello World"}'
  )
)
 

Server Streaming RPC

For server streaming RPCs, use a gRPC stream response to return multiple messages. Each message can have an optional delay:

curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
  "httpRequest": {
    "method": "POST",
    "path": "/com.example.grpc.GreetingService/ListGreetings",
    "headers": {
      "x-grpc-service": ["com.example.grpc.GreetingService"],
      "x-grpc-method": ["ListGreetings"]
    }
  },
  "grpcStreamResponse": {
    "statusName": "OK",
    "messages": [
      {"json": "{\"greeting\": \"Hello Alice\"}"},
      {"json": "{\"greeting\": \"Hello Bob\"}", "delay": {"timeUnit": "MILLISECONDS", "value": 100}},
      {"json": "{\"greeting\": \"Hello Charlie\"}", "delay": {"timeUnit": "MILLISECONDS", "value": 200}}
    ]
  }
}'
new MockServerClient("localhost", 1080)
    .when(
        request()
            .withMethod("POST")
            .withPath("/com.example.grpc.GreetingService/ListGreetings")
            .withHeader("x-grpc-service", "com.example.grpc.GreetingService")
            .withHeader("x-grpc-method", "ListGreetings")
    )
    .respondWithGrpcStream(
        grpcStreamResponse()
            .withStatusName("OK")
            .withMessage("{\"greeting\": \"Hello Alice\"}")
            .withMessage("{\"greeting\": \"Hello Bob\"}", delay(MILLISECONDS, 100))
            .withMessage("{\"greeting\": \"Hello Charlie\"}", delay(MILLISECONDS, 200))
    );
from mockserver import MockServerClient, HttpRequest, KeyToMultiValue, GrpcStreamResponse, GrpcStreamMessage, Delay

client = MockServerClient("localhost", 1080)
client.when(
    HttpRequest(
        method="POST",
        path="/com.example.grpc.GreetingService/ListGreetings",
        headers=[
            KeyToMultiValue(name="x-grpc-service", values=["com.example.grpc.GreetingService"]),
            KeyToMultiValue(name="x-grpc-method", values=["ListGreetings"])
        ]
    )
).respond_with_grpc_stream(
    GrpcStreamResponse(
        status_name="OK",
        messages=[
            GrpcStreamMessage(json='{"greeting": "Hello Alice"}'),
            GrpcStreamMessage(json='{"greeting": "Hello Bob"}', delay=Delay(time_unit="MILLISECONDS", value=100)),
            GrpcStreamMessage(json='{"greeting": "Hello Charlie"}', delay=Delay(time_unit="MILLISECONDS", value=200))
        ]
    )
)
require 'mockserver-client'
include MockServer

client = MockServer::Client.new('localhost', 1080)
client.when(
  HttpRequest.new(
    method: 'POST',
    path: '/com.example.grpc.GreetingService/ListGreetings',
    headers: [
      KeyToMultiValue.new(name: 'x-grpc-service', values: ['com.example.grpc.GreetingService']),
      KeyToMultiValue.new(name: 'x-grpc-method', values: ['ListGreetings'])
    ]
  )
).respond_with_grpc_stream(
  GrpcStreamResponse.new(
    status_name: 'OK',
    messages: [
      GrpcStreamMessage.new(json: '{"greeting": "Hello Alice"}'),
      GrpcStreamMessage.new(json: '{"greeting": "Hello Bob"}', delay: Delay.new(time_unit: 'MILLISECONDS', value: 100)),
      GrpcStreamMessage.new(json: '{"greeting": "Hello Charlie"}', delay: Delay.new(time_unit: 'MILLISECONDS', value: 200))
    ]
  )
)
 

Client Streaming RPC

Client streaming requests are converted with the combined stream messages in the request body. MockServer adds an x-grpc-client-streaming header to indicate this is a client streaming request. Client streaming support is limited — see Limitations below.

 

Matching gRPC Requests

Since gRPC requests are converted to JSON, all standard MockServer matchers work:

 

gRPC Status Codes

For unary RPCs, set the gRPC status via the grpc-status response header (as shown in the unary example above). For server streaming RPCs, use the statusName field in the grpcStreamResponse action instead. You can also set a grpc-message header (unary) or statusMessage field (streaming) to provide error details. Standard gRPC status codes are supported:

Code Name
0OK
1CANCELLED
2UNKNOWN
3INVALID_ARGUMENT
4DEADLINE_EXCEEDED
5NOT_FOUND
6ALREADY_EXISTS
7PERMISSION_DENIED
8RESOURCE_EXHAUSTED
9FAILED_PRECONDITION
10ABORTED
11OUT_OF_RANGE
12UNIMPLEMENTED
13INTERNAL
14UNAVAILABLE
15DATA_LOSS
16UNAUTHENTICATED
 

Limitations

 

gRPC Fault Injection (Chaos)

MockServer can inject gRPC-level faults — UNAVAILABLE, DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED, and other status codes — into matched RPC calls, with optional latency and request-quota controls. Faults are registered per gRPC service name via a dedicated control-plane endpoint and apply before normal request conversion in GrpcToHttpRequestHandler.

This is separate from the health-check serving-status feature described below. See the gRPC Fault Injection section on the Chaos Testing page for the full profile reference and REST API examples.

 

gRPC Health Checking Protocol

Kubernetes readiness and liveness probes commonly use the gRPC Health Checking Protocol (grpc.health.v1.Health/Check) to verify that a service is ready to receive traffic. MockServer auto-responds to this well-known method without requiring a proto descriptor — protobuf encoding and decoding is handled manually so health checks work out of the box even when no descriptors have been loaded.

Health checks are enabled by default (grpcHealthCheckEnabled=true). The default serving status for all services is SERVING. You can override the status for individual services or for the global default via a REST endpoint.

ServingStatus values

Value Proto code Meaning
SERVING 1 The service is healthy and ready to accept requests (default)
NOT_SERVING 2 The service is temporarily unavailable (probe will fail)
UNKNOWN 0 Status is unknown
SERVICE_UNKNOWN 3 The named service is not known to this server

REST API

Override the status for a named service:

curl -v -X PUT "http://localhost:1080/mockserver/grpc/health" \
  -H "Content-Type: application/json" \
  -d '{"service": "my.payments.PaymentService", "status": "NOT_SERVING"}'

Set service to the fully-qualified gRPC service name. Use an empty string ("") to override the default status that applies to all services without an explicit override. The response confirms the registration:

{ "status": "registered", "service": "my.payments.PaymentService", "servingStatus": "NOT_SERVING" }

Read all current status overrides:

curl -v "http://localhost:1080/mockserver/grpc/health"

Returns a JSON object mapping service names to their current status. The empty string key ("_default") shows the global default:

{
  "_default": "SERVING",
  "my.payments.PaymentService": "NOT_SERVING"
}

All status overrides are cleared on server reset. The GET endpoint returns only services that have had their status explicitly set, plus the global default.

How it works

When MockServer receives a request whose path is exactly /grpc.health.v1.Health/Check, the request is intercepted in GrpcToHttpRequestHandler before descriptor lookup — no proto descriptor for the health service is needed. GrpcHealthCheckHandler decodes the 5-byte gRPC frame header and then manually parses the protobuf HealthCheckRequest (field 1 = service name string). It looks up the serving status in GrpcHealthRegistry, which falls back to the default status when no per-service override is registered. The response is a manually-encoded gRPC-framed HealthCheckResponse (field 1 = status enum varint). The whole path bypasses the expectation matching engine so health checks always respond, even with no expectations registered.

 

Server Reflection

MockServer supports the gRPC Server Reflection Protocol out of the box. Tools such as grpcurl and grpcui can use reflection to discover services and describe message types without needing a local .proto file.

Both the v1 and v1alpha reflection service paths are supported:

The reflection service answers from the proto descriptors already loaded into MockServer (via grpcDescriptorDirectory, grpcProtoDirectory, or the REST API upload). No additional configuration is required.

Example: listing services with grpcurl

# List all services known to MockServer
grpcurl -plaintext localhost:1080 list

# Describe a specific service
grpcurl -plaintext localhost:1080 describe com.example.grpc.GreetingService

# Describe a message type
grpcurl -plaintext localhost:1080 describe com.example.grpc.HelloRequest

Limitation

MockServer's gRPC path is buffered-unary: each HTTP/2 request carries exactly one gRPC message. The reflection handler therefore processes a single ServerReflectionRequest per call. This is sufficient for grpcurl list, single symbol lookups, and single file lookups. Fully interactive bidirectional-streaming reflection (a long-lived stream with multiple back-and-forth messages) is not supported by the current pipeline.

 

gRPC-Web Support

MockServer supports gRPC-Web, the variant of gRPC designed for browser clients and environments that cannot use HTTP/2 trailers. gRPC-Web requests are automatically detected and translated to standard gRPC for matching against existing expectations, so no additional configuration or separate expectations are needed.

Supported Content Types

How It Works

When MockServer receives a request with a gRPC-Web content type:

  1. The request body is decoded (base64-decoded for the -text variant) and the content type is translated to application/grpc
  2. The request is processed through the normal gRPC pipeline — descriptor lookup, protobuf-to-JSON conversion, and expectation matching all work unchanged
  3. The response is re-framed as gRPC-Web: the message frame(s) are followed by a trailer frame (flag byte 0x80) containing grpc-status and grpc-message as ASCII lines in the body, instead of HTTP/2 trailers
  4. For the -text variant, the entire response body is base64-encoded

gRPC-Web works over both HTTP/1.1 and HTTP/2, making it suitable for browser-based gRPC clients such as grpc-web and Improbable grpc-web.

Built-in Services via gRPC-Web

The built-in gRPC health check (/grpc.health.v1.Health/Check), server reflection, and chaos fault injection all work transparently via gRPC-Web. No special configuration is needed.

Connect Protocol (connectrpc)

The Connect protocol (used by connectrpc) is not currently supported. Connect uses a different framing format (JSON or proto over standard HTTP POST with application/connect+proto content type and trailers in a JSON envelope) that is distinct from gRPC-Web. If you need Connect support, please open a feature request.

 

Configuration

For full details on gRPC configuration properties, see the gRPC Configuration section on the Configuration page.