@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.
- package/README.md +74 -31
- package/dist/auth.d.ts +39 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +201 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +5 -7
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +63 -52
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +459 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +20 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +41 -8
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/contract.d.ts +2 -2
- package/dist/contract.js +2 -2
- package/dist/credentials.d.ts +41 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +203 -0
- package/dist/credentials.js.map +1 -0
- package/dist/fixtures.d.ts.map +1 -1
- package/dist/fixtures.js +23 -2
- package/dist/fixtures.js.map +1 -1
- package/dist/http.d.ts +23 -9
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +106 -104
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -5
- package/dist/server.js.map +1 -1
- package/dist/stdio.d.ts.map +1 -1
- package/dist/stdio.js +25 -3
- package/dist/stdio.js.map +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +37 -16
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +18 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -4
package/dist/http.js
CHANGED
|
@@ -1,124 +1,126 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Hosted
|
|
2
|
+
* Hosted MCP Streamable HTTP transport.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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 {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
|
122
|
-
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EACL,gBAAgB,GAIjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,oCAAoC,EACpC,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,GAErB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAsBpD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAgC,EAAE;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,SAAS,CAAC;IACnD,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC;IAC3F,MAAM,WAAW,GAAG,cAAc,IAAI,YAAY,CAAC;IAEnD,IAAI,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAChC,IAAI,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC1C,IAAI,WAAW,EAAE,CAAC;QAChB,UAAU,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACzC,QAAQ,KAAK,yBAAyB,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1E,aAAa,KAAK,MAAM,qBAAqB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC;SAAM,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,UAAU;QAC7B,CAAC,CAAC,aAAa,CAAC;YACZ,UAAU,CAAC,WAAW,CAAC,QAAQ;YAC/B,WAAW;YACX,WAAW;YACX,OAAO;YACP,GAAG,CAAC,GAAG,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;SACtD,CAAC;QACJ,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,GAAG,GAAG,mBAAmB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAE1E,MAAM,OAAO,GAAG,gBAAgB,CAC9B,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACf,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QAC3C,OAAO,qBAAqB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;IAC1D,CAAC,EACD;QACE,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,OAAO,IAAI,CAAC;KAC9F,CACF,CAAC;IACF,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,EAAE;QACzC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,KAAK,CAAC,OAAO,IAAI,CAAC;KAClG,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAChC,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,2BAA2B;YACtC,IAAI,EAAE,WAAW;gBACf,CAAC,CAAC,oBAAoB;gBACtB,CAAC,CAAC,UAAU,CAAC,IAAI;oBACf,CAAC,CAAC,kBAAkB;oBACpB,CAAC,CAAC,iBAAiB;SACxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,WAAW,IAAI,UAAU,IAAI,QAAQ,IAAI,aAAa,EAAE,CAAC;QAC3D,GAAG,CAAC,GAAG,CACL,qBAAqB,CAAC;YACpB,aAAa;YACb,iBAAiB,EAAE,UAAU,CAAC,WAAW;YACzC,uBAAuB,EAAE,UAAU,CAAC,uBAAuB;YAC3D,eAAe,EAAE,UAAU,CAAC,eAAe;YAC3C,YAAY,EAAE,eAAe;SAC9B,CAAC,CACH,CAAC;QACF,GAAG,CAAC,GAAG,CACL,MAAM,EACN,iBAAiB,CAAC;YAChB,QAAQ;YACR,mBAAmB,EAAE,oCAAoC,CAAC,UAAU,CAAC,WAAW,CAAC;SAClF,CAAC,EACF,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;YAC9B,KAAK,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CACF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;YAC9C,KAAK,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,UAA6B,EAAE;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,SAAS,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAE/D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qDAAqD,IAAI,IAAI,IAAI,UAC/D,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,YACtD,IAAI,CACL,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAqB,EAAE,YAAgC;IAC/E,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,eAAe,CAAC,MAAc,EAAE,OAAgB;IACvD,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,SAAS,CAAC,KAAyB;IAC1C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,aAAa,CAAC,MAAgB;IACrC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC"}
|
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 {
|
|
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,
|
|
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/
|
|
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 {
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
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/
|
|
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.
|
|
16
|
-
" 2. create_inbox — mint
|
|
17
|
-
" 3. send_email / reply_email —
|
|
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",
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
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"}
|
package/dist/stdio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
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/
|
|
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
|
|
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
|
|
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,
|
|
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/
|
|
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 {
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,
|
|
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
|
|
31
|
+
inputSchema,
|
|
31
32
|
annotations: spec.annotations,
|
|
32
33
|
},
|
|
33
|
-
// The SDK validates `args` against `inputSchema` before invoking us
|
|
34
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
`
|
|
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
|
|
486
|
-
"
|
|
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
|
},
|