One Agent Plugin Package Can Hide Four Trust Decisions
Agent Plugins 1.0 makes skills and MCP tools portable, but installation, execution, authority, and updates still need separate review.
GitHub's 12 August Agent Plugins 1.0 release makes one package usable across VS Code, Copilot CLI, the Copilot app, and compatible agent clients. A plugin can combine reusable skills with Model Context Protocol servers, while client-specific behaviour lives in a namespaced directory. GitHub positions this as an answer to duplicated manifests and layouts across agent products.
That portability is useful. It also changes the unit operators are asked to trust. Installing one plugin can add instructions the model follows, launch a local executable, connect to a remote MCP endpoint, and activate client-specific hooks or commands. Those components travel together, but they do not have the same risk, authority, or failure mode.
The Agent Plugins 1.0 specification, published on 6 August, makes an important boundary explicit: it standardises package shape, component discovery, path containment, and some connection configuration. It does not turn the package manifest into a permission manifest, sandbox an MCP subprocess, define portable credentials, or govern how clients install and update plugins.
The repeated angle to avoid
The ten most recent posts here covered agent context copies, form-security boundaries, server-side agent conversion tracking, agent ROI receipts, prototype exits, Copilot billing handovers, code-quality policy, comment-triggered agents, gateway budgets, and model entitlements. Older overlapping posts covered agent harnesses, review-agent instructions, worktree isolation, MCP authorization, runtime credentials, package malware, and permission budgets.
The weak version would repeat the old X needs Y formula: agent plugins need governance. The sharper thesis is that plugin portability compresses four independent trust decisions into one install action. The useful operator response is not a generic approval list. It is a component-level receipt that shows what the package can instruct, execute, reach, and extend in every client where it is enabled.
Fresh evidence and background context
The source map separates this week's primary evidence from durable implementation context:
| Source | Freshness | What it contributes |
|---|---|---|
| Agent Plugins 1.0 in GitHub clients | 12 August 2026 | Cross-client support, marketplace installation, portable skills and MCP configuration, Copilot-specific namespaces, managed marketplaces, and MCP allowlists |
| Agent Plugins Specification v1.0.0 | Published 6 August 2026 | Exact package boundaries, manifest fields, component loading, subprocess configuration, secret limitations, client extensions, and failure isolation |
| Build an Agent Plugin | Current official author guide for v1.0 | Minimal package layout and the explicit boundary between portable format and client-managed installation, updates, enablement, and UI |
| Cloudflare's next-generation MCP implementation | 6 August 2026 | Fresh evidence that MCP authorization depends on client identity, resource audience, method context, and gateway policy rather than package discovery alone |
| Agent runtime harnesses | Background, 13 June 2026 | The earlier distinction between portable runtime concepts and provider-specific permissions, sessions, tools, and events |
The first three sources describe the same standard from announcement, normative, and authoring perspectives. Cloudflare's MCP work supplies the execution-side contrast: finding a server configuration is not the same as authorising a caller to use its tools.
Portability standardises discovery, not consequences
A minimal portable package can be tiny:
customer-ops-plugin/
├── plugin.json
├── skills/
│ └── triage-lead/
│ └── SKILL.md
├── mcp.json
└── com.github.copilot/
└── hooks/
The standard gives those files predictable locations. plugin.json identifies the package. Immediate children of skills/ can expose Agent Skills. mcp.json can declare local or remote MCP servers. A reverse-domain directory can hold behaviour for one client without changing the portable core.
That solves a packaging problem. It does not make all four layers equivalent:
| Layer | What the package may add | Trust question |
|---|---|---|
| Instruction | Skills, references, scripts, and operating guidance | What behaviour can the model be persuaded to follow, and in which contexts? |
| Local execution | A stdio MCP command plus arguments, environment, and working directory |
What process starts, under which OS identity, with access to which files and ambient variables? |
| Remote authority | A streamable HTTP or legacy SSE MCP endpoint | Which principal authenticates, which tools are exposed, and what records or side effects can they reach? |
| Client extension | Namespaced commands, agents, rules, hooks, canvases, or other client-defined features | What extra behaviour does this client load that another compatible client ignores? |
The installation interface may present one plugin name. The operating system underneath sees several different mechanisms.
The manifest is identity metadata, not an authority declaration
The v1 manifest schema is intentionally small. Its permitted top-level fields cover schema version, name, version, description, author, homepage, repository, licence, keywords, and namespaced extensions. It does not contain portable fields such as permissions, network, filesystem, secrets, tools, approval_required, or data_classes.
That is not a defect in the specification. Permission semantics differ across clients, operating systems, MCP servers, and business workflows. Pretending one portable boolean could describe them would create false assurance.
It does create an implementation consequence: a marketplace card or valid plugin.json cannot answer whether installation is safe for a checkout repository, a customer-support workspace, or an internal documentation project.
Treat manifest validation as the first gate only:
- Identity gate: Does the package name, version, repository, author, and source match what the operator intended to install?
- Content gate: Which skills, scripts, executable files, MCP entries, and client namespaces are actually present in this version?
- Authority gate: What can the resulting processes and remote servers read or change in this environment?
- Lifecycle gate: Who controls updates, what changes require reapproval, and how can the package be disabled or rolled back?
A package can pass the identity gate and still fail the other three.
Path containment is not process sandboxing
The specification has useful containment rules. Plugin-relative paths must start with ./ and remain inside the resolved plugin root. Clients must reject paths that escape through .., symlinks, junctions, or equivalent mechanisms. A bundled executable must be referenced with a plugin-relative command.
Those rules prevent a package from disguising an outside file as one of its own components. They do not contain what a launched process can do after it starts. The specification says this directly: package-path containment does not sandbox a plugin subprocess or restrict paths supplied at runtime.
Consider a valid local MCP entry:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"lead-tools": {
"type": "stdio",
"command": "./bin/lead-tools",
"args": ["--data", "${PLUGIN_DATA}/leads"],
"cwd": "${PLUGIN_ROOT}"
}
}
}
This can conform perfectly. The process may still inherit network access, user-readable files, repository credentials, cloud CLI sessions, or other ambient capabilities depending on the client and host. ${PLUGIN_DATA} is a persistent writable directory for plugin state; it is not automatically a secure vault. ${PLUGIN_ROOT} proves where packaged files came from; it does not prove what the executable does.
For local servers, review the runtime envelope separately:
- OS user and group;
- inherited versus sanitised environment variables;
- readable and writable filesystem roots;
- allowed network destinations;
- child-process permission;
- repository and workspace scope;
- persistent data location and deletion path;
- resource limits, timeout, and termination behaviour;
- logs and payload retention.
A plugin that formats public Markdown deserves a different envelope from one that can read production logs or update customer records.
MCP configuration discovers an endpoint; it does not grant safe authority
The portable mcp.json format supports local stdio, current streamable-http, and legacy sse transports. For remote endpoints, non-loopback connections must use HTTPS. The spec also prevents configured headers from being forwarded to a different origin through redirects without explicit authorisation.
Those are valuable transport protections. They are not an access policy.
Agent Plugins v1 deliberately defines no portable OAuth configuration or credential-reference fields. Static header and environment values are visible package data and must not contain credentials. Authentication discovery, user interaction, and credential storage belong to the client.
That separation means the same package can have different effective authority in two installations:
plugin package
-> client A authenticates as read-only support analyst
-> client B authenticates as CRM administrator
The package version is identical. The reachable business actions are not.
Cloudflare's recent MCP design work reinforces the point. Its implementation makes protocol version, client identity, capabilities, request method, authorization server, and resource audience more explicit. These are request-time controls. A marketplace allowlist can approve the package source, while an MCP allowlist can approve a server address, yet neither says whether refund_order, publish_page, change_dns, or export_customers should be available to this principal in this workflow.
Use a second allowlist at the tool boundary:
| Control | Good for | Not sufficient for |
|---|---|---|
| Approved marketplace | Limiting where packages can be discovered | Proving package contents or runtime behaviour |
| Approved plugin name/version | Pinning a reviewed distribution artifact | Restricting the authority of its MCP credentials |
| Approved MCP server URL or command | Blocking unknown connections and executables | Restricting individual tools or business records |
| Tool and capability policy | Limiting read, draft, or mutation operations | Proving the package has not changed |
| Human or policy confirmation | Authorising a sensitive action now | Controlling unattended retries or later updates |
Each control answers a narrower question. Keeping them separate makes incidents diagnosable.
Client-specific directories break the illusion of identical behaviour
GitHub's migration guidance puts Copilot-specific files under com.github.copilot/, which other clients ignore. In Copilot clients, that directory can carry custom agents, commands, rules, hooks, and extensions such as canvases. The core standard intentionally assigns no portable loading or failure semantics to another client's namespace.
This is the correct extensibility design. It also means "works across clients" does not mean "behaves identically across clients."
A plugin may expose the same skill and MCP server everywhere while adding a pre-tool hook in one client, a custom command in another, and no equivalent control in a third. A policy tested in VS Code can therefore disappear when the package runs in a CLI that ignores that namespace—or a client-specific hook can add behaviour that a reviewer never saw in the portable files.
Build a client conformance matrix before broad rollout:
| Question | VS Code | Copilot CLI | Copilot app | Other client |
|---|---|---|---|---|
| Loads skills | Test | Test | Test | Test |
| Loads local MCP | Test | Test | Test | Test |
| Loads remote MCP | Test | Test | Test | Test |
| Loads namespaced hooks or rules | Record | Record | Record | Record |
| Prompts before sensitive tools | Exercise | Exercise | Exercise | Exercise |
| Sanitises ambient environment | Verify | Verify | Verify | Verify |
| Stores credentials in approved location | Verify | Verify | Verify | Verify |
| Pins and reports plugin version | Verify | Verify | Verify | Verify |
| Produces an uninstall and data-deletion path | Exercise | Exercise | Exercise | Exercise |
Do not fill this table from marketing compatibility claims. Exercise it with the actual client version, account policy, and workspace type your team uses.
A plugin installation receipt
The operator asset should join the portable artifact to the local authority it receives. Keep one receipt per plugin version and client policy combination:
agent_plugin_install_receipt:
plugin:
name: customer-ops-plugin
version: 1.2.0
source_marketplace: approved-internal-marketplace
repository: https://github.com/example/customer-ops-plugin
reviewed_commit: 4f81d2c
artifact_digest: recorded-by-installer
portable_components:
skills:
- triage-lead
local_mcp:
- lead-tools
remote_mcp:
- https://crm.example.com/mcp
client_namespaces:
- com.github.copilot
instruction_review:
allowed_tasks:
- classify_lead
- draft_follow_up
blocked_tasks:
- publish_offer
- alter_qualification_policy
runtime:
client: copilot_cli
client_version: tested-version
workspace_scope: selected_repository
ambient_environment: sanitised
network_allowlist:
- crm.example.com
persistent_data: approved-plugin-data-directory
authority:
principal: customer-ops-agent
tool_capabilities:
- read_lead
- create_follow_up_draft
blocked_capabilities:
- export_customers
- delete_lead
- send_message
confirmation_required:
- update_lead_status
lifecycle:
version_pin: 1.2.0
automatic_updates: false
reapprove_when:
- skill_content_changes
- mcp_entry_changes
- executable_digest_changes
- client_namespace_changes
- requested_capabilities_change
disable_owner: operations
data_deletion_tested: true
The package does not have to provide every field. In fact, it cannot know several of them. The installer or operator records the client, principal, environment, and business authority because those facts exist outside the portable artifact.
Update policy should follow changed capability, not version label
The specification recommends Semantic Versioning, but clients are free to use the plugin version for update checks and cache freshness. A patch release can still alter skill wording, replace a bundled executable, point to a different remote service, or change client-specific hooks. SemVer describes the publisher's compatibility intention. It is not evidence that effective authority stayed constant.
Calculate review scope from the package diff:
- Manifest metadata only: verify identity and distribution record.
- Skill or reference change: rerun instruction and prompt-injection fixtures.
- Local executable or script change: repeat provenance, malware, sandbox, and runtime tests.
- MCP URL, command, argument, environment, or working-directory change: require connection and authority review.
- Client namespace change: retest only affected clients, but do not assume ignored clients are unchanged if shared components also moved.
- Requested tool or data-class change: require business-owner approval, even if the version bump is minor.
A digest or reviewed commit belongs in the receipt because a human-readable version alone does not identify the exact bytes that were installed.
Failure modes worth exercising
The skill is harmless, but the server is not
Reviewers read SKILL.md, approve the wording, and miss that mcp.json launches a new binary or connects to a write-capable CRM server. Inventory components before evaluating prose.
One client enforces a hook that another ignores
A sensitive tool requires confirmation in the Copilot-specific extension, but another compatible client loads the portable MCP server without that extension. Put essential authorisation at the server or business-operation boundary, not only in client-specific behaviour.
A valid path launches an over-privileged process
The executable stays inside the plugin root and passes schema validation, then reads ambient cloud credentials from the host. Run local MCP processes with a sanitised environment and the narrowest filesystem and network access the task permits.
A remote endpoint is approved too broadly
The server URL is allowlisted, so every tool exposed by that server is treated as safe. Separate server trust from tool capability, principal identity, resource scope, and confirmation policy.
Automatic update changes effective authority
A marketplace update adds a local server or a namespaced hook without changing the plugin's familiar name. Diff package components and reapprove on capability changes.
Uninstall leaves credentials or state behind
The client removes the package but preserves ${PLUGIN_DATA}, cached tokens, server-side grants, or audit records indefinitely. Test local deletion and remote revocation as separate steps.
The practical conclusion
Agent Plugins 1.0 removes real duplication. A developer can package a skill and its MCP integration once, compatible clients can discover the same structure, and organisations can use managed marketplaces and plugin settings instead of inventing a format for every agent surface.
The standard is strongest when operators respect what it does not claim. A valid manifest identifies a package. Path rules contain package files. MCP configuration describes how to start or connect. Namespaces preserve client-specific features. None of those statements, alone, proves that the installed capability is appropriate for customer data, production code, payments, publishing, CRM records, or DNS.
Review the four trust decisions separately, then join them in one installation receipt. That preserves the benefit of portability without letting one convenient Install button silently approve instructions, executables, remote authority, and client extensions as if they were the same thing.