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

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.
Files changed (51) hide show
  1. package/README.md +74 -31
  2. package/dist/auth.d.ts +39 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +201 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/bin.d.ts +5 -7
  7. package/dist/bin.d.ts.map +1 -1
  8. package/dist/bin.js +63 -52
  9. package/dist/bin.js.map +1 -1
  10. package/dist/cli.d.ts +14 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +459 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/client.d.ts +20 -1
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +41 -8
  17. package/dist/client.js.map +1 -1
  18. package/dist/config.d.ts +1 -1
  19. package/dist/config.js +1 -1
  20. package/dist/contract.d.ts +2 -2
  21. package/dist/contract.js +2 -2
  22. package/dist/credentials.d.ts +41 -0
  23. package/dist/credentials.d.ts.map +1 -0
  24. package/dist/credentials.js +203 -0
  25. package/dist/credentials.js.map +1 -0
  26. package/dist/fixtures.d.ts.map +1 -1
  27. package/dist/fixtures.js +23 -2
  28. package/dist/fixtures.js.map +1 -1
  29. package/dist/http.d.ts +23 -9
  30. package/dist/http.d.ts.map +1 -1
  31. package/dist/http.js +106 -104
  32. package/dist/http.js.map +1 -1
  33. package/dist/index.d.ts +4 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +3 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/server.d.ts +1 -1
  38. package/dist/server.d.ts.map +1 -1
  39. package/dist/server.js +8 -5
  40. package/dist/server.js.map +1 -1
  41. package/dist/stdio.d.ts.map +1 -1
  42. package/dist/stdio.js +25 -3
  43. package/dist/stdio.js.map +1 -1
  44. package/dist/tools.d.ts +1 -1
  45. package/dist/tools.d.ts.map +1 -1
  46. package/dist/tools.js +37 -16
  47. package/dist/tools.js.map +1 -1
  48. package/dist/types.d.ts +18 -1
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js.map +1 -1
  51. package/package.json +10 -4
package/dist/http.js CHANGED
@@ -1,124 +1,126 @@
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
  */
13
- import { randomUUID } from "node:crypto";
14
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
15
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
16
- import express from "express";
9
+ import { createMcpHandler, } from "@modelcontextprotocol/server";
10
+ import { createMcpExpressApp, getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, requireBearerAuth, } from "@modelcontextprotocol/express";
11
+ import { toNodeHandler } from "@modelcontextprotocol/node";
12
+ import { createHostedTokenVerifier, discoverOAuthMetadata, loadHostedAuthConfig, } from "./auth.js";
17
13
  import { ExtrovertClient } from "./client.js";
18
14
  import { loadConfig, SERVER_NAME, SERVER_VERSION } from "./config.js";
19
15
  import { createExtrovertServer } from "./server.js";
