@extrovert.dev/mcp 0.1.0-pre.3 → 0.1.0-pre.4

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/README.md CHANGED
@@ -10,9 +10,8 @@ persistent inbox on a domain Extrovert owns: created in one tool call, sends and
10
10
  **scoped key that expires and revokes on its own**. The key is bound to a fixed org + project (call
11
11
  `whoami` to see them) — there is no project selector to manage.
12
12
 
13
- > **Prerelease status:** the package is published on npm under the `next` dist-tag. Extrovert does
14
- > not currently operate a hosted MCP endpoint; use the packaged stdio server or an HTTP deployment
15
- > you operate yourself.
13
+ > **Prerelease status:** the package is published on npm under the `next` dist-tag. Extrovert also
14
+ > operates `https://mcp.extrovert.dev/mcp` as a stateless Streamable HTTP endpoint with browser OAuth.
16
15
 
17
16
  The standout tool is **`wait_for_email`** — a blocking call that returns the next matching message
18
17
  with the **OTP code and verification link already extracted**. Trigger a sign-in elsewhere, then act
@@ -66,6 +65,21 @@ ever reaches the model host. Keep every model host on the narrowest scoped key i
66
65
 
67
66
  ---
68
67
 
68
+ ## Connect with hosted OAuth
69
+
70
+ Give an OAuth-capable MCP client this URL:
71
+
72
+ ```text
73
+ https://mcp.extrovert.dev/mcp
74
+ ```
75
+
76
+ The endpoint publishes RFC 9728 protected-resource metadata and Clerk authorization-server
77
+ discovery. Compatible clients open the browser sign-in and consent flow, then store and refresh the
78
+ grant. Existing scoped `pk_agent_…` bearer keys also work when a client is configured explicitly.
79
+
80
+ The hosted service runs MCP SDK v2's fresh-server-per-request handler: no process-local session map,
81
+ sticky routing, or session teardown is required.
82
+
69
83
  ## Install and run the prerelease
70
84
 
71
85
  Use the explicit prerelease tag:
@@ -78,12 +92,12 @@ npx -y @extrovert.dev/mcp@next
78
92
  npx -y @extrovert.dev/mcp@next --help
79
93
  ```
80
94
 
81
- Pin `@extrovert.dev/mcp@0.1.0-pre.3` for a reproducible dogfood environment. The package installs the
95
+ Pin `@extrovert.dev/mcp@0.1.0-pre.4` for a reproducible dogfood environment. The package installs the
82
96
  `extrovert-mcp` binary; this is the only Extrovert CLI currently shipped.
83
97
 
84
98
  ## Build and run from source
85
99
 
86
- Requires Node ≥ 18.18. From this directory:
100
+ Requires Node ≥ 20. From this directory:
87
101
 
88
102
  ```bash
89
103
  pnpm install --frozen-lockfile
@@ -96,7 +110,7 @@ Two transports, one binary:
96
110
  # stdio — for local hosts (Claude Desktop, Claude Code, Cursor)
97
111
  node /absolute/path/to/extrovert/mcp/dist/bin.js
98
112
 
99
- # self-hosted Streamable HTTP at POST /mcp (default :8787)
113
+ # self-hosted stateless Streamable HTTP at /mcp (default :8787)
100
114
  node /absolute/path/to/extrovert/mcp/dist/bin.js --http --port 8787
101
115
  ```
102
116
 
@@ -116,6 +130,9 @@ pnpm run dev -- --http # tsx watch, HTTP
116
130
  | `EXTROVERT_MOCK` | *(off)* | Set `1` to force offline fixtures. |
117
131
  | `EXTROVERT_REQUEST_TIMEOUT_MS` | `30000` | Per-request timeout for non-blocking calls. |
118
132
  | `EXTROVERT_MAX_WAIT_MS` | `300000` | Upper bound the server allows `wait_for_email` to block. |
133
+ | `EXTROVERT_MCP_OAUTH_ENABLED` | *(off)* | Require Clerk OAuth or an introspected agent key on HTTP. |
134
+ | `EXTROVERT_MCP_OAUTH_ISSUER` | `https://clerk.extrovert.dev` | Clerk OAuth authorization-server issuer. |
135
+ | `EXTROVERT_MCP_PUBLIC_URL` | `https://mcp.extrovert.dev/mcp` | Public RFC 9728 resource identifier. |
119
136
  | `PORT` / `HOST` | `8787` / `0.0.0.0` | `--http` bind. |
