Skip to content

feat(rules): add delete-rule tool and fix edit-rule-sequence imports - #55

Open
FelixAsencioEncephalon wants to merge 1 commit into
ryaker:mainfrom
EncephalonAI:feat/delete-rule-tool
Open

feat(rules): add delete-rule tool and fix edit-rule-sequence imports#55
FelixAsencioEncephalon wants to merge 1 commit into
ryaker:mainfrom
EncephalonAI:feat/delete-rule-tool

Conversation

@FelixAsencioEncephalon

@FelixAsencioEncephalon FelixAsencioEncephalon commented Apr 11, 2026

Copy link
Copy Markdown

Summary

Adds a new delete-rule MCP tool that removes an existing inbox rule via DELETE /me/mailFolders/inbox/messageRules/{id}. Also fixes a pre-existing ReferenceError bug in rules/index.js that would crash edit-rule-sequence at runtime.

Motivation

ryaker/outlook-mcp currently exposes create-rule, list-rules, and edit-rule-sequence but not delete-rule. This creates a trap: if a caller accidentally creates a mis-scoped rule (e.g. a filter that's too broad and catches legitimate mail), the only way to remove it is to click through the Outlook Web settings UI — which defeats the purpose of having an MCP abstraction over mailbox rule management.

I hit this in real use: I created a rule that matched all emails from `no-reply@substack.com` when I actually wanted it scoped to specific subject patterns. Without `delete-rule`, I had to either manually clean up in Outlook or reach past the MCP to call Graph API directly.

What's in this PR

1. New `delete-rule` tool (`rules/delete.js`)

  • Takes either `ruleName` or `ruleId`
  • When called with `ruleName`:
    • 0 matches → returns "not found"
    • 1 match → deletes it
    • 2+ matches → returns a disambiguated list with IDs and conditions (`from`, `subjectContains`, `hasAttachment`), asking the caller to re-invoke with a specific `ruleId`
  • When called with `ruleId` → deletes directly, no lookup
  • Standard MCP error handling: Authentication required path, generic error path
  • Mirrors the response shape and error patterns of `create-rule` and `edit-rule-sequence` for consistency

2. Bug fix in `rules/index.js`

`handleEditRuleSequence` uses `ensureAuthenticated` and `callGraphAPI` but these aren't imported at the top of the file. Anyone calling `edit-rule-sequence` would get a `ReferenceError: ensureAuthenticated is not defined` at runtime. Hoisted the imports alongside the new `delete-rule` imports so both paths work.

Testing

  • Loaded the patched module via `node -e "const r = require('./rules'); ..."` — confirms 4 tool handlers registered (list, create, edit-sequence, delete), `handleDeleteRule` exports as a function
  • Started the MCP server via `node index.js` — boots cleanly with the new tool
  • Real-world smoke test against a live Outlook mailbox:
    • Called `delete-rule` with a name that matched 2 rules → returned the disambiguated list as expected
    • Called `delete-rule` with a specific `ruleId` → deleted the targeted rule successfully
    • Called `delete-rule` with a nonexistent name → returned "not found" message (verified error path)
    • Called `delete-rule` with a unique name → deleted successfully (also verified that the tool is destructive when the name is unique — documented this in the tool description so callers don't accidentally use it as a verification probe)

Tool description tradeoff

The tool description explicitly warns about the multi-match → single-match transition: if you delete one of two duplicate-named rules, the remaining one can be deleted by the same `ruleName` call that previously returned a disambiguated list. This is documented so MCP clients don't use delete-rule as a verification probe after a delete.

Files changed

  • New: `rules/delete.js` (handler)
  • Modified: `rules/index.js` (register new tool, hoist missing imports)

No dependencies added. No breaking changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added ability to delete inbox message rules by name or ID, with input validation and clear feedback when no matches or multiple matches are found.

Adds a new delete-rule MCP tool that removes an existing inbox rule
via DELETE /me/mailFolders/inbox/messageRules/{id}. Supports lookup
by name or explicit ruleId. When multiple rules share a name, the
handler returns a disambiguated list with IDs and their conditions
so the caller can re-invoke with a specific ruleId.

Also fixes a pre-existing bug in rules/index.js where the
handleEditRuleSequence function references ensureAuthenticated and
callGraphAPI without importing them at the top of the file, which
would cause edit-rule-sequence to throw ReferenceError at runtime.
Hoisting those imports next to the delete-rule imports so both work.

Closes the gap where users who accidentally create a mis-scoped rule
(e.g. a filter that's too broad) can only remove it by clicking
through the Outlook Web settings UI, which defeats the purpose of
having an MCP abstraction over mailbox rule management.
@codeant-ai

codeant-ai Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

User does not have a PR Review subscription.

Go to Team management and add this email to the PR Review subscription.

@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

A new delete-rule handler module is introduced that validates input parameters, authenticates users, resolves rule names to IDs via Microsoft Graph, and executes rule deletion with comprehensive error messaging for various scenarios.

Changes

Cohort / File(s) Summary
Delete Rule Handler
rules/delete.js, rules/index.js
Introduced new delete-rule functionality with a dedicated handler module that validates inputs (ruleName or ruleId), authenticates users, resolves rule names to IDs with user-facing feedback for no matches or conflicts, and deletes rules via Microsoft Graph API. Integrated into rules tooling with schema definition and handler wiring.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Handler as Delete Rule Handler
    participant Auth as Authentication
    participant Graph as Microsoft Graph API
    
    User->>Handler: Call delete-rule (ruleName or ruleId)
    Handler->>Auth: Ensure authenticated
    Auth-->>Handler: Authentication verified
    Handler->>Graph: GET /me/mailFolders/inbox/messageRules
    Graph-->>Handler: List of rules
    Handler->>Handler: Resolve ruleName to ruleId
    alt No matches or multiple matches
        Handler-->>User: User-facing message (ID/condition list)
    else Single match found
        Handler->>Graph: DELETE /me/mailFolders/inbox/messageRules/{targetRuleId}
        Graph-->>Handler: Deletion confirmed
        Handler-->>User: Success response
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rule goes whoosh, into the bin,
With graph-fu strong and auth to win,
No more confusion when names collide,
The inbox tidied far and wide!
🗑️✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding a delete-rule tool and fixing imports in the rules module, which matches both files modified.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the delete-rule tool for deleting Outlook inbox rules by name or ID, including logic to resolve name conflicts. The review feedback suggests using optional chaining when mapping email addresses to improve resilience against malformed API responses and recommends implementing pagination for rule retrieval to avoid missing entries when a user has many rules.

Comment thread rules/delete.js
.map((r, i) => {
const conditions = [];
if (r.conditions?.fromAddresses?.length > 0) {
conditions.push(`from: ${r.conditions.fromAddresses.map(a => a.emailAddress.address).join(', ')}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The mapping function assumes that each object in fromAddresses has an emailAddress property with an address. While the Microsoft Graph API typically provides this structure, using optional chaining would make the code more resilient to unexpected or malformed API responses and prevent a potential runtime crash.

Suggested change
conditions.push(`from: ${r.conditions.fromAddresses.map(a => a.emailAddress.address).join(', ')}`);
conditions.push(`from: ${r.conditions.fromAddresses.map(a => a.emailAddress?.address || 'unknown').join(', ')}`);

Comment thread rules/delete.js

// If only ruleName was provided, resolve it to an ID
if (!targetRuleId) {
const rules = await getInboxRules(accessToken);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The getInboxRules function (imported from ./list) currently uses a non-paginated Graph API call. If a user has a large number of inbox rules (typically more than 10-100 depending on API defaults), this tool might fail to find a rule by ruleName if it resides on a subsequent page of results. Consider updating getInboxRules in rules/list.js to use callGraphAPIPaginated to ensure all rules are searched.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
rules/index.js (1)

174-187: Push the “ruleName OR ruleId required” constraint into JSON schema.

The schema currently accepts an empty object and relies on runtime rejection. Adding schema-level validation gives earlier feedback and cleaner tool-contract enforcement.

Suggested fix
     inputSchema: {
       type: "object",
       properties: {
         ruleName: {
           type: "string",
           description: "Name of the rule to delete. If multiple rules share this name, the tool will return the list and ask for a specific ID."
         },
         ruleId: {
           type: "string",
           description: "Specific rule ID (from Microsoft Graph) to delete. Use this when multiple rules share the same name."
         }
       },
-      required: []
+      anyOf: [
+        { required: ["ruleName"] },
+        { required: ["ruleId"] }
+      ]
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/index.js` around lines 174 - 187, Update the inputSchema object so the
JSON Schema enforces that at least one of ruleName or ruleId is provided
(instead of allowing an empty object); modify the schema (inside rules/index.js
where inputSchema is defined) to keep the properties for ruleName and ruleId but
add a oneOf (or anyOf) clause requiring either ["ruleName"] or ["ruleId"] so the
validator fails early when both are missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rules/delete.js`:
- Around line 13-15: The function handleDeleteRule destructures ruleName and
ruleId from args which will throw if args is undefined; guard by checking that
args is present (e.g., if (!args || typeof args !== 'object') return a
structured MCP error response) or use a safe default (const { ruleName, ruleId }
= args || {}) before using them; update handleDeleteRule to validate
ruleName/ruleId after guarding and return the appropriate MCP response when
missing so the handler never throws.

---

Nitpick comments:
In `@rules/index.js`:
- Around line 174-187: Update the inputSchema object so the JSON Schema enforces
that at least one of ruleName or ruleId is provided (instead of allowing an
empty object); modify the schema (inside rules/index.js where inputSchema is
defined) to keep the properties for ruleName and ruleId but add a oneOf (or
anyOf) clause requiring either ["ruleName"] or ["ruleId"] so the validator fails
early when both are missing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0400c32a-0bfc-492c-bb83-2191be5622d6

📥 Commits

Reviewing files that changed from the base of the PR and between 95d6ff2 and da8821a.

📒 Files selected for processing (2)
  • rules/delete.js
  • rules/index.js

Comment thread rules/delete.js
Comment on lines +13 to +15
async function handleDeleteRule(args) {
const { ruleName, ruleId } = args;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Guard args before destructuring to avoid runtime throw.

On Line 14, destructuring from args will throw when the tool is invoked without arguments, so the handler never returns a structured MCP response.

Suggested fix
-async function handleDeleteRule(args) {
-  const { ruleName, ruleId } = args;
+async function handleDeleteRule(args = {}) {
+  const { ruleName, ruleId } = args;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function handleDeleteRule(args) {
const { ruleName, ruleId } = args;
async function handleDeleteRule(args = {}) {
const { ruleName, ruleId } = args;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/delete.js` around lines 13 - 15, The function handleDeleteRule
destructures ruleName and ruleId from args which will throw if args is
undefined; guard by checking that args is present (e.g., if (!args || typeof
args !== 'object') return a structured MCP error response) or use a safe default
(const { ruleName, ruleId } = args || {}) before using them; update
handleDeleteRule to validate ruleName/ruleId after guarding and return the
appropriate MCP response when missing so the handler never throws.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants