@agentvalet/mcp-server 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.js +89 -0
- package/dist/context.js +8 -0
- package/dist/index.js +29 -719
- package/dist/net.js +80 -0
- package/dist/tools/handlers.js +272 -0
- package/dist/tools/schemas.js +272 -0
- package/package.json +47 -46
package/dist/auth.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// apps/mcp-server/src/auth.ts
|
|
2
|
+
//
|
|
3
|
+
// Credentialed request layer: JWT signing, the auth+retry fetch wrapper, the
|
|
4
|
+
// credential gate, and the two no-key response shapes. All take the
|
|
5
|
+
// ServerContext (config + server) explicitly — extracted from index.ts during
|
|
6
|
+
// the modularization (Critique-Roadmap prompt 06.4); behavior unchanged.
|
|
7
|
+
import { SignJWT } from "jose";
|
|
8
|
+
import { fetchWithTimeout } from "./net.js";
|
|
9
|
+
export async function signJWT(ctx) {
|
|
10
|
+
if (!ctx.privateKey)
|
|
11
|
+
throw new Error("Private key not loaded");
|
|
12
|
+
return new SignJWT({ agent_id: ctx.AGENT_ID, owner_id: ctx.OWNER_ID })
|
|
13
|
+
.setProtectedHeader({ alg: "RS256" })
|
|
14
|
+
.setIssuedAt()
|
|
15
|
+
.setExpirationTime("60s")
|
|
16
|
+
.sign(ctx.privateKey);
|
|
17
|
+
}
|
|
18
|
+
async function notifyBindSecret(ctx) {
|
|
19
|
+
try {
|
|
20
|
+
await fetchWithTimeout(`${ctx.PROXY_URL}/v1/bind-secret`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: { "Content-Type": "application/json" },
|
|
23
|
+
body: JSON.stringify({ agent_id: ctx.AGENT_ID, owner_id: ctx.OWNER_ID }),
|
|
24
|
+
}, 8_000);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// best-effort — don't block the error response
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function pendingFirstCallResponse() {
|
|
31
|
+
return {
|
|
32
|
+
content: [{
|
|
33
|
+
type: "text",
|
|
34
|
+
text: JSON.stringify({
|
|
35
|
+
error: "Agent not yet activated — owner confirmation pending. Retry in 60 seconds.",
|
|
36
|
+
}),
|
|
37
|
+
}],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// State C — no credentials at all (empty env / Glama-style sandbox). The
|
|
42
|
+
// server still boots and answers introspection; an authed tool call lands
|
|
43
|
+
// here and gets an actionable message instead of a crash. Distinct from the
|
|
44
|
+
// state-B "owner confirmation pending" response above, which means an identity
|
|
45
|
+
// IS configured but its key hasn't arrived yet.
|
|
46
|
+
function credentialsNotConfiguredResponse() {
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "AgentValet credentials are not configured. Set AGENTVALET_AGENT_ID, " +
|
|
51
|
+
"AGENTVALET_OWNER_ID, and the agent private key (and optionally " +
|
|
52
|
+
"AGENTVALET_PROXY_URL). Run npx @agentvalet/register to create an agent. " +
|
|
53
|
+
"Docs: https://github.com/AgentValet/AgentValet#quickstart",
|
|
54
|
+
}],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Credential gate for authed tools/call. Returns null when the call may
|
|
59
|
+
// proceed (state A — a JWT can be signed), or a ready-to-return MCP tool
|
|
60
|
+
// result for the two no-key states:
|
|
61
|
+
// • state B (identity present, key pending) → existing invite-bind pending
|
|
62
|
+
// response, preserving the MCPB first-run flow.
|
|
63
|
+
// • state C (no identity at all) → credentials-not-configured.
|
|
64
|
+
// The no-auth tools (agent_register / agent_status) intentionally never call
|
|
65
|
+
// this — you must be able to register in order to OBTAIN credentials.
|
|
66
|
+
export async function requireCredentials(ctx) {
|
|
67
|
+
if (ctx.AGENT_PRIVATE_KEY_RAW !== null)
|
|
68
|
+
return null;
|
|
69
|
+
if (ctx.AGENT_ID && ctx.OWNER_ID) {
|
|
70
|
+
await notifyBindSecret(ctx);
|
|
71
|
+
return pendingFirstCallResponse();
|
|
72
|
+
}
|
|
73
|
+
return credentialsNotConfiguredResponse();
|
|
74
|
+
}
|
|
75
|
+
export async function fetchWithAuth(ctx, url, init) {
|
|
76
|
+
const makeRequest = async () => {
|
|
77
|
+
const token = await signJWT(ctx);
|
|
78
|
+
return fetchWithTimeout(url, {
|
|
79
|
+
...init,
|
|
80
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", ...init.headers },
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
const response = await makeRequest();
|
|
84
|
+
// Retry once on 401 — the JWT may have been issued just before clock skew threshold
|
|
85
|
+
if (response.status === 401) {
|
|
86
|
+
return makeRequest();
|
|
87
|
+
}
|
|
88
|
+
return response;
|
|
89
|
+
}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// apps/mcp-server/src/context.ts
|
|
2
|
+
//
|
|
3
|
+
// The resolved-config + server bundle threaded into auth.ts and the tool
|
|
4
|
+
// handlers, so they don't reach for module-level globals (the pattern the
|
|
5
|
+
// 963-line index.ts used). Built once in index.ts after validateConfig() and
|
|
6
|
+
// server construction. Field names mirror the originals so handler bodies
|
|
7
|
+
// moved verbatim.
|
|
8
|
+
export {};
|