Microsoft 365 Copilot Extensibility — Complete Guide
Plugins · Declarative Agents · Graph Connectors · Security · Scenarios · Cheat Sheet
Table of Contents
- Core Concepts — Basics
- Plugins — API Plugins & Message Extensions
- Declarative Agents
- Microsoft Graph Connectors
- Security, Governance & Responsible AI
- Scenario-Based Questions
- Cheat Sheet — Quick Reference
1. Core Concepts — Basics
What is Microsoft 365 Copilot and what does it do?
Microsoft 365 Copilot is an AI assistant integrated across Microsoft 365 apps (Teams, Outlook, Word, Excel, PowerPoint, SharePoint, Loop). It combines large language models (GPT-4 class) with the Microsoft Graph — giving it access to your organisation's data (emails, meetings, documents, chats) to generate contextually relevant responses.
Key capabilities:
- Microsoft 365 Chat (BizChat): cross-app AI assistant — ask questions across emails, meetings, documents, chats
- In-app Copilot: context-aware AI within specific apps — Word (draft, rewrite), Excel (analyse data), PowerPoint (create), Teams (meeting summaries)
- Extensibility: developers extend Copilot with plugins, agents, and Graph Connectors
Key positioning: M365 Copilot = LLM + Microsoft Graph (your org data) + Microsoft 365 apps. Extensibility = adding YOUR data and YOUR actions to this system.
What are the three main extensibility mechanisms for Microsoft 365 Copilot?
| Mechanism | What It Does | Who Builds It |
|---|---|---|
| Plugins | Extend Copilot's ability to take actions and retrieve real-time data from external systems | Developers |
| Declarative Agents | Customised Copilot experiences with specific persona, scope, knowledge, and plugins | Makers + Developers |
| Graph Connectors | Index external data into Microsoft Graph so Copilot can search and reason over it | Developers |
Mental model: Graph Connectors = bring your data IN. Plugins = let Copilot take actions OUT. Declarative Agents = package it all into a focused experience.
What is the Microsoft 365 Copilot architecture and how does it process a user prompt?
User types a prompt in Teams / BizChat
↓
Copilot orchestrator (powered by Semantic Kernel)
1. Understands intent via LLM
2. Decides which skills/plugins to invoke
3. Calls Microsoft Graph for user context
(emails, calendar, files, chats, contacts)
4. Calls relevant plugins for external data/actions
5. Passes all retrieved data as grounding context to LLM
↓
LLM (GPT-4 class) generates a response
grounded in the user's actual organisational data
↓
Response rendered in Teams/Outlook/BizChat
with citations to source documents and items
Tip: The orchestrator is powered by Semantic Kernel — Microsoft's open-source AI SDK. Understanding this pipeline is essential for architect-level extensibility.
What is Teams App Manifest v1.13+ and how does it relate to Copilot extensibility?
The Teams App Manifest (now called Microsoft 365 App Manifest) defines an app's capabilities across Microsoft 365 surfaces. Version 1.13+ introduced Copilot extensibility support:
{
"$schema": "https://developer.microsoft.com/json-schemas/teams/v1.17/MicrosoftTeams.schema.json",
"manifestVersion": "1.17",
"id": "unique-app-guid",
"name": { "short": "Contoso HR", "full": "Contoso HR Assistant" },
"copilotAgents": {
"declarativeAgents": [{
"id": "hrAgent",
"file": "agents/hrAgent.json"
}]
},
"plugins": [{
"id": "hrApiPlugin",
"file": "plugins/hrApiPlugin.json"
}]
}
What is Teams Toolkit and how does it help with Copilot extensibility development?
Teams Toolkit is a VS Code extension and CLI providing project templates, local debugging, and deployment automation.
| Capability | Description |
|---|---|
| Project templates | Pre-built scaffolds for API plugins, declarative agents, Graph Connectors |
| Local debugging | Dev Tunnel for local API testing with real Copilot |
| Provision & deploy | Automates Azure resource creation and deployment |
| Environment management | Dev/test/prod configs with .env files |
| App publishing | Packages and submits to Teams Admin Center |
What is the difference between extending Copilot and building a standalone chatbot?
| Extending M365 Copilot | Standalone Chatbot | |
|---|---|---|
| Base AI | Uses M365 Copilot's LLM + Graph | Bring your own LLM |
| User experience | Within Teams/Outlook — familiar surface | Separate app/interface |
| Org data access | Built-in via Microsoft Graph | Custom integration needed |
| Authentication | Inherits M365 SSO | Build your own auth |
| Governance | Managed by Teams Admin Center | Custom governance |
| Licence required | M365 Copilot licence per user | Depends on platform |
| Best for | Enhancing existing M365 workflows | Fully custom experiences |
2. Plugins — API Plugins & Message Extensions
What is an API Plugin for Microsoft 365 Copilot and how does it work?
An API Plugin allows Copilot to call a REST API based on an OpenAPI (Swagger) specification. When a user asks something requiring real-time data or an external action, Copilot invokes the relevant API operation.
How it works:
1. Developer creates an OpenAPI spec for the REST API
2. Developer creates an AI plugin definition (ai-plugin.json)
describing which operations Copilot can call + when
3. Plugin packaged in Teams app manifest (.zip)
4. Copilot's orchestrator reads plugin description + OpenAPI spec
5. When user prompt matches plugin's purpose → orchestrator calls the API
6. API response passed to LLM as grounding context
7. LLM generates response citing real-time API data
Key files:
manifest.json ← Teams app manifest referencing the plugin
apiPlugin.json ← AI plugin definition (name, desc, auth, api spec)
openapi.json ← OpenAPI 3.0 spec describing REST endpoints
Tip: The quality of descriptions in the OpenAPI spec and plugin definition determines whether Copilot invokes the plugin correctly. Poor descriptions = plugin never triggered or triggered for wrong queries.
What is an AI Plugin definition file (ai-plugin.json) and what does it contain?
{
"schema_version": "v2.1",
"name_for_human": "Contoso HR Plugin",
"name_for_model": "ContosoHR",
"description_for_human": "Access HR data including leave balances and policies",
"description_for_model": "Use this plugin to retrieve employee leave balances, HR policies, and submit leave requests. Call this when users ask about their leave, time off, holidays, annual leave, sick leave, or HR policies.",
"auth": {
"type": "OAuthPluginVault",
"reference_id": "${{OAUTH_CONNECTION_NAME}}"
},
"api": {
"type": "openapi",
"url": "https://hrapi.contoso.com/openapi.json"
},
"logo_url": "https://hrapi.contoso.com/logo.png",
"contact_email": "support@contoso.com",
"functions": [
{
"name": "getLeaveBalance",
"description": "Get the current leave balance for the authenticated employee. Use when user asks about remaining leave days, annual leave, sick leave, or time off balance."
},
{
"name": "submitLeaveRequest",
"description": "Submit a leave request for the employee. Use when user wants to apply for leave, book time off, or request annual/sick/personal leave."
}
]
}
Warning: The
description_for_modelis what the Copilot orchestrator reads to decide when to invoke the plugin. Be very specific and include example scenarios. Vague descriptions cause the plugin to be ignored or misused.
What authentication options are available for API Plugins?
| Auth Type | Description | Best For |
|---|---|---|
| None (anonymous) | No authentication | Public, non-sensitive APIs |
| API Key | Static API key in header/query string | Simple external APIs |
| OAuth 2.0 (OAuthPluginVault) | User authenticates via OAuth. Token stored in Teams token vault. | External systems with OAuth support |
| Microsoft Entra ID SSO | Seamless SSO — user's M365 identity used automatically. No login prompt. | Internal enterprise APIs |
Tip: OAuthPluginVault with Entra ID is the recommended enterprise pattern — users get seamless SSO and the API receives a proper OAuth token scoped to the user's identity. No shared credentials.
What is a Message Extension plugin and how does it differ from an API plugin?
Message Extension plugin: a Teams Message Extension (search/action command) also surfaced as a Copilot plugin. Existing Teams apps can become Copilot plugins with minimal changes.
API plugin: built purely for Copilot, based on OpenAPI spec. No Teams UI surface — only callable by Copilot's orchestrator.
| Message Extension Plugin | API Plugin | |
|---|---|---|
| Works in | Teams compose box AND Copilot | Copilot only |
| Backend | Bot Framework handler | Any REST API |
| Best for | Search and insert records into Teams messages | Read/write operations, complex workflows |
| Code required | Yes (Bot Framework) | No (just OpenAPI spec + api-plugin.json) |
What are Adaptive Cards in the context of Copilot plugins?
Adaptive Cards are JSON-based UI templates that Copilot renders as rich structured responses when a plugin returns data.
{
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"text": "Your Leave Balance",
"weight": "Bolder",
"size": "Large"
},
{
"type": "FactSet",
"facts": [
{ "title": "Annual Leave", "value": "12 days remaining" },
{ "title": "Sick Leave", "value": "5 days remaining" },
{ "title": "Personal", "value": "2 days remaining" }
]
}
],
"actions": [
{
"type": "Action.Execute",
"title": "Apply for Leave",
"verb": "submitLeaveRequest"
}
]
}
Tip: Always design Adaptive Card responses for data-heavy plugin results. Structured cards are far more readable than plain text responses — and they support actionable buttons for follow-up operations.
How do you write effective OpenAPI descriptions for Copilot plugins?
The Copilot orchestrator reads operation descriptions to decide when and how to invoke plugin functions.
# POOR description (will be ignored or mis-triggered):
operationId: getItems
summary: Get items
# GOOD description (Copilot knows exactly when to use this):
operationId: getEmployeeLeaveBalance
summary: Get an employee's current leave balance and entitlements
description: >
Returns the authenticated employee's current leave balances for all
leave types including annual leave, sick leave, personal leave, and
parental leave. Use this operation when the user asks about:
- How many days of leave they have left
- Their annual/sick/personal leave balance
- Time off entitlements
- Remaining holidays
parameters:
- name: leaveType
description: >
Optional. Filter by leave type: 'annual', 'sick', 'personal',
'parental'. Omit to return all leave types.
3. Declarative Agents
What is a Declarative Agent and how does it differ from Microsoft 365 Copilot?
Microsoft 365 Copilot (general): broad AI assistant across all M365 data. General-purpose, answers any work question. No persona customisation.
Declarative Agent: a focused, scoped Copilot experience with:
- Custom persona: name, description, avatar — "Contoso HR Assistant", "IT Helpdesk Bot"
- Scoped knowledge: only specific SharePoint sites, OneDrive folders, or Graph Connector data
- Custom instructions: system prompt defining tone, behaviour, what to answer/refuse
- Specific plugins: only the plugins relevant to this agent's purpose
- Conversation starters: suggested prompts shown to users on first open
Tip: Declarative Agents are the answer to "build a custom Copilot for our HR team." They are not a separate AI model — they are a configured, scoped view of M365 Copilot.
What is the declarative agent manifest file and what does it contain?
{
"$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.4/schema.json",
"version": "v1.4",
"name": "Contoso HR Assistant",
"description": "Your personal HR assistant for leave, policies, and benefits.",
"instructions": "You are an HR assistant for Contoso. Only answer HR-related questions about leave policies, employee benefits, and HR procedures. If asked about non-HR topics, politely redirect. Always be professional and empathetic. Never share other employees' personal information.",
"conversation_starters": [
{
"title": "Check leave balance",
"text": "How many days of annual leave do I have remaining?"
},
{
"title": "Submit leave request",
"text": "I want to apply for annual leave next week"
},
{
"title": "Find HR policy",
"text": "What is the remote working policy?"
}
],
"capabilities": [
{
"name": "OneDriveAndSharePoint",
"items_by_sharepoint_ids": [
{
"site_id": "contoso.sharepoint.com,abc123,...",
"web_id": "...",
"list_id": "..."
}
]
},
{
"name": "GraphConnectors",
"connections": [{ "connection_id": "hrdocuments" }]
}
],
"actions": [
{ "id": "hrPlugin", "file": "plugins/hrApiPlugin.json" }
]
}
What knowledge sources can a Declarative Agent use?
| Source | Description |
|---|---|
| SharePoint sites and libraries | Specific sites, libraries, or folders scoped to the agent |
| OneDrive files | Specific folders or files |
| Microsoft Graph Connectors | External data indexed into Graph (ServiceNow, SAP, Confluence, custom DBs) |
| Web search | Public internet via Bing (can be enabled/disabled) |
| Plugins | Real-time data and actions via API plugins |
Warning: Knowledge source scoping is a security control — an agent scoped to HR SharePoint sites cannot access Finance sites, even if the user has permission. The agent's scope is a strict constraint on what Copilot searches.
How do you write effective instructions for a Declarative Agent?
The instructions field is the system prompt defining persona, scope, behaviour, and constraints.
Effective instruction structure:
1. PERSONA: "You are [name], the [role] for [organisation]."
2. SCOPE: "Only answer questions about [domain]. If asked about
[out-of-scope topic], say [specific redirect message]."
3. TONE: "Always be [professional/friendly/concise]. Use
[plain language / technical language appropriate for audience]."
4. DATA CONSTRAINTS: "Never reveal other employees' [personal data].
Only show the current user's own [records]."
5. PLUGIN GUIDANCE: "When asked about [specific topic], always use
the [plugin name] to retrieve real-time data rather than relying
on documents."
6. ESCALATION: "For questions you cannot answer, direct users to
[contact/resource]."
Example — IT Helpdesk Agent:
"You are ITBot, the IT Helpdesk assistant for Contoso. Only answer
questions about IT support, software, hardware, network connectivity,
and access requests. For HR questions, direct users to the HR
Assistant. Always check the user's open tickets using the
ServiceNow plugin before suggesting solutions. Never close a ticket
without explicit user confirmation."
Tip: Treat instructions like a detailed job description. The more specific and clear, the better the agent behaves. Vague instructions lead to unpredictable responses and scope creep.
What is Copilot Studio and how does it relate to Declarative Agents?
Copilot Studio provides a low-code UI for building and publishing Declarative Agents without writing JSON files.
Copilot Studio for M365 Copilot agents:
- Create and configure declarative agents visually
- Add plugins from the catalogue or connect to custom APIs
- Add knowledge sources (SharePoint sites, web URLs, uploaded files)
- Test the agent in the test panel
- Publish to Microsoft 365 Copilot — appears in the Copilot agent store
- Share with specific users or deploy org-wide via Teams Admin Center
| Copilot Studio | Teams Toolkit + JSON | |
|---|---|---|
| Audience | Business users, makers | Developers |
| Authoring | GUI-based, low-code | Code-first, JSON manifests |
| Source control | Limited | Full Git/DevOps support |
| Best for | Quick deployment, business-owned agents | Complex agents, ALM, pro-code |
4. Microsoft Graph Connectors
What is a Microsoft Graph Connector and what problem does it solve?
A Microsoft Graph Connector indexes external data into the Microsoft Graph — making it searchable by Microsoft 365 Search, Microsoft 365 Copilot, and other Graph-aware services.
The problem it solves: organisations have valuable data in non-Microsoft systems (ServiceNow, Confluence, SAP, Salesforce, SQL databases, intranets). Without a connector, Copilot cannot access this data. A Graph Connector brings it into the Microsoft Search and Copilot ecosystem without migrating data to SharePoint.
Data flow:
ServiceNow / Confluence / SAP / Custom DB
↓ (Graph Connector indexes items via Graph API)
Microsoft Graph — external items index
↓
Microsoft 365 Search + Copilot can find and cite it
↓
User: "What is the status of IT ticket #12345?"
Copilot: retrieves from ServiceNow index → answers with citation
Tip: Graph Connectors are what makes Copilot truly enterprise-ready — they eliminate "Copilot doesn't know about our systems" by bringing external data into Graph's searchable index.
What are the components of a Graph Connector solution?
| Component | Description | API |
|---|---|---|
| Connection | Defines the connector — name, description | POST /external/connections |
| Schema | Structure of external items — property types, searchability | PATCH /external/connections/{id}/schema |
| External items | The actual data records pushed into the index | PUT /external/connections/{id}/items/{itemId} |
| Result type | How search results are displayed (Adaptive Card template) | Admin Center configuration |
| Crawler/sync agent | Your app that reads external system and pushes to Graph | Custom application |
// 1. Create connection
POST https://graph.microsoft.com/v1.0/external/connections
{
"id": "contosohr",
"name": "Contoso HR Documents",
"description": "HR policies, procedures, and employee handbook"
}
// 2. Define schema
PATCH https://graph.microsoft.com/v1.0/external/connections/contosohr/schema
{
"baseType": "microsoft.graph.externalItem",
"properties": [
{ "name": "title", "type": "String", "isSearchable": true,
"isRetrievable": true, "labels": ["title"] },
{ "name": "content", "type": "String", "isSearchable": true,
"isRetrievable": true, "labels": ["body"] },
{ "name": "url", "type": "String", "isRetrievable": true,
"labels": ["url"] },
{ "name": "lastModified", "type": "DateTime",
"isRetrievable": true, "labels": ["lastModifiedDateTime"] },
{ "name": "category", "type": "String", "isSearchable": true,
"isRefinable": true, "isRetrievable": true }
]
}
// 3. Push an external item
PUT https://graph.microsoft.com/v1.0/external/connections/contosohr/items/policy_001
{
"acl": [
{ "type": "everyone", "value": "everyone", "accessType": "grant" }
],
"properties": {
"title": "Remote Working Policy 2025",
"content": "Employees may work remotely up to 3 days per week...",
"url": "https://intranet.contoso.com/hr/policies/remote-working",
"lastModified": "2025-01-15T10:00:00Z",
"category": "Work Arrangements"
},
"content": {
"value": "Full policy text for search indexing...",
"type": "text"
}
}
What is ACL in Graph Connectors and why is it critical?
The ACL (Access Control List) on each external item defines who can see it in search results and Copilot responses.
"acl": [
// Everyone in the org can see:
{ "type": "everyone", "value": "everyone",
"accessType": "grant" },
// Specific Entra ID user can see:
{ "type": "user",
"value": "entra-user-object-id",
"accessType": "grant" },
// Members of an Azure AD group can see:
{ "type": "group",
"value": "aad-group-object-id",
"accessType": "grant" },
// Deny a specific user (overrides grants):
{ "type": "user",
"value": "blocked-user-object-id",
"accessType": "deny" }
]
Critical: ACL is the security boundary for Graph Connector data. If ACLs are misconfigured (e.g., everyone can see confidential HR records), Copilot will expose that data to all users. Always map source system permissions to Entra ID identities — never default to "everyone" for sensitive data.
What are pre-built Graph Connectors and when would you build custom?
Pre-built connectors (available in M365 Admin Center → Search → Data Sources): ServiceNow, Confluence, Jira, Salesforce, SAP, Azure DevOps, GitHub, MediaWiki, and more.
Build custom when:
- No pre-built connector exists for your system
- Pre-built connector doesn't index the specific data/schema you need
- Custom ACL mapping logic is required for your org's permission model
- You need to transform or enrich data before indexing
- You need incremental sync with custom change detection
Tip: Always check the pre-built catalogue first. ServiceNow, Confluence, and Jira connectors cover the majority of enterprise use cases. Custom connectors are for unique or proprietary systems.
5. Security, Governance & Responsible AI
How does Microsoft 365 Copilot enforce data security and permissions?
- Microsoft Graph respects existing permissions: Copilot only retrieves data the current user has permission to access in SharePoint, OneDrive, Exchange, and Teams. It cannot elevate permissions.
- Graph Connector ACLs: external items only shown to users whose Entra ID identity matches the item's ACL
- Plugin authentication: OAuth plugins call external API as the current user — not a service account. Users only see their own data.
- Tenant isolation: Copilot data never crosses tenant boundaries. Org data is never used to train or improve the LLM.
- Microsoft Purview integration: sensitivity labels on documents are respected — confidential documents are not surfaced to users without appropriate permissions
Key principle: Copilot can only show what the user could find themselves. It is a search and reasoning layer on top of existing permissions — not a permission bypass.
What admin controls exist for governing Copilot extensibility?
| Control | Location | Purpose |
|---|---|---|
| App approval | Teams Admin Center → Manage apps | Allow/block specific plugins and agents |
| App permission policies | Teams Admin Center | Control which users can access which Copilot apps |
| App setup policies | Teams Admin Center | Pre-install agents for users automatically |
| Copilot settings | M365 Admin Center → Copilot | Tenant-wide: web search, connected experiences |
| Purview audit | Microsoft Purview | Audit Copilot interactions, retention policies |
| Graph Connector admin | M365 Admin Center → Search | Enable/disable connections, view indexed items |
Warning: Any plugin or agent published to the organisation must be approved in Teams Admin Center before users can access it. Unapproved apps are blocked by default.
What is Responsible AI and how does it apply to Copilot extensibility?
Microsoft's Responsible AI principles applied to extensibility:
| Principle | Developer Responsibility |
|---|---|
| Transparency | Be honest about what the agent can/cannot do. Don't design agents that deceive users about their AI nature. |
| Fairness | Don't design agents that return different quality responses based on protected characteristics. |
| Privacy | Don't log user prompts in violation of privacy policies. Use minimum data needed. Respect sensitivity labels. |
| Reliability | Handle plugin errors gracefully. Never let a failed API call result in a misleading response. |
| Human oversight | For high-stakes actions (approvals, purchases, deletions), require explicit confirmation via Adaptive Card before executing. |
| Accountability | Maintain audit logs of agent actions. Ensure humans can review and override agent decisions. |
6. Scenario-Based Questions
Scenario: Build a Copilot plugin that lets employees check their ServiceNow IT tickets.
- Approach: API Plugin (not message extension) — structured data, Copilot-only needed
- ServiceNow API: use Table API. OpenAPI spec for:
GET /api/now/table/incident?caller_id={userId}— get user's ticketsGET /api/now/table/incident/{id}— get ticket detail
- Authentication: OAuth 2.0 with Entra ID SSO — users authenticate once
- Critical — OpenAPI descriptions:
operationId: getMyTicketsdescription: "Retrieves all IT support tickets raised by the current employee. Use when user asks about their tickets, incidents, IT requests, open issues, support cases, or IT problems." - Adaptive Card: ticket number, title, status, priority, last updated + "View in ServiceNow" deep-link button
- ai-plugin.json: detailed description_for_model with example user queries
- Deploy: Teams Toolkit → package → Teams Admin Center → admin approves
Key insight: Description quality determines plugin invocation. Poor descriptions = Copilot never uses the plugin even when it should.
Scenario: Build a Declarative Agent for the Sales team with CRM and product data.
Agent configuration:
- Name: "Contoso Sales Assistant"
- Instructions: "You are a Sales Assistant for Contoso. Help sales reps with product information, pricing, opportunity management, and competitive analysis. Always reference official pricing from the pricing API. Only access the current user's opportunities from Salesforce."
Knowledge sources:
- SharePoint: Product catalogue site, Sales playbooks, Pricing documents
- Graph Connector: Salesforce CRM (opportunities, accounts, contacts — indexed nightly)
- OneDrive: Sales team shared folder
Plugins:
- Salesforce API plugin: get/update opportunities, log activities
- Pricing API plugin: real-time pricing for product configurations
Conversation starters:
- "What are my open opportunities this quarter?"
- "What is the pricing for Product X with Enterprise support?"
- "Help me prepare talking points for my meeting with [Company]"
Deploy: Copilot Studio → publish → share with Sales Azure AD group
Scenario: Your organisation has a legacy intranet with thousands of HR policy documents. How do you make them available to Copilot?
Solution: Custom Graph Connector
- Build a sync agent: Azure Function or .NET app that reads the intranet's content via its API or crawl
- Create connection:
POST /external/connectionswith id: "hrintranet", descriptive name and description - Define schema: properties for Title, Content, URL, Author, LastModified, PolicyCategory — mark Content and Title as
isSearchable: true, set appropriate labels - Map permissions: if HR policies are org-wide, use ACL type "everyone". For restricted policies (e.g., management-only), map intranet groups to Entra ID group object IDs
- Push items: for each document,
PUT /external/connections/hrintranet/items/{id}with properties and content - Schedule incremental sync: track
lastCrawledDateTime, only push items modified since last sync - Configure result type: Adaptive Card template for how results appear in search
- Add to HR Declarative Agent: reference
"connection_id": "hrintranet"in agent capabilities - Test: ask Copilot "What is the parental leave policy?" — should cite intranet document with link
Scenario: How do you handle a plugin write operation with user confirmation before executing?
Requirement: Plugin submits a leave request. User must confirm before the request is submitted — Copilot should not submit automatically on a single ambiguous prompt.
Two-step API design:
# Step 1 — Preview (safe, no side effects):
GET /leaveRequest/preview?type={leaveType}&start={date}&end={date}
Returns: { dates, days, remainingBalance, approver, confirmation_id }
# Step 2 — Submit (only called after user confirms):
POST /leaveRequest/submit
Body: { confirmation_id }
Adaptive Card confirmation returned from preview:
{
"type": "AdaptiveCard",
"body": [
{ "type": "TextBlock", "text": "Leave Request Preview", "weight": "Bolder" },
{ "type": "FactSet", "facts": [
{ "title": "Type", "value": "Annual Leave" },
{ "title": "Dates", "value": "15 Jan – 19 Jan 2026" },
{ "title": "Days", "value": "5 days" },
{ "title": "Balance after", "value": "7 days remaining" }
]}
],
"actions": [
{ "type": "Action.Execute", "title": "✓ Confirm & Submit",
"verb": "submitLeave" },
{ "type": "Action.Execute", "title": "✗ Cancel",
"verb": "cancelLeave" }
]
}
Plugin instructions in ai-plugin.json:
"Always call the preview endpoint first and display the confirmation card. Only call the submit endpoint when the user explicitly clicks Confirm in the card."
Responsible AI principle: The two-step preview-then-confirm pattern is the standard for any write operation in Copilot plugins. It gives users agency and prevents accidental actions from ambiguous prompts.
Scenario: How do you ensure a Declarative Agent doesn't leak confidential Finance data to HR users?
- Scope knowledge sources strictly: only add HR SharePoint sites to the HR agent — never Finance sites, even if the admin has access to both
- Use Graph Connector ACLs: HR-specific connector items have ACL entries for the HR security group only — Finance documents have Finance group ACL. Copilot automatically enforces these.
- Plugin authentication: use OAuth SSO — the plugin calls the HR API as the current user. The API enforces its own role-based access. Copilot cannot bypass API-level security.
- Instructions boundary: "Only answer questions about HR. If asked about financial data, budgets, or Finance matters, say 'I only have access to HR information.'"
- Test with non-HR users: verify Finance users cannot retrieve HR-restricted content through the agent
7. Cheat Sheet — Quick Reference
Extensibility Mechanisms at a Glance
API Plugin
→ OpenAPI spec + ai-plugin.json + manifest.json
→ Copilot calls your REST API for real-time data/actions
→ Auth: None / API Key / OAuth / Entra SSO
→ Response: plain text or Adaptive Cards
Message Extension Plugin
→ Existing Teams app (composeExtension) surfaced in Copilot
→ Works in Teams compose box AND Copilot
→ Uses Bot Framework
→ Good for search + insert into Teams messages
Declarative Agent
→ agents/myAgent.json + manifest.json
→ Scoped Copilot with custom persona + knowledge + plugins
→ No custom AI model — configured view of M365 Copilot
→ Authoring: Teams Toolkit (code) or Copilot Studio (low-code)
Graph Connector
→ Custom app calling Graph API to index external items
→ Creates: connection → schema → push items
→ Items appear in M365 Search and Copilot responses
→ ACL per item controls who can see it
AI Plugin Definition — Key Fields
{
"name_for_model": "ShortNoSpacesName",
"description_for_model": "DETAILED description of what this plugin does,
when to use it, example scenarios. This is what Copilot reads.",
"auth": {
"type": "OAuthPluginVault | ApiKeyAuth | None",
"reference_id": "${{OAUTH_CONNECTION}}"
},
"functions": [{
"name": "operationId from OpenAPI spec",
"description": "SPECIFIC description of this function with
example user queries that should trigger it"
}]
}
Declarative Agent — Key Fields
{
"name": "Display name shown to users",
"instructions": "System prompt — persona, scope, tone, data rules",
"conversation_starters": [
{ "title": "Short title", "text": "Full prompt to send" }
],
"capabilities": [
{
"name": "OneDriveAndSharePoint",
"items_by_sharepoint_ids": [{ "site_id": "..." }]
},
{
"name": "GraphConnectors",
"connections": [{ "connection_id": "myconnection" }]
}
],
"actions": [
{ "id": "myPlugin", "file": "plugins/plugin.json" }
]
}
Graph Connector — API Flow
1. Create connection
POST /v1.0/external/connections
{ "id": "myconn", "name": "...", "description": "..." }
2. Register schema (async — poll until Completed)
PATCH /v1.0/external/connections/myconn/schema
{ "baseType": "microsoft.graph.externalItem",
"properties": [{ "name": "title", "type": "String",
"isSearchable": true, "labels": ["title"] }] }
3. Push items
PUT /v1.0/external/connections/myconn/items/{itemId}
{ "acl": [...],
"properties": { "title": "...", "content": "..." },
"content": { "value": "...", "type": "text" } }
4. Update items (same PUT — upsert semantics)
5. Delete items
DELETE /v1.0/external/connections/myconn/items/{itemId}
Schema property labels (map to Microsoft semantics):
title, url, iconUrl, createdBy, lastModifiedBy,
createdDateTime, lastModifiedDateTime, fileName, fileExtension, body
Deployment Path
Development:
Teams Toolkit → scaffold project → code → local debug with Dev Tunnel
Packaging:
Teams Toolkit → Provision → Deploy → Package
Internal deployment:
Upload .zip to Teams Admin Center → Admin approves → Users access
Public (Teams Store):
Microsoft Partner Center → Submit for validation → Store listing
Top 10 Tips
- Three mechanisms, one sentence each — "Graph Connectors bring data IN. Plugins let Copilot act OUT. Declarative Agents package it into a focused experience." Start every architecture question here.
- description_for_model quality = plugin success — the orchestrator reads this to decide when to invoke the plugin. Vague descriptions = plugin never used. This is the #1 developer mistake.
- Copilot cannot bypass permissions — it only surfaces what the user could already access. Copilot is a reasoning layer, not a permission bypass. Security questions always return to this principle.
- ACL misconfiguration is the #1 Graph Connector risk — defaulting to "everyone" on sensitive items exposes confidential data to all users through Copilot queries.
- Two-step confirm pattern for write operations — preview first, submit only on explicit user confirmation. Responsible AI standard for any destructive or irreversible action.
- Declarative Agents ≠ new AI model — they are a configured, scoped view of M365 Copilot. Many candidates think they require a custom LLM — they do not.
- Teams Admin Center approval is mandatory — no plugin or agent reaches users without admin approval. This is the governance gate — always mention it in deployment discussions.
- OAuthPluginVault with Entra SSO is the correct enterprise auth answer. Shared service account credentials in plugins are a security anti-pattern.
- Copilot Studio vs Teams Toolkit — Copilot Studio for makers and business users; Teams Toolkit for developers needing source control and ALM. Both produce the same underlying manifest JSON.
- Schema property labels in Graph Connectors map external properties to Microsoft's semantic understanding —
labels: ["title"],labels: ["body"]etc. Correct labelling dramatically improves Copilot's ability to summarise and cite your external content.
No comments:
Post a Comment