← Back to Blog

Build M365 Copilot Declarative Agents

Step-by-step guide to building custom declarative agents for Microsoft 365 Copilot. Learn Teams Toolkit, plugins, and deployment in 30 minutes.

Build M365 Copilot Declarative Agents


Declarative agents are the fastest way to extend Microsoft 365 Copilot without building your own AI infrastructure. You define what the agent knows, what it can do, and how it should behave — and Copilot's orchestrator handles the rest.

This guide walks you through building a declarative agent from scratch using Teams Toolkit, adding API plugins for custom actions, and connecting Graph connectors for external data.

What Are Declarative Agents?



Declarative agents are extensions of Microsoft 365 Copilot that run on the same orchestrator, LLM, and security stack. You don't train a model or host an inference endpoint. Instead, you declare three things in a JSON manifest:

  • Instructions — system prompt that shapes the agent's personality and behavior

  • Knowledge sources — SharePoint sites, Graph connectors, or files the agent can reference

  • Actions — API plugins the agent can call to read or write external data


The key difference from custom engine agents: declarative agents use Copilot's own LLM and orchestration layer. You are configuring the existing Copilot, not replacing it.

Declarative Agents vs Custom Engine Agents



AspectDeclarative AgentsCustom Engine Agents

|--------|-------------------|---------------------|
LLMMicrosoft 365 Copilot (hosted)Your own (Azure OpenAI, etc.)

HostingNo infrastructure neededYou manage compute and endpoints

Data accessM365 Graph, SharePoint, connectorsWhatever you wire up

AuthenticationM365 SSO built-inYou implement auth

CustomizationInstructions + plugins + knowledgeFull control over prompts and models

Best forExtending Copilot with org-specific contextScenarios requiring custom models or non-M365 data


If your use case lives inside the Microsoft 365 ecosystem, declarative agents are almost always the right choice. You get Copilot's grounding, citation, and responsible AI controls out of the box.

Architecture Overview



When a user interacts with a declarative agent, the request flows through the same pipeline as standard Copilot:

  • User sends a prompt in Copilot Chat, Teams, or another M365 surface

  • Copilot's orchestrator identifies which agent should handle the request

  • The agent's instructions shape the system prompt

  • The orchestrator queries the agent's knowledge sources (SharePoint, Graph connectors) for grounding data

  • If the query requires an external action, the orchestrator calls the agent's API plugins

  • The LLM generates a response grounded in the retrieved data

  • The response is returned with citations pointing to source documents


Your declarative agent manifest is the configuration layer that customizes steps 3-5. Everything else is handled by Copilot.

Prerequisites



Before you start building, make sure you have:

  • Teams Toolkit v5.10+ installed in VS Code (or the CLI equivalent via npm install -g @microsoft/teamsapp-cli)

  • Microsoft 365 developer tenant with Copilot licenses assigned

  • Node.js 18+ and npm

  • Copilot enabled for your tenant (admin center > Copilot settings)

  • Sideloading enabled for your development account (Teams admin center > Teams apps > Setup policies)


If you don't have a developer tenant, sign up at developer.microsoft.com/microsoft-365/dev-program.

Step-by-Step: Build Your First Declarative Agent



Create the Project



Open VS Code with Teams Toolkit installed and create a new project:

  • Open the command palette (Ctrl+Shift+P)

  • Select Teams Toolkit: Create a New App

  • Choose Copilot Agent > Declarative Agent

  • Select No plugin for now (you will add one later)

  • Name the project hr-policy-agent


Teams Toolkit generates the following structure:

