gogcli-mcp-calendar 2.23.2 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +53 -36
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/src/tools/calendar-extra.ts +11 -6
- package/tests/tools/calendar-extra.test.ts +33 -8
package/dist/index.js
CHANGED
|
@@ -31756,6 +31756,7 @@ function formatAuthHealth(raw, now) {
|
|
|
31756
31756
|
// ../gogcli-mcp/src/tools/auth.ts
|
|
31757
31757
|
function registerAuthToolsWith(server, defaultServices) {
|
|
31758
31758
|
const servicesDescribe = `Services to authorize: "all" or comma-separated list (e.g. "sheets,gmail,calendar"). Default: "${defaultServices}". Prefer the narrowest set you need \u2014 requesting a service whose Google API is not enabled on the OAuth client's project makes Google reject the WHOLE request with invalid_scope.`;
|
|
31759
|
+
const extraScopesDescribe = "Additional raw OAuth scope URIs to request, comma-separated, on top of the ones `services` implies. Use for scopes no service covers \u2014 e.g. https://www.googleapis.com/auth/bigquery.readonly, required before gog_sheets_datasource_* can read BigQuery-backed Connected Sheets. Leave unset otherwise: an extra scope whose API is not enabled on the OAuth client project makes Google reject the WHOLE authorization with invalid_scope.";
|
|
31759
31760
|
server.registerTool("gog_auth_list", {
|
|
31760
31761
|
description: "List the Google accounts stored in gogcli, with their scopes. This reads local configuration only \u2014 it does not contact Google and does NOT tell you whether an account still works: a signed-out account whose refresh token expired or was revoked is listed here exactly like a healthy one, scopes and all. Use gog_auth_health to check whether an account can actually authenticate.",
|
|
31761
31762
|
annotations: { readOnlyHint: true },
|
|
@@ -31805,11 +31806,14 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
31805
31806
|
annotations: { destructiveHint: true },
|
|
31806
31807
|
inputSchema: {
|
|
31807
31808
|
email: external_exports.string().describe("Google account email to authorize"),
|
|
31808
|
-
services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
|
|
31809
|
+
services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
|
|
31810
|
+
extraScopes: external_exports.string().optional().describe(extraScopesDescribe)
|
|
31809
31811
|
}
|
|
31810
|
-
}, async ({ email: email3, services = defaultServices }) => {
|
|
31812
|
+
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
31811
31813
|
try {
|
|
31812
|
-
|
|
31814
|
+
const args = ["auth", "add", email3, "--services", services];
|
|
31815
|
+
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`, "--force-consent");
|
|
31816
|
+
return rawTextResult(await run(args, {
|
|
31813
31817
|
interactive: true,
|
|
31814
31818
|
timeout: 3e5
|
|
31815
31819
|
}));
|
|
@@ -31821,14 +31825,14 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
31821
31825
|
description: "Begin REMOTE/headless Google authorization (step 1 of 2). Returns a sign-in URL to open in any browser \u2014 no local server or terminal on the gogcli host is needed, so this works over the hosted connector where the interactive gog_auth_add cannot. Hand the URL to the user; after they sign in, the browser is redirected to a localhost URL that fails to load \u2014 that is expected. They copy that full redirected URL (from the address bar) and you pass it to gog_auth_add_complete. The link is valid for 10 minutes. If you pass a custom `services` here, pass the SAME value to gog_auth_add_complete or the second step will not match this one.",
|
|
31822
31826
|
inputSchema: {
|
|
31823
31827
|
email: external_exports.string().describe("Google account email to authorize"),
|
|
31824
|
-
services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
|
|
31828
|
+
services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
|
|
31829
|
+
extraScopes: external_exports.string().optional().describe(`${extraScopesDescribe} Pass the SAME value to gog_auth_add_complete.`)
|
|
31825
31830
|
}
|
|
31826
|
-
}, async ({ email: email3, services = defaultServices }) => {
|
|
31831
|
+
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
31827
31832
|
try {
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
|
|
31831
|
-
));
|
|
31833
|
+
const args = ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"];
|
|
31834
|
+
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
|
|
31835
|
+
return rawTextResult(await run(args, { redactMode: "tokens" }));
|
|
31832
31836
|
} catch (err) {
|
|
31833
31837
|
return errorResult(errorText(err));
|
|
31834
31838
|
}
|
|
@@ -31843,25 +31847,28 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
31843
31847
|
),
|
|
31844
31848
|
services: external_exports.string().optional().default(defaultServices).describe(
|
|
31845
31849
|
`Services authorized \u2014 MUST match the value passed to gog_auth_add_url. Default: "${defaultServices}".`
|
|
31850
|
+
),
|
|
31851
|
+
extraScopes: external_exports.string().optional().describe(
|
|
31852
|
+
"Extra OAuth scope URIs \u2014 MUST match the value passed to gog_auth_add_url, for the same reason `services` must: the two steps have to describe the same grant."
|
|
31846
31853
|
)
|
|
31847
31854
|
}
|
|
31848
|
-
}, async ({ email: email3, redirectUrl, services = defaultServices }) => {
|
|
31855
|
+
}, async ({ email: email3, redirectUrl, services = defaultServices, extraScopes }) => {
|
|
31849
31856
|
try {
|
|
31850
|
-
|
|
31851
|
-
|
|
31852
|
-
|
|
31853
|
-
|
|
31854
|
-
|
|
31855
|
-
|
|
31856
|
-
|
|
31857
|
-
|
|
31858
|
-
|
|
31859
|
-
|
|
31860
|
-
|
|
31861
|
-
|
|
31862
|
-
|
|
31863
|
-
|
|
31864
|
-
));
|
|
31857
|
+
const args = [
|
|
31858
|
+
"auth",
|
|
31859
|
+
"add",
|
|
31860
|
+
email3,
|
|
31861
|
+
"--remote",
|
|
31862
|
+
"--step",
|
|
31863
|
+
"2",
|
|
31864
|
+
"--auth-url",
|
|
31865
|
+
redirectUrl,
|
|
31866
|
+
"--services",
|
|
31867
|
+
services,
|
|
31868
|
+
"--force-consent"
|
|
31869
|
+
];
|
|
31870
|
+
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
|
|
31871
|
+
return rawTextResult(await run(args));
|
|
31865
31872
|
} catch (err) {
|
|
31866
31873
|
return errorResult(errorText(err));
|
|
31867
31874
|
}
|
|
@@ -31880,13 +31887,19 @@ function authToolsFor(defaultServices) {
|
|
|
31880
31887
|
// ../gogcli-mcp/src/tools/calendar.ts
|
|
31881
31888
|
function registerCalendarTools(server) {
|
|
31882
31889
|
server.registerTool("gog_calendar_events", {
|
|
31883
|
-
description: 'List calendar events.
|
|
31890
|
+
description: 'List calendar events. Describe the window ONE way and one way only (gog >= 0.36.0 rejects the rest as ambiguous rather than silently discarding a flag): today on its own; or from + to; or from + days; or days on its own (a window of that many days starting today). today cannot be combined with from, to or days, and days cannot be combined with to. gog returns only 10 events by default, so a wide date range is USUALLY INCOMPLETE: raise max, or page with pageToken until the response carries no nextPageToken. A response carrying "truncated": true is an incomplete view \u2014 never conclude an event does not exist from one.',
|
|
31884
31891
|
annotations: { readOnlyHint: true },
|
|
31885
31892
|
inputSchema: {
|
|
31886
31893
|
calendarId: external_exports.string().optional().describe("Calendar ID (default: primary calendar)"),
|
|
31887
31894
|
from: external_exports.string().optional().describe("Start time filter (RFC3339, date, or natural language)"),
|
|
31888
|
-
to: external_exports.string().optional().describe("End time filter (RFC3339, date, or natural language)"),
|
|
31889
|
-
|
|
31895
|
+
to: external_exports.string().optional().describe("End time filter (RFC3339, date, or natural language). Mutually exclusive with today and with days."),
|
|
31896
|
+
// gog >= 0.36.0 (openclaw/gogcli#981). Before that release --days sat in
|
|
31897
|
+
// a switch arm evaluated ahead of --from, so `--from 2026-09-25 --days 5`
|
|
31898
|
+
// silently threw --from away and answered for today instead — at exit 0,
|
|
31899
|
+
// in a well-formed table. It is only exposed here now that it means what
|
|
31900
|
+
// it says.
|
|
31901
|
+
days: external_exports.number().int().positive().optional().describe('Window LENGTH in days (calendar days, DST-aware), measured from `from` when one is given and from today otherwise. Use from + days for "the week of the 25th"; days alone for "the next N days". Mutually exclusive with to and with today.'),
|
|
31902
|
+
today: external_exports.boolean().optional().describe("Only show today's events. A complete window on its own \u2014 mutually exclusive with from, to and days."),
|
|
31890
31903
|
query: external_exports.string().optional().describe("Free text search within events"),
|
|
31891
31904
|
max: external_exports.number().int().optional().describe("Max events to return. gog defaults to 10, which silently hides the rest \u2014 raise it, or page with pageToken."),
|
|
31892
31905
|
pageToken: pageTokenParam,
|
|
@@ -31896,11 +31909,12 @@ function registerCalendarTools(server) {
|
|
|
31896
31909
|
timezone: external_exports.string().optional().describe(`Display timezone for event times (IANA name, e.g. America/New_York, or "local" for the system timezone). Default: each event's timezone, then its calendar's timezone.`),
|
|
31897
31910
|
account: accountParam
|
|
31898
31911
|
}
|
|
31899
|
-
}, async ({ calendarId, from, to, today, query, max, pageToken, page, all, eventTypes, timezone, account }) => {
|
|
31912
|
+
}, async ({ calendarId, from, to, days, today, query, max, pageToken, page, all, eventTypes, timezone, account }) => {
|
|
31900
31913
|
const args = ["calendar", "events"];
|
|
31901
31914
|
if (calendarId) args.push(calendarId);
|
|
31902
31915
|
if (from) args.push(`--from=${from}`);
|
|
31903
31916
|
if (to) args.push(`--to=${to}`);
|
|
31917
|
+
if (days !== void 0) args.push(`--days=${days}`);
|
|
31904
31918
|
if (today) args.push("--today");
|
|
31905
31919
|
if (query) args.push(`--query=${query}`);
|
|
31906
31920
|
if (max !== void 0) args.push(`--max=${max}`);
|
|
@@ -32027,7 +32041,7 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
|
|
|
32027
32041
|
);
|
|
32028
32042
|
|
|
32029
32043
|
// ../gogcli-mcp/src/server.ts
|
|
32030
|
-
var VERSION = true ? "2.
|
|
32044
|
+
var VERSION = true ? "2.24.0" : "0.0.0";
|
|
32031
32045
|
|
|
32032
32046
|
// ../gogcli-mcp/src/auth-log.ts
|
|
32033
32047
|
var FAILURES = /* @__PURE__ */ new Set([
|
|
@@ -32630,16 +32644,19 @@ function registerExtraCalendarTools(server) {
|
|
|
32630
32644
|
return runOrDiagnose(args, { account });
|
|
32631
32645
|
});
|
|
32632
32646
|
server.registerTool("gog_calendar_search", {
|
|
32633
|
-
description: "Full-text search for events matching a query string, with optional time filters.",
|
|
32647
|
+
description: "Full-text search for events matching a query string, with optional time filters. Describe the window ONE way only (gog >= 0.36.0 rejects the rest as ambiguous instead of discarding a flag): one of today / tomorrow / week on its own, or from + to, or from + days, or days on its own. The fixed presets cannot be combined with from, to or days, and days cannot be combined with to.",
|
|
32634
32648
|
annotations: { readOnlyHint: true },
|
|
32635
32649
|
inputSchema: {
|
|
32636
32650
|
query: external_exports.string().describe("Search query"),
|
|
32637
32651
|
from: external_exports.string().optional().describe("Start time (RFC3339, date, or relative: now, today, tomorrow, monday)"),
|
|
32638
|
-
to: external_exports.string().optional().describe("End time (RFC3339, date, or relative: now, today, tomorrow, monday)"),
|
|
32639
|
-
today: external_exports.boolean().optional().describe("Today only"),
|
|
32640
|
-
tomorrow: external_exports.boolean().optional().describe("Tomorrow only"),
|
|
32641
|
-
week: external_exports.boolean().optional().describe("This week (uses weekStart, default Mon)"),
|
|
32642
|
-
|
|
32652
|
+
to: external_exports.string().optional().describe("End time (RFC3339, date, or relative: now, today, tomorrow, monday). Mutually exclusive with days."),
|
|
32653
|
+
today: external_exports.boolean().optional().describe("Today only. A complete window on its own \u2014 not combinable with from/to/days."),
|
|
32654
|
+
tomorrow: external_exports.boolean().optional().describe("Tomorrow only. A complete window on its own \u2014 not combinable with from/to/days."),
|
|
32655
|
+
week: external_exports.boolean().optional().describe("This week (uses weekStart, default Mon). A complete window on its own \u2014 not combinable with from/to/days."),
|
|
32656
|
+
// gog >= 0.36.0 (openclaw/gogcli#981) anchors --days at --from. It used
|
|
32657
|
+
// to mean "next N days from today" no matter what --from said, which is
|
|
32658
|
+
// why the old description here read that way.
|
|
32659
|
+
days: external_exports.number().optional().describe('Window LENGTH in days, measured from `from` when one is given and from today otherwise \u2014 NOT always "the next N days".'),
|
|
32643
32660
|
weekStart: external_exports.string().optional().describe("Week start day for week (sun, mon, ...)"),
|
|
32644
32661
|
calendar: external_exports.string().optional().describe("Calendar ID (default: primary)"),
|
|
32645
32662
|
max: external_exports.number().optional().describe("Max results (default: 25)"),
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.3",
|
|
4
4
|
"name": "gogcli-mcp-calendar",
|
|
5
5
|
"display_name": "gogcli (Calendar)",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.24.0",
|
|
7
7
|
"description": "Extended Google Calendar for Claude via gogcli — auth + Calendar events + Meet space management",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Chris Hall",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gogcli-mcp-calendar",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"mcpName": "io.github.chrischall/gogcli-mcp-calendar",
|
|
5
5
|
"description": "Extended Google Calendar + Meet MCP server via gogcli — auth + Calendar events + Meet space management",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -134,16 +134,21 @@ export function registerExtraCalendarTools(server: McpServer): void {
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
server.registerTool('gog_calendar_search', {
|
|
137
|
-
description: 'Full-text search for events matching a query string, with optional time filters.'
|
|
137
|
+
description: 'Full-text search for events matching a query string, with optional time filters. '
|
|
138
|
+
+ 'Describe the window ONE way only (gog >= 0.36.0 rejects the rest as ambiguous instead of discarding a flag): one of today / tomorrow / week on its own, '
|
|
139
|
+
+ 'or from + to, or from + days, or days on its own. The fixed presets cannot be combined with from, to or days, and days cannot be combined with to.',
|
|
138
140
|
annotations: { readOnlyHint: true },
|
|
139
141
|
inputSchema: {
|
|
140
142
|
query: z.string().describe('Search query'),
|
|
141
143
|
from: z.string().optional().describe('Start time (RFC3339, date, or relative: now, today, tomorrow, monday)'),
|
|
142
|
-
to: z.string().optional().describe('End time (RFC3339, date, or relative: now, today, tomorrow, monday)'),
|
|
143
|
-
today: z.boolean().optional().describe('Today only'),
|
|
144
|
-
tomorrow: z.boolean().optional().describe('Tomorrow only'),
|
|
145
|
-
week: z.boolean().optional().describe('This week (uses weekStart, default Mon)'),
|
|
146
|
-
|
|
144
|
+
to: z.string().optional().describe('End time (RFC3339, date, or relative: now, today, tomorrow, monday). Mutually exclusive with days.'),
|
|
145
|
+
today: z.boolean().optional().describe('Today only. A complete window on its own — not combinable with from/to/days.'),
|
|
146
|
+
tomorrow: z.boolean().optional().describe('Tomorrow only. A complete window on its own — not combinable with from/to/days.'),
|
|
147
|
+
week: z.boolean().optional().describe('This week (uses weekStart, default Mon). A complete window on its own — not combinable with from/to/days.'),
|
|
148
|
+
// gog >= 0.36.0 (openclaw/gogcli#981) anchors --days at --from. It used
|
|
149
|
+
// to mean "next N days from today" no matter what --from said, which is
|
|
150
|
+
// why the old description here read that way.
|
|
151
|
+
days: z.number().optional().describe('Window LENGTH in days, measured from `from` when one is given and from today otherwise — NOT always "the next N days".'),
|
|
147
152
|
weekStart: z.string().optional().describe('Week start day for week (sun, mon, ...)'),
|
|
148
153
|
calendar: z.string().optional().describe('Calendar ID (default: primary)'),
|
|
149
154
|
max: z.number().optional().describe('Max results (default: 25)'),
|
|
@@ -172,16 +172,16 @@ describe('gog_calendar_search', () => {
|
|
|
172
172
|
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'search', 'standup'], { account: undefined });
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
// One case per LEGAL window, not one case passing every flag at once. gog
|
|
176
|
+
// >= 0.36.0 (openclaw/gogcli#981) rejects a fixed preset alongside
|
|
177
|
+
// from/to/days, and days alongside to, with exit 2 — so the all-flags array
|
|
178
|
+
// this used to assert is one gog will not run, and a mocked test asserting
|
|
179
|
+
// it would keep passing forever while the tool was broken in the field.
|
|
180
|
+
it('passes an explicit from/to range with the non-window filters', async () => {
|
|
176
181
|
await harness.callTool('gog_calendar_search', {
|
|
177
182
|
query: 'standup',
|
|
178
183
|
from: 'today',
|
|
179
184
|
to: 'tomorrow',
|
|
180
|
-
today: true,
|
|
181
|
-
tomorrow: true,
|
|
182
|
-
week: true,
|
|
183
|
-
days: 7,
|
|
184
|
-
weekStart: 'sun',
|
|
185
185
|
calendar: 'primary',
|
|
186
186
|
max: 10,
|
|
187
187
|
});
|
|
@@ -189,14 +189,39 @@ describe('gog_calendar_search', () => {
|
|
|
189
189
|
[
|
|
190
190
|
'calendar', 'search', 'standup',
|
|
191
191
|
'--from=today', '--to=tomorrow',
|
|
192
|
-
'--today', '--tomorrow', '--week',
|
|
193
|
-
'--days=7', '--week-start=sun',
|
|
194
192
|
'--calendar=primary', '--max=10',
|
|
195
193
|
],
|
|
196
194
|
{ account: undefined },
|
|
197
195
|
);
|
|
198
196
|
});
|
|
199
197
|
|
|
198
|
+
it('anchors --days at --from when both are given', async () => {
|
|
199
|
+
await harness.callTool('gog_calendar_search', { query: 'standup', from: '2026-09-25', days: 7 });
|
|
200
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
201
|
+
['calendar', 'search', 'standup', '--from=2026-09-25', '--days=7'],
|
|
202
|
+
{ account: undefined },
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('passes each fixed preset on its own', async () => {
|
|
207
|
+
for (const [param, flag] of [['today', '--today'], ['tomorrow', '--tomorrow'], ['week', '--week']] as const) {
|
|
208
|
+
vi.mocked(lib.runOrDiagnose).mockClear();
|
|
209
|
+
await harness.callTool('gog_calendar_search', { query: 'standup', [param]: true });
|
|
210
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
211
|
+
['calendar', 'search', 'standup', flag],
|
|
212
|
+
{ account: undefined },
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('passes --week-start alongside --week', async () => {
|
|
218
|
+
await harness.callTool('gog_calendar_search', { query: 'standup', week: true, weekStart: 'sun' });
|
|
219
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
220
|
+
['calendar', 'search', 'standup', '--week', '--week-start=sun'],
|
|
221
|
+
{ account: undefined },
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
|
|
200
225
|
it('omits boolean flags when false', async () => {
|
|
201
226
|
await harness.callTool('gog_calendar_search', {
|
|
202
227
|
query: 'standup', today: false, tomorrow: false, week: false,
|