Replies: 4 comments
-
|
Following up with the MCP findings and the revised proposal.
DesignThe key distinction
It comes down to where the discriminator lives. REST/LLM split on the route, which the controller owns — so the controller can offer a generic "global = drop the route from the key." MCP splits on the payload, which only the policy can read — so scope is the policy's call, and there's no generic controller switch for it. MCP: api-level works, but "global" is policy-boundMCP already attaches policies server-wide: The catch is that MCP rate-limit scope is decided by the policy, not the route. Every MCP call is JSON-RPC over the same endpoint, so "methods": [ { "name": "*", "limits": [ { "limit": 5, "duration": "1m" } ] } ]That's 5/min per distinct method (separate buckets for So a generic "make any policy global" doesn't fit MCP: the unit being counted is defined and parsed by the policy itself, and each policy differs. Api-level support here is really policy-bound — the controller already treats every policy as api-level; global vs per-capability is up to the policy. LLM: one list vs two, and ordering
Point 1 — how do mixed entries order?
Preference: (ii) grouping, for the reasons below. Point 2 — implementation cost (grouping vs custom order)
Point 3 — would custom ordering pull LLM away from REST and MCP? Yes. REST groups (api → resource); MCP is single-level. Custom interleaving makes LLM a third model:
Discussion points
|
Beta Was this translation helpful? Give feedback.
-
|
Following is the finalised feature design:
Designspec:
# ...
globalPolicies: # global: applies to ALL operations, evaluated first
- name: basic-ratelimit
version: v1
params:
limits: [ { requests: 100, duration: "1m" } ]
operationPolicies: # operation-level: evaluate after global policies
- name: token-based-ratelimit
version: v1
paths:
- path: /chat/completions
methods: [POST]
params: { totalTokenLimits: [ { count: 1000, duration: "1m" } ] }
policies: # current operation-level policy array (deprecated, but supported for backward compatability)
- name: token-based-ratelimit
version: v1
paths:
- path: /chat/completions
methods: [POST]
params: { totalTokenLimits: [ { count: 1000, duration: "1m" } ] }A pending action item was to determine the appropriate wording for resource-level policies:
|
Beta Was this translation helpful? Give feedback.
-
|
Update on the feature design:
globalPolicies:
type: array
description: Global (api-level) policies applied across ALL operations as one shared scope, evaluated before operation-level policies.
items:
$ref: "#/components/schemas/Policy"
operationPolicies:
type: array
description: Operation-level policies scoped to specific paths/methods, evaluated after global policies.
items:
$ref: "#/components/schemas/OperationPolicy"
policies:
deprecated: true
type: array
description: DEPRECATED - use operationPolicies. Still honoured (treated identically to operationPolicies).
items:
$ref: "#/components/schemas/LLMPolicy"
|
Beta Was this translation helpful? Give feedback.
-
|
Update on the backward-compatibility discussion:
Also, the following were discussed to be added as new packages to handle these data transformations:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Problem
On a REST API you can attach a policy at the API level (
spec.policies) and it applies to every resource at once. For rate limiting that gives you one shared bucket for the whole API — use up the limit on one resource and the rest are limited too.You can't do this on an LLM provider or proxy. Every policy has to be tied to specific
paths, so it only ever covers those resources — there's no way to apply something across the whole provider, like one rate limit shared by all resources or one guardrail that covers everything.Under the hood, when an LLM artifact is turned into a REST API its policies are always attached per-resource, never at the API level.
Solution
Introduce a global policy scope for LLM providers and proxies: policies applied across all resources as a single shared scope, evaluated before any resource-level policy. The capability is policy-agnostic (accepts any policy type); rate limiting is the primary motivating use case. Existing path-scoped policies are unchanged.
Design
Options considered
globalPoliciessection ✅ (proposed)policies, reusing the existing genericPolicyschema (name/version/params, no paths).LLMPolicyuntouched.policiesand its validation are intact.policiespathson an entry in the existingpolicieslist ⇒ global.LLMPolicy: makepathsoptional, add top-levelparams; add a rule to rejectpaths+paramstogether.pathssilently becomes "global" instead of erroring.scopeflagscope: global|resourceto a policy entry.LLMPolicy.resource), butpathsis dead weight whenscope=global./or/*with methods["*"]as global.Proposed: Option A — a separate
globalPoliciessectionKeep the existing path-bound
spec.policies(resource-level) exactly as-is, and add a new optionalspec.globalPolicieslist that reuses the genericPolicyschema already used by REST APIs:Why Option A
LLMPolicyis not touched, sopathsstays required and no existing artifact, validation rule, or behaviour changes. (Option B has to mutateLLMPolicyand add an ambiguity rule.)globalPoliciesis[]Policy(the generic policy type), so a global policy of any kind is routed straight into the api-level chain with no conversion and no per-policy special-casing.Naming: the field is
globalPoliciesto match the existing "Global Guardrails & Policies" UI label, and it reads naturally for both providers and proxies. The existing path-boundpoliciesis the "Resource-wise" list and is left unchanged. (Note the cross-artifact asymmetry: on LLM artifactspoliciesis resource-level, while on RESTpoliciesis api-level — forced by backward-compat, since LLM'spoliciesis already path-bound.)Implementation outline
globalPoliciesinto the derived REST API'sspec.policiesduring the LLM→REST transform; path-scopedpolicieskeep their per-operation attachment. No change to the REST transformer or the policy-engine — global policies reuse the existingattachedTo: "api"api-level path (taggedLevelAPI, prepended to every route, api-scoped bucket key for stateful policies).globalPolicies: []PolicytoLLMProviderConfigDataandLLMProxyConfigData; regenerate types.Discussion points
globalPoliciesaccept any policy type (as REST api-level does), or be restricted to a curated set that is meaningful globally?globalPolicies; alternatives welcome:globalPolicies(proposed) — matches the existing "Global Guardrails & Policies" UI label; reads naturally for both providers and proxies.sharedPolicies— emphasises the single shared scope/bucket.Beta Was this translation helpful? Give feedback.
All reactions