Protect a portfolio slice by applying one Universal (canonical) policy across API instances on any gateway (Kong, Apigee, Azure, AWS, MuleSoft). Use when the user says all / many / my APIs / a portfolio slice — JWT validation, rate limiting, spike arrest, IP filtering, or apply one config across providers. DO NOT TRIGGER for "what protection do I have" / listing or editing already- applied native policies — use skill apply-native-policy-to-instance. DO NOT TRIGGER for a single already-chosen instance that needs a provider-native plugin — same skill. Do not use to remove, detach, enable, or disable a policy (those tools do not exist).
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Protect APIs across gateways with one Universal policy: discover what is missing, collect configuration once, apply in one call, and wait until the work has actually finished.
Use this skill when the user asks to:
Trigger keywords: all my APIs · portfolio · missing this policy · universal policy · canonical policy · JWT validation · rate limiting · spike arrest.
Do NOT use this skill when:
You must be connected to the MuleSoft Platform MCP Server
(urn:mcp:mulesoft-platform). Probe with a read-only call:
list_universal_policies. If the tool is not in the catalog, STOP
and say the Platform MCP catalog on this host does not include the Universal
policy tools yet. Do not substitute Anypoint REST calls.status=not_configured or
an empty policies list with that message), say so and stop — do not invent
a fallback apply path.references/presentation-format.md — pinned tables. Read it when you
are about to render a user-facing list, schema, mapping, or result.references/payloads.md — how to join find_assets rows and branch on
apply status. Read it before the first apply.This skill is Protect only. If the latest turn is "what's applied" or "change this native policy", switch to skill apply-native-policy-to-instance — do not run Steps 1–4.
apply_universal_policy. A missing confirmation writes
policies the user did not approve.policyCoverage + instancesMissingPolicy,
never on hasPolicy alone (hasPolicy is any-instance and would skip
unprotected siblings).instancesMissingPolicy is {instanceId, environment} only. Build display rows and instance_ids using
references/payloads.md — do not invent names or providers.references/presentation-format.md),
then collect the entire configuration for the fields you showed in one
reply. Reuse it across every targeted instance. Never walk field by field.accepted / HTTP 202) is not
success. Poll until COMPLETED or FAILED. Distinguish retryable vs
terminal from error.retryable.providerMapping, not IDs.Call find_assets with:
query — search terms from the request (names, "finance", "payments").
Include tag-like words when the user said "tagged", but do not claim a
tag filter the backend did not apply — if hits look unrelated, say you
searched by those terms.asset_type — api when they mean APIs (expands to the API Exchange types)user_query — the verbatim user messageinclude_applied_policies — truepolicy_name_filter — the protection they named ("JWT validation",
"rate-limiting"; matching is case- and separator-insensitive)max_results — raise it when they asked for "all" / a large slice
(default is 20)If userOrgAssets is empty, say you found no matching API instances and
stop. Do not search the public catalog for apply targets.
Present the API-instance list (references/presentation-format.md)
using the join in references/payloads.md. Summarize per instance:
"N instances found, M missing this policy, K unknown."
Coverage rules:
policyCoverage | Meaning | Apply to |
|---|---|---|
all | Every readable instance has it | skip (already protected) |
partial / none | Some or none have it | exactly the joined instancesMissingPolicy |
unknown | Incomplete read (error or cap) | re-check with view_api_instance_policies. Never count as missing. |
If appliedPolicyEnrichment.assetCapApplied is true, fan out
view_api_instance_policies for the remaining instances rather than
treating the truncated set as complete.
[GATE] Wait for the user to confirm they want you to fix the gap.
Call list_universal_policies with policy_name_hint from the user's
protection. If more than one template matches, list their labels and ask
which to use — do not pick silently.
Each entry has configurationSchema, supportedProviders, and
providerMapping (what it becomes on Kong / Apigee / …).
Drop any target instance whose provider is not in supportedProviders. If
that leaves none, say so and stop. Keep the surviving list — that is the
apply set for Steps 3–4, not the raw Step 1 missing list.
Present the policy configuration schema table
(references/presentation-format.md). If the flattened schema is too long
to scan, show required fields only, say how many optionals are hidden, and
offer to expand. Then ask the user to fill the visible fields in one
reply. Do not invent optional values; omitted hidden fields keep schema
defaults.
Build the policy → API + instance mapping by joining each remaining
instance's provider to providerMapping. Show it. [GATE] Wait for okay.
Call apply_universal_policy once with:
policy_name — the canonical kebab-case template nameinstance_ids — remaining missing instances from Step 2 (after the
provider drop), not the raw Step 1 listconfiguration — the collected config, reused as-isDo not loop apply_policy_to_instance for a Universal/canonical template.
That tool is one native plugin on one instance — skill apply-native-policy-to-instance.
Branch on the apply status (references/payloads.md):
accepted — poll get_policy_operation_status with operationId until
COMPLETED or FAILED (not RUNNING). A few seconds between polls;
give up after ~20 attempts and report Still running.ok — synchronous success. Report immediately. Do not poll.partial — some targets failed. Report Partially succeeded from
results. Do not poll.Then the same policy → API + instance mapping as the preview (now as
the result). On FAILED, say whether error.retryable is true.
policy_name_filter + apply GATE on an audit turn.apply_universal_policy with the
Step-2 remaining ids. ❌ looping native apply; ❌ sending the pre-drop
Step 1 list.instanceId as in
references/payloads.md. ❌ filling provider/name from memory.Universal policy tools are missing from the catalog: say so and stop. Do not substitute Anypoint REST calls.
policyCoverage is unknown, or the table shows ?: re-read those
instances with view_api_instance_policies. Do not apply as if they were
missing.
403 / not entitled / gate closed: the org cannot manage that provider's policies. Say so plainly and stop.
Apply returned ok or partial and you started polling: those statuses
are already terminal. Report from results; only accepted has an
operationId to poll.
User asks to undo / remove / disable the policy: not supported. There is no detach tool and no enable/disable parameter on the agent surface. Explain and stop.
urn:api:*), not MCP.4cf0cf6
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.