120
137
 
121
138
  > **Offline fixtures are opt-in.** With no `EXTROVERT_API_KEY`, the server still talks to the live
@@ -225,23 +242,23 @@ continue. No polling, no separate "check the inbox" round-trips.
225
242
 
226
243
  ---
227
244
 
228
- ## Self-hosted HTTP notes
245
+ ## Stateless HTTP notes
229
246
 
230
247
  `extrovert-mcp --http` speaks MCP Streamable HTTP:
231
248
 
232
- - `POST /mcp` — client→server messages (the first must be `initialize`); the SDK assigns an
233
- `mcp-session-id` returned on the response.
234
- - `GET /mcp` — server→client SSE stream for an established session.
235
- - `DELETE /mcp` — tear a session down.
236
- - `GET /healthz` — liveness + mode (`mock`/`live`) + active session count.
249
+ - `POST /mcp` — one authenticated client→server request, served by a fresh MCP server instance.
250
+ - `GET /mcp` and `DELETE /mcp` — legacy stateless compatibility responses; no session is retained.
251
+ - `GET /healthz` — liveness, version, transport, and authentication mode.
252
+ - `GET /.well-known/oauth-protected-resource/mcp` — RFC 9728 protected-resource metadata when
253
+ OAuth is enabled.
237
254
 
238
- Each session gets an isolated server + client. A **per-request scoped key** may be supplied via
239
- `Authorization: Bearer …` (or `x-extrovert-api-key`), so one hosted deployment can serve many agents,
240
- each with their own scoped key falling back to `EXTROVERT_API_KEY` when no header is present. This
241
- is how a single hosted endpoint stays multi-tenant without ever holding an org-wide key.
255
+ Each request gets an isolated server + client and emits no `mcp-session-id`, so requests can land on
256
+ any cluster node. Production requires `Authorization: Bearer …` with either a Clerk OAuth access
257
+ token or an existing scoped `pk_agent_…` key. The OAuth principal and its fixed safe capabilities
258
+ are enforced again by the Extrovert API; the raw bearer token is never persisted by MCP or API.
242
259
 
243
- Extrovert does not operate this transport as a public hosted endpoint. These notes apply only to a
244
- deployment you control.
260
+ `EXTROVERT_API_KEY` and unauthenticated fixture mode remain local/self-hosting conveniences only;
261
+ the production service refuses to start without OAuth enabled.
245
262
 
246
263
  ---
247
264
 
@@ -252,7 +269,8 @@ src/
252
269
  bin.ts CLI entrypoint (--http | stdio)
253
270
  server.ts McpServer factory + instructions
254
271
  stdio.ts stdio transport
255
- http.ts Streamable HTTP transport (Express, per-session, bearer key)
272
+ http.ts stateless Streamable HTTP transport (Express, OAuth + scoped keys)
273
+ auth.ts Clerk OAuth verification, RFC discovery, and agent-key introspection
256
274
  tools.ts manifest-driven tools — zod schemas, annotations, handlers, registration
257
275
  client.ts thin typed Extrovert REST client (one method per /v1 endpoint)
258
276
  config.ts env-driven configuration
