Skip to content

feat: custom provider CRUD for MCP connectors#159

Merged
AkshayParihar33 merged 8 commits into
mainfrom
custom-providers-crud
May 12, 2026
Merged

feat: custom provider CRUD for MCP connectors#159
AkshayParihar33 merged 8 commits into
mainfrom
custom-providers-crud

Conversation

@AkshayParihar33
Copy link
Copy Markdown
Contributor

@AkshayParihar33 AkshayParihar33 commented May 12, 2026

Summary

Adds client.actions.providers — a typed Python API for managing custom providers (MCP connectors) in the Scalekit catalog. Developers can now create, update, list, and delete custom providers programmatically without going through the dashboard, enabling automated provisioning of MCP server integrations at scale.

Changes

  • New ProvidersClient (gRPC layer) + ActionProviders facade with typed Pydantic request/response models
  • Auth pattern types: OAUTH (with PKCE), BEARER, and API_KEY, each with configurable credential fields
  • Integration tests covering create → update → list → delete for all three auth types
  • REFERENCE.md updated with usage examples for all four operations

Test plan

  • Run make test with SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET set in tests/.env
  • Confirm test_oauth_mcp_create_and_list, test_bearer_mcp_create_update_and_list, and test_api_key_mcp_create_and_delete all pass

Summary by CodeRabbit

  • New Features

    • Custom provider management: create, update, list, delete (OAuth / BEARER / API_KEY) with MCP support, filters, and pagination
  • Documentation

    • Added "Custom Providers" API reference detailing request/response shapes and behaviors (create/update/list/delete semantics)
  • Tests

    • End-to-end integration tests covering create/list/update/delete provider flows
  • Chores

    • .gitignore expanded to ignore the entire .claude directory

Review Change Stack

…to custom-providers-crud

# Conflicts:
#	.gitignore
Introduces typed Pydantic models for auth patterns (AuthField, OAuthConfig,
AuthPattern, Provider) with typed request/response wrappers, a low-level
ProvidersClient wrapping ProviderServiceStub, and ActionProviders accessible
via client.actions.providers and client.connect.providers.
…te fields

display_name and proxy_url are required by the server on every UpdateCustomProvider
call. Updated UpdateCustomProviderRequest, ProvidersClient, and ActionProviders
accordingly. Adds test_providers.py covering OAuth, Bearer, and API Key MCP flows.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: af90d751-5f20-44e8-b98b-bd2be38c84d5

📥 Commits

Reviewing files that changed from the base of the PR and between 46f2363 and cb59ebc.

📒 Files selected for processing (1)
  • scalekit/actions/models/custom_provider.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • scalekit/actions/models/custom_provider.py

Walkthrough

Adds full custom-provider management: auth models, request/response contracts, ProvidersClient gRPC CRUD, ActionProviders wrapper wired into ActionClient/ScalekitClient, REFERENCE.md docs, integration tests, and a .gitignore update.

Changes

Custom Providers Feature

