AI agents are increasingly moving beyond simple prompt-and-response applications. Enterprise agents now need access to domain-specific policies, operational procedures, reference material, scripts, and tools.
Agent Skills provide a structured way to package that domain expertise and load it only when an agent needs it. In .NET, Microsoft Agent Framework provides a stable Agent Skills API, supporting file-based, class-based, and code-defined skills. Skills can also be discovered from MCP servers, allowing organizations to centralize and distribute skills across multiple agents.
However, centralized skill distribution creates an important enterprise security problem.
A single skills platform may serve hundreds or thousands of agents belonging to different tenants. Not every tenant should see every skill, and not every agent should be allowed to execute every skill operation.
The challenge is therefore not simply:
How do I load an Agent Skill?
It is:
How do I ensure each tenant gets only
the skills, resources, and actions it is authorized to use?
This article presents a practical architecture for building a multi-tenant Agent Skills platform with tenant isolation, authorization, filtering, approval controls, audit logging, and secure MCP-based distribution.
What Is an Agent Skill?
An Agent Skill is a reusable package of domain expertise that an agent can discover and load when required.
A file-based skill can contain:
expense-policy/
├── SKILL.md
├── references/
│ └── reimbursement-rules.md
├── scripts/
│ └── validate-expense.py
└── assets/
The SKILL.md file contains metadata and instructions.
For example:
---
name: expense-policy
description: >
Help employees understand company expense and reimbursement policies.
Use when questions involve travel, meals, accommodation, or reimbursements.
---
## Instructions
1. Identify the expense category.
2. Check the applicable policy.
3. Identify applicable limits.
4. Ask for missing information.
5. Do not approve expenses automatically.
Agent Skills use progressive disclosure: the agent initially sees the skill's metadata and loads detailed instructions or resources only when needed. This keeps unnecessary content out of the agent's context.
Why Multi-Tenancy Changes the Security Model
Consider an enterprise platform with three tenants:
Tenant A → Financial Services
Tenant B → Healthcare
Tenant C → Retail
The platform may contain:
Shared Skills
├── Incident Response
├── Document Analysis
└── General Reporting
Tenant A Skills
├── Financial Compliance
└── Trading Policy
Tenant B Skills
├── Healthcare Compliance
└── Patient Data Handling
Tenant C Skills
├── Retail Returns
└── Inventory Operations
A naive implementation might expose the entire skill directory to every agent.
That creates several problems:
A tenant may discover skills it should not know about.
Sensitive instructions may enter an agent's context.
Scripts may expose unauthorized operations.
A compromised agent could attempt to load another tenant's resources.
Skill updates could unintentionally affect unrelated tenants.
Therefore, tenant isolation must happen before skill content reaches the agent.
Establish Tenant Context First
Every request should have an authenticated tenant identity.
Conceptually:
Incoming Request
|
v
Authentication
|
v
Tenant Resolution
|
v
Authorization
|
v
Skill Filtering
|
v
Agent
Do not allow the model to determine the tenant.
For example, this is unsafe:
var tenantId = agentResponse.TenantId;
The tenant should come from an authenticated request or trusted execution context instead.
A simplified ASP.NET Core model might look like:
public sealed record TenantContext(
string TenantId,
string UserId,
IReadOnlySet<string> Roles);
The application can resolve this context from authenticated claims:
public static TenantContext GetTenantContext(
ClaimsPrincipal user)
{
var tenantId = user.FindFirst("tenant_id")?.Value
?? throw new UnauthorizedAccessException();
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value
?? throw new UnauthorizedAccessException();
var roles = user.FindAll(ClaimTypes.Role)
.Select(c => c.Value)
.ToHashSet();
return new TenantContext(tenantId, userId, roles);
}
The exact claims model depends on the identity provider, but the architectural rule remains the same:
tenant identity must be established outside the model.
Use Allowlisting Instead of Broad Skill Access
Microsoft Agent Framework provides filtering capabilities for shared skill libraries. This is particularly useful in multi-tenant environments because a platform can maintain a large skill repository while exposing only an approved subset to an individual agent.
For example:
var approvedSkills = new HashSet<string>
{
"expense-policy",
"travel-policy"
};
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(
Path.Combine(
AppContext.BaseDirectory,
"skills"))
.UseFilter((skill, context) =>
approvedSkills.Contains(skill.Frontmatter.Name))
.Build();
This is safer than relying on the agent to ignore skills it should not use.
The distinction is important:
Weak model:
Expose everything
↓
Ask agent to choose correctly
Stronger model:
Expose only authorized skills
↓
Agent chooses from approved capabilities
Authorization should be enforced by the application, not delegated entirely to model behavior.
Make Skill Authorization Tenant-Aware
A static allowlist is useful, but multi-tenant platforms normally require dynamic authorization.
For example:
public sealed record SkillAuthorizationContext(
string TenantId,
string UserId,
IReadOnlySet<string> Roles);
The authorization service can evaluate:
public interface ISkillAuthorizationService
{
Task<bool> CanUseSkillAsync(
SkillAuthorizationContext context,
string skillName,
CancellationToken cancellationToken);
}
A filtering layer can then ask the authorization service whether a skill should be exposed.
Conceptually:
Tenant
|
+-- Subscription
|
+-- Roles
|
+-- Skill Entitlements
|
v
Skill Authorization
|
v
Allowed Skills
This gives the platform a central place to enforce policies such as:
Tenant A → expense-policy
Tenant A → financial-reporting
Tenant B → healthcare-policy
Tenant C → inventory-policy
The actual authorization rules should live outside the model prompt.
Separate Skill Discovery from Skill Execution
One of the most important design decisions is to distinguish between:
Discovering a skill.
Loading its instructions.
Reading its resources.
Executing its scripts.
These are not equivalent security operations.
Microsoft's Agent Skills implementation exposes tools including load_skill, read_skill_resource, and run_skill_script. The framework requires approval for these operations by default, providing a human-in-the-loop checkpoint.
A useful security model is:
| Operation | Risk | Recommended Control |
|---|---|---|
| Discover skill | Low | Tenant filtering |
| Load instructions | Medium | Authorization |
| Read resource | Medium | Authorization + tenant isolation |
| Execute script | High | Approval + sandboxing |
| Modify external system | High | Authorization + approval |
| Access sensitive data | High | Data-level authorization |
The mistake is treating all skills as static documentation.
A skill containing executable operations can become an application capability and should therefore be governed like any other privileged operation.
Secure Script Execution
Scripts deserve special treatment.
A skill may contain a script such as:
scripts/
└── validate-provisioning.py
The script could potentially interact with:
Files
Network resources
Databases
Operating-system processes
Environment variables
Cloud credentials
Therefore, never assume that a skill script is safe simply because it came from a trusted repository.
Microsoft's .NET Agent Skills model delegates file-based script execution to a runner supplied by the application, allowing the application to control sandboxing, resource limits, and audit logging.
A conceptual runner boundary might look like:
Agent
|
v
Approval
|
v
Authorization
|
v
Sandboxed Runner
|
+-- CPU limit
+-- Memory limit
+-- Time limit
+-- Restricted filesystem
+-- Restricted network
Do not execute untrusted skill scripts directly with unrestricted application privileges.
Protect MCP-Based Skill Distribution
Agent Skills can also be distributed through MCP servers.
Microsoft's .NET implementation allows an agent to connect to an MCP server and discover skills through UseMcpSkills. The skills can be served as skill-md resources or packaged as archives.
A simplified connection looks like:
await using var client =
await McpClient.CreateAsync(transport);
var skillsProvider =
new AgentSkillsProviderBuilder()
.UseMcpSkills(client)
.Build();
This architecture is powerful because a central team can publish a skill once and make it available to multiple agents without packaging the skill into every application.
But it also introduces a new trust boundary:
Remote MCP Server
|
v
Skill Content
|
v
Agent Runtime
The MCP server is now a source of executable application context.
Therefore, authenticate the MCP connection, authorize the tenant, validate skill metadata, and apply local policy before allowing remote skills into the agent.
Protect Archive-Based Skills
Archive-based skills introduce an additional risk because remote content must be downloaded and extracted.
A malicious archive could contain:
Excessive numbers of files
Extremely large compressed data
Files that expand dramatically after extraction
Microsoft's MCP skills provider exposes explicit limits for archive size, uncompressed size, and file count.
For example:
var skillsProvider =
new AgentSkillsProviderBuilder()
.UseMcpSkills(
client,
new AgentMcpSkillsSourceOptions
{
ArchiveSkillsDirectory =
Path.Combine(
AppContext.BaseDirectory,
"extracted-skills"),
ArchiveMaxFileCount = 50,
ArchiveMaxSizeBytes =
2 * 1024 * 1024,
ArchiveMaxUncompressedSizeBytes =
4 * 1024 * 1024
})
.Build();
These limits protect against oversized downloads, excessive file creation, and decompression-bomb-style payloads.
Remote archive scripts are not executed by this MCP skills integration. The framework treats executable content received through the archive as untrusted.
Use Tenant-Isolated Storage
A multi-tenant skill platform should avoid ambiguous storage layouts.
Instead of:
/skills/
expense-policy/
consider an explicit ownership model:
/skills/
shared/
incident-response/
tenants/
tenant-a/
financial-policy/
tenant-b/
healthcare-policy/
For object storage or databases, use tenant identifiers as part of the storage boundary:
skills/{tenantId}/{skillName}/{version}
The storage layer should still enforce authorization. A path convention alone is not a security boundary.
Version Skills Independently
Centralized skills are useful because they can be updated without rebuilding every agent.
However, this creates a governance challenge.
Suppose:
v1.4 → Approved
v1.5 → New policy
v2.0 → Breaking workflow change
An enterprise platform should know which version each tenant is allowed to consume.
A useful model is:
| Tenant | Skill | Allowed Version |
|---|---|---|
| Tenant A | Expense Policy | 1.x |
| Tenant B | Expense Policy | 1.5 |
| Tenant C | Expense Policy | 2.x |
Do not automatically expose every newly published skill version to every production tenant.
Use controlled rollout where policy or behavior changes can affect business operations.
Add Audit Logging
Every privileged skill operation should produce an audit event.
For example:
public sealed record SkillAuditEvent(
string TenantId,
string UserId,
string SkillName,
string Operation,
string? Version,
bool Approved,
DateTimeOffset Timestamp);
Record events such as:
Skill discovered
Skill loaded
Resource accessed
Script requested
Script approved
Script rejected
Authorization denied
For security investigations, the audit trail should answer:
Who?
Which tenant?
Which agent?
Which skill?
Which version?
Which operation?
When?
Was approval required?
Was approval granted?
What was the result?
Avoid logging sensitive skill contents or user data unnecessarily.
Common Security Mistakes
Trusting the Model With Authorization
A prompt such as:
Never use skills belonging to another tenant.
is not an authorization boundary.
The application must filter and authorize skills before exposing them.
Sharing a Global Skill Cache
A cache keyed only by:
skillName
can accidentally reuse one tenant's resolved skill for another tenant.
Use an isolation-aware cache key when tenant-specific content exists:
tenantId + skillName + version
Microsoft's Agent Skills provider supports caching and optional per-key isolation, which can be useful when serving different skill sets from a shared provider.
Giving Every Tenant the Same Skill Library
Shared infrastructure does not imply shared authorization.
Explicitly distinguish:
Shared Skills
Tenant Skills
Restricted Skills
Executing Scripts With Application Privileges
Do not give a skill unrestricted access to the host operating system.
Use a controlled runner and enforce resource limits.
Treating MCP as a Trusted Network
An MCP connection is still a trust boundary.
Authenticate it, authorize access, validate content, and monitor activity.
Troubleshooting
A Tenant Can See Another Tenant's Skill
Check the filtering layer first.
Verify that the tenant identity is established before skill discovery and that the authorization predicate uses the authenticated tenant context.
Skill Changes Affect Every Tenant
Check whether all tenants reference the same mutable skill version.
Introduce explicit versioning or tenant-specific release channels.
The Same Skill Appears With Different Content
Inspect caching.
If tenant-specific skill content is being cached, ensure the cache key includes the tenant or another appropriate isolation boundary.
A Remote Skill Consumes Excessive Disk Space
For archive-based MCP skills, configure archive size, uncompressed-size, and file-count limits. These controls are specifically designed to prevent oversized or decompression-heavy archives from consuming excessive local resources.
A Script Requires Human Approval
This is expected behavior.
Agent Skills' privileged tools require approval by default. The application can implement its approval workflow and selectively relax controls for trusted operations.
Recommended Multi-Tenant Architecture
A production-oriented architecture can look like this:
Identity Provider
|
v
Authentication
|
v
Tenant Resolver
|
v
Authorization Service
|
+----------+----------+
| |
v v
Skill Registry MCP Skill Server
| |
+----------+----------+
|
v
Skill Filtering
|
v
Agent Framework
|
+--------+--------+
| |
v v
LLM Provider Approval Service
|
v
Script Runner
The key security principle is that the model sits inside a set of application-controlled boundaries.
The model should not be responsible for deciding whether a tenant is entitled to a skill.
Security Checklist
Before deploying a multi-tenant Agent Skills platform, verify:
Tenant identity comes from trusted authentication context.
Skill authorization is enforced outside the model.
Skills are filtered before being exposed to the agent.
Tenant-specific skill storage is isolated.
Cache keys prevent cross-tenant data reuse.
Skill versions are controlled.
Remote MCP connections are authenticated.
Remote skill content is treated as untrusted input.
Archive extraction limits are configured.
Script execution uses a controlled runner.
Privileged operations require approval where appropriate.
Skill operations are audited.
Sensitive content is excluded from unnecessary logs.
Production skills are reviewed before release.
Frequently Asked Questions
Can multiple tenants use the same Agent Skills server?
Yes. A central MCP or skills server can distribute skills to multiple agents and organizations. However, tenant-specific authorization and filtering must be enforced before the skill is exposed to an agent. MCP-based skills are specifically designed to support centralized distribution.
Should every tenant have a separate MCP server?
Not necessarily.
A shared server can be appropriate when strong tenant-aware authorization and isolation controls exist. Separate servers may be preferable when regulatory, network, or data-isolation requirements demand stronger physical or deployment boundaries.
Are Agent Skills themselves executable code?
Not necessarily. A skill can consist of instructions and reference resources. Some skills can also contain scripts, which introduce a substantially higher security risk and require controlled execution.
Can an Agent Skill bypass application authorization?
The skill should never be treated as an authorization mechanism.
Application services, APIs, databases, and external systems should independently enforce their own authorization requirements.
Is Agent Skills for .NET production-ready?
Microsoft announced the .NET Agent Skills API as stable and production-ready in July 2026. The separate MCP-based skills integration is documented as experimental, so organizations adopting MCP-based skill discovery should account for potential API or specification changes.
Conclusion
Agent Skills solve an important problem for enterprise AI systems: they allow domain expertise, instructions, resources, and workflows to be packaged and reused without embedding everything into an agent's core prompt.
For a multi-tenant platform, however, centralized skill distribution also creates a new authorization boundary.
The safest architecture is to treat every skill as a capability that must pass through multiple controls:
Authenticate
↓
Resolve Tenant
↓
Authorize
↓
Filter Skills
↓
Load Skill
↓
Approve Sensitive Operations
↓
Execute in Controlled Environment
↓
Audit
The model should decide which authorized capability is relevant, not whether the user is authorized to access that capability.
This distinction becomes especially important when skills are distributed through MCP. Microsoft now supports discovering skills directly from MCP servers in .NET, making centralized skill distribution practical, but also making MCP a meaningful trust boundary in the application architecture.
For enterprise teams, the objective should not be to expose the largest possible skill library. It should be to expose the smallest authorized capability set required for each tenant and agent, with explicit controls around data access, script execution, versioning, and auditing.
That is the foundation for building Agent Skills that are not only useful, but governable in a multi-tenant production environment.

Join the conversation! Your thoughts help the community grow.