package/dist/auth.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { type AuthInfo, type OAuthMetadata, type OAuthTokenVerifier } from "@modelcontextprotocol/server";
2
+ interface ClerkRequestState {
3
+ isAuthenticated: boolean;
4
+ toAuth(): unknown;
5
+ }
6
+ interface ClerkOAuthClient {
7
+ authenticateRequest(request: Request, options: {
8
+ acceptsToken: "oauth_token";
9
+ }): Promise<ClerkRequestState>;
10
+ }
11
+ export interface HostedAuthConfig {
12
+ issuer: URL;
13
+ resourceUrl: URL;
14
+ serviceDocumentationUrl: URL;
15
+ scopesSupported: string[];
16
+ clerkSecretKey: string;
17
+ clerkPublishableKey: string;
18
+ }
19
+ export interface ExtrovertTokenVerifierOptions {
20
+ clerk: ClerkOAuthClient;
21
+ resourceUrl: URL;
22
+ apiBaseUrl: string;
23
+ fetch?: typeof fetch;
24
+ }
25
+ /** Verify Clerk OAuth tokens and existing scoped Extrovert agent keys. */
26
+ export declare class ExtrovertTokenVerifier implements OAuthTokenVerifier {
27
+ private readonly clerk;
28
+ private readonly resourceUrl;
29
+ private readonly apiBaseUrl;
30
+ private readonly doFetch;
31
+ constructor(options: ExtrovertTokenVerifierOptions);
32
+ verifyAccessToken(token: string): Promise<AuthInfo>;
33
+ private verifyAgentKey;
34
+ }
35
+ export declare function loadHostedAuthConfig(env?: NodeJS.ProcessEnv): HostedAuthConfig;
36
+ export declare function createHostedTokenVerifier(config: HostedAuthConfig, apiBaseUrl: string): ExtrovertTokenVerifier;
37
+ export declare function discoverOAuthMetadata(issuer: URL, doFetch?: typeof fetch): Promise<OAuthMetadata>;
38
+ export {};
39
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,8BAA8B,CAAC;AAkBtC,UAAU,iBAAiB;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,IAAI,OAAO,CAAC;CACnB;AAED,UAAU,gBAAgB;IACxB,mBAAmB,CACjB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;QAAE,YAAY,EAAE,aAAa,CAAA;KAAE,GACvC,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,EAAE,GAAG,CAAC;IACjB,uBAAuB,EAAE,GAAG,CAAC;IAC7B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,GAAG,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,0EAA0E;AAC1E,qBAAa,sBAAuB,YAAW,kBAAkB;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAM;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,OAAO,EAAE,6BAA6B;IAO5C,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;YA0C3C,cAAc;CAiC7B;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CA8B3F;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,MAAM,GACjB,sBAAsB,CASxB;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,GAAG,EACX,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,aAAa,CAAC,CAwBxB"}
package/dist/auth.js ADDED
@@ -0,0 +1,201 @@
1
+ import { createClerkClient } from "@clerk/backend";
2
+ import { OAuthError, OAuthErrorCode, } from "@modelcontextprotocol/server";
3
+ const DEFAULT_ISSUER = "https://clerk.extrovert.dev";
4
+ const DEFAULT_PUBLIC_URL = "https://mcp.extrovert.dev/mcp";
5
+ const DISCOVERY_TIMEOUT_MS = 10_000;
6
+ const AGENT_KEY_ATTESTATION_SECONDS = 300;
7
+ /** Verify Clerk OAuth tokens and existing scoped Extrovert agent keys. */
8
+ export class ExtrovertTokenVerifier {
9
+ clerk;
10
+ resourceUrl;
11
+ apiBaseUrl;
12
+ doFetch;
13
+ constructor(options) {
14
+ this.clerk = options.clerk;
15
+ this.resourceUrl = options.resourceUrl;
16
+ this.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
17
+ this.doFetch = options.fetch ?? fetch;
18
+ }
19
+ async verifyAccessToken(token) {
20
+ if (token.startsWith("pk_agent_"))
21
+ return this.verifyAgentKey(token);
22
+ if (token.startsWith("pk_enroll_")) {
23
+ throw invalidToken("Enrollment tokens cannot authenticate the hosted MCP endpoint");
24
+ }
25
+ const request = new Request(this.resourceUrl, {
26
+ headers: { authorization: `Bearer ${token}` },
27
+ });
28
+ let state;
29
+ try {
30
+ state = await this.clerk.authenticateRequest(request, {
31
+ acceptsToken: "oauth_token",
32
+ });
33
+ }
34
+ catch {
35
+ throw invalidToken("OAuth access token verification failed");
36
+ }
37
+ if (!state.isAuthenticated)
38
+ throw invalidToken("OAuth access token is invalid or expired");
39
+ const auth = state.toAuth();
40
+ if (!isClerkOAuthAuth(auth)) {
41
+ throw invalidToken("Bearer token is not a Clerk OAuth access token");
42
+ }
43
+ const expiresAt = jwtExpiry(token);
44
+ if (expiresAt === undefined) {
45
+ // Production is deliberately configured for Clerk JWT access tokens. The
46
+ // MCP bearer gate requires a concrete expiry and must not invent one.
47
+ throw invalidToken("OAuth access token has no verifiable expiration");
48
+ }
49
+ return {
50
+ token,
51
+ clientId: auth.oauth_token.clientId,
52
+ scopes: auth.scopes,
53
+ expiresAt,
54
+ resource: this.resourceUrl,
55
+ extra: {
56
+ tokenType: "oauth_token",
57
+ userId: auth.oauth_token.userId,
58
+ subject: auth.subject,
59
+ },
60
+ };
61
+ }
62
+ async verifyAgentKey(token) {
63
+ const controller = new AbortController();
64
+ const timeout = setTimeout(() => controller.abort(), DISCOVERY_TIMEOUT_MS);
65
+ try {
66
+ const response = await this.doFetch(`${this.apiBaseUrl}/v1/auth/me`, {
67
+ headers: { authorization: `Bearer ${token}` },
68
+ signal: controller.signal,
69
+ });
70
+ if (!response.ok)
71
+ throw invalidToken("Extrovert agent key is invalid or revoked");
72
+ const body = (await response.json());
73
+ const keyId = requiredString(body.key_id);
74
+ const agentId = requiredString(body.agent_id);
75
+ const scopes = stringArray(body.scopes);
76
+ if (!keyId || !agentId) {
77
+ throw invalidToken("Extrovert agent-key introspection returned an invalid principal");
78
+ }
79
+ return {
80
+ token,
81
+ clientId: `extrovert-agent:${agentId}`,
82
+ scopes,
83
+ // This is the lifetime of the successful introspection result. Because
84
+ // HTTP is stateless, every later request validates the key again.
85
+ expiresAt: Math.floor(Date.now() / 1000) + AGENT_KEY_ATTESTATION_SECONDS,
86
+ resource: this.resourceUrl,
87
+ extra: { tokenType: "agent_key", keyId, agentId },
88
+ };
89
+ }
90
+ catch (error) {
91
+ if (OAuthError.isInstance(error))
92
+ throw error;
93
+ throw invalidToken("Extrovert agent-key verification failed");
94
+ }
95
+ finally {
96
+ clearTimeout(timeout);
97
+ }
98
+ }
99
+ }
100
+ export function loadHostedAuthConfig(env = process.env) {
101
+ const issuer = new URL((env.EXTROVERT_MCP_OAUTH_ISSUER ?? DEFAULT_ISSUER).trim());
102
+ const resourceUrl = new URL((env.EXTROVERT_MCP_PUBLIC_URL ?? DEFAULT_PUBLIC_URL).trim());
103
+ const serviceDocumentationUrl = new URL((env.EXTROVERT_MCP_DOCUMENTATION_URL ?? "https://docs.extrovert.dev/mcp/overview/").trim());
104
+ const clerkSecretKey = (env.CLERK_SECRET_KEY ?? "").trim();
105
+ const clerkPublishableKey = (env.CLERK_PUBLISHABLE_KEY ??
106
+ env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY ??
107
+ "").trim();
108
+ if (!clerkSecretKey || !clerkPublishableKey) {
109
+ throw new Error("hosted MCP OAuth requires CLERK_SECRET_KEY and CLERK_PUBLISHABLE_KEY");
110
+ }
111
+ if (issuer.protocol !== "https:" || resourceUrl.protocol !== "https:") {
112
+ throw new Error("hosted MCP OAuth issuer and resource URL must use HTTPS");
113
+ }
114
+ const scopesSupported = (env.EXTROVERT_MCP_OAUTH_SCOPES ?? "openid profile email")
115
+ .split(/[\s,]+/)
116
+ .map((scope) => scope.trim())
117
+ .filter(Boolean);
118
+ return {
119
+ issuer,
120
+ resourceUrl,
121
+ serviceDocumentationUrl,
122
+ scopesSupported,
123
+ clerkSecretKey,
124
+ clerkPublishableKey,
125
+ };
126
+ }
127
+ export function createHostedTokenVerifier(config, apiBaseUrl) {
128
+ return new ExtrovertTokenVerifier({
129
+ clerk: createClerkClient({
130
+ secretKey: config.clerkSecretKey,
131
+ publishableKey: config.clerkPublishableKey,
132
+ }),
133
+ resourceUrl: config.resourceUrl,
134
+ apiBaseUrl,
135
+ });
136
+ }
137
+ export async function discoverOAuthMetadata(issuer, doFetch = fetch) {
138
+ const url = new URL("/.well-known/oauth-authorization-server", issuer);
139
+ const controller = new AbortController();
140
+ const timeout = setTimeout(() => controller.abort(), DISCOVERY_TIMEOUT_MS);
141
+ try {
142
+ const response = await doFetch(url, {
143
+ headers: { accept: "application/json" },
144
+ signal: controller.signal,
145
+ });
146
+ if (!response.ok)
147
+ throw new Error(`OAuth discovery returned HTTP ${response.status}`);
148
+ const metadata = (await response.json());
149
+ if (metadata.issuer !== issuer.toString().replace(/\/$/, "")) {
150
+ throw new Error("OAuth discovery issuer does not match EXTROVERT_MCP_OAUTH_ISSUER");
151
+ }
152
+ for (const field of ["authorization_endpoint", "token_endpoint"]) {
153
+ const value = metadata[field];
154
+ if (typeof value !== "string" || new URL(value).protocol !== "https:") {
155
+ throw new Error(`OAuth discovery is missing a secure ${field}`);
156
+ }
157
+ }
158
+ return metadata;
159
+ }
160
+ finally {
161
+ clearTimeout(timeout);
162
+ }
163
+ }
164
+ function isClerkOAuthAuth(value) {
165
+ if (!value || typeof value !== "object")
166
+ return false;
167
+ const candidate = value;
168
+ return (candidate.isAuthenticated === true &&
169
+ candidate.tokenType === "oauth_token" &&
170
+ typeof candidate.subject === "string" &&
171
+ Array.isArray(candidate.scopes) &&
172
+ !!candidate.oauth_token &&
173
+ typeof candidate.oauth_token.userId === "string" &&
174
+ typeof candidate.oauth_token.clientId === "string");
175
+ }
176
+ function jwtExpiry(token) {
177
+ const payload = token.split(".")[1];
178
+ if (!payload)
179
+ return undefined;
180
+ try {
181
+ const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
182
+ return typeof decoded.exp === "number" && Number.isSafeInteger(decoded.exp)
183
+ ? decoded.exp
184
+ : undefined;
185
+ }
186
+ catch {
187
+ return undefined;
188
+ }
189
+ }
190
+ function requiredString(value) {
191
+ return typeof value === "string" ? value.trim() : "";
192
+ }
193
+ function stringArray(value) {
194
+ return Array.isArray(value)
195
+ ? value.filter((item) => typeof item === "string" && item.trim() !== "")
196
+ : [];
197
+ }
198
+ function invalidToken(message) {
199
+ return new OAuthError(OAuthErrorCode.InvalidToken, message);
200
+ }
201
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,UAAU,EACV,cAAc,GAIf,MAAM,8BAA8B,CAAC;AAEtC,MAAM,cAAc,GAAG,6BAA6B,CAAC;AACrD,MAAM,kBAAkB,GAAG,+BAA+B,CAAC;AAC3D,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAyC1C,0EAA0E;AAC1E,MAAM,OAAO,sBAAsB;IAChB,KAAK,CAAmB;IACxB,WAAW,CAAM;IACjB,UAAU,CAAS;IACnB,OAAO,CAAe;IAEvC,YAAY,OAAsC;QAChD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,KAAa;QACnC,IAAI,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACrE,IAAI,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,MAAM,YAAY,CAAC,+DAA+D,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE;YAC5C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QACH,IAAI,KAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE;gBACpD,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,YAAY,CAAC,wCAAwC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,eAAe;YAAE,MAAM,YAAY,CAAC,0CAA0C,CAAC,CAAC;QAC3F,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,YAAY,CAAC,gDAAgD,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,yEAAyE;YACzE,sEAAsE;YACtE,MAAM,YAAY,CAAC,iDAAiD,CAAC,CAAC;QACxE,CAAC;QACD,OAAO;YACL,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;YACnC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS;YACT,QAAQ,EAAE,IAAI,CAAC,WAAW;YAC1B,KAAK,EAAE;gBACL,SAAS,EAAE,aAAa;gBACxB,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;gBAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB;SACF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,KAAa;QACxC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,oBAAoB,CAAC,CAAC;QAC3E,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,aAAa,EAAE;gBACnE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;gBAC7C,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,YAAY,CAAC,2CAA2C,CAAC,CAAC;YAClF,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;YAChE,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBACvB,MAAM,YAAY,CAAC,iEAAiE,CAAC,CAAC;YACxF,CAAC;YACD,OAAO;gBACL,KAAK;gBACL,QAAQ,EAAE,mBAAmB,OAAO,EAAE;gBACtC,MAAM;gBACN,uEAAuE;gBACvE,kEAAkE;gBAClE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,6BAA6B;gBACxE,QAAQ,EAAE,IAAI,CAAC,WAAW;gBAC1B,KAAK,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE;aAClD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YAC9C,MAAM,YAAY,CAAC,yCAAyC,CAAC,CAAC;QAChE,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACvE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,0BAA0B,IAAI,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAClF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,wBAAwB,IAAI,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACzF,MAAM,uBAAuB,GAAG,IAAI,GAAG,CACrC,CAAC,GAAG,CAAC,+BAA+B,IAAI,0CAA0C,CAAC,CAAC,IAAI,EAAE,CAC3F,CAAC;IACF,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,MAAM,mBAAmB,GAAG,CAC1B,GAAG,CAAC,qBAAqB;QACzB,GAAG,CAAC,iCAAiC;QACrC,EAAE,CACH,CAAC,IAAI,EAAE,CAAC;IACT,IAAI,CAAC,cAAc,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,WAAW,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,eAAe,GAAG,CAAC,GAAG,CAAC,0BAA0B,IAAI,sBAAsB,CAAC;SAC/E,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO;QACL,MAAM;QACN,WAAW;QACX,uBAAuB;QACvB,eAAe;QACf,cAAc;QACd,mBAAmB;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAwB,EACxB,UAAkB;IAElB,OAAO,IAAI,sBAAsB,CAAC;QAChC,KAAK,EAAE,iBAAiB,CAAC;YACvB,SAAS,EAAE,MAAM,CAAC,cAAc;YAChC,cAAc,EAAE,MAAM,CAAC,mBAAmB;SAC3C,CAAC;QACF,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU;KACX,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAW,EACX,UAAwB,KAAK;IAE7B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,yCAAyC,EAAE,MAAM,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAC3E,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;YAClC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACtF,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;QACpE,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACtF,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,EAAE,CAAC;YACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACtE,MAAM,IAAI,KAAK,CAAC,uCAAuC,KAAK,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QACD,OAAO,QAAyB,CAAC;IACnC,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,OAAO,CACL,SAAS,CAAC,eAAe,KAAK,IAAI;QAClC,SAAS,CAAC,SAAS,KAAK,aAAa;QACrC,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ;QACrC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC;QAC/B,CAAC,CAAC,SAAS,CAAC,WAAW;QACvB,OAAO,SAAS,CAAC,WAAW,CAAC,MAAM,KAAK,QAAQ;QAChD,OAAO,SAAS,CAAC,WAAW,CAAC,QAAQ,KAAK,QAAQ,CACnD,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAE5E,CAAC;QACF,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC;YACzE,CAAC,CAAC,OAAO,CAAC,GAAG;YACb,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QACxF,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,IAAI,UAAU,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC"}
package/dist/bin.js CHANGED
@@ -59,7 +59,9 @@ Environment:
59
59
  EXTROVERT_API_BASE_URL Base URL of the Extrovert REST API (default https://api.extrovert.dev)
60
60
  EXTROVERT_API_KEY Scoped agent key (pk_agent_…) or enrollment key (pk_enroll_…)
61
61
  EXTROVERT_MOCK Set to 1 to force offline fixture mode
62
- PORT / HOST Override --http bind (also honored by hosting platforms)
62
+ EXTROVERT_MCP_OAUTH_ENABLED Set to 1 to protect HTTP with Clerk OAuth + scoped agent keys
63
+ EXTROVERT_MCP_PUBLIC_URL Public OAuth resource URL (default https://mcp.extrovert.dev/mcp)
64
+ PORT / HOST Override --http bind (also honored by hosting platforms)
63
65
 
64
66
  Tools: redeem_enrollment, create_inbox, list_inboxes, get_inbox, update_inbox, delete_inbox,
65
67
  send_email, reply_email, read_messages, list_threads, search, wait_for_email
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAStC,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAY,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ,CAAC;YACd,KAAK,UAAU;gBACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;gBAClB,MAAM;YACR,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,IAAI;oBAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAChD,MAAM;YACR,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,IAAI;oBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBAC3B,MAAM;YACR,CAAC;YACD,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR;gBACE,gEAAgE;gBAChE,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;CAiBZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,GAAqC,EAAE,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAStC,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAY,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ,CAAC;YACd,KAAK,UAAU;gBACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;gBAClB,MAAM;YACR,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,IAAI;oBAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAChD,MAAM;YACR,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,IAAI;oBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBAC3B,MAAM;YACR,CAAC;YACD,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR;gBACE,gEAAgE;gBAChE,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;CAmBZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,GAAqC,EAAE,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/config.d.ts CHANGED
@@ -46,6 +46,6 @@ type ReviewPolicy = "require_review" | "auto_send_graduated" | "allow_direct";
46
46
  */
47
47
  export declare function loadConfig(env?: NodeJS.ProcessEnv): ExtrovertConfig;
48
48
  export declare const SERVER_NAME = "extrovert";
49
- export declare const SERVER_VERSION = "0.1.0-pre.3";
49
+ export declare const SERVER_VERSION = "0.1.0-pre.4";
50
50
  export {};
51
51
  //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -49,5 +49,5 @@ export function loadConfig(env = process.env) {
49
49
  };
50
50
  }