Layer / File(s) Summary
Provider authentication models and type exports
scalekit/actions/models/custom_provider.py, scalekit/actions/types.py
Introduces Pydantic models AuthField, OAuthConfig, AuthPattern, and Provider with serialization/validation and exports them via scalekit/actions/types.py.
Request and response models for CRUD operations
scalekit/actions/models/requests/*, scalekit/actions/models/responses/*
Adds CreateCustomProviderRequest/Response, UpdateCustomProviderRequest/Response, ListProvidersRequest/Response, and DeleteCustomProviderRequest/Response with validators, from_proto() decoders, and to_dict() serializers.
ProvidersClient gRPC implementation
scalekit/providers.py
New low-level gRPC client implementing create_custom_provider, update_custom_provider, list_providers (pagination/filtering), and delete_custom_provider, plus helper to convert auth patterns to protobuf ListValue.
ActionProviders wrapper and client integration
scalekit/actions/actions.py, scalekit/client.py
Adds ActionProviders delegating to ProvidersClient; ActionClient accepts an optional providers_client and exposes a lazy providers property; ScalekitClient constructs and passes ProvidersClient into action wiring.
API documentation and ignore update
REFERENCE.md, .gitignore
Adds a “Custom Providers” section documenting create/update/list/delete semantics (including auth_patterns replacement on update) and broadens .claude ignore to .claude/*.
Integration tests
tests/test_providers.py
Adds end-to-end tests covering OAuth MCP create+list, Bearer MCP create+update+list, and API Key MCP create+delete with cleanup handling.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ScalekitClient
  participant ActionClient
  participant ActionProviders
  participant ProvidersClient
  participant ProviderServiceStub
  User->>ScalekitClient: instantiate client / access actions
  User->>ActionClient: actions.providers.create_custom_provider(request)
  ActionProviders->>ProvidersClient: create_custom_provider(proto_request)
  ProvidersClient->>ProviderServiceStub: gRPC CreateCustomProvider
  ProviderServiceStub-->>ProvidersClient: proto_response
  ProvidersClient-->>ActionProviders: proto_response
  ActionProviders->>User: CreateCustomProviderResponse (typed)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Avinash-Kamath

Poem

🐰 I hopped through models, gRPC, and docs,

Auth patterns twitched in tidy flocks,
Create, update, list, delete in a row,
Tests nodded yes, the types all glow,
A small ignore and exports now show.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: custom provider CRUD for MCP connectors' accurately reflects the main change: adding create, read, update, delete operations for custom providers supporting MCP connectors.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch custom-providers-crud

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@REFERENCE.md`:
- Around line 6083-6428: The Custom Providers documentation block uses repeated
fourth-level headings (####) for labels like "📝 Description", "🔌 Usage", "⚙️
Parameters", and "📦 Response", causing markdownlint MD024; replace those
repeated #### headings with bold inline labels (e.g., **📝 Description**, **🔌
Usage**, **⚙️ Parameters**, **📦 Response**) throughout the "Creates a new
custom provider" section and the related method blocks for
create_custom_provider, update_custom_provider, list_providers, and
delete_custom_provider so headings are unique and lint warnings are cleared.

In `@scalekit/actions/models/custom_provider.py`:
- Around line 35-41: The model currently allows arbitrary strings for input_type
and does not enforce cross-field invariants for auth payloads; change input_type
to a constrained Enum (e.g., InputType = Enum('text','password')) and update the
Field declaration (input_type) to use that Enum, and add pydantic
validators/root_validator on the provider/auth model (referencing oauth_config,
fields, and the auth type field—e.g., auth_type or provider_type) to enforce: if
auth_type == "OAUTH" then oauth_config must be present and fields must be empty;
for non-OAUTH ensure oauth_config is None if required; raise clear
ValidationError messages when invariants fail. Ensure validator names (e.g.,
validate_oauth_invariants or root_validator) are added to the same model in
custom_provider.py.

In `@scalekit/actions/models/requests/create_custom_provider_request.py`:
- Around line 25-32: The proxy_url Field currently accepts any string but must
be validated as an HTTPS URL; change its type to pydantic.HttpUrl (or
pydantic.AnyUrl with a validator) or add a `@validator` for "proxy_url" in the
request model (the class that defines proxy_url /
create_custom_provider_request) that parses the URL and raises ValueError if the
scheme is not "https" or if parsing fails; update the Field description only if
needed and ensure errors surface during request validation rather than at
runtime.

In `@scalekit/actions/models/requests/delete_custom_provider_request.py`:
- Around line 12-18: The model currently allows an empty string for the
identifier field which defers a predictable validation failure to runtime;
update the identifier declaration in delete_custom_provider_request.py (the
identifier: str = Field(...) in the DeleteCustomProviderRequest model) to reject
empty values at the model boundary by adding a non-empty constraint (e.g.,
Field(..., min_length=1, description=...) or change the type to
pydantic.constr(min_length=1) or add a root/field validator that raises
ValueError when identifier == ""), so the SDK fails fast for empty identifiers.

In `@scalekit/actions/models/requests/list_providers_request.py`:
- Around line 1-21: The model currently allows invalid values; update
ListProvidersRequest to validate provider_type and page_size: change
provider_type Field to include ge=0 and le=2 (restrict to 0,1,2) and change
page_size Field to include gt=0 (must be positive), or alternatively use
pydantic conint types or add `@validator` methods on ListProvidersRequest to
enforce these constraints and raise clear validation errors when values are out
of range.

In `@scalekit/actions/models/requests/update_custom_provider_request.py`:
- Around line 44-53: The auth_patterns field currently allows any-length lists
despite the comment that only a single AuthPattern is supported; add a Pydantic
validator on auth_patterns (e.g., `@validator`("auth_patterns") or a
root_validator inside the same model class, likely UpdateCustomProviderRequest)
that checks if value is not None and len(value) == 1, and raise a ValueError
with a clear message (e.g., "auth_patterns must be a list with exactly one
AuthPattern when provided") to enforce the single-item constraint during
validation.

In `@scalekit/providers.py`:
- Around line 204-211: The ListProvidersRequest construction is passing
filter=filter_obj which will raise if filter_obj is None; update the call that
builds the request (the ListProvidersRequest passed into
self.core_client.grpc_exec / self._stub.ListProviders.with_call) to avoid
passing None for the nested filter field—either omit the filter kwarg when
filter_obj is None or instantiate ListProvidersRequest without filter and set
request.filter = filter_obj only when filter_obj is not None so you never pass
None into the protobuf constructor.

In `@tests/test_providers.py`:
- Around line 25-30: The teardown currently swallows all exceptions when calling
self.scalekit_client.actions.providers.delete_custom_provider(DeleteCustomProviderRequest(identifier=self.created_identifier)),
which hides failures; change this to catch only expected exceptions or let
errors surface and log them—e.g., replace the broad except Exception: pass with
either re-raising the exception after logging via the test logger or asserting
deletion succeeded, or catch a specific API-not-found exception if that's
acceptable; ensure you reference delete_custom_provider,
DeleteCustomProviderRequest, and self.created_identifier so the deletion failure
is visible in CI logs rather than silently ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 19b68869-ad1e-4242-ab58-16e90e08582c

📥 Commits

Reviewing files that changed from the base of the PR and between c2f476a and f6c54f6.

📒 Files selected for processing (16)
  • .gitignore
  • REFERENCE.md
  • scalekit/actions/actions.py
  • scalekit/actions/models/custom_provider.py
  • scalekit/actions/models/requests/create_custom_provider_request.py
  • scalekit/actions/models/requests/delete_custom_provider_request.py
  • scalekit/actions/models/requests/list_providers_request.py
  • scalekit/actions/models/requests/update_custom_provider_request.py
  • scalekit/actions/models/responses/create_custom_provider_response.py
  • scalekit/actions/models/responses/delete_custom_provider_response.py
  • scalekit/actions/models/responses/list_providers_response.py
  • scalekit/actions/models/responses/update_custom_provider_response.py
  • scalekit/actions/types.py
  • scalekit/client.py
  • scalekit/providers.py
  • tests/test_providers.py

Comment thread REFERENCE.md Outdated
Comment thread scalekit/actions/models/custom_provider.py Outdated
Comment thread scalekit/actions/models/requests/create_custom_provider_request.py
Comment thread scalekit/actions/models/requests/delete_custom_provider_request.py
Comment thread scalekit/actions/models/requests/list_providers_request.py
Comment thread scalekit/actions/models/requests/update_custom_provider_request.py
Comment thread scalekit/providers.py Outdated
Comment thread tests/test_providers.py
- Fix protobuf filter=None TypeError in ProvidersClient.list_providers
- Constrain AuthField.input_type to Literal['text','password']
- Constrain AuthPattern.type to Literal['OAUTH','BEARER','API_KEY']
- Enforce cross-field invariants: OAUTH requires oauth_config and no fields;
  BEARER/API_KEY require oauth_config=None
- Add HTTPS validation for proxy_url in create/update requests
- Add min_length=1 to identifier in delete/update requests
- Constrain provider_type to valid enum values (0/1/2) and page_size >= 1
- Enforce single-item auth_patterns in create/update requests
- Replace bare except Exception in tearDown with ScalekitNotFoundException
- Replace #### headings with bold text in REFERENCE.md Custom Providers section
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scalekit/actions/models/requests/list_providers_request.py`:
- Around line 34-40: The identifier field on ListProvidersRequest currently
allows empty strings; change validation to reject empty values by either typing
identifier as Optional[constr(min_length=1)] (or adding Field(...,
min_length=1)) or adding a Pydantic validator on ListProvidersRequest for
'identifier' that raises a ValueError when identifier == "" so only None or
non-empty strings are accepted.

In `@scalekit/actions/models/requests/update_custom_provider_request.py`:
- Around line 56-60: The current validator validate_proxy_url_https only checks
that proxy_url starts with "https://", allowing malformed values like
"https://"; update it to perform proper URL validation by either changing the
proxy_url field to a Pydantic type such as HttpUrl/AnyHttpUrl or, if keeping a
string, parse and validate using urllib.parse (or validators.url) inside
validate_proxy_url_https: ensure scheme == "https" and that parsed_url.netloc is
non-empty (and optionally check port/hostname validity), and raise ValueError if
the URL is malformed so only well-formed HTTPS endpoints pass.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a95429bb-b913-4225-8618-50cd6d0a3cd0

📥 Commits

Reviewing files that changed from the base of the PR and between f6c54f6 and 92b3b5a.

📒 Files selected for processing (8)
  • REFERENCE.md
  • scalekit/actions/models/custom_provider.py
  • scalekit/actions/models/requests/create_custom_provider_request.py
  • scalekit/actions/models/requests/delete_custom_provider_request.py
  • scalekit/actions/models/requests/list_providers_request.py
  • scalekit/actions/models/requests/update_custom_provider_request.py
  • scalekit/providers.py
  • tests/test_providers.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • scalekit/actions/models/requests/create_custom_provider_request.py
  • scalekit/providers.py
  • REFERENCE.md
  • tests/test_providers.py

Comment thread scalekit/actions/models/requests/list_providers_request.py
Comment thread scalekit/actions/models/requests/update_custom_provider_request.py
- Add min_length=1 to ListProvidersRequest.identifier
- Strengthen proxy_url check to use urlparse (scheme=https + netloc required)
  in both CreateCustomProviderRequest and UpdateCustomProviderRequest
@AkshayParihar33 AkshayParihar33 merged commit 89d7567 into main May 12, 2026
2 checks passed
@AkshayParihar33 AkshayParihar33 deleted the custom-providers-crud branch May 12, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants