gmail-workspace-mcp-server 0.4.6 → 0.4.8

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.
@@ -3,11 +3,13 @@ import type { ElicitationConfig } from './types.js';
3
3
  * Reads elicitation configuration from environment variables.
4
4
  *
5
5
  * Environment variables:
6
- * ELICITATION_ENABLED - "true" (default) or "false"
7
- * ELICITATION_REQUEST_URL - POST endpoint for HTTP fallback
8
- * ELICITATION_POLL_URL - GET endpoint for HTTP fallback polling
9
- * ELICITATION_TTL_MS - Request TTL in milliseconds (default: 300000)
10
- * ELICITATION_POLL_INTERVAL_MS - Poll interval in milliseconds (default: 5000, min: 1000)
11
- * ELICITATION_SESSION_ID - Session identifier for HTTP fallback `_meta`
6
+ * ELICITATION_ENABLED - "true" (default) or "false"
7
+ * ELICITATION_REQUEST_URL - POST endpoint for HTTP fallback
8
+ * ELICITATION_POLL_URL - GET endpoint for HTTP fallback polling
9
+ * ELICITATION_TTL_MS - Request TTL in milliseconds (default: 300000)
10
+ * ELICITATION_POLL_INTERVAL_MS - Poll interval in milliseconds (default: 5000, min: 1000)
11
+ * ELICITATION_SESSION_ID - Session identifier for HTTP fallback `_meta`
12
+ * ELICITATION_PREFER_HTTP_FALLBACK - "true" forces HTTP fallback over native elicitation
13
+ * when both are available. Default: "false".
12
14
  */
13
15
  export declare function readElicitationConfig(env?: Record<string, string | undefined>): ElicitationConfig;
