feat: custom provider CRUD for MCP connectors#159
Conversation
…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.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds 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. ChangesCustom Providers Feature
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)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (16)
.gitignoreREFERENCE.mdscalekit/actions/actions.pyscalekit/actions/models/custom_provider.pyscalekit/actions/models/requests/create_custom_provider_request.pyscalekit/actions/models/requests/delete_custom_provider_request.pyscalekit/actions/models/requests/list_providers_request.pyscalekit/actions/models/requests/update_custom_provider_request.pyscalekit/actions/models/responses/create_custom_provider_response.pyscalekit/actions/models/responses/delete_custom_provider_response.pyscalekit/actions/models/responses/list_providers_response.pyscalekit/actions/models/responses/update_custom_provider_response.pyscalekit/actions/types.pyscalekit/client.pyscalekit/providers.pytests/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
There was a problem hiding this comment.
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
📒 Files selected for processing (8)
REFERENCE.mdscalekit/actions/models/custom_provider.pyscalekit/actions/models/requests/create_custom_provider_request.pyscalekit/actions/models/requests/delete_custom_provider_request.pyscalekit/actions/models/requests/list_providers_request.pyscalekit/actions/models/requests/update_custom_provider_request.pyscalekit/providers.pytests/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
- Add min_length=1 to ListProvidersRequest.identifier - Strengthen proxy_url check to use urlparse (scheme=https + netloc required) in both CreateCustomProviderRequest and UpdateCustomProviderRequest
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
ProvidersClient(gRPC layer) +ActionProvidersfacade with typed Pydantic request/response modelsOAUTH(with PKCE),BEARER, andAPI_KEY, each with configurable credential fieldsREFERENCE.mdupdated with usage examples for all four operationsTest plan
make testwithSCALEKIT_ENV_URL,SCALEKIT_CLIENT_ID,SCALEKIT_CLIENT_SECRETset intests/.envtest_oauth_mcp_create_and_list,test_bearer_mcp_create_update_and_list, andtest_api_key_mcp_create_and_deleteall passSummary by CodeRabbit
New Features
Documentation
Tests
Chores