20
- const SESSION_HEADER = "mcp-session-id";
21
- /** Read a per-request scoped key from standard headers, if present. */
22
- function keyFromRequest(req) {
23
- const auth = req.header("authorization");
24
- if (auth?.toLowerCase().startsWith("bearer "))
25
- return auth.slice(7).trim();
26
- const custom = req.header("x-extrovert-api-key");
27
- if (custom)
28
- return custom.trim();
29
- return undefined;
30
- }
31
- /** Build a per-session config, layering an optional request key over env. */
32
- function configForRequest(base, req) {
33
- const key = keyFromRequest(req);
34
- if (key === undefined)
35
- return base;
36
- // A request key implies a live caller; honor it for this session.
37
- return { ...base, apiKey: key, mock: base.mock && key === "" };
38
- }
39
- export async function runHttp(options = {}) {
40
- const baseConfig = loadConfig();
41
- const port = options.port ?? Number.parseInt(process.env.PORT ?? "8787", 10);
42
- const host = options.host ?? process.env.HOST ?? "0.0.0.0";
43
- const app = express();
44
- app.use(express.json({ limit: "4mb" }));
45
- const sessions = new Map();
16
+ export async function createHttpApp(options = {}) {
17
+ const env = options.env ?? process.env;
18
+ const baseConfig = options.baseConfig ?? loadConfig(env);
19
+ const host = options.host ?? env.HOST ?? "0.0.0.0";
20
+ const productionAuth = parseBool(env.EXTROVERT_MCP_OAUTH_ENABLED);
21
+ const injectedAuth = options.verifier !== undefined || options.oauthMetadata !== undefined;
22
+ const authEnabled = productionAuth || injectedAuth;
23
+ let authConfig = options.authConfig;
24
+ let verifier = options.verifier;
25
+ let oauthMetadata = options.oauthMetadata;
26
+ if (authEnabled) {
27
+ authConfig ??= loadHostedAuthConfig(env);
28
+ verifier ??= createHostedTokenVerifier(authConfig, baseConfig.apiBaseUrl);
29
+ oauthMetadata ??= await discoverOAuthMetadata(authConfig.issuer);
30
+ }
31
+ else if (!baseConfig.mock && baseConfig.apiKey === "") {
32
+ throw new Error("HTTP transport requires EXTROVERT_MCP_OAUTH_ENABLED=1, EXTROVERT_API_KEY, or EXTROVERT_MOCK=1");
33
+ }
34
+ const allowedHosts = authConfig
35
+ ? uniqueStrings([
36
+ authConfig.resourceUrl.hostname,
37
+ "127.0.0.1",
38
+ "localhost",
39
+ "[::1]",
40
+ ...(env.EXTROVERT_MCP_ALLOWED_HOSTS ?? "").split(","),
41
+ ])
42
+ : undefined;
43
+ const app = createMcpExpressApp({ host, allowedHosts, jsonLimit: "4mb" });
44
+ const handler = createMcpHandler(({ authInfo }) => {
45
+ const config = configForRequest(baseConfig, authInfo?.token);
46
+ const client = new ExtrovertClient(config);
47
+ return createExtrovertServer({ config, client }).server;
48
+ }, {
49
+ legacy: "stateless",
50
+ onerror: (error) => process.stderr.write(`extrovert-mcp: protocol error: ${error.message}\n`),
51
+ });
52
+ const nodeHandler = toNodeHandler(handler, {
53
+ onerror: (error) => process.stderr.write(`extrovert-mcp: HTTP adapter error: ${error.message}\n`),
54
+ });
46
55
  app.get("/healthz", (_req, res) => {
47
56
  res.json({
48
57
  ok: true,
49
58
  server: SERVER_NAME,
50
59
  version: SERVER_VERSION,
51
- mode: baseConfig.mock ? "mock" : "live",
52
- sessions: sessions.size,
60
+ transport: "streamable-http-stateless",
61
+ auth: authEnabled
62
+ ? "oauth-or-agent-key"
63
+ : baseConfig.mock
64
+ ? "offline-fixtures"
65
+ : "environment-key",
53
66
  });
54
67
  });
55
- // Primary MCP endpoint: client→server messages (incl. initialize).
56
- app.post("/mcp", async (req, res) => {
57
- const sessionId = req.header(SESSION_HEADER);
58
- if (sessionId && sessions.has(sessionId)) {
59
- await sessions.get(sessionId).transport.handleRequest(req, res, req.body);
60
- return;
61
- }
62
- if (sessionId && !sessions.has(sessionId)) {
63
- res.status(404).json(jsonRpcError(-32001, "Unknown or expired session"));
64
- return;
65
- }
66
- if (!isInitializeRequest(req.body)) {
67
- res
68
- .status(400)
69
- .json(jsonRpcError(-32000, "First request must be an MCP initialize call"));
70
- return;
71
- }
72
- // New session: stand up a fresh server + client with the caller's key.
73
- const config = configForRequest(baseConfig, req);
74
- const client = new ExtrovertClient(config);
75
- const { server } = createExtrovertServer({ config, client });
76
- const transport = new StreamableHTTPServerTransport({
77
- sessionIdGenerator: () => randomUUID(),
78
- onsessioninitialized: (id) => {
79
- sessions.set(id, {
80
- transport,
81
- close: async () => {
82
- await server.close().catch(() => { });
83
- },
84
- });
85
- },
68
+ if (authEnabled && authConfig && verifier && oauthMetadata) {
69
+ app.use(mcpAuthMetadataRouter({
70
+ oauthMetadata,
71
+ resourceServerUrl: authConfig.resourceUrl,
72
+ serviceDocumentationUrl: authConfig.serviceDocumentationUrl,
73
+ scopesSupported: authConfig.scopesSupported,
74
+ resourceName: "Extrovert MCP",
75
+ }));
76
+ app.all("/mcp", requireBearerAuth({
77
+ verifier,
78
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(authConfig.resourceUrl),
79
+ }), (req, res) => {
80
+ void nodeHandler(req, res, req.body);
86
81
  });
87
- transport.onclose = () => {
88
- const id = transport.sessionId;
89
- if (id)
90
- sessions.delete(id);
91
- };
92
- await server.connect(transport);
93
- await transport.handleRequest(req, res, req.body);
94
- });
95
- // Server→client SSE stream + session teardown.
96
- const replay = async (req, res) => {
97
- const sessionId = req.header(SESSION_HEADER);
98
- if (!sessionId || !sessions.has(sessionId)) {
99
- res.status(404).json(jsonRpcError(-32001, "Unknown or expired session"));
100
- return;
101
- }
102
- await sessions.get(sessionId).transport.handleRequest(req, res);
103
- };
104
- app.get("/mcp", replay);
105
- app.delete("/mcp", replay);
106
- await new Promise((resolve) => {
107
- const httpServer = app.listen(port, host, () => {
108
- const mode = baseConfig.mock ? "offline fixtures" : `live API ${baseConfig.apiBaseUrl}`;
109
- process.stderr.write(`extrovert-mcp: HTTP transport listening on http://${host}:${port}/mcp — ${mode}\n`);
82
+ }
83
+ else {
84
+ app.all("/mcp", (req, res) => {
85
+ void nodeHandler(req, res, req.body);
86
+ });
87
+ }
88
+ return { app, handler, authEnabled, close: () => handler.close() };
89
+ }
90
+ export async function runHttp(options = {}) {
91
+ const env = options.env ?? process.env;
92
+ const port = options.port ?? Number.parseInt(env.PORT ?? "8787", 10);
93
+ const host = options.host ?? env.HOST ?? "0.0.0.0";
94
+ const runtime = await createHttpApp({ ...options, host, env });
95
+ await new Promise((resolve, reject) => {
96
+ const httpServer = runtime.app.listen(port, host, () => {
97
+ process.stderr.write(`extrovert-mcp: stateless HTTP listening on http://${host}:${port}/mcp — ${runtime.authEnabled ? "OAuth + scoped agent keys" : "local mode"}\n`);
110
98
  resolve();
111
99
  });
112
- const shutdown = () => {
113
- for (const session of sessions.values())
114
- void session.close();
115
- httpServer.close(() => process.exit(0));
116
- };
117
- process.on("SIGINT", shutdown);
118
- process.on("SIGTERM", shutdown);
100
+ httpServer.once("error", reject);
101
+ installShutdown(httpServer, runtime);
119
102
  });
120
103
  }
121
- function jsonRpcError(code, message) {
122
- return { jsonrpc: "2.0", error: { code, message }, id: null };
104
+ function configForRequest(base, requestToken) {
105
+ if (!requestToken)
106
+ return base;
107
+ return { ...base, apiKey: requestToken, mock: false };
108
+ }
109
+ function installShutdown(server, runtime) {
110
+ let closing = false;
111
+ const shutdown = () => {
112
+ if (closing)
113
+ return;
114
+ closing = true;
115
+ void runtime.close().finally(() => server.close(() => process.exit(0)));
116
+ };
117
+ process.on("SIGINT", shutdown);
118
+ process.on("SIGTERM", shutdown);
119
+ }
120
+ function parseBool(value) {
121
+ return ["1", "true", "yes", "on"].includes((value ?? "").trim().toLowerCase());
122
+ }
123
+ function uniqueStrings(values) {
124
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
123
125
  }
124
126
  //# sourceMappingURL=http.js.map
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,8 +6,10 @@
6
6
  */
7
7
  export { createExtrovertServer, type CreateExtrovertServerOptions } from "./server.js";
8
8
  export { runStdio } from "./stdio.js";
9
- export { runHttp, type HttpServerOptions } from "./http.js";
10
- export { ExtrovertClient, ExtrovertApiError, type CreateInboxInput, type UpdateInboxInput, type SendEmailInput, type ReplyEmailInput, type WaitForEmailInput, type RedeemEnrollmentInput, } from "./client.js";
9
+ export { createHttpApp, runHttp, type CreateHttpAppOptions, type HttpApp, type HttpServerOptions, } from "./http.js";
10
+ export { createHostedTokenVerifier, discoverOAuthMetadata, ExtrovertTokenVerifier, loadHostedAuthConfig, type ExtrovertTokenVerifierOptions, type HostedAuthConfig, } from "./auth.js";
11
+ export { ExtrovertClient, ExtrovertApiError, type CreateInboxInput, type UpdateInboxInput, type SendEmailInput, type ReplyEmailInput, type WaitForEmailInput, type RedeemEnrollmentInput, type DurableCredentialPersistenceStatus, type ExtrovertClientOptions, } from "./client.js";
12
+ export { createCredentialStore, credentialPaths, type CredentialPaths, type CredentialStore, type PendingSignup, type StoredCredential, } from "./credentials.js";
11
13
  export { loadConfig, SERVER_NAME, SERVER_VERSION, type ExtrovertConfig } from "./config.js";
12
14
  export { registerTools, TOOL_NAMES } from "./tools.js";
13
15
  export { extractOtpCode, extractVerificationLink, extractSignals } from "./extract.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKvF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE7F,YAAY,EACV,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,OAAO,EACP,gBAAgB,EAChB,kBAAkB,EAClB,IAAI,EACJ,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EACL,aAAa,EACb,OAAO,EACP,KAAK,oBAAoB,EACzB,KAAK,OAAO,EACZ,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,6BAA6B,EAClC,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,kCAAkC,EACvC,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKvF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE7F,YAAY,EACV,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,OAAO,EACP,gBAAgB,EAChB,kBAAkB,EAClB,IAAI,EACJ,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -6,8 +6,10 @@
6
6
  */
7
7
  export { createExtrovertServer } from "./server.js";
8
8
  export { runStdio } from "./stdio.js";
9
- export { runHttp } from "./http.js";
9
+ export { createHttpApp, runHttp, } from "./http.js";
10
+ export { createHostedTokenVerifier, discoverOAuthMetadata, ExtrovertTokenVerifier, loadHostedAuthConfig, } from "./auth.js";
10
11
  export { ExtrovertClient, ExtrovertApiError, } from "./client.js";
12
+ export { createCredentialStore, credentialPaths, } from "./credentials.js";
11
13
  export { loadConfig, SERVER_NAME, SERVER_VERSION } from "./config.js";
12
14
  export { registerTools, TOOL_NAMES } from "./tools.js";
13
15
  export { extractOtpCode, extractVerificationLink, extractSignals } from "./extract.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAqC,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAE5D,OAAO,EACL,eAAe,EACf,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEvF,+EAA+E;AAC/E,kFAAkF;AAClF,qDAAqD;AACrD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAqC,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EACL,aAAa,EACb,OAAO,GAIR,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GAGrB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,eAAe,EACf,iBAAiB,GASlB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,eAAe,GAKhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEvF,+EAA+E;AAC/E,kFAAkF;AAClF,qDAAqD;AACrD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
package/dist/server.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Builds an `McpServer` with the Extrovert toolset registered. Transport-agnostic:
5
5
  * the same server is used over stdio (local hosts) and Streamable HTTP (hosted).
6
6
  */
7
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { McpServer } from "@modelcontextprotocol/server";
8
8
  import { ExtrovertClient } from "./client.js";
9
9
  import { type ExtrovertConfig } from "./config.js";
10
10
  export interface CreateExtrovertServerOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAA2C,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAkB5F,MAAM,WAAW,4BAA4B;IAC3C,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG;IACjF,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB,CAeA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAA2C,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAqB5F,MAAM,WAAW,4BAA4B;IAC3C,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG;IACjF,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB,CAeA"}
package/dist/server.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Builds an `McpServer` with the Extrovert toolset registered. Transport-agnostic:
5
5
  * the same server is used over stdio (local hosts) and Streamable HTTP (hosted).
6
6
  */
7
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { McpServer } from "@modelcontextprotocol/server";
8
8
  import { ExtrovertClient } from "./client.js";
9
9
  import { loadConfig, SERVER_NAME, SERVER_VERSION } from "./config.js";
10
10
  import { registerTools } from "./tools.js";
@@ -12,11 +12,14 @@ const INSTRUCTIONS = [
12
12
  "Extrovert gives an AI agent a real, persistent inbox in one call.",
13
13
  "",
14
14
  "Typical flow:",
15
- " 1. redeem_enrollment if started without a key, exchange an enrollment token (pk_enroll_…) for a scoped agent key.",
16
- " 2. create_inbox — mint an inbox (omit username/domain for an instant shared-subdomain address).",
17
- " 3. send_email / reply_email — send via the inbox's authenticated sender.",
15
+ " 1. sign_up then verify_signup when started with no key, or redeem_enrollment when given an enrollment token.",
16
+ " 2. create_inbox — mint another inbox (omit username/domain for an instant shared-subdomain address).",
17
+ " 3. send_email / reply_email — submit via the inbox's authenticated sender and its review policy.",
18
18
  " 4. wait_for_email — block for an incoming message and read the extracted OTP code / verification link.",
19
- " 5. read_messages / list_threads / search — inspect the inbox.",
19
+ " 5. read_messages / get_message / list_threads / search — inspect the inbox directly; do not build raw HTTP or jq helpers.",
20
+ "",
21
+ "The packaged local stdio server stores full keys after verify_signup or redeem_enrollment and reloads them in future sessions.",
22
+ "The limited signup key is never promoted into that durable credential store.",
20
23
  "",
21
24
  "The agent key is bound to a FIXED org + project (call whoami to see them); there is no project selector. Addresses are",
22
25
  "real and live on domains Extrovert controls (smtp.extrovert.dev subdomains). Identifiers, addresses, and keys are stable",
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,YAAY,GAAG;IACnB,mEAAmE;IACnE,EAAE;IACF,eAAe;IACf,uHAAuH;IACvH,mGAAmG;IACnG,4EAA4E;IAC5E,0GAA0G;IAC1G,iEAAiE;IACjE,EAAE;IACF,wHAAwH;IACxH,0HAA0H;IAC1H,oCAAoC;CACrC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAOb,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,UAAwC,EAAE;IAK9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,EAC9C;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,YAAY,EAAE,YAAY;KAC3B,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,YAAY,GAAG;IACnB,mEAAmE;IACnE,EAAE;IACF,eAAe;IACf,gHAAgH;IAChH,wGAAwG;IACxG,oGAAoG;IACpG,0GAA0G;IAC1G,6HAA6H;IAC7H,EAAE;IACF,gIAAgI;IAChI,8EAA8E;IAC9E,EAAE;IACF,wHAAwH;IACxH,0HAA0H;IAC1H,oCAAoC;CACrC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAOb,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,UAAwC,EAAE;IAK9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,EAC9C;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,YAAY,EAAE,YAAY;KAC3B,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAe9C"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAmC9C"}
package/dist/stdio.js CHANGED
@@ -4,13 +4,35 @@
4
4
  * The host spawns this process and speaks MCP over stdin/stdout. Diagnostics go
5
5
  * to stderr only; stdout is reserved for the JSON-RPC stream.
6
6
  */
7
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
8
+ import { ExtrovertClient } from "./client.js";
9
+ import { loadConfig } from "./config.js";
10
+ import { createCredentialStore } from "./credentials.js";
8
11
  import { createExtrovertServer } from "./server.js";
9
12
  export async function runStdio() {
10
- const { server, config } = createExtrovertServer();
13
+ const credentialStore = createCredentialStore();
14
+ const stored = credentialStore.load();
15
+ const env = { ...process.env };
16
+ if (!(env.EXTROVERT_API_KEY ?? "").trim() && stored) {
17
+ env.EXTROVERT_API_KEY = stored.agent_key;
18
+ if (!(env.EXTROVERT_API_BASE_URL ?? "").trim()) {
19
+ env.EXTROVERT_API_BASE_URL = stored.api_base_url;
20
+ }
21
+ }
22
+ const config = loadConfig(env);
23
+ const client = new ExtrovertClient(config, {
24
+ onDurableAgentKey: config.mock
25
+ ? undefined
26
+ : (agentKey, apiBaseUrl) => {
27
+ credentialStore.save(agentKey, apiBaseUrl);
28
+ return { location: credentialStore.paths.credential };
29
+ },
30
+ });
31
+ const { server } = createExtrovertServer({ config, client });
11
32
  const transport = new StdioServerTransport();
12
33
  await server.connect(transport);
13
- const mode = config.mock ? "offline fixtures" : `live API ${config.apiBaseUrl}`;
34
+ const auth = config.apiKey ? "authenticated" : "ready for sign_up";
35
+ const mode = config.mock ? "offline fixtures" : `live API ${config.apiBaseUrl} · ${auth}`;
14
36
  process.stderr.write(`extrovert-mcp: stdio transport ready — ${mode}\n`);
15
37
  const shutdown = async () => {
16
38
  await server.close().catch(() => { });
package/dist/stdio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,qBAAqB,EAAE,CAAC;IAEnD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC;IAChF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,IAAI,IAAI,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,eAAe,GAAG,qBAAqB,EAAE,CAAC;IAChD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;QACpD,GAAG,CAAC,iBAAiB,GAAG,MAAM,CAAC,SAAS,CAAC;QACzC,IAAI,CAAC,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,GAAG,CAAC,sBAAsB,GAAG,MAAM,CAAC,YAAY,CAAC;QACnD,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,EAAE;QACzC,iBAAiB,EAAE,MAAM,CAAC,IAAI;YAC5B,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE;gBACvB,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAC3C,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YACxD,CAAC;KACN,CAAC,CAAC;IACH,MAAM,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,mBAAmB,CAAC;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,UAAU,MAAM,IAAI,EAAE,CAAC;IAC1F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,IAAI,IAAI,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC"}
package/dist/tools.d.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  * an org-wide master key. `redeem_enrollment` lets an agent exchange a
13
13
  * single-use enrollment token for that scoped key at runtime.
14
14
  */
15
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
15
+ import type { McpServer } from "@modelcontextprotocol/server";
16
16
  import { type ExtrovertClient } from "./client.js";
17
17
  import type { ExtrovertConfig } from "./config.js";
18
18
  interface ToolContext {
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,yCAAyC,CAAC;AAIvF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA0CnD,UAAU,WAAW;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB;AAg3FD,wEAAwE;AACxE,eAAO,MAAM,UAAU,EAAE,MAAM,EAAiC,CAAC;AAEjE,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAIvE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,8BAA8B,CAAC;AAG/E,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA0CnD,UAAU,WAAW;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB;AAw4FD,wEAAwE;AACxE,eAAO,MAAM,UAAU,EAAE,MAAM,EAAiC,CAAC;AAEjE,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAIvE"}
package/dist/tools.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * an org-wide master key. `redeem_enrollment` lets an agent exchange a
13
13
  * single-use enrollment token for that scoped key at runtime.
14
14
  */
15
- import { z } from "zod";
15
+ import { z } from "zod/v4";
16
16
  import { ExtrovertApiError } from "./client.js";
17
17
  import { isTerminalReviewEvent } from "./types.js";
18
18
  /**
@@ -24,23 +24,22 @@ function defineTool(spec) {
24
24
  return {
25
25
  name: spec.name,
26
26
  register(server, ctx) {
27
+ const inputSchema = z.object(spec.inputSchema);
27
28
  server.registerTool(spec.name, {
28
29
  title: spec.title,
29
30
  description: spec.description,
30
- inputSchema: spec.inputSchema,
31
+ inputSchema,
31
32
  annotations: spec.annotations,
32
33
  },
33
- // The SDK validates `args` against `inputSchema` before invoking us, so
34
- // `args` already has the handler's input shape. Typed as the SDK's own
35
- // `ToolCallback<Shape>` so the registration overload resolves cleanly.
36
- (async (args) => {
34
+ // The SDK validates `args` against `inputSchema` before invoking us.
35
+ async (args) => {
37
36
  try {
38
37
  return await spec.handler(args, ctx);
39
38
  }
40
39
  catch (err) {
41
40
  return toErrorResult(err);
42
41
  }
43
- }));
42
+ });
44
43
  },
45
44
  };
46
45
  }
@@ -72,7 +71,7 @@ const metadataValue = z.union([z.string().max(256), z.number(), z.boolean()]);
72
71
  * CreateInboxInput docstring + the SDK InboxMetadataPatch create shape).
73
72
  */
74
73
  const createMetadata = z
75
- .record(metadataValue.nullable())
74
+ .record(z.string(), metadataValue.nullable())
76
75
  .describe("Arbitrary key-value metadata to store on the inbox (string/number/boolean values; ≤256 keys, " +
77
76
  "≤256 chars per key/string value; nested objects/arrays rejected; a key with a null value is " +
78
77
  "dropped). Echoed back on the response and replayed on idempotent retries.");
@@ -81,7 +80,7 @@ const createMetadata = z
81
80
  * key, `null` DELETES that key, and a top-level `null` clears ALL metadata.
82
81
  */
83
82
  const updateMetadata = z
84
- .record(metadataValue.nullable())
83
+ .record(z.string(), metadataValue.nullable())
85
84
  .nullable()
86
85
  .describe("Patch the inbox's metadata with a shallow merge: an object merges in (a key whose value is null " +
87
86
  "DELETES that key); a top-level null clears ALL metadata; omit the field to leave it unchanged. " +
@@ -437,6 +436,7 @@ const redeemEnrollment = defineTool({
437
436
  agent_handle: args.agent_handle,
438
437
  client_id: args.client_id,
439
438
  });
439
+ const persistence = client.credentialPersistenceStatus();
440
440
  const text = [
441
441
  `Enrollment redeemed. Agent ${result.agent_id} is ready.`,
442
442
  `agent_key (shown once): ${result.agent_key}`,
@@ -445,7 +445,7 @@ const redeemEnrollment = defineTool({
445
445
  // whoami call — consistent with whoami's text.
446
446
  `org: ${result.org_id || "(none)"} · project: ${result.project_id || "(none)"} (fixed — bound to this key)`,
447
447
  `scopes: ${result.scopes.join(", ") || "(none)"}`,
448
- "This MCP session will use the returned key. Store the complete returned agent_key as EXTROVERT_API_KEY for future sessions; it is not retrievable again.",
448
+ credentialPersistenceMessage(persistence),
449
449
  ].join("\n");
450
450
  return ok(text, result);
451
451
  },
@@ -455,8 +455,8 @@ const signUp = defineTool({
455
455
  title: "Sign up for a free account",
456
456
  description: "Grab a free Extrovert account in one call (no enrollment token needed). Provisions a tenant and a first inbox, then " +
457
457
  "emails a one-time verification code to your human_email. Returns a LIMITED (read-only) agent key that this " +
458
- "MCP session keeps for verify_signup; store it as EXTROVERT_API_KEY for future sessions. Re-calling with the same " +
459
- "human_email rotates the key and resends the code.",
458
+ "MCP session keeps only through verify_signup; it expires with the code and is revoked after verification. " +
459
+ "Re-calling with the same human_email rotates the bootstrap key and resends the code.",
460
460
  inputSchema: {
461
461
  human_email: emailAddress.describe("Your email — receives the one-time verification code."),
462
462
  username: z
@@ -474,7 +474,9 @@ const signUp = defineTool({
474
474
  `inbox: ${res.address}`,
475
475
  `agent_key (limited, shown once): ${res.agent_key}`,
476
476
  `scopes: ${res.scopes.join(", ")}`,
477
- `This MCP session will use the limited key. Call verify_signup with the code to unlock full scopes; store the key as EXTROVERT_API_KEY for future sessions if needed.`,
477
+ `expires: ${res.otp_expires_at}`,
478
+ `This MCP session will use the limited key until verify_signup atomically exchanges it for the durable key. Do not store this bootstrap key for long-term use.`,
479
+ `After verification, verify_signup repeats the inbox and returns exact read_messages / get_message / wait_for_email calls so mailbox use can continue without raw HTTP.`,
478
480
  ].join("\n");
479
481
  return ok(text, res);
480
482
  },
@@ -482,22 +484,41 @@ const signUp = defineTool({
482
484
  const verifySignup = defineTool({
483
485
  name: "verify_signup",
484
486
  title: "Verify signup code",
485
- description: "Confirm the one-time code emailed by sign_up. On success you receive a NEW full-scope agent key (create/read/send) " +
486
- "this MCP session switches to it automatically. Store it as EXTROVERT_API_KEY for future sessions.",
487
+ description: "Confirm the one-time code emailed by sign_up. On success the bootstrap key is revoked and you receive a NEW " +
488
+ "full-scope agent key (create/read/send/webhooks). This MCP session switches to it automatically. The packaged " +
489
+ "local stdio server also stores it in its permission-restricted credential file for future sessions.",
487
490
  inputSchema: {
488
491
  otp: z.string().min(4).max(12).describe("The verification code from your signup email."),
489
492
  },
490
493
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
491
494
  handler: async (args, { client }) => {
492
495
  const res = await client.verify({ otp: args.otp });
496
+ const quick = res.mailbox_quickstart;
497
+ const persistence = client.credentialPersistenceStatus();
493
498
  const text = [
494
499
  `Verified. ${res.message}`,
495
500
  `agent_key (full, shown once): ${res.agent_key}`,
496
501
  `scopes: ${res.scopes.join(", ")}`,
502
+ credentialPersistenceMessage(persistence),
503
+ `mailbox ready: ${res.address}`,
504
+ `First call: ${quick.list_mail.tool} ${JSON.stringify(quick.list_mail.arguments)}`,
505
+ `Read one result: ${quick.read_message.tool} ${JSON.stringify(quick.read_message.arguments)}`,
506
+ `Wait for new mail: ${quick.wait_for_mail.tool} ${JSON.stringify(quick.wait_for_mail.arguments)}`,
507
+ `These tools return readable text plus structured message fields; do not download raw responses or invoke jq for ordinary mailbox work.`,
508
+ `For outbound mail, use send_email or reply_email through the review workflow; read get_inbox first to see the effective review policy.`,
497
509
  ].join("\n");
498
510
  return ok(text, res);
499
511
  },
500
512
  });
513
+ function credentialPersistenceMessage(status) {
514
+ if (status.persisted) {
515
+ return `Credential saved for future local sessions${status.location ? ` at ${status.location}` : ""}.`;
516
+ }
517
+ if (status.attempted) {
518
+ return `Automatic credential storage failed${status.error ? `: ${status.error}` : ""}. Store the complete returned agent_key now; it is not retrievable again.`;
519
+ }
520
+ return "This host did not provide durable credential storage. Store the complete returned agent_key now; it is not retrievable again.";
521
+ }
501
522
  const whoami = defineTool({
502
523
  name: "whoami",
503
524
  title: "Who am I",
@@ -1500,7 +1521,7 @@ const proposeGraduation = defineTool({
1500
1521
  inputSchema: {
1501
1522
  id: z.string().min(1).describe("Category id (cat_…)."),
1502
1523
  evidence: z
1503
- .record(z.unknown())
1524
+ .record(z.string(), z.unknown())
1504
1525
  .optional()
1505
1526
  .describe("Optional structured evidence for the human (e.g. {approvals: 20, last_edits: 0})."),
1506
1527
  },