feat(calendar): add startAfter/startBefore/subject filters to list-events#193
feat(calendar): add startAfter/startBefore/subject filters to list-events#193Taranasus (taranasus) wants to merge 2 commits into
Conversation
…ents The list-events tool previously hardcoded a `start/dateTime ge '<now>'` filter, making past or already-started events invisible — surfaced in practice when an event that started earlier today couldn't be found and the Graph API had to be hit directly. Add three optional, backward-compatible parameters: - startAfter (ISO 8601): replaces the default "now" lower bound - startBefore (ISO 8601): strict upper bound on start - subject (string): case-insensitive substring match via Graph contains() When all three are absent, behaviour is unchanged. When any are supplied, the default "now" filter is replaced by the AND of the provided predicates. User input is escaped via the existing escapeODataString helper to prevent OData filter injection. Tests added in test/calendar/list.test.js cover: default-now preservation, each filter in isolation, combined filters, single-quote injection defence (skeleton check), and a regression guard for the "any-filter-replaces-now" semantic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 46 minutes and 39 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR adds optional filtering parameters to calendar event listing. The tool schema is extended with ChangesCalendar Event Filtering
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@calendar/index.js`:
- Around line 29-38: The schema for the query parameters currently allows any
string for startAfter and startBefore; update the calendar query/schema
definition that declares startAfter and startBefore to validate ISO 8601
datetimes at the boundary (e.g., add a JSON Schema "format": "date-time" or a
strict ISO8601 regex "pattern" to both startAfter and startBefore in
calendar/index.js) so invalid values are rejected before reaching runtime;
ensure both properties use the same validation rule and keep their existing
descriptions.
🪄 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: 7d3cb371-2c0e-42d1-ab08-6f26cbd2bc5c
📒 Files selected for processing (3)
calendar/index.jscalendar/list.jstest/calendar/list.test.js
Addresses CodeRabbit review feedback on PR littlebearapps#193: the schema only declared `type: 'string'` for the new datetime parameters, accepting anything. - Add `format: "date-time"` to the schema (declarative; honoured by MCP clients that validate format hints, otherwise documentary). - Add runtime `assertIsoDateTime()` guard in `buildListEventsFilter` since the project's schema-coerce layer does not enforce JSON Schema `format`. Invalid values now raise a clear error before any Graph call is made, instead of being passed through to Microsoft. - Tests: replace the redundant "escape quotes in startAfter" case with three rejection tests (malformed startAfter, malformed startBefore, injection-style string in startAfter) plus an acceptance test for valid forms (Z suffix and +01:00 offset). 760/760 passing.
Motivation
The
list-eventstool hardcodes astart/dateTime ge '<now>'filter, so any event that has already started (or that ended in the past) is invisible to the assistant. I hit this today trying to find a calendar event that started this morning — I had to bypass the MCP and call Graph API directly to locate it. Reasonable use cases like "find that meeting from last week" or "search my calendar for events titled 'X'" are currently impossible through the MCP.What this PR adds
Three optional parameters on
list-events. They are pure additions — the schema'srequiredarray is still empty and the default behaviour with no args is unchanged.startAfterstartBeforestartAfterto bound a window.subjectcontains(subject, '...')).Backward compatibility
When all three parameters are absent,
list-eventsbuilds exactly the samestart/dateTime ge '<now>'filter as before. The moment ANY of the three is supplied, the implicit "now" lower bound is removed and the provided predicates are AND-ed together — that's the whole point: a caller who explicitly asks for past events should not be silently filtered down to the future.Security
User-supplied strings are passed through the existing
escapeODataStringhelper ('→'') before interpolation into the$filter. A test verifies that an injection-style payload likex') or '1'='1ends up fully contained inside a single quoted-string literal and the resulting filter "skeleton" (with quoted segments stripped) contains noorkeyword or=operator outside quotes.Test coverage (
test/calendar/list.test.js)start ≥ now(captured timestamp falls between two test bookends, asserting it really is "now" at call time, not a constant).startAfter='2026-01-01T00:00:00Z'overrides the default filter.startBefore='2026-02-01T00:00:00Z'produces a strict upper bound.subject='Miele'producescontains(subject, 'Miele').subjectare escaped (skeleton-stripping check guards againstor 1=1style injection).buildListEventsFilterhelper covering the default-now and quote-escape paths.Quality gates
npm test— 757 / 757 passing (30 suites)npm run lint— no new errors; warnings are all pre-existing in unrelated filesnpm run format:check— clean🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests