AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Kora Grpc Client

skill-kora-projects-kora-skills-kora-grpc-client · by kora-projects

Builds gRPC clients in Kora via GrpcClientModule, the protobuf Gradle plugin, and generated stubs injected directly into components. Covers grpcClient.<ServiceName> HOCON/YAML config, plaintext vs TLS through the URL scheme, custom ClientInterceptor scoped with @Tag(ServiceGrpc.class) for metadata auth and logging, and unary plus server/client/bidirectional streaming with blocking and async stubs…

No reviews yet
0 installs
29 views
0.0% view→install

Install

$ agentstack add skill-kora-projects-kora-skills-kora-grpc-client

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kora-projects-kora-skills-kora-grpc-client)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Kora Grpc Client? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Kora gRPC Client

Generate gRPC client stubs from a .proto contract and inject them as components through GrpcClientModule. Kora wires the configured channel and the generated stubs into the application graph; your code just builds protobuf requests and calls stub methods.

Read this first when:

  • enabling GrpcClientModule and injecting a generated *BlockingStub/*FutureStub/*Stub,
  • configuring a client under grpcClient..*,
  • adding a ClientInterceptor for metadata headers, auth, or logging,
  • making unary or streaming calls.

Key facts (do not get these wrong)

  • Stubs are injected directly by type — no @Tag on the constructor parameter. Kora produces one stub per generated *Grpc class. Injecting UserServiceGrpc.UserServiceBlockingStub is enough.
  • @Tag(ServiceGrpc.class) belongs on a ClientInterceptor, to scope that interceptor to one service's client. It is not used for stub injection.
  • Annotations come from ru.tinkoff.kora.common.* (@Component, @Tag, @KoraApp), not from any annotation.processor.* package.
  • Plaintext vs TLS is chosen by the URL scheme (http:// = plaintext, https:///grpc:// per transport). There is no usePlaintext config key.
  • The mandatory annotation processor must be present: Java annotationProcessor "ru.tinkoff.kora:annotation-processors", Kotlin ksp "ru.tinkoff.kora:symbol-processors".

Quick Start

1. Dependencies

Pin the BOM (kora-parent); never version individual ru.tinkoff.kora:* artifacts.

plugins {
    id "application"
    id "com.google.protobuf" version "0.9.4"
}

configurations {
    koraBom
    annotationProcessor.extendsFrom(koraBom)
    implementation.extendsFrom(koraBom)
}

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")
    annotationProcessor "ru.tinkoff.kora:annotation-processors"

    implementation "ru.tinkoff.kora:grpc-client"
    implementation "ru.tinkoff.kora:config-hocon"
    implementation "ru.tinkoff.kora:logging-logback"
    implementation "io.grpc:grpc-protobuf:1.74.0"
    compileOnly "javax.annotation:javax.annotation-api:1.3.2"
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.25.3" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.74.0" }
    }
    generateProtoTasks {
        all()*.plugins { grpc {} }
    }
}

sourceSets {
    main {
        java {
            srcDirs "build/generated/source/proto/main/grpc"
            srcDirs "build/generated/source/proto/main/java"
        }
    }
}

2. Define the protobuf service

src/main/proto/user_service.proto:

syntax = "proto3";
package ru.tinkoff.kora.example.grpc;
option java_multiple_files = true;

service UserService {
  rpc GetUser (GetUserRequest) returns (UserResponse) {}
}

message GetUserRequest { string user_id = 1; }
message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
}

3. Enable the module

import ru.tinkoff.grpc.client.GrpcClientModule;
import ru.tinkoff.kora.application.graph.KoraApplication;
import ru.tinkoff.kora.common.KoraApp;
import ru.tinkoff.kora.config.hocon.HoconConfigModule;
import ru.tinkoff.kora.logging.logback.LogbackModule;

@KoraApp
public interface Application extends HoconConfigModule, LogbackModule, GrpcClientModule {
    static void main(String[] args) {
        KoraApplication.run(ApplicationGraph::graph);
    }
}

4. Inject the stub and wrap it in a service

Inject the generated stub directly by type. Wrap it so protobuf builders and gRPC status handling stay at the transport boundary.

import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.example.grpc.UserServiceGrpc;
import ru.tinkoff.kora.example.grpc.GetUserRequest;

@Component
public final class UserClientService {

    private final UserServiceGrpc.UserServiceBlockingStub userService;

    public UserClientService(UserServiceGrpc.UserServiceBlockingStub userService) {
        this.userService = userService;
    }

    public UserDto getUser(String userId) {
        var response = userService.getUser(GetUserRequest.newBuilder()
            .setUserId(userId)
            .build());
        return new UserDto(response.getId(), response.getName(), response.getEmail());
    }
}

5. Configure the client

A service named UserService is configured under grpcClient.UserService. Use the URL scheme to control plaintext vs TLS; externalize the URL with ${?VAR}.

grpcClient {
  UserService {
    url = "http://localhost:8090"   // http:// => plaintext for local
    url = ${?GRPC_SERVER_URL}
    timeout = "10s"
    telemetry.logging.enabled = true
  }
}

Stub types

| Stub | Use for | |------|---------| | *BlockingStub | Unary calls and server-streaming reads (returns Iterator) | | *FutureStub | Unary calls returning ListenableFuture | | *Stub (async) | Client-streaming and bidirectional streaming via StreamObserver |

A service may inject several stub types at once (e.g. a *BlockingStub for reads and a *Stub for client streaming). See [grpc-client-stubs-reference.md](references/grpc-client-stubs-reference.md).

Client interceptors

Register a ClientInterceptor as a @Component and scope it to one service with @Tag(ServiceGrpc.class). Kora applies it to that service's channel automatically; it does not change stub injection.

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.common.Tag;
import ru.tinkoff.kora.example.grpc.UserServiceGrpc;

@Tag(UserServiceGrpc.class)
@Component
public final class AuthInterceptor implements ClientInterceptor {

    private static final Metadata.Key AUTHORIZATION =
        Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

    private final AuthConfig authConfig;

    public AuthInterceptor(AuthConfig authConfig) {
        this.authConfig = authConfig;
    }

    @Override
    public  ClientCall interceptCall(
            MethodDescriptor method, CallOptions callOptions, Channel next) {
        return new ForwardingClientCall.SimpleForwardingClientCall<>(next.newCall(method, callOptions)) {
            @Override
            public void start(Listener responseListener, Metadata headers) {
                headers.put(AUTHORIZATION, authConfig.value());
                super.start(responseListener, headers);
            }
        };
    }
}

The default GrpcClientConfigInterceptor (applies grpcClient.* config) is always present. See [grpc-client-interceptors-reference.md](references/grpc-client-interceptors-reference.md) for logging, metadata, and GraphInterceptor patterns.

Streaming

Server streaming can be consumed with a *BlockingStub (returns an Iterator) or asynchronously with a *Stub. Client and bidirectional streaming require the async *Stub and a StreamObserver. See [grpc-client-streaming-reference.md](references/grpc-client-streaming-reference.md).

Configuration

grpcClient..* keys: url (required), timeout, keepAliveTime, keepAliveTimeout, loadBalancingPolicy, maxInboundMessageSize, and telemetry.{logging,metrics,tracing}. Full reference (HOCON + YAML, defaults, env substitution): [grpc-client-config-reference.md](references/grpc-client-config-reference.md).

Common pitfalls

| Symptom | Fix | |---------|-----| | Required dependency not found: ...BlockingStub | Enable GrpcClientModule on @KoraApp; run ./gradlew classes so protobuf + processors run | | Stub class does not exist | Run protobuf generation and add the build/generated/source/proto/... source dirs to sourceSets | | Tried to add @Tag(...) on a stub parameter | Remove it — stubs inject by type; @Tag is only for interceptors | | UNAVAILABLE | Check grpcClient..url host/port and that the server is up | | UNAUTHENTICATED | Add an AuthInterceptor (above) putting credentials into Metadata | | Interceptor never runs | Ensure @Component + @Tag(ServiceGrpc.class) matches the generated class exactly | | Wanted plaintext but got TLS | Use an http:// URL; there is no usePlaintext key |

References & assets

| File | Purpose | |------|---------| | [references/grpc-client-stubs-reference.md](references/grpc-client-stubs-reference.md) | Stub types, direct injection, service wrappers | | [references/grpc-client-config-reference.md](references/grpc-client-config-reference.md) | Full config + protobuf plugin setup | | [references/grpc-client-interceptors-reference.md](references/grpc-client-interceptors-reference.md) | Interceptor patterns, metadata, GraphInterceptor | | [references/grpc-client-streaming-reference.md](references/grpc-client-streaming-reference.md) | Server/client/bidirectional streaming | | [assets/README.md](assets/README.md) | Template catalog and usage |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.