51
51
  export const SERVER_NAME = "extrovert";
52
- export const SERVER_VERSION = "0.1.0-pre.3";
52
+ export const SERVER_VERSION = "0.1.0-pre.4";
53
53
  //# sourceMappingURL=config.js.map
@@ -36,10 +36,10 @@ export interface DiffJson {
36
36
  export type { ReviewIntent, ReviewFeedback, Rule, ReviewEvent } from "./types.js";
37
37
  /**
38
38
  * The published version of the Extrovert Review-Loop open contract (D14).
39
- * `0.1.0-pre.3` — PROVISIONAL, pre-1.0; aligned to the SDK package version + the MCP
39
+ * `0.1.0-pre.4` — PROVISIONAL, pre-1.0; aligned to the SDK package version + the MCP
40
40
  * `SERVER_VERSION` + the openapi `info.version`.
41
41
  */
42
- export declare const CONTRACT_VERSION: "0.1.0-pre.3";
42
+ export declare const CONTRACT_VERSION: "0.1.0-pre.4";
43
43
  /** The stability posture of a published contract version. */
44
44
  export type ContractStability = "provisional" | "stable";
45
45
  /** The machine-readable manifest of the open contract (D14) — mirrors the SDK. */
package/dist/contract.js CHANGED
@@ -15,10 +15,10 @@
15
15
  */
16
16
  /**
17
17
  * The published version of the Extrovert Review-Loop open contract (D14).
18
- * `0.1.0-pre.3` — PROVISIONAL, pre-1.0; aligned to the SDK package version + the MCP
18
+ * `0.1.0-pre.4` — PROVISIONAL, pre-1.0; aligned to the SDK package version + the MCP
19
19
  * `SERVER_VERSION` + the openapi `info.version`.
20
20
  */
21
- export const CONTRACT_VERSION = "0.1.0-pre.3";
21
+ export const CONTRACT_VERSION = "0.1.0-pre.4";
22
22
  /**
23
23
  * The published manifest. Mirrors the SDK `CONTRACT_MANIFEST` (the MCP surface is
24
24
  * a subset of the SDK's, so `shapes` lists the agent-plane shapes the MCP server
package/dist/http.d.ts CHANGED
@@ -1,18 +1,32 @@
1
1
  /**
2
- * Hosted HTTP transport — MCP Streamable HTTP over Express.
2
+ * Hosted MCP Streamable HTTP transport.
3
3
  *
4
- * Serves the same toolset as stdio at `POST /mcp` (plus `GET`/`DELETE /mcp` for
5
- * the SSE stream and session teardown). A scoped agent key may be supplied per
6
- * request via `Authorization: Bearer …` (or `x-extrovert-api-key`) so one hosted
7
- * deployment can serve many agents, each with their own scoped key — never an
8
- * org-wide key (spec §14). Falls back to the env key when no header is present.
9
- *
10
- * Sessions are tracked by the `mcp-session-id` header the SDK assigns on
11
- * initialize, so each agent gets an isolated server + client instance.
4
+ * MCP SDK v2 constructs a fresh server for every request. There is no in-memory
5
+ * session map, so any cluster node can serve any request and a rolling deploy
6
+ * cannot strand client sessions. Clerk remains the OAuth authorization server;
7
+ * this process is only a protected resource server.
12
8
  */
9
+ import { type McpHttpHandler, type OAuthMetadata, type OAuthTokenVerifier } from "@modelcontextprotocol/server";
10
+ import type { Express } from "express";
11
+ import { type HostedAuthConfig } from "./auth.js";
12
+ import { type ExtrovertConfig } from "./config.js";
13
13
  export interface HttpServerOptions {
14
14
  port?: number;
15
15
  host?: string;
16
+ env?: NodeJS.ProcessEnv;
17
+ }
18
+ export interface CreateHttpAppOptions extends HttpServerOptions {
19
+ verifier?: OAuthTokenVerifier;
20
+ oauthMetadata?: OAuthMetadata;
21
+ authConfig?: HostedAuthConfig;
22
+ baseConfig?: ExtrovertConfig;
23
+ }
24
+ export interface HttpApp {
25
+ app: Express;
26
+ handler: McpHttpHandler;
27
+ authEnabled: boolean;
28
+ close(): Promise<void>;
16
29
  }
30
+ export declare function createHttpApp(options?: CreateHttpAppOptions): Promise<HttpApp>;
17
31
  export declare function runHttp(options?: HttpServerOptions): Promise<void>;
18
32
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqBD,wBAAsB,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+F5E"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,8BAA8B,CAAC;AAQtC,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE1D,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAA2C,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAG5F,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwFxF;AAED,wBAAsB,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5E"}