mcp-google-multi 6.0.0-alpha.10 → 6.0.0-alpha.11
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/arg-normalize.d.ts +9 -3
- package/dist/arg-normalize.js +14 -4
- package/dist/http-transport.d.ts +2 -1
- package/dist/registry.d.ts +4 -2
- package/dist/registry.js +24 -4
- package/package.json +1 -1
package/dist/arg-normalize.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
2
2
|
import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
export declare function argNormalizationEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
4
|
-
|
|
4
|
+
/** Declared scalar kind per schema key; drives value coercion on RENAMED keys
|
|
5
|
+
* only. Clients string-encode values for keys absent from the advertised
|
|
6
|
+
* schema, so a renamed key almost always arrives as a string — without
|
|
7
|
+
* coercion the rename would just move the -32602 from the key to the value. */
|
|
8
|
+
export type ArgKind = 'number' | 'boolean' | 'other';
|
|
9
|
+
export type ArgShape = ReadonlyMap<string, ArgKind>;
|
|
10
|
+
export declare function normalizeCallArguments(shape: ArgShape, args: Record<string, unknown>): {
|
|
5
11
|
args: Record<string, unknown>;
|
|
6
12
|
renamed: [string, string][];
|
|
7
13
|
};
|
|
8
|
-
export declare function normalizeMessage(msg: JSONRPCMessage, shapeFor: (tool: string) =>
|
|
14
|
+
export declare function normalizeMessage(msg: JSONRPCMessage, shapeFor: (tool: string) => ArgShape | undefined, log?: (line: string) => void): JSONRPCMessage;
|
|
9
15
|
/** Wrap a server-side transport so tools/call argument keys are normalized
|
|
10
16
|
* before the SDK validates them. The Protocol assigns `onmessage` during
|
|
11
17
|
* connect(); the interceptor lives in that setter, so the wrapper works
|
|
12
18
|
* identically for stdio and (per-request, stateless) HTTP transports. */
|
|
13
|
-
export declare function withArgNormalization(transport: Transport, shapeFor: (tool: string) =>
|
|
19
|
+
export declare function withArgNormalization(transport: Transport, shapeFor: (tool: string) => ArgShape | undefined, log?: (line: string) => void): Transport;
|
package/dist/arg-normalize.js
CHANGED
|
@@ -10,16 +10,26 @@ export function argNormalizationEnabled(env = process.env) {
|
|
|
10
10
|
return !/^(0|false|off|no)$/i.test((env.GOOGLE_ARG_NORMALIZE ?? '').trim());
|
|
11
11
|
}
|
|
12
12
|
const snakeToCamel = (key) => key.replace(/_([a-z0-9])/g, (_m, c) => c.toUpperCase());
|
|
13
|
-
|
|
13
|
+
function coerceRenamedValue(value, kind) {
|
|
14
|
+
if (typeof value !== 'string')
|
|
15
|
+
return value;
|
|
16
|
+
const v = value.trim();
|
|
17
|
+
if (kind === 'number' && /^-?\d+(\.\d+)?$/.test(v))
|
|
18
|
+
return Number(v);
|
|
19
|
+
if (kind === 'boolean' && /^(true|false)$/i.test(v))
|
|
20
|
+
return v.toLowerCase() === 'true';
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
export function normalizeCallArguments(shape, args) {
|
|
14
24
|
const renamed = [];
|
|
15
25
|
let out;
|
|
16
26
|
for (const key of Object.keys(args)) {
|
|
17
|
-
if (
|
|
27
|
+
if (shape.has(key) || !key.includes('_'))
|
|
18
28
|
continue;
|
|
19
29
|
const camel = snakeToCamel(key);
|
|
20
|
-
if (camel !== key &&
|
|
30
|
+
if (camel !== key && shape.has(camel) && !(camel in args)) {
|
|
21
31
|
out ??= { ...args };
|
|
22
|
-
out[camel] = out[key];
|
|
32
|
+
out[camel] = coerceRenamedValue(out[key], shape.get(camel));
|
|
23
33
|
delete out[key];
|
|
24
34
|
renamed.push([key, camel]);
|
|
25
35
|
}
|
package/dist/http-transport.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
2
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import type { HttpConfig } from './http-config.js';
|
|
4
|
+
import { type ArgShape } from './arg-normalize.js';
|
|
4
5
|
export type AuthOutcome = {
|
|
5
6
|
ok: true;
|
|
6
7
|
} | {
|
|
@@ -29,7 +30,7 @@ export interface HttpHostOptions {
|
|
|
29
30
|
* shared lock instead of wedging the transport (default 120s). */
|
|
30
31
|
dispatchTimeoutMs?: number;
|
|
31
32
|
/** tools/call argument-key normalization lookup (arg-normalize.ts); absent = off. */
|
|
32
|
-
argShapeFor?: (tool: string) =>
|
|
33
|
+
argShapeFor?: (tool: string) => ArgShape | undefined;
|
|
33
34
|
}
|
|
34
35
|
export declare function parseOwnerEmails(env?: NodeJS.ProcessEnv): string[];
|
|
35
36
|
/** Front guard: an Origin, if present, must be allowlisted; a Host must be
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { type Policy } from './write-control.js';
|
|
4
|
+
import type { ArgShape } from './arg-normalize.js';
|
|
4
5
|
export type Cud = 'read' | 'create' | 'update' | 'delete';
|
|
5
6
|
export type DiscoveryMode = 'lazy' | 'curated' | 'eager';
|
|
6
7
|
export declare function resolveDiscoveryMode(env?: NodeJS.ProcessEnv): DiscoveryMode;
|
|
@@ -49,8 +50,9 @@ export declare class ToolRegistry {
|
|
|
49
50
|
constructor(server: McpServer, policy: Policy, mode?: DiscoveryMode);
|
|
50
51
|
registerMeta: McpServer['registerTool'];
|
|
51
52
|
services(): string[];
|
|
52
|
-
/** Declared input-schema keys for one tool (tools/call arg
|
|
53
|
-
|
|
53
|
+
/** Declared input-schema keys + scalar kinds for one tool (tools/call arg
|
|
54
|
+
* normalization; the kind drives value coercion on renamed keys). */
|
|
55
|
+
argShape(name: string): ArgShape | undefined;
|
|
54
56
|
catalog(service: string, query?: string): CatalogOperation[];
|
|
55
57
|
reveal(service: string): boolean;
|
|
56
58
|
/** discover_all: advertise the full curated set at once. Idempotent. */
|
package/dist/registry.js
CHANGED
|
@@ -38,6 +38,23 @@ const SERVICE_OVERRIDES = {
|
|
|
38
38
|
};
|
|
39
39
|
// read tools that write local files — same savePath fanned across accounts would clobber
|
|
40
40
|
const FANOUT_EXCLUDE = new Set(['gmail_download_attachment', 'drive_download', 'drive_export']);
|
|
41
|
+
/** Unwrap optional/default/nullable to the declared scalar kind (zod 4 defs). */
|
|
42
|
+
function scalarKindOf(field) {
|
|
43
|
+
let cur = field;
|
|
44
|
+
for (let i = 0; i < 4 && cur?._zod?.def; i++) {
|
|
45
|
+
const def = cur._zod.def;
|
|
46
|
+
if (def.type === 'number')
|
|
47
|
+
return 'number';
|
|
48
|
+
if (def.type === 'boolean')
|
|
49
|
+
return 'boolean';
|
|
50
|
+
if (def.type === 'optional' || def.type === 'default' || def.type === 'nullable') {
|
|
51
|
+
cur = def.innerType;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
return 'other';
|
|
55
|
+
}
|
|
56
|
+
return 'other';
|
|
57
|
+
}
|
|
41
58
|
function isAccountEnum(field) {
|
|
42
59
|
const def = field?._zod?.def;
|
|
43
60
|
if (!def)
|
|
@@ -193,7 +210,8 @@ export class ToolRegistry {
|
|
|
193
210
|
services() {
|
|
194
211
|
return [...new Set(this.tools.filter((t) => !t.meta).map((t) => t.service))];
|
|
195
212
|
}
|
|
196
|
-
/** Declared input-schema keys for one tool (tools/call arg
|
|
213
|
+
/** Declared input-schema keys + scalar kinds for one tool (tools/call arg
|
|
214
|
+
* normalization; the kind drives value coercion on renamed keys). */
|
|
197
215
|
argShape(name) {
|
|
198
216
|
const cached = this.argShapeCache.get(name);
|
|
199
217
|
if (cached)
|
|
@@ -201,9 +219,11 @@ export class ToolRegistry {
|
|
|
201
219
|
const entry = this.tools.find((t) => t.name === name);
|
|
202
220
|
if (!entry)
|
|
203
221
|
return undefined;
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
222
|
+
const shape = new Map();
|
|
223
|
+
for (const [key, field] of Object.entries(entry.inputShape))
|
|
224
|
+
shape.set(key, scalarKindOf(field));
|
|
225
|
+
this.argShapeCache.set(name, shape);
|
|
226
|
+
return shape;
|
|
207
227
|
}
|
|
208
228
|
catalog(service, query) {
|
|
209
229
|
const q = query?.trim().toLowerCase();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-multi",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.11",
|
|
4
4
|
"description": "Local MCP server for Google Workspace (Gmail, Drive, Calendar, Sheets, Docs, Contacts, Tasks, Meet, Search Console, +Forms/Chat/Admin) across multiple accounts — OAuth-only, encrypted token storage, deny-by-default writes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|