``
hr-policy-agent/
appPackage/
declarativeAgent.json
manifest.json
color.png
outline.png
env/
.env.dev
teamsapp.yml
`

The two critical files are
manifest.json (the Teams app manifest) and declarativeAgent.json (the agent definition).

Define the Agent Manifest



Open
appPackage/declarativeAgent.json. This is where you define the agent's behavior:

`json
{
"$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.3/schema.json",
"version": "v1.3",
"name": "HR Policy Agent",
"description": "Answers questions about company HR policies, benefits, and leave procedures.",
"instructions": "You are the HR Policy Agent for Contoso. Answer questions about HR policies, employee benefits, leave procedures, and onboarding processes. Always cite the specific policy document you are referencing. If you do not have enough information to answer a question, say so clearly and direct the user to contact HR at hr@contoso.com. Never speculate about policies that are not in your knowledge sources.",
"capabilities": [
{
"name": "WebSearch",
"isEnabled": false
},
{
"name": "GraphicArt",
"isEnabled": false
},
{
"name": "CodeInterpreter",
"isEnabled": false
}
],
"conversation_starters": [
{ "text": "What is our parental leave policy?" },
{ "text": "How do I submit a PTO request?" },
{ "text": "Explain the annual benefits enrollment process." }
]
}
`

Key decisions in this manifest:

  • instructions — This is the system prompt. Be specific about what the agent should and should not do. Vague instructions produce vague results.

  • capabilities — Disable capabilities the agent does not need. An HR policy bot has no reason to generate images or run code.

  • conversation_starters — These appear as suggested prompts when users open the agent.


Add Knowledge Sources



Knowledge sources ground the agent in your organization's data. Add a
knowledge array to the manifest:

`json
{
"knowledge": [
{
"type": "SharePoint",
"sites": [
{
"url": "https://contoso.sharepoint.com/sites/HR"
},
{
"url": "https://contoso.sharepoint.com/sites/HR/PolicyDocuments"
}
]
},
{
"type": "GraphConnector",
"connections": [
{
"connection_id": "contosoHRIS"
}
]
}
]
}
`

The agent will use Copilot's semantic index to search these sources when responding to queries. SharePoint sites are indexed automatically. Graph connectors require separate setup (covered below).

Adding API Plugins



API plugins let your agent call external services — read data from a CRM, submit a support ticket, or query a custom database. You define the API using an OpenAPI spec and a plugin manifest.

Create the OpenAPI Spec



Add an
apiSpecificationFile to your project at appPackage/apispec.yaml:

`yaml
openapi: 3.0.3
info:
title: HR Service API
version: 1.0.0
servers:
- url: https://hr-api.contoso.com
paths:
/api/leave-balance:
get:
operationId: getLeaveBalance
summary: Get an employee's remaining leave balance
parameters:
- name: employeeId
in: query
required: true
schema:
type: string
responses:
'200':
description: Leave balance details
content:
application/json:
schema:
type: object
properties:
annualLeave:
type: number
sickLeave:
type: number
personalDays:
type: number
/api/leave-request:
post:
operationId: submitLeaveRequest
summary: Submit a new leave request
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
startDate:
type: string
format: date
endDate:
type: string
format: date
leaveType:
type: string
enum: [annual, sick, personal]
responses:
'201':
description: Leave request submitted
`

Plugin Manifest



Create
appPackage/plugin.json to link the API spec to the agent:

`json
{
"$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.2/schema.json",
"schema_version": "v2.2",
"name_for_human": "HR Service Plugin",
"description_for_human": "Check leave balances and submit leave requests.",
"description_for_model": "Use this plugin when the user asks about their leave balance, remaining PTO, or wants to submit a leave request. Do not use this plugin for general HR policy questions.",
"functions": [
{
"name": "getLeaveBalance",
"description": "Retrieves the remaining leave balance for an employee."
},
{
"name": "submitLeaveRequest",
"description": "Submits a new leave request for the signed-in user."
}
],
"runtimes": [
{
"type": "OpenApi",
"auth": {
"type": "OAuthPluginVault",
"reference_id": "contoso-hr-oauth"
},
"spec": {
"url": "apispec.yaml"
}
}
]
}
`

Then reference the plugin in your
declarativeAgent.json:

`json
{
"actions": [
{
"id": "hrServicePlugin",
"file": "plugin.json"
}
]
}
`

Authentication Configuration



For API plugins that require auth, register your API in the Teams Developer Portal under Tools > OAuth client registration. The
OAuthPluginVault type stores the OAuth configuration securely and handles token exchange with Copilot's auth layer.

For APIs behind Microsoft Entra ID, use the
OAuthPluginVault type with these settings:

  • Authorization URL: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize

  • Token URL: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token

  • Scope: Your API's application ID URI (e.g., api://hr-api.contoso.com/.default)


Copilot will initiate an OAuth consent flow the first time a user triggers the plugin.

Adding Graph Connectors for External Data



Graph connectors bring external data into the Microsoft 365 semantic index, making it searchable by Copilot. If your HR data lives in an external HRIS, a Graph connector makes it available to your declarative agent without building a custom API.

The high-level steps:

  • Register a connection using the Microsoft Graph API

  • Define the schema for your external items (fields, types, labels)

  • Ingest items via the Graph API

  • Reference the connection in your declarative agent's knowledge sources


`typescript
import { Client } from "@microsoft/microsoft-graph-client";

const client = Client.initWithMiddleware({ authProvider });

// Create the connection
await client.api("/external/connections").post({
id: "contosoHRIS",
name: "Contoso HRIS",
description: "Employee records from the Contoso HR system"
});

