@scavio/mcp-server 0.13.1 → 0.14.1
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 +23 -10
- package/dist/auth/cimd.d.ts +2 -0
- package/dist/auth/cimd.js +20 -0
- package/dist/auth/cimd.js.map +1 -0
- package/dist/auth/provider.d.ts +12 -0
- package/dist/auth/provider.js +43 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/routes.d.ts +2 -0
- package/dist/auth/routes.js +214 -0
- package/dist/auth/routes.js.map +1 -0
- package/dist/auth/stores.d.ts +33 -0
- package/dist/auth/stores.js +69 -0
- package/dist/auth/stores.js.map +1 -0
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/client.js +4 -1
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/env.d.ts +3 -0
- package/dist/lib/env.js +4 -0
- package/dist/lib/env.js.map +1 -1
- package/dist/lib/errors.d.ts +5 -1
- package/dist/lib/errors.js +5 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/tool-error.js +10 -0
- package/dist/lib/tool-error.js.map +1 -1
- package/dist/lib/trim-response.d.ts +6 -0
- package/dist/lib/trim-response.js +26 -0
- package/dist/lib/trim-response.js.map +1 -0
- package/dist/tools/airbnb.js +30 -49
- package/dist/tools/airbnb.js.map +1 -1
- package/dist/tools/amazon.js +11 -18
- package/dist/tools/amazon.js.map +1 -1
- package/dist/tools/appstore.js +16 -15
- package/dist/tools/appstore.js.map +1 -1
- package/dist/tools/booking.js +28 -45
- package/dist/tools/booking.js.map +1 -1
- package/dist/tools/capterra.js +16 -15
- package/dist/tools/capterra.js.map +1 -1
- package/dist/tools/companieshouse.js +11 -10
- package/dist/tools/companieshouse.js.map +1 -1
- package/dist/tools/ebay.js +21 -30
- package/dist/tools/ebay.js.map +1 -1
- package/dist/tools/extract.js +6 -5
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/g2.js +23 -22
- package/dist/tools/g2.js.map +1 -1
- package/dist/tools/glassdoor.js +18 -17
- package/dist/tools/glassdoor.js.map +1 -1
- package/dist/tools/google.js +154 -153
- package/dist/tools/google.js.map +1 -1
- package/dist/tools/googleads.js +20 -19
- package/dist/tools/googleads.js.map +1 -1
- package/dist/tools/googleplay.js +14 -13
- package/dist/tools/googleplay.js.map +1 -1
- package/dist/tools/homedepot.js +15 -28
- package/dist/tools/homedepot.js.map +1 -1
- package/dist/tools/indeed.js +20 -39
- package/dist/tools/indeed.js.map +1 -1
- package/dist/tools/index.d.ts +5 -4
- package/dist/tools/index.js +5 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/instagram.js +59 -58
- package/dist/tools/instagram.js.map +1 -1
- package/dist/tools/kuaishou.js +47 -46
- package/dist/tools/kuaishou.js.map +1 -1
- package/dist/tools/linkedin.js +26 -25
- package/dist/tools/linkedin.js.map +1 -1
- package/dist/tools/metaads.js +21 -20
- package/dist/tools/metaads.js.map +1 -1
- package/dist/tools/reddit.js +48 -47
- package/dist/tools/reddit.js.map +1 -1
- package/dist/tools/redfin.js +29 -28
- package/dist/tools/redfin.js.map +1 -1
- package/dist/tools/sec.js +36 -35
- package/dist/tools/sec.js.map +1 -1
- package/dist/tools/target.js +19 -40
- package/dist/tools/target.js.map +1 -1
- package/dist/tools/threads.js +20 -19
- package/dist/tools/threads.js.map +1 -1
- package/dist/tools/tiktok-shop.js +38 -37
- package/dist/tools/tiktok-shop.js.map +1 -1
- package/dist/tools/tiktok.js +54 -53
- package/dist/tools/tiktok.js.map +1 -1
- package/dist/tools/tripadvisor.js +20 -43
- package/dist/tools/tripadvisor.js.map +1 -1
- package/dist/tools/usage.js +3 -2
- package/dist/tools/usage.js.map +1 -1
- package/dist/tools/walmart.js +35 -34
- package/dist/tools/walmart.js.map +1 -1
- package/dist/tools/x.js +44 -43
- package/dist/tools/x.js.map +1 -1
- package/dist/tools/yelp.js +21 -20
- package/dist/tools/yelp.js.map +1 -1
- package/dist/tools/youtube.js +77 -76
- package/dist/tools/youtube.js.map +1 -1
- package/dist/tools/zillow.js +38 -53
- package/dist/tools/zillow.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
[Scavio](https://scavio.dev) is a unified [Web Search API](https://scavio.dev/docs/search-api) and MCP server that gives AI agents web search, page extraction, and structured data from e-commerce, social, travel, jobs, real-estate, app-store, ad-library and company-filing sources. 191 tools across 31 platforms plus Extract, one API key.
|
|
7
7
|
|
|
8
|
-
**The 22 platforms added in 0.13.0 are opt-in.** Registering all 191 tools puts
|
|
8
|
+
**The 22 platforms added in 0.13.0 are opt-in.** Registering all 191 tools puts 136KB of tool definitions — roughly 35k tokens — into every session before you type anything. So the default is the surface 0.12.x already had, plus Extract: 106 tools, 63KB. Upgrading never removes a tool you were using. Everything else is one env var away: see [Choosing which tools load](#choosing-which-tools-load).
|
|
9
9
|
|
|
10
10
|
## Remote MCP Server
|
|
11
11
|
|
|
@@ -15,7 +15,10 @@ Connect directly to Scavio's remote MCP server without any local installation:
|
|
|
15
15
|
https://mcp.scavio.dev/mcp
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Two ways to authenticate:
|
|
19
|
+
|
|
20
|
+
- **Sign in with OAuth, no key to copy.** Claude Desktop, claude.ai and Claude Code sign in to your Scavio account through the server. In Claude Desktop or claude.ai: Settings > Connectors > Add custom connector, name it Scavio, paste the URL, then Connect and Authorize. In Claude Code: `claude mcp add --transport http scavio https://mcp.scavio.dev/mcp`, then run `/mcp` and choose Authenticate.
|
|
21
|
+
- **API key.** Pass it in the `x-api-key` header. Get your key at [scavio.dev](https://scavio.dev).
|
|
19
22
|
|
|
20
23
|
---
|
|
21
24
|
|
|
@@ -53,13 +56,23 @@ Requires Node.js 20+. Get your API key at [scavio.dev](https://scavio.dev).
|
|
|
53
56
|
|
|
54
57
|
### Claude Code
|
|
55
58
|
|
|
59
|
+
Sign in with OAuth, then run `/mcp` inside Claude Code and choose Authenticate:
|
|
60
|
+
|
|
56
61
|
```bash
|
|
57
|
-
claude mcp add
|
|
62
|
+
claude mcp add --transport http scavio https://mcp.scavio.dev/mcp
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or pass an API key:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
claude mcp add --transport http scavio https://mcp.scavio.dev/mcp --header "x-api-key: YOUR_SCAVIO_API_KEY"
|
|
58
69
|
```
|
|
59
70
|
|
|
60
71
|
### Claude Desktop
|
|
61
72
|
|
|
62
|
-
Add
|
|
73
|
+
No API key needed: Settings > Connectors > Add custom connector, name it Scavio, paste `https://mcp.scavio.dev/mcp`, then Connect and sign in to your Scavio account. The same steps work on claude.ai.
|
|
74
|
+
|
|
75
|
+
Or run the server locally. Add to `claude_desktop_config.json` (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
|
|
63
76
|
|
|
64
77
|
```json
|
|
65
78
|
{
|
|
@@ -194,8 +207,8 @@ Add to settings (`Cmd+,`):
|
|
|
194
207
|
|
|
195
208
|
## Choosing which tools load
|
|
196
209
|
|
|
197
|
-
Scavio exposes 191 tools. Loading all of them costs
|
|
198
|
-
roughly
|
|
210
|
+
Scavio exposes 191 tools. Loading all of them costs 136KB of `tools/list` —
|
|
211
|
+
roughly 35k tokens of context in every session before the user has said anything,
|
|
199
212
|
and more tools than some clients will accept at all. So the server registers a
|
|
200
213
|
curated subset by default and lets you pick the rest. The sizes below are
|
|
201
214
|
measured, not estimated: `npm run toolslist` reproduces them.
|
|
@@ -204,10 +217,10 @@ measured, not estimated: `npm run toolslist` reproduces them.
|
|
|
204
217
|
|
|
205
218
|
| Value | Registers |
|
|
206
219
|
|-------|-----------|
|
|
207
|
-
| *(unset)* | Everything 0.12.x had, plus `extract` — **106 tools,
|
|
208
|
-
| `all` | every platform — **191 tools,
|
|
209
|
-
| `extract,sec,g2` | just those platforms — 11 tools,
|
|
210
|
-
| `default,
|
|
220
|
+
| *(unset)* or `default` | Everything 0.12.x had, plus `extract` — **106 tools, 63KB** |
|
|
221
|
+
| `all` | every platform — **191 tools, 136KB** |
|
|
222
|
+
| `extract,sec,g2` | just those platforms — 11 tools, 10KB |
|
|
223
|
+
| `default,zillow,metaads` | the default set plus two more — 112 tools, 70KB |
|
|
211
224
|
| `none` | no platform tools, only `get_usage` |
|
|
212
225
|
|
|
213
226
|
Keys are matched case- and punctuation-insensitively, so `meta-ads`, `metaads`
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export async function fetchClientMetadata(clientIdUrl) {
|
|
2
|
+
try {
|
|
3
|
+
const res = await fetch(clientIdUrl, {
|
|
4
|
+
headers: { Accept: "application/json" },
|
|
5
|
+
signal: AbortSignal.timeout(5000),
|
|
6
|
+
});
|
|
7
|
+
if (!res.ok)
|
|
8
|
+
return null;
|
|
9
|
+
const meta = await res.json();
|
|
10
|
+
if (!meta.client_id || !Array.isArray(meta.redirect_uris))
|
|
11
|
+
return null;
|
|
12
|
+
if (meta.client_id !== clientIdUrl)
|
|
13
|
+
return null;
|
|
14
|
+
return meta;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cimd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cimd.js","sourceRoot":"","sources":["../../src/auth/cimd.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC;YAAE,OAAO,IAAI,CAAC;QACvE,IAAI,IAAI,CAAC,SAAS,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAChD,OAAO,IAAkC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AuthCodeStore, PendingSessionStore, ClientStore } from "./stores.js";
|
|
2
|
+
type SignedPayload = {
|
|
3
|
+
key: string;
|
|
4
|
+
sid: string;
|
|
5
|
+
exp: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function verifySignedToken(token: string): SignedPayload | null;
|
|
8
|
+
export declare function verifyApiKey(apiKey: string): Promise<boolean>;
|
|
9
|
+
export declare const authCodeStore: AuthCodeStore;
|
|
10
|
+
export declare const pendingSessionStore: PendingSessionStore;
|
|
11
|
+
export declare const clientStore: ClientStore;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { env } from "../lib/env.js";
|
|
3
|
+
import { ScavioClient } from "../lib/client.js";
|
|
4
|
+
import { AuthCodeStore, PendingSessionStore, ClientStore } from "./stores.js";
|
|
5
|
+
export function verifySignedToken(token) {
|
|
6
|
+
const secret = env.MCP_AUTH_SECRET;
|
|
7
|
+
if (!secret)
|
|
8
|
+
return null;
|
|
9
|
+
const dotIndex = token.indexOf(".");
|
|
10
|
+
if (dotIndex < 0)
|
|
11
|
+
return null;
|
|
12
|
+
const payloadB64 = token.slice(0, dotIndex);
|
|
13
|
+
const sigB64 = token.slice(dotIndex + 1);
|
|
14
|
+
const expectedSig = createHmac("sha256", secret)
|
|
15
|
+
.update(payloadB64)
|
|
16
|
+
.digest();
|
|
17
|
+
const actualSig = Buffer.from(sigB64, "base64url");
|
|
18
|
+
if (expectedSig.length !== actualSig.length || !timingSafeEqual(expectedSig, actualSig))
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
22
|
+
if (payload.exp < Date.now())
|
|
23
|
+
return null;
|
|
24
|
+
return payload;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function verifyApiKey(apiKey) {
|
|
31
|
+
try {
|
|
32
|
+
const client = new ScavioClient(apiKey);
|
|
33
|
+
await client.get("/api/v1/usage");
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export const authCodeStore = new AuthCodeStore();
|
|
41
|
+
export const pendingSessionStore = new PendingSessionStore();
|
|
42
|
+
export const clientStore = new ClientStore();
|
|
43
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/auth/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ9E,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAEzC,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC7C,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,EAAE,CAAC;IACZ,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAEnD,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAErG,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,CAC/B,CAAC;QACnB,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;AACjD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { cors } from "hono/cors";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { env } from "../lib/env.js";
|
|
5
|
+
import { authCodeStore, pendingSessionStore, clientStore, verifySignedToken, } from "./provider.js";
|
|
6
|
+
export const authApp = new Hono();
|
|
7
|
+
// --- OAuth Metadata ---
|
|
8
|
+
const buildOAuthMetadata = () => ({
|
|
9
|
+
issuer: env.ISSUER_URL,
|
|
10
|
+
authorization_endpoint: `${env.ISSUER_URL}/authorize`,
|
|
11
|
+
token_endpoint: `${env.ISSUER_URL}/token`,
|
|
12
|
+
registration_endpoint: `${env.ISSUER_URL}/register`,
|
|
13
|
+
response_types_supported: ["code"],
|
|
14
|
+
grant_types_supported: ["authorization_code"],
|
|
15
|
+
code_challenge_methods_supported: ["S256"],
|
|
16
|
+
token_endpoint_auth_methods_supported: ["none"],
|
|
17
|
+
client_id_metadata_document_supported: true,
|
|
18
|
+
});
|
|
19
|
+
const buildResourceMetadata = () => ({
|
|
20
|
+
resource: `${env.ISSUER_URL}/mcp`,
|
|
21
|
+
authorization_servers: [env.ISSUER_URL],
|
|
22
|
+
resource_name: "Scavio MCP Server",
|
|
23
|
+
resource_documentation: "https://scavio.dev/docs/mcp",
|
|
24
|
+
});
|
|
25
|
+
authApp.get("/.well-known/oauth-authorization-server", cors({ origin: "*" }), (c) => c.json(buildOAuthMetadata()));
|
|
26
|
+
authApp.get("/.well-known/oauth-protected-resource/mcp", cors({ origin: "*" }), (c) => c.json(buildResourceMetadata()));
|
|
27
|
+
// --- Dynamic Client Registration (RFC 7591) ---
|
|
28
|
+
authApp.post("/register", cors({ origin: "*" }), async (c) => {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
let body;
|
|
31
|
+
try {
|
|
32
|
+
body = await c.req.json();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return c.json({ error: "invalid_client_metadata", error_description: "Invalid JSON" }, 400);
|
|
36
|
+
}
|
|
37
|
+
if (!body.redirect_uris || !Array.isArray(body.redirect_uris)) {
|
|
38
|
+
return c.json({ error: "invalid_client_metadata", error_description: "redirect_uris required" }, 400);
|
|
39
|
+
}
|
|
40
|
+
const invalidScheme = body.redirect_uris.some((uri) => {
|
|
41
|
+
try {
|
|
42
|
+
const u = new URL(uri);
|
|
43
|
+
if (u.protocol === "https:")
|
|
44
|
+
return false;
|
|
45
|
+
if (u.protocol === "http:" && (u.hostname === "localhost" || u.hostname === "127.0.0.1"))
|
|
46
|
+
return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
if (invalidScheme) {
|
|
54
|
+
return c.json({ error: "invalid_client_metadata", error_description: "redirect_uris must use https (or http for localhost)" }, 400);
|
|
55
|
+
}
|
|
56
|
+
const client = await clientStore.registerClient(body);
|
|
57
|
+
return c.json(client, 201);
|
|
58
|
+
});
|
|
59
|
+
// --- Authorization Endpoint ---
|
|
60
|
+
authApp.all("/authorize", async (c) => {
|
|
61
|
+
if (!env.MCP_AUTH_SECRET) {
|
|
62
|
+
return c.json({ error: "server_error", error_description: "OAuth not configured" }, 500);
|
|
63
|
+
}
|
|
64
|
+
const params = c.req.method === "GET" ? c.req.query() : await c.req.parseBody();
|
|
65
|
+
const clientId = params.client_id;
|
|
66
|
+
const redirectUri = params.redirect_uri;
|
|
67
|
+
const responseType = params.response_type;
|
|
68
|
+
const codeChallenge = params.code_challenge;
|
|
69
|
+
const codeChallengeMethod = params.code_challenge_method;
|
|
70
|
+
const state = params.state;
|
|
71
|
+
const scope = params.scope;
|
|
72
|
+
// Validate client
|
|
73
|
+
if (!clientId) {
|
|
74
|
+
return c.json({ error: "invalid_request", error_description: "client_id required" }, 400);
|
|
75
|
+
}
|
|
76
|
+
const client = await clientStore.getClient(clientId);
|
|
77
|
+
if (!client) {
|
|
78
|
+
return c.json({ error: "invalid_client", error_description: "Unknown client_id" }, 400);
|
|
79
|
+
}
|
|
80
|
+
// Resolve redirect_uri
|
|
81
|
+
let resolvedRedirect = redirectUri;
|
|
82
|
+
if (!resolvedRedirect) {
|
|
83
|
+
if (client.redirect_uris.length === 1) {
|
|
84
|
+
resolvedRedirect = client.redirect_uris[0].toString();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
return c.json({ error: "invalid_request", error_description: "redirect_uri required" }, 400);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Validate redirect_uri against registered URIs
|
|
91
|
+
if (!client.redirect_uris.some(u => u.toString() === resolvedRedirect)) {
|
|
92
|
+
return c.json({ error: "invalid_request", error_description: "Unregistered redirect_uri" }, 400);
|
|
93
|
+
}
|
|
94
|
+
// Validate remaining params (errors redirect to client)
|
|
95
|
+
const errorRedirect = (error, desc) => {
|
|
96
|
+
const url = new URL(resolvedRedirect);
|
|
97
|
+
url.searchParams.set("error", error);
|
|
98
|
+
url.searchParams.set("error_description", desc);
|
|
99
|
+
if (state)
|
|
100
|
+
url.searchParams.set("state", state);
|
|
101
|
+
return c.redirect(url.toString(), 302);
|
|
102
|
+
};
|
|
103
|
+
if (responseType !== "code")
|
|
104
|
+
return errorRedirect("unsupported_response_type", "Only 'code' supported");
|
|
105
|
+
if (!codeChallenge)
|
|
106
|
+
return errorRedirect("invalid_request", "code_challenge required");
|
|
107
|
+
if (codeChallengeMethod !== "S256")
|
|
108
|
+
return errorRedirect("invalid_request", "Only S256 supported");
|
|
109
|
+
// Store pending session, redirect to dashboard consent page
|
|
110
|
+
const sessionId = pendingSessionStore.create({
|
|
111
|
+
clientId,
|
|
112
|
+
redirectUri: resolvedRedirect,
|
|
113
|
+
state,
|
|
114
|
+
codeChallenge,
|
|
115
|
+
scopes: scope ? scope.split(" ") : [],
|
|
116
|
+
});
|
|
117
|
+
const callbackUrl = `${env.ISSUER_URL}/oauth/callback`;
|
|
118
|
+
const dashboardUrl = new URL(`${env.DASHBOARD_URL}/mcp/authorize`);
|
|
119
|
+
dashboardUrl.searchParams.set("session", sessionId);
|
|
120
|
+
dashboardUrl.searchParams.set("callback", callbackUrl);
|
|
121
|
+
return c.redirect(dashboardUrl.toString(), 302);
|
|
122
|
+
});
|
|
123
|
+
// --- OAuth Callback (from dashboard consent page) ---
|
|
124
|
+
authApp.get("/oauth/callback", async (c) => {
|
|
125
|
+
const token = c.req.query("token");
|
|
126
|
+
const sessionId = c.req.query("session");
|
|
127
|
+
const error = c.req.query("error");
|
|
128
|
+
if (!sessionId) {
|
|
129
|
+
return c.json({ error: "invalid_request", error_description: "Missing session" }, 400);
|
|
130
|
+
}
|
|
131
|
+
const session = pendingSessionStore.consume(sessionId);
|
|
132
|
+
if (!session) {
|
|
133
|
+
return c.json({ error: "invalid_request", error_description: "Invalid or expired session" }, 400);
|
|
134
|
+
}
|
|
135
|
+
const errorRedirect = (errCode, desc) => {
|
|
136
|
+
const url = new URL(session.redirectUri);
|
|
137
|
+
url.searchParams.set("error", errCode);
|
|
138
|
+
url.searchParams.set("error_description", desc);
|
|
139
|
+
if (session.state)
|
|
140
|
+
url.searchParams.set("state", session.state);
|
|
141
|
+
return c.redirect(url.toString(), 302);
|
|
142
|
+
};
|
|
143
|
+
// User denied
|
|
144
|
+
if (error === "access_denied") {
|
|
145
|
+
return errorRedirect("access_denied", "User denied authorization");
|
|
146
|
+
}
|
|
147
|
+
if (!token) {
|
|
148
|
+
return errorRedirect("server_error", "Missing token");
|
|
149
|
+
}
|
|
150
|
+
// Verify the signed token from the backend
|
|
151
|
+
const payload = verifySignedToken(token);
|
|
152
|
+
if (!payload) {
|
|
153
|
+
return errorRedirect("server_error", "Invalid or expired token");
|
|
154
|
+
}
|
|
155
|
+
if (payload.sid !== sessionId) {
|
|
156
|
+
return errorRedirect("server_error", "Session mismatch");
|
|
157
|
+
}
|
|
158
|
+
// Generate auth code
|
|
159
|
+
const code = authCodeStore.generate({
|
|
160
|
+
apiKey: payload.key,
|
|
161
|
+
codeChallenge: session.codeChallenge,
|
|
162
|
+
redirectUri: session.redirectUri,
|
|
163
|
+
clientId: session.clientId,
|
|
164
|
+
});
|
|
165
|
+
const redirectUrl = new URL(session.redirectUri);
|
|
166
|
+
redirectUrl.searchParams.set("code", code);
|
|
167
|
+
if (session.state)
|
|
168
|
+
redirectUrl.searchParams.set("state", session.state);
|
|
169
|
+
return c.redirect(redirectUrl.toString(), 302);
|
|
170
|
+
});
|
|
171
|
+
// --- Token Endpoint ---
|
|
172
|
+
authApp.post("/token", cors({ origin: "*" }), async (c) => {
|
|
173
|
+
const body = await c.req.parseBody();
|
|
174
|
+
const grantType = body.grant_type;
|
|
175
|
+
const code = body.code;
|
|
176
|
+
const codeVerifier = body.code_verifier;
|
|
177
|
+
const clientId = body.client_id;
|
|
178
|
+
const redirectUri = body.redirect_uri;
|
|
179
|
+
if (grantType !== "authorization_code") {
|
|
180
|
+
return c.json({ error: "unsupported_grant_type" }, 400);
|
|
181
|
+
}
|
|
182
|
+
if (!code || !codeVerifier || !clientId) {
|
|
183
|
+
return c.json({ error: "invalid_request", error_description: "code, code_verifier, client_id required" }, 400);
|
|
184
|
+
}
|
|
185
|
+
// Validate client
|
|
186
|
+
const client = await clientStore.getClient(clientId);
|
|
187
|
+
if (!client) {
|
|
188
|
+
return c.json({ error: "invalid_client" }, 401);
|
|
189
|
+
}
|
|
190
|
+
// Consume the auth code
|
|
191
|
+
const codeData = authCodeStore.consume(code);
|
|
192
|
+
if (!codeData) {
|
|
193
|
+
return c.json({ error: "invalid_grant", error_description: "Invalid or expired code" }, 400);
|
|
194
|
+
}
|
|
195
|
+
if (codeData.clientId !== clientId) {
|
|
196
|
+
return c.json({ error: "invalid_grant", error_description: "Client mismatch" }, 400);
|
|
197
|
+
}
|
|
198
|
+
if (redirectUri && codeData.redirectUri !== redirectUri) {
|
|
199
|
+
return c.json({ error: "invalid_grant", error_description: "redirect_uri mismatch" }, 400);
|
|
200
|
+
}
|
|
201
|
+
// PKCE: verify S256
|
|
202
|
+
const expectedChallenge = createHash("sha256")
|
|
203
|
+
.update(codeVerifier)
|
|
204
|
+
.digest("base64url");
|
|
205
|
+
if (expectedChallenge !== codeData.codeChallenge) {
|
|
206
|
+
return c.json({ error: "invalid_grant", error_description: "PKCE verification failed" }, 400);
|
|
207
|
+
}
|
|
208
|
+
// Issue the access token (the user's actual API key)
|
|
209
|
+
return c.json({
|
|
210
|
+
access_token: codeData.apiKey,
|
|
211
|
+
token_type: "Bearer",
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/auth/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { OAuthClientInformationFull } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
2
|
+
import type { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
|
|
3
|
+
type AuthCodeData = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
codeChallenge: string;
|
|
6
|
+
redirectUri: string;
|
|
7
|
+
clientId: string;
|
|
8
|
+
expiresAt: number;
|
|
9
|
+
};
|
|
10
|
+
type PendingSession = {
|
|
11
|
+
clientId: string;
|
|
12
|
+
redirectUri: string;
|
|
13
|
+
state?: string;
|
|
14
|
+
codeChallenge: string;
|
|
15
|
+
scopes: string[];
|
|
16
|
+
expiresAt: number;
|
|
17
|
+
};
|
|
18
|
+
export declare class AuthCodeStore {
|
|
19
|
+
private codes;
|
|
20
|
+
generate(data: Omit<AuthCodeData, "expiresAt">): string;
|
|
21
|
+
consume(code: string): AuthCodeData | null;
|
|
22
|
+
}
|
|
23
|
+
export declare class PendingSessionStore {
|
|
24
|
+
private sessions;
|
|
25
|
+
create(data: Omit<PendingSession, "expiresAt">): string;
|
|
26
|
+
consume(id: string): PendingSession | null;
|
|
27
|
+
}
|
|
28
|
+
export declare class ClientStore implements OAuthRegisteredClientsStore {
|
|
29
|
+
private clients;
|
|
30
|
+
getClient(clientId: string): Promise<OAuthClientInformationFull | undefined>;
|
|
31
|
+
registerClient(client: Omit<OAuthClientInformationFull, "client_id" | "client_id_issued_at">): Promise<OAuthClientInformationFull>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { fetchClientMetadata } from "./cimd.js";
|
|
3
|
+
const AUTH_CODE_TTL = 5 * 60 * 1000; // 5 min
|
|
4
|
+
const SESSION_TTL = 10 * 60 * 1000; // 10 min
|
|
5
|
+
const CLIENT_CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
|
6
|
+
export class AuthCodeStore {
|
|
7
|
+
codes = new Map();
|
|
8
|
+
generate(data) {
|
|
9
|
+
const code = randomBytes(32).toString("hex");
|
|
10
|
+
this.codes.set(code, { ...data, expiresAt: Date.now() + AUTH_CODE_TTL });
|
|
11
|
+
return code;
|
|
12
|
+
}
|
|
13
|
+
consume(code) {
|
|
14
|
+
const data = this.codes.get(code);
|
|
15
|
+
if (!data)
|
|
16
|
+
return null;
|
|
17
|
+
this.codes.delete(code);
|
|
18
|
+
if (data.expiresAt < Date.now())
|
|
19
|
+
return null;
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class PendingSessionStore {
|
|
24
|
+
sessions = new Map();
|
|
25
|
+
create(data) {
|
|
26
|
+
const id = randomBytes(24).toString("hex");
|
|
27
|
+
this.sessions.set(id, { ...data, expiresAt: Date.now() + SESSION_TTL });
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
consume(id) {
|
|
31
|
+
const data = this.sessions.get(id);
|
|
32
|
+
if (!data)
|
|
33
|
+
return null;
|
|
34
|
+
this.sessions.delete(id);
|
|
35
|
+
if (data.expiresAt < Date.now())
|
|
36
|
+
return null;
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class ClientStore {
|
|
41
|
+
clients = new Map();
|
|
42
|
+
async getClient(clientId) {
|
|
43
|
+
// Check cache first
|
|
44
|
+
const cached = this.clients.get(clientId);
|
|
45
|
+
if (cached && cached.cachedAt + CLIENT_CACHE_TTL > Date.now()) {
|
|
46
|
+
return cached.client;
|
|
47
|
+
}
|
|
48
|
+
// CIMD: if client_id is a URL, fetch metadata from it
|
|
49
|
+
if (clientId.startsWith("https://")) {
|
|
50
|
+
const meta = await fetchClientMetadata(clientId);
|
|
51
|
+
if (meta) {
|
|
52
|
+
this.clients.set(clientId, { client: meta, cachedAt: Date.now() });
|
|
53
|
+
return meta;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return cached?.client;
|
|
57
|
+
}
|
|
58
|
+
async registerClient(client) {
|
|
59
|
+
const clientId = `scavio_${randomBytes(16).toString("hex")}`;
|
|
60
|
+
const full = {
|
|
61
|
+
...client,
|
|
62
|
+
client_id: clientId,
|
|
63
|
+
client_id_issued_at: Math.floor(Date.now() / 1000),
|
|
64
|
+
};
|
|
65
|
+
this.clients.set(clientId, { client: full, cachedAt: Date.now() });
|
|
66
|
+
return full;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=stores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../../src/auth/stores.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,9 @@ async function startHttp() {
|
|
|
39
39
|
const { Hono } = await import("hono");
|
|
40
40
|
const { serve } = await import("@hono/node-server");
|
|
41
41
|
const { WebStandardStreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
|
|
42
|
+
const { authApp } = await import("./auth/routes.js");
|
|
42
43
|
const app = new Hono();
|
|
44
|
+
// Health / info endpoints
|
|
43
45
|
app.get("/", (c) => c.json({
|
|
44
46
|
status: "ok",
|
|
45
47
|
server: SERVER_NAME,
|
|
@@ -48,12 +50,18 @@ async function startHttp() {
|
|
|
48
50
|
default_platforms: DEFAULT_PLATFORMS,
|
|
49
51
|
}));
|
|
50
52
|
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
53
|
+
// Mount OAuth routes (well-known, authorize, token, register, callback)
|
|
54
|
+
app.route("/", authApp);
|
|
55
|
+
// MCP endpoint with dual auth: OAuth bearer or legacy API key
|
|
51
56
|
app.post("/mcp", async (c) => {
|
|
52
57
|
const apiKey = c.req.header("x-api-key") ??
|
|
53
58
|
c.req.header("authorization")?.replace("Bearer ", "") ??
|
|
54
59
|
c.req.query("api_key");
|
|
55
60
|
if (!apiKey) {
|
|
56
|
-
|
|
61
|
+
// Return 401 with OAuth discovery for OAuth-capable clients
|
|
62
|
+
const resourceMetadataUrl = `${env.ISSUER_URL}/.well-known/oauth-protected-resource/mcp`;
|
|
63
|
+
c.header("WWW-Authenticate", `Bearer resource_metadata="${resourceMetadataUrl}"`);
|
|
64
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
57
65
|
}
|
|
58
66
|
// A hosted remote has no per-user env var, so the allowlist is selectable
|
|
59
67
|
// per connection. Falls back to SCAVIO_PLATFORMS, then to the default set.
|
|
@@ -67,6 +75,12 @@ async function startHttp() {
|
|
|
67
75
|
});
|
|
68
76
|
serve({ fetch: app.fetch, port: env.PORT }, (info) => {
|
|
69
77
|
console.error(`${SERVER_NAME} v${SERVER_VERSION} started (http) on port ${info.port}`);
|
|
78
|
+
if (env.MCP_AUTH_SECRET) {
|
|
79
|
+
console.error(`OAuth enabled (issuer: ${env.ISSUER_URL})`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.error("OAuth disabled (MCP_AUTH_SECRET not set)");
|
|
83
|
+
}
|
|
70
84
|
});
|
|
71
85
|
}
|
|
72
86
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,MAAM,WAAW,GAAG,YAAY,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,cAAc,GAClB,IAAI,CAAC,KAAK,CACR,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAE5F,CAAC,OAAO,CAAC;AAEV,IAAI,GAAG,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;IAC9B,MAAM,UAAU,EAAE,CAAC;AACrB,CAAC;KAAM,CAAC;IACN,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,UAAU;IACvB,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAC3C,2CAA2C,CAC5C,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CACX,GAAG,WAAW,KAAK,cAAc,iCAAiC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE;QAChG,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6DAA6D,EAAE,CACjG,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACpD,MAAM,EAAE,wCAAwC,EAAE,GAAG,MAAM,MAAM,CAC/D,+DAA+D,CAChE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/client.js
CHANGED
|
@@ -19,14 +19,17 @@ export class ScavioClient {
|
|
|
19
19
|
if (!response.ok) {
|
|
20
20
|
const text = await response.text();
|
|
21
21
|
let message;
|
|
22
|
+
let billingUrl;
|
|
22
23
|
try {
|
|
23
24
|
const json = JSON.parse(text);
|
|
24
25
|
message = json.error ?? json.message ?? text;
|
|
26
|
+
if (typeof json.billing_url === "string")
|
|
27
|
+
billingUrl = json.billing_url;
|
|
25
28
|
}
|
|
26
29
|
catch {
|
|
27
30
|
message = text;
|
|
28
31
|
}
|
|
29
|
-
throw new ApiError(response.status, message);
|
|
32
|
+
throw new ApiError(response.status, message, undefined, billingUrl);
|
|
30
33
|
}
|
|
31
34
|
return response.json();
|
|
32
35
|
}
|
package/dist/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,OAAO,YAAY;IACf,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QACnE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACrD,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,OAAO,YAAY;IACf,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QACnE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACrD,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,OAAe,CAAC;YACpB,IAAI,UAA8B,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;gBAC7C,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;oBAAE,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC;YAC1E,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QACtE,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY;QACvB,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAc;QACxC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF"}
|
package/dist/lib/env.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export declare const env: {
|
|
|
2
2
|
SCAVIO_API_BASE_URL: string;
|
|
3
3
|
PORT: number;
|
|
4
4
|
TRANSPORT: "http" | "stdio";
|
|
5
|
+
ISSUER_URL: string;
|
|
6
|
+
DASHBOARD_URL: string;
|
|
5
7
|
SCAVIO_API_KEY?: string | undefined;
|
|
6
8
|
SCAVIO_PLATFORMS?: string | undefined;
|
|
9
|
+
MCP_AUTH_SECRET?: string | undefined;
|
|
7
10
|
};
|
package/dist/lib/env.js
CHANGED
|
@@ -11,6 +11,10 @@ const envSchema = z.object({
|
|
|
11
11
|
.default(3000),
|
|
12
12
|
TRANSPORT: z.enum(["http", "stdio"])
|
|
13
13
|
.default("stdio"),
|
|
14
|
+
// OAuth
|
|
15
|
+
MCP_AUTH_SECRET: z.string().min(32).optional(),
|
|
16
|
+
ISSUER_URL: z.string().url().default("https://mcp.scavio.dev"),
|
|
17
|
+
DASHBOARD_URL: z.string().url().default("https://dashboard.scavio.dev"),
|
|
14
18
|
});
|
|
15
19
|
export const env = envSchema.parse(process.env);
|
|
16
20
|
//# sourceMappingURL=env.js.map
|
package/dist/lib/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;SAClC,OAAO,CAAC,wBAAwB,CAAC;IACpC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,mFAAmF;IACnF,+EAA+E;IAC/E,8EAA8E;IAC9E,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;SAC5C,OAAO,CAAC,IAAI,CAAC;IAChB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACjC,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;SAClC,OAAO,CAAC,wBAAwB,CAAC;IACpC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,mFAAmF;IACnF,+EAA+E;IAC/E,8EAA8E;IAC9E,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;SAC5C,OAAO,CAAC,IAAI,CAAC;IAChB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACjC,OAAO,CAAC,OAAO,CAAC;IACnB,QAAQ;IACR,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC9C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC;IAC9D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC;CACxE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC"}
|