# Add Workiq Tools

> >

- **Type:** Skill
- **Install:** `agentstack add skill-microsoft-agent365-skills-add-workiq-tools`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [microsoft](https://agentstack.voostack.com/s/microsoft)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [microsoft](https://github.com/microsoft)
- **Source:** https://github.com/microsoft/agent365-skills/tree/main/plugins/agent365/skills/add-workiq-tools

## Install

```sh
agentstack add skill-microsoft-agent365-skills-add-workiq-tools
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Add WorkIQ Tools (A365 CLI + SDK)

> **Trigger phrases** — any of these will activate this skill automatically:
> - "add workiq tools to this agent"
> - "add work intelligence tools"
> - "give this agent access to m365 data"
> - "give my agent access to email and calendar"
> - "add sharepoint access to this agent"
> - "add work iq mail to this agent"
> - "add work iq calendar to this agent"
> - "let this agent read emails and calendar events"
> - "wire up workiq MCP servers"

---

## Overview

This skill adds WorkIQ MCP tool servers to an existing A365 agent using the A365 CLI.

**WorkIQ tools** give your agent pre-built access to M365 work data via MCP. The capability categories below describe what each catalog server does — but **always pull the exact CLI argument names from `a365 develop list-available`**. V2 catalog names look like `mcp_MailTools`, `mcp_CalendarTools`, etc., and they evolve over time.

- **Mail** — Read, send, and manage email
- **Calendar** — Read/create events, check availability
- **Teams** — Read channel messages, list teams
- **SharePoint** — Search documents, read files, list sites
- **OneDrive** — Manage OneDrive files
- **Word** — Read and write Word documents
- **User/Presence** — Get user profile and presence
- **Copilot** — Chat with Microsoft 365 Copilot
- **Dataverse and Dynamics 365** — CRUD and domain actions

**How it works:**
1. `a365 develop list-available` — shows the catalog of available MCP servers
2. `a365 develop add-mcp-servers` — adds selected servers to `ToolingManifest.json`
3. Agent code is wired to load those tools at runtime via `GetMcpToolsAsync`
4. Permissions are applied separately by a developer or Global Administrator

All changes are **additive** and **idempotent** — rerunning is safe.

---

## Phase 0A — Workspace Triage and Detection Cache

### Step 1 — Triage the workspace

Run in parallel:

- **Glob** `**/*.csproj`, `package.json`, `requirements.txt`, `pyproject.toml`, `src/**/*.ts`, `**/*.cs`, `**/*.py` → `hasProjectFiles`.
- **Read** `.a365-workspace-detection.local.json` → `cacheState` (`fresh` if `detectedAt` 

    Options:
      1. Switch the agent to a supported framework via /agent365:make-ai-teammate.
      2. (Advanced) Author your own MCP wrapper modeled on the Claude SDK sample's DIY scaffold:
         https://github.com/microsoft/Agent365-Samples/blob/main/python/claude/sample-agent/mcp_tool_registration_service.py
         — out of scope for this skill.
```

Mark all tasks cancelled and end the session. Do **not** proceed to Phase 0C.

---

## Phase 0C — Create and Display Task List

**Show this checklist to the user BEFORE running Phase 1.** Use whichever mechanism the runtime supports — the user must see the list before any CLI command or code edit happens, and items must be updated as work progresses:

- **Claude Code:** call `TaskCreate` for each item below; it's already in `allowed-tools` and renders natively as a checklist with status icons. Use `TaskUpdate` to mark in_progress / completed.
- **VS Code Copilot Chat / GitHub Copilot CLI:** `allowed-tools` is ignored — emit a markdown checklist directly in chat (`- [ ] Detect agent type…`) and edit the list to flip items to `- [x]` as each phase completes.

**Either way: exactly one task in_progress at a time; complete it before moving on.**

```
TaskCreate: "Detect agent type and check prerequisites"
TaskCreate: "Show available WorkIQ tools catalog"
TaskCreate: "Add WorkIQ MCP servers via CLI"
TaskCreate: "Wire MCP tool service in agent code"
TaskCreate: "Offer Word @mention handler (if applicable)"
TaskCreate: "Guide permissions handoff"
TaskCreate: "Set up dev token for testing"
TaskCreate: "Validate build"
```

---

## Phase 1 — Detect Agent Type and Check Prerequisites

**Mark task in progress: "Detect agent type and check prerequisites"**

### 1.1 Detect agent type

1. **Read** `${CLAUDE_PLUGIN_ROOT}/shared/agent-detection.md` for detection heuristics.

2. Run detection:
   - **Glob** `**/*.csproj` + **Grep** `AgentApplication` in `**/*.cs` → .NET AgentFramework
   - **Glob** `**/package.json` + `.ts`/`.js` files present → Node.js
   - **Glob** `**/*.py` or `requirements.txt` / `pyproject.toml` → Python

3. Load reference patterns:
   - If .NET: **Read** `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/dotnet-workiq.md`
   - If Node.js: **Read** `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/nodejs-workiq.md`
   - If Python: **Read** `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/python-workiq.md`

### 1.2 Check prerequisites

Run both checks in one step:

```bash
a365 --version; a365 develop list-configured 2>/dev/null || echo "a365 CLI not found — will install"
```

If `a365` is missing:
```bash
dotnet tool install -g Microsoft.Agents.A365.DevTools.Cli
a365 --version; a365 develop list-configured
```

Report the current state to the user — which servers are already in `ToolingManifest.json`.

### 1.3 Check for AGENTIC_APP_ID

Following `agent-detection.md` AGENTIC_APP_ID detection order:
- Check `.env` / `.env.example` for `AGENTIC_APP_ID=`
- Check `appsettings.json` for `AgenticAppId`
- Check `a365.generated.config.json` for `agentBlueprintId`

If not found, note this — user will need to run `a365 setup` at some point. Do not block.

**Mark task complete: "Detect agent type and check prerequisites"**

---

## Phase 2 — Show Available WorkIQ Tools Catalog

**Mark task in progress: "Show available WorkIQ tools catalog"**

### 2.1 List available servers

```bash
a365 develop list-available
```

> **Note:** `a365 develop list-available` does not require `a365.config.json` — it reads the environment from `A365_ENVIRONMENT` env var (defaults to `prod`). The output now includes a `Version` column showing `V1` or `V2` for each server.

Show the output to the user. The catalog includes WorkIQ servers (mail, calendar, Teams, SharePoint,
OneDrive, Word, user/presence, Copilot) and Dataverse/Dynamics 365.

### 2.2 Ask which tools to add

If the user provided specific tool names as the skill argument, use those and skip the question.

Otherwise, parse the `a365 develop list-available` output to extract the server names, then present them as numbered options. Also check `a365 develop list-configured` output (from Phase 1.2) to mark already-installed servers so the developer can see what's new vs already present.

```
AskUserQuestion:
  question: |
    Which WorkIQ tool servers would you like to add?
    (Servers already in ToolingManifest.json are marked ✅)

    
    . All of the above
    . Let me type specific names
  options: 
```

For each option: if the server name appears in the `a365 develop list-configured` output, append ` (✅ already configured)` to the label. Include it in the list anyway — user may want to re-add or upgrade version.

**Mark task complete: "Show available WorkIQ tools catalog"**

---

## Phase 3 — Add WorkIQ MCP Servers via CLI

**Mark task in progress: "Add WorkIQ MCP servers via CLI"**

### 3.1 Add selected servers

Run `a365 develop add-mcp-servers` with the selected server names.
Run the command **once** with all selected names space-separated:

```bash
# Substitute the exact mcpServerName values from your `list-available` output.
# Example shown using the current V2 catalog names — yours may differ if the catalog evolved.
a365 develop add-mcp-servers "mcp_MailTools" "mcp_CalendarTools"

# If running from a different directory, use --project-path:
a365 develop add-mcp-servers "mcp_MailTools" "mcp_CalendarTools" --project-path ""
```

(Adjust the server names to match whichever servers the user selected from the live catalog. The CLI does case-insensitive trim-comparison, but the names must otherwise match the catalog's `mcpServerName` exactly.)

This command creates `ToolingManifest.json` if it does not exist, or adds the selected servers to it if it does.

> ⚠️ This command **only writes `ToolingManifest.json`** — it does NOT grant permissions.
> Permissions are handled separately in Phase 5.

### 3.2 Verify the manifest was updated

```bash
a365 develop list-configured
```

Confirm each selected server now appears in the output. The `Version` column shows `V1` or `V2` based on the server's scope pattern.

If a server was already configured, that is expected — the CLI is idempotent.

**Mark task complete: "Add WorkIQ MCP servers via CLI"**

---

## Phase 4 — Wire MCP Tool Service in Agent Code

**Mark task in progress: "Wire MCP tool service in agent code"**

The wiring pattern depends on **both** `programmingLanguage` and `agentStack` from the detection cache (loaded in Phase 0A Step 2; framework support guard in Phase 0B has already hard-stopped any unsupported pair). Pick the branch from the routing table:

| `programmingLanguage` | `agentStack` | Branch |
|----------------------|--------------|--------|
| `DotNet` | `Agent Framework` | §4.1 — .NET Agent Framework |
| `DotNet` | `Semantic Kernel` | §4.2 — .NET Semantic Kernel |
| `DotNet` | `Azure AI Foundry` | §4.3 — .NET Azure AI Foundry (best-effort; no published sample) |
| `NodeJS` | `LangChain` | §4.4 — Node.js LangChain |
| `NodeJS` | `OpenAI` | §4.5 — Node.js OpenAI |
| `NodeJS` | `Claude` | §4.6 — Node.js Claude SDK |
| `Python` | `Agent Framework` | §4.7 — Python Agent Framework |
| `Python` | `OpenAI` | §4.8 — Python OpenAI |
| `Python` | `Google ADK` | §4.9 — Python Google ADK |
| `Python` | `Semantic Kernel` | §4.10 — Python Semantic Kernel (best-effort; no published sample) |
| `Python` | `Azure AI Foundry` | §4.11 — Python Azure AI Foundry (best-effort; no published sample) |

> Detailed code patterns for each branch live in the language-specific reference docs:
> - .NET: `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/dotnet-workiq.md`
> - Node.js: `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/nodejs-workiq.md`
> - Python: `${CLAUDE_PLUGIN_ROOT}/skills/add-workiq-tools/references/python-workiq.md`

For every branch:
1. Mark new code with `// A365 WorkIQ — added by add-workiq-tools skill` (.NET / Node.js) or `# A365 WorkIQ — added by add-workiq-tools skill` (Python). For **best-effort** branches use `… best-effort wiring (verify against SDK source before production)` instead.
2. **Grep** for the framework's wiring symbol (`GetMcpToolsAsync` / `AddToolServersToAgentAsync` / `addToolServersToAgent` / `add_tool_servers_to_agent` / `McpToolRegistrationService`) before editing — skip the wiring step if already present.

### ⚠️ Preserve-observability rule (applies to ALL §4.x branches that edit the message-handler file)

`instrument-observability` writes anchors into the **same** files §4.x will touch — for .NET / Python the WorkIQ call goes into the same method body that the observability skill wraps with `BaggageBuilder` + `InvokeAgentScope` (.NET `OnMessageAsync`, Python `process_user_message`); for Node.js Claude SDK both skills edit `src/client.ts`. A naïve `Edit` with a too-broad `old_string` will silently delete the observability wrapping. **Before any `Edit` call inside §4.x, follow this checklist:**

1. **Grep the target file for the observability anchor symbols:**
   - **.NET** (`AgentApplication` subclass): `BaggageBuilder`, `InvokeAgentScope`, `InferenceScope`, `Agent365ObservabilityContext`
   - **Node.js** (`src/agent.ts` and `src/client.ts`): `BaggageBuilder`, `BaggageBuilderUtils`, `InvokeAgentScope`, `InferenceScope`, `AgenticTokenCacheInstance`, `preloadObservabilityToken`
   - **Python** (`agent.py`): `BaggageBuilder`, `populate_baggage`, `InvokeAgentScope`, `with builder.build()`, `AgenticTokenCache`

2. **If any of those symbols are present**, scope your `Edit` `old_string` **as narrowly as possible** — anchor on the **single statement immediately before/after** the new line, never a multi-statement block, never the method signature alone, never the full method body. Examples:
   - ✅ Good: anchor on the `var response = await chatClient.GetResponseAsync(...)` line and insert `GetMcpToolsAsync` immediately above it.
   - ❌ Bad: anchor on `protected override async Task OnMessageAsync(...)` plus the entire body — the replacement will obliterate the `using var baggageScope = ...` and `using var invokeScope = ...` blocks observability put there.

3. **After the `Edit` completes, re-grep the file** for the same observability anchors. If any disappeared, the edit clobbered observability — **revert the edit and re-apply with a narrower anchor**. Do not proceed to the next file.

4. If `instrument-observability` has NOT run yet in this project (no anchor symbols anywhere), wire WorkIQ normally — there is nothing to preserve. The composite `has_obs` signal in the parent skill (`make-ai-teammate` Phase 0A.3) is what tells you which case you're in; the cache reflects it.

This rule is enforced by `validate-add-workiq-tools.js` at session end: if `has_obs = true` was in the cache at session start, the validator re-checks for the observability anchors and **fails the session** if they were removed.

---

### §4.1 .NET Agent Framework

1. **Grep** `Microsoft.Agents.A365.Tooling` in `**/*.csproj`. If missing:
   ```bash
   dotnet add package Microsoft.Agents.A365.Tooling
   dotnet add package Microsoft.Agents.A365.Tooling.Extensions.AgentFramework
   ```
2. **Read** `dotnet-workiq.md` — sections "Program.cs — Service Registration" and "Agent Class — GetMcpToolsAsync (Agent Framework)".
3. **Edit** `Program.cs`: add the two-line `AddSingleton` + `AddSingleton` form (matches the verified `Agent365-Samples` AF sample). `builder.Services.AddMcpServices()` exists as a one-liner alternative but registers both as **Scoped** — the AF sample uses Singleton lifetimes to match `AgentApplication`'s singleton agent host and avoid captive-dependency issues. Skip if already present.
4. **Edit** the `AgentApplication` subclass: add the `GetMcpToolsAsync` call inside **`OnMessageAsync`** (Agent Framework's per-turn handler) — **not** `OnMessageActivityAsync` (older docs in this repo had that wrong; the verified sample uses `OnMessageAsync`).

### §4.2 .NET Semantic Kernel

> **SK API differs from AF.** SK uses `AddToolServersToAgentAsync` (mutates `Kernel`, void return), called **during agent initialization** — not per-message. Do not copy the AF pattern.

1. Install:
   ```bash
   dotnet add package Microsoft.Agents.A365.Tooling
   dotnet add package Microsoft.Agents.A365.Tooling.Extensions.SemanticKernel
   ```
2. **Read** `dotnet-workiq.md` — section "Agent Class — AddToolServersToAgentAsync (Semantic Kernel)".
3. **Edit** the agent-initialization code: call `AddToolServersToAgentAsync(kernel, userAuthorization, authHandlerName, turnContext, bearerToken?)` after the `Kernel` is built and before the first run.

### §4.3 .NET Azure AI Foundry (BEST-EFFORT — no published sample)

Tell the user verbatim: *"Microsoft publishes the `Microsoft.Agents.A365.Tooling.Extensions.AzureAIFoundry` package but no sample exists for it. Skill installs the package and stops — wire the call manually after reading the SDK source."*

1. Install:
   ```bash
   dotnet add package Microsoft.Agents.A365.Tooling.Extensions.AzureAIFoundry
   ```
2. Direct the user to the SDK source: https://github.com/microsoft/Agent365-dotnet/tree/main/src/Tooling/Extensions/AzureAIFoundry
3. Do **not** generate wiring code. Mark this branch complete with a best-effort note in the final summary.

### §4.4 Node.js LangChain

1. **Grep** `agents-a365-tooling` in `**/package.json`. If missing:
   ```bash
   npm install @microsoft/agents-a365-tooling @microsoft/agents-a365-tooling-extensions-langchain
   ```
2. **Read** `nodejs-workiq.md` — section "LangChain — Wiring (VERIFIED)".
3. **Edit** `src/client.ts` (or wherever the `getClient` factory lives). Add module-level `toolService = new McpToolRegistrationService()` singleton and the per-turn call inside `getClient`. **Capture the return value** — LangChain rebuilds the agent because `createAgent`'s tools are immutable.
4. After

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [microsoft](https://github.com/microsoft)
- **Source:** [microsoft/agent365-skills](https://github.com/microsoft/agent365-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-microsoft-agent365-skills-add-workiq-tools
- Seller: https://agentstack.voostack.com/s/microsoft
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
