mcp-google-multi 6.0.0-alpha.69 → 6.0.0-alpha.70
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/compose.d.ts +8 -1
- package/dist/compose.js +7 -0
- package/dist/index.js +4 -5
- package/dist/registry.js +9 -3
- package/package.json +1 -1
package/dist/compose.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
2
2
|
import type { ServerTarget } from './http-transport.js';
|
|
3
3
|
import { ToolRegistry, type DiscoveryMode } from './registry.js';
|
|
4
4
|
import { type IdentityContext } from './identity.js';
|
|
5
5
|
import type { Metrics } from './usage-metrics.js';
|
|
6
|
+
export interface McpServerOptions {
|
|
7
|
+
/** Sent in the initialize result; omitted entirely when absent or blank. */
|
|
8
|
+
instructions?: string;
|
|
9
|
+
}
|
|
10
|
+
/** The one place the MCP server is constructed, so an embedding host can pass
|
|
11
|
+
* per-session `instructions` without re-deriving the server identity. */
|
|
12
|
+
export declare function createMcpServer(version: string, opts?: McpServerOptions): McpServer;
|
|
6
13
|
export declare function buildRegistry(server: McpServer, ctx: IdentityContext, mode?: DiscoveryMode, metrics?: Metrics | null): ToolRegistry;
|
|
7
14
|
/** The per-request hooks bound to one registry: argument shapes, unknown-
|
|
8
15
|
* argument screening and the account a validation envelope names. Both
|
package/dist/compose.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// module must stay free of import-time side effects of its own: no argv
|
|
4
4
|
// parsing, no process.exit, no prints (accounts.js module-load resolution is
|
|
5
5
|
// the one inherited, pre-existing exception on the import chain).
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
6
7
|
import { GENERATED_SERVICES } from './tools/generated/index.js';
|
|
7
8
|
import { GENERATED_GATES, SERVICES, servicesAwaitingRestart, unknownToolMessage } from './services.js';
|
|
8
9
|
import { argNormalizationEnabled } from './arg-normalize.js';
|
|
@@ -16,6 +17,12 @@ import { registerAccountWizardTools } from './tools/account-wizard.js';
|
|
|
16
17
|
import { getToolsets, toolsetEnabled } from './toolsets.js';
|
|
17
18
|
import { isOwnerContext } from './identity.js';
|
|
18
19
|
import { resolveScopesForAccount } from './auth.js';
|
|
20
|
+
/** The one place the MCP server is constructed, so an embedding host can pass
|
|
21
|
+
* per-session `instructions` without re-deriving the server identity. */
|
|
22
|
+
export function createMcpServer(version, opts = {}) {
|
|
23
|
+
const instructions = opts.instructions?.trim() ? opts.instructions : undefined;
|
|
24
|
+
return new McpServer({ name: 'mcp-google-multi', version }, instructions ? { instructions } : undefined);
|
|
25
|
+
}
|
|
19
26
|
export function buildRegistry(server, ctx, mode, metrics = null) {
|
|
20
27
|
const policy = ctx.policy;
|
|
21
28
|
// The registry's account view IS the context's: fan-out expansion,
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,10 @@ import { readFileSync } from 'node:fs';
|
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
10
|
-
import { McpServer } from "@modelcontextprotocol/server";
|
|
11
10
|
import { resolveDiscoveryMode } from './registry.js';
|
|
12
11
|
import { isAllowed, describePolicy } from './write-control.js';
|
|
13
12
|
import { buildIdentityContext } from './identity.js';
|
|
14
|
-
import { buildRegistry, requestHooksFor } from './compose.js';
|
|
13
|
+
import { buildRegistry, createMcpServer, requestHooksFor } from './compose.js';
|
|
15
14
|
import { registerSetupPrompt } from './setup-prompt.js';
|
|
16
15
|
import { applyNetTuning } from './net-tuning.js';
|
|
17
16
|
import { withArgNormalization, withValidationEnvelope } from './arg-normalize.js';
|
|
@@ -81,7 +80,7 @@ async function main() {
|
|
|
81
80
|
if (process.argv.includes('config') && process.argv.includes('check')) {
|
|
82
81
|
const ctx = buildIdentityContext();
|
|
83
82
|
const policy = ctx.policy;
|
|
84
|
-
const registry = buildRegistry(
|
|
83
|
+
const registry = buildRegistry(createMcpServer(pkg.version), ctx);
|
|
85
84
|
const cud = registry.tools.filter((t) => t.cud !== 'read');
|
|
86
85
|
const disabled = cud.filter((t) => !isAllowed(t, policy));
|
|
87
86
|
const counts = registry.visibleCount();
|
|
@@ -190,7 +189,7 @@ async function main() {
|
|
|
190
189
|
// Build one McpServer + registry per transport at boot (P1 / BV gap #4:
|
|
191
190
|
// never rebuilt per request); `both` runs the two concurrently.
|
|
192
191
|
if (wantStdio) {
|
|
193
|
-
const server =
|
|
192
|
+
const server = createMcpServer(pkg.version);
|
|
194
193
|
const stdioMetrics = initMetricsFor('stdio', resolveDiscoveryMode());
|
|
195
194
|
const stdioCtx = buildIdentityContext(process.env, { transport: 'stdio' });
|
|
196
195
|
const registry = buildRegistry(server, stdioCtx, undefined, stdioMetrics);
|
|
@@ -239,7 +238,7 @@ async function main() {
|
|
|
239
238
|
if (configuredMode && configuredMode !== 'curated') {
|
|
240
239
|
process.stderr.write(`GOOGLE_DISCOVERY="${configuredMode}" is ignored over HTTP; the stateless transport forces "curated".\n`);
|
|
241
240
|
}
|
|
242
|
-
const httpServer =
|
|
241
|
+
const httpServer = createMcpServer(pkg.version);
|
|
243
242
|
const httpMetrics = initMetricsFor('http', 'curated');
|
|
244
243
|
const httpCtx = buildIdentityContext(process.env, { transport: 'http' });
|
|
245
244
|
const registry = buildRegistry(httpServer, httpCtx, 'curated', httpMetrics);
|
package/dist/registry.js
CHANGED
|
@@ -47,6 +47,10 @@ export function serviceOf(name) {
|
|
|
47
47
|
}
|
|
48
48
|
// read tools that write local files — same savePath fanned across accounts would clobber
|
|
49
49
|
const FANOUT_EXCLUDE = new Set(['gmail_download_attachment', 'drive_download', 'drive_export']);
|
|
50
|
+
/** cud=read for gating/fan-out, yet they write (local files, the account
|
|
51
|
+
* registry, an MCP-client config): advertised as writes so annotation-keyed
|
|
52
|
+
* clients prompt instead of auto-running them. */
|
|
53
|
+
const WRITES_DESPITE_READ = new Set([...FANOUT_EXCLUDE, 'account_add', 'account_reauth', 'account_write_config']);
|
|
50
54
|
/** Account-management tools: the `account` they take is the SUBJECT of the
|
|
51
55
|
* operation, not the identity it runs as, so injecting the configured default
|
|
52
56
|
* would silently retarget them. `account_add` would adopt the default as the
|
|
@@ -130,12 +134,14 @@ export class ToolRegistry {
|
|
|
130
134
|
this.registerTool = ((name, config, handler) => {
|
|
131
135
|
const service = serviceOf(name);
|
|
132
136
|
const cud = config.cud ?? inferCud(name);
|
|
133
|
-
//
|
|
137
|
+
// Every write is destructive: clients key per-call approval on it, and a
|
|
138
|
+
// create (send, share, upload) is no less consequential than an update.
|
|
134
139
|
// idempotent: reads trivially, deletes (already-gone = same), updates
|
|
135
140
|
// (overwrite converges); creates are not (send twice = two emails).
|
|
141
|
+
const writes = cud !== 'read' || WRITES_DESPITE_READ.has(name);
|
|
136
142
|
const annotations = {
|
|
137
|
-
readOnlyHint:
|
|
138
|
-
destructiveHint:
|
|
143
|
+
readOnlyHint: !writes,
|
|
144
|
+
destructiveHint: writes,
|
|
139
145
|
idempotentHint: cud !== 'create',
|
|
140
146
|
...config.annotations,
|
|
141
147
|
};
|
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.70",
|
|
4
4
|
"mcpName": "io.github.bakissation/mcp-google-multi",
|
|
5
5
|
"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.",
|
|
6
6
|
"type": "module",
|