@@ -14,16 +14,20 @@ function parsePositiveInt(value, defaultValue) {
14
14
  * Reads elicitation configuration from environment variables.
15
15
  *
16
16
  * Environment variables:
17
- * ELICITATION_ENABLED - "true" (default) or "false"
18
- * ELICITATION_REQUEST_URL - POST endpoint for HTTP fallback
19
- * ELICITATION_POLL_URL - GET endpoint for HTTP fallback polling
20
- * ELICITATION_TTL_MS - Request TTL in milliseconds (default: 300000)
21
- * ELICITATION_POLL_INTERVAL_MS - Poll interval in milliseconds (default: 5000, min: 1000)
22
- * ELICITATION_SESSION_ID - Session identifier for HTTP fallback `_meta`
17
+ * ELICITATION_ENABLED - "true" (default) or "false"
18
+ * ELICITATION_REQUEST_URL - POST endpoint for HTTP fallback
19
+ * ELICITATION_POLL_URL - GET endpoint for HTTP fallback polling
20
+ * ELICITATION_TTL_MS - Request TTL in milliseconds (default: 300000)
21
+ * ELICITATION_POLL_INTERVAL_MS - Poll interval in milliseconds (default: 5000, min: 1000)
22
+ * ELICITATION_SESSION_ID - Session identifier for HTTP fallback `_meta`
23
+ * ELICITATION_PREFER_HTTP_FALLBACK - "true" forces HTTP fallback over native elicitation
24
+ * when both are available. Default: "false".
23
25
  */
24
26
  export function readElicitationConfig(env = process.env) {
25
27
  const enabledRaw = env.ELICITATION_ENABLED;
26
28
  const enabled = enabledRaw === undefined ? true : enabledRaw.toLowerCase() !== 'false';
29
+ const preferHttpFallbackRaw = env.ELICITATION_PREFER_HTTP_FALLBACK;
30
+ const preferHttpFallback = preferHttpFallbackRaw !== undefined && preferHttpFallbackRaw.toLowerCase() === 'true';
27
31
  const pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, parsePositiveInt(env.ELICITATION_POLL_INTERVAL_MS, DEFAULT_POLL_INTERVAL_MS));
28
32
  return {
29
33
  enabled,
@@ -32,5 +36,6 @@ export function readElicitationConfig(env = process.env) {
32
36
  ttlMs: parsePositiveInt(env.ELICITATION_TTL_MS, DEFAULT_TTL_MS),
33
37
  pollIntervalMs,
34
38
  sessionId: env.ELICITATION_SESSION_ID,
39
+ preferHttpFallback,
35
40
  };
36
41
  }
@@ -2,12 +2,17 @@ import type { ElicitationConfig, ElicitationRequestedSchema, ElicitationResult,
2
2
  /**
3
3
  * Requests user confirmation through the best available mechanism.
4
4
  *
5
- * Decision tree:
5
+ * Decision tree (default):
6
6
  * 1. If elicitation is disabled (`ELICITATION_ENABLED=false`), returns `accept` immediately.
7
7
  * 2. If the client supports native elicitation, uses `server.elicitInput()`.
8
8
  * 3. If HTTP fallback URLs are configured, posts to the external endpoint and polls.
9
9
  * 4. Otherwise, throws an error indicating no elicitation mechanism is available.
10
10
  *
11
+ * When `cfg.preferHttpFallback` is true (set via `ELICITATION_PREFER_HTTP_FALLBACK=true`)
12
+ * AND both fallback URLs are configured, tier 3 runs before tier 2. This is intended for
13
+ * headless agent runtimes that falsely advertise elicitation capability but cannot actually
14
+ * surface the prompt to a user.
15
+ *
11
16
  * @param options - Configuration for the confirmation request.
12
17
  * @param config - Elicitation config (defaults to reading from env vars).
13
18
  * @returns The user's response.
@@ -98,15 +98,37 @@ async function pollElicitationStatus(config, requestId, expiresAt) {
98
98
  }
99
99
  return { action: 'expired' };
100
100
  }
101
+ /**
102
+ * Runs the HTTP fallback flow: POST a request, then poll until resolved or expired.
103
+ */
104
+ async function httpFallbackElicit(cfg, options) {
105
+ const clientRequestId = randomUUID();
106
+ const expiresAt = Date.now() + cfg.ttlMs;
107
+ const meta = {
108
+ 'com.pulsemcp/request-id': clientRequestId,
109
+ 'com.pulsemcp/expires-at': new Date(expiresAt).toISOString(),
110
+ ...(cfg.sessionId && { 'com.pulsemcp/session-id': cfg.sessionId }),
111
+ ...options.meta,
112
+ };
113
+ const postResponse = await postElicitationRequest(cfg, options.message, options.requestedSchema, meta);
114
+ // Use the server-provided requestId if available, otherwise fall back to the client-generated one
115
+ const requestId = postResponse.requestId || clientRequestId;
116
+ return pollElicitationStatus(cfg, requestId, expiresAt);
117
+ }
101
118
  /**
102
119
  * Requests user confirmation through the best available mechanism.
103
120
  *
104
- * Decision tree:
121
+ * Decision tree (default):
105
122
  * 1. If elicitation is disabled (`ELICITATION_ENABLED=false`), returns `accept` immediately.
106
123
  * 2. If the client supports native elicitation, uses `server.elicitInput()`.
107
124
  * 3. If HTTP fallback URLs are configured, posts to the external endpoint and polls.
108
125
  * 4. Otherwise, throws an error indicating no elicitation mechanism is available.
109
126
  *
127
+ * When `cfg.preferHttpFallback` is true (set via `ELICITATION_PREFER_HTTP_FALLBACK=true`)
128
+ * AND both fallback URLs are configured, tier 3 runs before tier 2. This is intended for
129
+ * headless agent runtimes that falsely advertise elicitation capability but cannot actually
130
+ * surface the prompt to a user.
131
+ *
110
132
  * @param options - Configuration for the confirmation request.
111
133
  * @param config - Elicitation config (defaults to reading from env vars).
112
134
  * @returns The user's response.
@@ -117,24 +139,18 @@ export async function requestConfirmation(options, config) {
117
139
  if (!cfg.enabled) {
118
140
  return { action: 'accept' };
119
141
  }
142
+ const httpFallbackAvailable = Boolean(cfg.requestUrl && cfg.pollUrl);
143
+ // Opt-in: prefer HTTP fallback over native elicitation when both are available.
144
+ if (cfg.preferHttpFallback && httpFallbackAvailable) {
145
+ return httpFallbackElicit(cfg, options);
146
+ }
120
147
  // Tier 2: Native elicitation
121
148
  if (clientSupportsElicitation(options.server)) {
122
149
  return nativeElicit(options.server, options.message, options.requestedSchema);
123
150
  }
124
151
  // Tier 3: HTTP fallback
125
- if (cfg.requestUrl && cfg.pollUrl) {
126
- const clientRequestId = randomUUID();
127
- const expiresAt = Date.now() + cfg.ttlMs;
128
- const meta = {
129
- 'com.pulsemcp/request-id': clientRequestId,
130
- 'com.pulsemcp/expires-at': new Date(expiresAt).toISOString(),
131
- ...(cfg.sessionId && { 'com.pulsemcp/session-id': cfg.sessionId }),
132
- ...options.meta,
133
- };
134
- const postResponse = await postElicitationRequest(cfg, options.message, options.requestedSchema, meta);
135
- // Use the server-provided requestId if available, otherwise fall back to the client-generated one
136
- const requestId = postResponse.requestId || clientRequestId;
137
- return pollElicitationStatus(cfg, requestId, expiresAt);
152
+ if (httpFallbackAvailable) {
153
+ return httpFallbackElicit(cfg, options);
138
154
  }
139
155
  // Tier 4: No mechanism available
140
156
  throw new Error('Elicitation is enabled but no mechanism is available. ' +
@@ -64,6 +64,16 @@ export interface ElicitationConfig {
64
64
  pollIntervalMs: number;
65
65
  /** Session identifier included as `com.pulsemcp/session-id` in `_meta` of HTTP fallback requests. */
66
66
  sessionId?: string;
67
+ /**
68
+ * When true, prefer HTTP fallback (Tier 3) over native elicitation (Tier 2)
69
+ * when both are available. Default: false.
70
+ *
71
+ * Useful for headless agent runtimes (e.g., Claude Code under Agent Orchestrator)
72
+ * that advertise the `elicitation` client capability but have no real interactive
73
+ * user — native `elicitInput()` calls auto-cancel without ever surfacing a prompt.
74
+ * Forcing the HTTP fallback routes the request to an external approval UI instead.
75
+ */
76
+ preferHttpFallback?: boolean;
67
77
  }
68
78
  /**
69
79
  * The result of an elicitation request.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulsemcp/mcp-elicitation",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Elicitation support library for PulseMCP MCP servers - provides native elicitation with HTTP fallback",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gmail-workspace-mcp-server",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "MCP server for Gmail integration with OAuth2 and service account support",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -34,7 +34,7 @@
34
34
  "stage-publish": "npm version"
35
35
  },
36
36
  "dependencies": {
37
- "@modelcontextprotocol/sdk": "^1.19.1",
37
+ "@modelcontextprotocol/sdk": "^1.29.0",
38
38
  "@pulsemcp/mcp-elicitation": "file:../../../libs/elicitation",
39
39
  "google-auth-library": "^10.5.0",
40
40
  "zod": "^3.24.1"