// Define the schema
await client.api("/external/connections/contosoHRIS/schema").patch({
baseType: "microsoft.graph.externalItem",
properties: [
{ name: "employeeName", type: "String", isSearchable: true, isQueryable: true, labels: ["title"] },
{ name: "department", type: "String", isSearchable: true, isQueryable: true },
{ name: "role", type: "String", isSearchable: true },
{ name: "startDate", type: "DateTime", isQueryable: true }
]
});
`

Once ingested, reference the
contosoHRIS connection ID in your agent's knowledge array as shown in the knowledge sources section above.

For a deeper look at Graph API authentication patterns, see Microsoft Graph API Authentication Guide.

Testing and Debugging



Teams Toolkit makes local testing straightforward:

  • Press F5 in VS Code (or run teamsapp preview)

  • Teams Toolkit provisions the app in your dev tenant and opens Copilot Chat

  • Your agent appears in the agent flyout — select it to start a conversation

  • Test your conversation starters and edge cases


Debugging tips:

  • Check the Developer Portal (dev.teams.microsoft.com) for manifest validation errors

  • Use the Copilot activity log in the Teams admin center to see how queries are routed

  • Monitor API plugin calls in your API's logs — if Copilot isn't calling your plugin, refine the description_for_model field to be more specific about trigger conditions

  • Test knowledge grounding by asking questions that should pull from specific documents, then verify the citations


Deployment



When you are ready to ship:

  • Run teamsapp package to generate the app package (.zip)

  • Upload the package to the Teams admin center under Manage apps

  • Assign the app to the appropriate users or groups via setup policies

  • For organization-wide deployment, submit the app for admin approval


`bash
# Package the app
teamsapp package --env production

# Deploy to your tenant
teamsapp publish --env production
`

After deployment, users will find the agent in the Copilot Chat agent picker. Make sure your governance controls are in place before rolling out to production users.

Comparison: Declarative Agents vs Copilot Studio vs Custom Engine Agents



FeatureDeclarative AgentsCopilot StudioCustom Engine Agents

|---------|-------------------|----------------|---------------------|
LLMCopilot (hosted)Copilot (hosted)Your own model

Development toolTeams Toolkit / VS CodeLow-code designerAny framework

Knowledge sourcesSharePoint, Graph connectorsSharePoint, Dataverse, customWhatever you build

API integrationOpenAPI pluginsPower Automate connectorsDirect API calls

AuthenticationM365 SSOM365 SSOYou manage auth

Deployment surfaceCopilot Chat, TeamsCopilot Chat, Teams, webTeams, web, custom

Best forDevelopers extending CopilotCitizen developers, rapid prototypingComplex AI scenarios outside M365

LicensingM365 Copilot licenseCopilot Studio licenseAzure consumption


If you are deciding between Copilot Studio and declarative agents, the rule of thumb: use Copilot Studio for no-code scenarios and rapid prototyping, use declarative agents when you need source control, CI/CD pipelines, and developer-grade tooling. For a hands-on comparison, see Copilot Studio + SharePoint: Build AI Assistants.

FAQ



Do declarative agents require a Copilot license for every user?



Yes. Every user who interacts with a declarative agent needs a Microsoft 365 Copilot license. The agent runs on Copilot's orchestrator, so the licensing requirement is the same as using Copilot Chat directly.

Can I use declarative agents with data outside Microsoft 365?



Yes, through two mechanisms. API plugins let the agent call any REST API you expose with an OpenAPI spec. Graph connectors let you ingest external data into the Microsoft 365 index so the agent can search it alongside SharePoint content. For external data that changes frequently, API plugins are usually a better fit than Graph connectors.

How do I control what data the agent can access?



Declarative agents inherit the signed-in user's permissions. If a user does not have access to a SharePoint site listed in the agent's knowledge sources, Copilot will not surface documents from that site in responses. You can further restrict scope by specifying exact site URLs and folder paths in the knowledge configuration. For a full governance framework, see Microsoft Copilot Governance: 8 Controls Every M365 Admin Needs.

Can I add Adaptive Cards to the agent's responses?



Yes. API plugins can return Adaptive Card templates in their responses, and Copilot will render them inline. This is useful for displaying structured data like leave balances, approval forms, or status dashboards. Define the card template in your OpenAPI response schema using the
adaptiveCardTemplate` property in the plugin manifest. For more on building Adaptive Cards, see Adaptive Cards for Microsoft 365 Developers.

Free Developer Tool

M365 Architecture Canvas

Design SharePoint, Teams, and Power Platform architectures visually. Export a structured Markdown document ready for proposals or GitHub.

Try It Free →