stables-mcp-server 2.5.2 → 2.6.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 +1 -1
- package/build/http/handler.d.ts +2 -1
- package/build/http/handler.d.ts.map +1 -1
- package/build/http/handler.js +3 -3
- package/build/http/handler.js.map +1 -1
- package/build/oauth/auth0.d.ts +1 -1
- package/build/oauth/handlers.d.ts +7 -2
- package/build/oauth/handlers.d.ts.map +1 -1
- package/build/oauth/handlers.js +19 -8
- package/build/oauth/handlers.js.map +1 -1
- package/build/oauth/pages.d.ts +3 -1
- package/build/oauth/pages.d.ts.map +1 -1
- package/build/oauth/pages.js +10 -1
- package/build/oauth/pages.js.map +1 -1
- package/build/oauth/provider.d.ts +10 -1
- package/build/oauth/provider.d.ts.map +1 -1
- package/build/oauth/provider.js +54 -7
- package/build/oauth/provider.js.map +1 -1
- package/build/oauth/types.d.ts +13 -2
- package/build/oauth/types.d.ts.map +1 -1
- package/build/oauth/types.js +12 -3
- package/build/oauth/types.js.map +1 -1
- package/build/server.d.ts +11 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +20 -1
- package/build/server.js.map +1 -1
- package/build/tool-policy.d.ts +44 -0
- package/build/tool-policy.d.ts.map +1 -0
- package/build/tool-policy.js +110 -0
- package/build/tool-policy.js.map +1 -0
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ bearer_token_env_var = "STABLES_API_KEY"
|
|
|
125
125
|
|
|
126
126
|
Add `https://mcp.stables.money/mcp` as a custom connector with no key. The client discovers the server's OAuth endpoints, registers itself, and sends you to a Stables page that asks two things: whether to connect sandbox or production, and permission for that client. You then sign in with your Stables dashboard account (and pick an organisation if you belong to several).
|
|
127
127
|
|
|
128
|
-
Auth0 asks for your credentials every time (an existing browser session is never reused for an agent connection) and, when you belong to several organisations, which one to use. On success the server creates an API key in that organisation, named after the client and the account that signed in (for example `Claude via MCP (you@company.com)`), and uses it for every call the client makes. Revoke it any time under Developer → API keys in the dashboard, which disconnects the client. Nothing else is stored: the sign-in token is used once to create the key and then dropped.
|
|
128
|
+
You choose **Read only** (the default) or **Read and make changes**; with read only, the agent can look but every tool that changes something is refused until you reconnect and allow changes. Agents connected this way can never create or revoke API keys. Every tool is labelled read-only or destructive, so clients such as Claude ask you before each change. Auth0 asks for your credentials (and a second factor) every time (an existing browser session is never reused for an agent connection) and, when you belong to several organisations, which one to use. On success the server creates an API key in that organisation, named after the client and the account that signed in (for example `Claude via MCP (you@company.com)`), and uses it for every call the client makes. Revoke it any time under Developer → API keys in the dashboard, which disconnects the client. Nothing else is stored: the sign-in token is used once to create the key and then dropped.
|
|
129
129
|
|
|
130
130
|
- **Claude.ai / Claude Desktop:** Settings → Connectors → Add custom connector, URL `https://mcp.stables.money/mcp`, leave the OAuth client fields on their defaults.
|
|
131
131
|
- **ChatGPT:** Settings → Connectors → Create (developer mode), MCP server URL `https://mcp.stables.money/mcp`, authentication OAuth.
|
package/build/http/handler.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* nothing about one caller survives to the next and no session store is
|
|
9
9
|
* needed.
|
|
10
10
|
*/
|
|
11
|
+
import { type ServerOptions } from "../server.js";
|
|
11
12
|
import type { StablesApiClient } from "../lib/stables-client.js";
|
|
12
13
|
export declare const MCP_PATH = "/mcp";
|
|
13
14
|
export declare function withCors(response: Response): Response;
|
|
@@ -17,6 +18,6 @@ export declare function json(body: unknown, status?: number, extraHeaders?: Reco
|
|
|
17
18
|
* bearer-key path below and the OAuth path in the Worker, which resolves the
|
|
18
19
|
* caller's API key from the grant before calling this.
|
|
19
20
|
*/
|
|
20
|
-
export declare function serveMcp(request: Request, client: StablesApiClient): Promise<Response>;
|
|
21
|
+
export declare function serveMcp(request: Request, client: StablesApiClient, options?: ServerOptions): Promise<Response>;
|
|
21
22
|
export declare function handleRequest(request: Request): Promise<Response>;
|
|
22
23
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/http/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/http/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,eAAO,MAAM,QAAQ,SAAS,CAAC;AAW/B,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAIrD;AAED,wBAAgB,IAAI,CAClB,IAAI,EAAE,OAAO,EACb,MAAM,SAAM,EACZ,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACxC,QAAQ,CAKV;AAoCD;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,QAAQ,CAAC,CA+BnB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0CvE"}
|
package/build/http/handler.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* needed.
|
|
10
10
|
*/
|
|
11
11
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
12
|
-
import { SERVER_NAME, SERVER_VERSION, createStablesMcpServer } from "../server.js";
|
|
12
|
+
import { SERVER_NAME, SERVER_VERSION, createStablesMcpServer, } from "../server.js";
|
|
13
13
|
import { BEARER_CHALLENGE, authenticate } from "./auth.js";
|
|
14
14
|
export const MCP_PATH = "/mcp";
|
|
15
15
|
const CORS_HEADERS = {
|
|
@@ -63,7 +63,7 @@ function describe(origin) {
|
|
|
63
63
|
* bearer-key path below and the OAuth path in the Worker, which resolves the
|
|
64
64
|
* caller's API key from the grant before calling this.
|
|
65
65
|
*/
|
|
66
|
-
export async function serveMcp(request, client) {
|
|
66
|
+
export async function serveMcp(request, client, options = {}) {
|
|
67
67
|
// Stateless means no server-initiated SSE stream. Answering GET with 405
|
|
68
68
|
// is how the spec says to decline it; letting the transport open a stream
|
|
69
69
|
// that closes at once makes clients reconnect in a tight loop.
|
|
@@ -73,7 +73,7 @@ export async function serveMcp(request, client) {
|
|
|
73
73
|
message: "This server has no SSE stream. Send JSON-RPC with POST.",
|
|
74
74
|
}, 405, { allow: "POST, OPTIONS" });
|
|
75
75
|
}
|
|
76
|
-
const server = createStablesMcpServer(client);
|
|
76
|
+
const server = createStablesMcpServer(client, options);
|
|
77
77
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
78
78
|
// Stateless: no session ids, so any instance (or any edge location) can
|
|
79
79
|
// answer any request, and a client never has to re-initialise after a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/http/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/http/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EACL,WAAW,EACX,cAAc,EACd,sBAAsB,GAEvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG3D,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE/B,MAAM,YAAY,GAA2B;IAC3C,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,4BAA4B;IAC5D,8BAA8B,EAC5B,qGAAqG;IACvG,+BAA+B,EAAE,sCAAsC;IACvE,wBAAwB,EAAE,OAAO;CAClC,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,QAAkB;IACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnF,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,IAAa,EACb,MAAM,GAAG,GAAG,EACZ,eAAuC,EAAE;IAEzC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QACjD,MAAM;QACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,YAAY,EAAE;KACjE,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,IAAI,CACT;QACE,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,yIAAyI;QAC/I,IAAI,EAAE,oFAAoF;KAC3F,EACD,GAAG,EACH,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CACzC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc;IAC9B,OAAO,IAAI,CAAC;QACV,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;QACvB,WAAW,EACT,iJAAiJ;QACnJ,QAAQ,EAAE,GAAG,MAAM,GAAG,QAAQ,EAAE;QAChC,SAAS,EAAE,iBAAiB;QAC5B,cAAc,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,iCAAiC;YACzC,YAAY,EAAE;gBACZ,YAAY,EAAE,6CAA6C;gBAC3D,YAAY,EAAE,wCAAwC;aACvD;SACF;QACD,IAAI,EAAE,oFAAoF;QAC1F,MAAM,EAAE,6CAA6C;KACtD,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAgB,EAChB,MAAwB,EACxB,UAAyB,EAAE;IAE3B,yEAAyE;IACzE,0EAA0E;IAC1E,+DAA+D;IAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,OAAO,IAAI,CACT;YACE,KAAK,EAAE,oBAAoB;YAC3B,OAAO,EAAE,yDAAyD;SACnE,EACD,GAAG,EACH,EAAE,KAAK,EAAE,eAAe,EAAE,CAC3B,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,wCAAwC,CAAC;QAC7D,wEAAwE;QACxE,sEAAsE;QACtE,sEAAsE;QACtE,kBAAkB,EAAE,SAAS;QAC7B,yEAAyE;QACzE,0EAA0E;QAC1E,kBAAkB,EAAE,IAAI;KACzB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;YAAS,CAAC;QACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEjC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,QAAQ,GAAG,EAAE,CAAC;QACjE,yEAAyE;QACzE,0EAA0E;QAC1E,+DAA+D;QAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YAC7B,OAAO,QAAQ,CACb,IAAI,CACF;gBACE,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,yDAAyD;aACnE,EACD,GAAG,EACH,EAAE,KAAK,EAAE,eAAe,EAAE,CAC3B,CACF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACzD,OAAO,QAAQ,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,QAAQ,CACb,IAAI,CACF;QACE,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,cAAc,GAAG,CAAC,QAAQ,yBAAyB,QAAQ,GAAG;KACxE,EACD,GAAG,CACJ,CACF,CAAC;AACJ,CAAC"}
|
package/build/oauth/auth0.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { StablesEnvironment } from "./types.js";
|
|
|
14
14
|
* domain answers 403 to requests with no User-Agent, and Worker subrequests
|
|
15
15
|
* carry none by default.
|
|
16
16
|
*/
|
|
17
|
-
export declare const SERVER_USER_AGENT = "stables-mcp-server/2.
|
|
17
|
+
export declare const SERVER_USER_AGENT = "stables-mcp-server/2.6.1 (hosted)";
|
|
18
18
|
export declare const API_BASE: Record<StablesEnvironment, string>;
|
|
19
19
|
/** Auth0 API identifier the dashboard uses for this environment. */
|
|
20
20
|
export declare function dashboardAudience(environment: StablesEnvironment): string;
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* a valid token to handleDefault.
|
|
6
6
|
*/
|
|
7
7
|
import { type OAuthEnv } from "./types.js";
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The scopes a grant gets: always read; write only when the person chose
|
|
10
|
+
* "make changes"; offline_access when the client asked for refresh tokens.
|
|
11
|
+
*/
|
|
12
|
+
export declare function grantScope(requested: string[], allowChanges: boolean): string[];
|
|
13
|
+
/** Whether the client asked for write access (or the legacy all-access scope). */
|
|
14
|
+
export declare function requestsChanges(requested: string[]): boolean;
|
|
10
15
|
export declare function handleDefault(request: Request, env: OAuthEnv): Promise<Response>;
|
|
11
16
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/oauth/handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,OAAO,
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/oauth/handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,OAAO,EAML,KAAK,QAAQ,EAEd,MAAM,YAAY,CAAC;AAyBpB;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,EAAE,CAK/E;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAE5D;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8CtF"}
|
package/build/oauth/handlers.js
CHANGED
|
@@ -8,7 +8,7 @@ import { AuthorizationError, CimdFetchError, authorizationErrorRedirect, } from
|
|
|
8
8
|
import { MCP_PATH, handleRequest, json, withCors } from "../http/handler.js";
|
|
9
9
|
import { OAuthStepError, apiKeyName, auth0AuthorizeUrl, auth0ConfigFrom, exchangeAuth0Code, identityFromIdToken, mintApiKey, parseEnvironment, randomVerifier, s256, } from "./auth0.js";
|
|
10
10
|
import { consentPage, errorPage } from "./pages.js";
|
|
11
|
-
import { SCOPE,
|
|
11
|
+
import { LEGACY_SCOPE, READ_SCOPE, SCOPE, WRITE_SCOPE, } from "./types.js";
|
|
12
12
|
function html(body, status = 200, headers) {
|
|
13
13
|
const h = new Headers(headers);
|
|
14
14
|
h.set("content-type", "text/html; charset=utf-8");
|
|
@@ -23,13 +23,22 @@ function redirect(headers, location) {
|
|
|
23
23
|
function publicOrigin(request, env) {
|
|
24
24
|
return (env.MCP_PUBLIC_URL ?? new URL(request.url).origin).replace(/\/$/, "");
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The scopes a grant gets: always read; write only when the person chose
|
|
28
|
+
* "make changes"; offline_access when the client asked for refresh tokens.
|
|
29
|
+
*/
|
|
30
|
+
export function grantScope(requested, allowChanges) {
|
|
31
|
+
const scope = [READ_SCOPE];
|
|
32
|
+
if (allowChanges)
|
|
33
|
+
scope.push(WRITE_SCOPE);
|
|
34
|
+
if (requested.includes("offline_access"))
|
|
35
|
+
scope.push("offline_access");
|
|
31
36
|
return scope;
|
|
32
37
|
}
|
|
38
|
+
/** Whether the client asked for write access (or the legacy all-access scope). */
|
|
39
|
+
export function requestsChanges(requested) {
|
|
40
|
+
return requested.includes(WRITE_SCOPE) || requested.includes(LEGACY_SCOPE);
|
|
41
|
+
}
|
|
33
42
|
export async function handleDefault(request, env) {
|
|
34
43
|
const url = new URL(request.url);
|
|
35
44
|
const path = url.pathname;
|
|
@@ -76,7 +85,7 @@ async function authorizeGet(request, env, oauth) {
|
|
|
76
85
|
// describeConsent first: a failed client lookup leaves nothing in KV.
|
|
77
86
|
const details = await oauth.describeConsent(authRequest);
|
|
78
87
|
const consent = await oauth.beginConsent(authRequest);
|
|
79
|
-
return html(consentPage(details, consent.handle), 200, consent.headers);
|
|
88
|
+
return html(consentPage(details, consent.handle, { requestsChanges: requestsChanges(authRequest.scope) }), 200, consent.headers);
|
|
80
89
|
}
|
|
81
90
|
async function authorizePost(request, env, oauth) {
|
|
82
91
|
const config = auth0ConfigFrom(env);
|
|
@@ -94,7 +103,7 @@ async function authorizePost(request, env, oauth) {
|
|
|
94
103
|
return html(errorPage("Pick an environment", "Choose Sandbox or Production and try again."), 400);
|
|
95
104
|
}
|
|
96
105
|
const approved = await oauth.approveConsent(request, handle);
|
|
97
|
-
const scope = grantScope(approved.request.scope);
|
|
106
|
+
const scope = grantScope(approved.request.scope, form.get("access") === "write");
|
|
98
107
|
const verifier = randomVerifier();
|
|
99
108
|
const data = { environment, verifier, scope };
|
|
100
109
|
const { state, headers } = await oauth.beginUpstream(approved.request, {
|
|
@@ -138,9 +147,11 @@ async function callback(request, env, oauth) {
|
|
|
138
147
|
source: "mcp_oauth",
|
|
139
148
|
client: clientName,
|
|
140
149
|
user: identity.email ?? identity.sub,
|
|
150
|
+
access: data.scope.includes(WRITE_SCOPE) ? "read_write" : "read",
|
|
141
151
|
},
|
|
142
152
|
});
|
|
143
153
|
const props = {
|
|
154
|
+
source: "oauth",
|
|
144
155
|
apiKey: minted.plaintextKey,
|
|
145
156
|
apiKeyId: minted.apiKeyId,
|
|
146
157
|
environment: data.environment,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/oauth/handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,0BAA0B,GAG3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,IAAI,GACL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EACL,KAAK,EACL,
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/oauth/handlers.ts"],"names":[],"mappings":"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"}
|
package/build/oauth/pages.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ConsentDescription } from "@cloudflare/workers-oauth-provider";
|
|
11
11
|
export declare function escapeHtml(value: string): string;
|
|
12
|
-
export declare function consentPage(details: ConsentDescription, handle: string
|
|
12
|
+
export declare function consentPage(details: ConsentDescription, handle: string, options?: {
|
|
13
|
+
requestsChanges?: boolean;
|
|
14
|
+
}): string;
|
|
13
15
|
export declare function errorPage(title: string, message: string, hint?: string): string;
|
|
14
16
|
//# sourceMappingURL=pages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/oauth/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAiGD,wBAAgB,WAAW,
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/oauth/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAiGD,wBAAgB,WAAW,CACzB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,MAAM,CAyCR;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAU/E"}
|
package/build/oauth/pages.js
CHANGED
|
@@ -91,7 +91,8 @@ ${options.body}
|
|
|
91
91
|
}
|
|
92
92
|
const HERO_TITLE = "Connect your AI agent";
|
|
93
93
|
const HERO_SUB = "Let it move money and manage customers through Stables, with the access you approve.";
|
|
94
|
-
export function consentPage(details, handle) {
|
|
94
|
+
export function consentPage(details, handle, options = {}) {
|
|
95
|
+
const changes = options.requestsChanges === true;
|
|
95
96
|
const name = escapeHtml(details.clientName);
|
|
96
97
|
const origin = details.clientDomain
|
|
97
98
|
? `Published by <strong>${escapeHtml(details.clientDomain)}</strong>.`
|
|
@@ -106,6 +107,7 @@ export function consentPage(details, handle) {
|
|
|
106
107
|
body: `<h2>Connect ${name} to Stables?</h2>
|
|
107
108
|
<p class="sub">${origin} Access will be sent to <strong>${escapeHtml(details.redirectHost)}</strong>.</p>
|
|
108
109
|
${loopback}
|
|
110
|
+
${changes ? `<p class="warn"><strong>${name} is asking for permission to make changes,</strong> including moving money. Choose "Read only" below if you only want it to look.</p>` : ""}
|
|
109
111
|
<p class="notice">Next you'll sign in with your Stables dashboard account and choose an organisation. Allowing creates an API key there named after ${name}; revoke it any time under Developer → API keys.</p>
|
|
110
112
|
<form method="post" autocomplete="off" onsubmit="if(this.dataset.sent)return false;this.dataset.sent=1;setTimeout(()=>{for(const b of this.querySelectorAll('button'))b.disabled=true},0);">
|
|
111
113
|
<input type="hidden" name="handle" value="${escapeHtml(handle)}">
|
|
@@ -116,6 +118,13 @@ ${loopback}
|
|
|
116
118
|
<label class="env"><input type="radio" name="environment" value="production">
|
|
117
119
|
<span><span class="env-name">Production</span><span class="env-desc">Live organisation. The agent can move real money.</span></span></label>
|
|
118
120
|
</div>
|
|
121
|
+
<label class="lbl">Access</label>
|
|
122
|
+
<div class="env-list">
|
|
123
|
+
<label class="env"><input type="radio" name="access" value="read"${changes ? "" : " checked"}>
|
|
124
|
+
<span><span class="env-name">Read only</span><span class="env-desc">See customers, balances, quotes and transfers. Nothing in your account changes.</span></span></label>
|
|
125
|
+
<label class="env"><input type="radio" name="access" value="write"${changes ? " checked" : ""}>
|
|
126
|
+
<span><span class="env-name">Read and make changes</span><span class="env-desc">Also create customers, quotes and transfers, including moving money. Agents such as Claude ask you to confirm each change.</span></span></label>
|
|
127
|
+
</div>
|
|
119
128
|
<div class="actions">
|
|
120
129
|
<button type="submit" name="decision" value="approve" class="btn btn-primary">Allow and sign in</button>
|
|
121
130
|
<button type="submit" name="decision" value="deny" class="btn btn-secondary">Cancel</button>
|
package/build/oauth/pages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/oauth/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACzE,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,GACd,oGAAoG,CAAC;AACvG,MAAM,WAAW,GACf,6GAA6G,CAAC;AAChH,MAAM,IAAI,GACR,qGAAqG,CAAC;AACxG,MAAM,YAAY,GAChB,4GAA4G,CAAC;AAE/G,MAAM,KAAK,GAAG;;gDAEkC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C3D,CAAC;AAEF,SAAS,MAAM,CAAC,OAKf;IACC,OAAO;;;;;;SAMA,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;SACzB,KAAK;;;;;qDAKuC,WAAW,kBAAkB,UAAU;;4BAEhE,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;;;;oCAI3D,IAAI;EACtC,OAAO,CAAC,IAAI;;;;;QAKN,CAAC;AACT,CAAC;AAED,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAC3C,MAAM,QAAQ,GACZ,sFAAsF,CAAC;AAEzF,MAAM,UAAU,WAAW,
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/oauth/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACzE,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,GACd,oGAAoG,CAAC;AACvG,MAAM,WAAW,GACf,6GAA6G,CAAC;AAChH,MAAM,IAAI,GACR,qGAAqG,CAAC;AACxG,MAAM,YAAY,GAChB,4GAA4G,CAAC;AAE/G,MAAM,KAAK,GAAG;;gDAEkC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C3D,CAAC;AAEF,SAAS,MAAM,CAAC,OAKf;IACC,OAAO;;;;;;SAMA,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;SACzB,KAAK;;;;;qDAKuC,WAAW,kBAAkB,UAAU;;4BAEhE,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;;;;oCAI3D,IAAI;EACtC,OAAO,CAAC,IAAI;;;;;QAKN,CAAC;AACT,CAAC;AAED,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAC3C,MAAM,QAAQ,GACZ,sFAAsF,CAAC;AAEzF,MAAM,UAAU,WAAW,CACzB,OAA2B,EAC3B,MAAc,EACd,UAAyC,EAAE;IAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,KAAK,IAAI,CAAC;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY;QACjC,CAAC,CAAC,wBAAwB,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY;QACtE,CAAC,CAAC,0DAA0D,CAAC;IAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,kBAAkB;QACzC,CAAC,CAAC,0IAA0I;QAC5I,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,WAAW,OAAO,CAAC,UAAU,aAAa;QACjD,SAAS,EAAE,UAAU;QACrB,OAAO,EAAE,QAAQ;QACjB,IAAI,EAAE,eAAe,IAAI;iBACZ,MAAM,mCAAmC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC;EACxF,QAAQ;EACR,OAAO,CAAC,CAAC,CAAC,2BAA2B,IAAI,uIAAuI,CAAC,CAAC,CAAC,EAAE;sJACjC,IAAI;;8CAE5G,UAAU,CAAC,MAAM,CAAC;;;;;;;;;;uEAUO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU;;wEAExB,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;;;;;;;;0FAQP;KACvF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,OAAe,EAAE,IAAa;IACrE,OAAO,MAAM,CAAC;QACZ,KAAK;QACL,SAAS,EAAE,UAAU;QACrB,OAAO,EAAE,QAAQ;QACjB,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;mBACf,UAAU,CAAC,OAAO,CAAC;EACpC,IAAI,CAAC,CAAC,CAAC,kBAAkB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;mFAC6B;KAChF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
* /callback are ours (handlers.ts).
|
|
13
13
|
*/
|
|
14
14
|
import { OAuthProvider } from "@cloudflare/workers-oauth-provider";
|
|
15
|
+
import { type ToolGrant } from "../tool-policy.js";
|
|
15
16
|
import { StablesApiClient } from "../lib/stables-client.js";
|
|
16
|
-
import { type OAuthEnv } from "./types.js";
|
|
17
|
+
import { type GrantProps, type OAuthEnv } from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* What a connection may do. An API key presented directly keeps full access,
|
|
20
|
+
* as before. An OAuth grant reads with `stables:read`, writes with
|
|
21
|
+
* `stables:write` (or the legacy `stables`), and never gets admin tools.
|
|
22
|
+
*/
|
|
23
|
+
export declare function grantFor(props: GrantProps | undefined, scope: string[]): ToolGrant;
|
|
24
|
+
/** Tool names a JSON-RPC body calls (one message or a batch). */
|
|
25
|
+
export declare function calledTools(request: Request): Promise<string[]>;
|
|
17
26
|
export declare function resourceFor(origin: string): string;
|
|
18
27
|
export declare function apiClientFor(apiKey: string, env: OAuthEnv): StablesApiClient | null;
|
|
19
28
|
/** One provider per public origin; metadata and token audiences are bound to it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAEL,aAAa,EAGd,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,EAAE,gBAAgB,EAAgB,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EAML,KAAK,UAAU,EACf,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAKlF;AAED,iEAAiE;AACjE,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBrE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,gBAAgB,GAAG,IAAI,CAOnF;AAiDD,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAqDnE"}
|
package/build/oauth/provider.js
CHANGED
|
@@ -11,13 +11,43 @@
|
|
|
11
11
|
* /oauth/token and /oauth/register are the provider's; /authorize and
|
|
12
12
|
* /callback are ours (handlers.ts).
|
|
13
13
|
*/
|
|
14
|
-
import { ExternalTokenError, OAuthProvider } from "@cloudflare/workers-oauth-provider";
|
|
14
|
+
import { ExternalTokenError, OAuthProvider, insufficientScope, } from "@cloudflare/workers-oauth-provider";
|
|
15
|
+
import { FULL_ACCESS, TOOL_POLICY } from "../tool-policy.js";
|
|
15
16
|
import { SERVER_VERSION } from "../version.js";
|
|
16
17
|
import { serveMcp, withCors, json } from "../http/handler.js";
|
|
17
18
|
import { StablesApiClient, apiUrlForKey } from "../lib/stables-client.js";
|
|
18
19
|
import { environmentForKey } from "./auth0.js";
|
|
19
20
|
import { handleDefault } from "./handlers.js";
|
|
20
|
-
import { SCOPE, SUPPORTED_SCOPES } from "./types.js";
|
|
21
|
+
import { LEGACY_SCOPE, READ_SCOPE, SCOPE, SUPPORTED_SCOPES, WRITE_SCOPE, } from "./types.js";
|
|
22
|
+
/**
|
|
23
|
+
* What a connection may do. An API key presented directly keeps full access,
|
|
24
|
+
* as before. An OAuth grant reads with `stables:read`, writes with
|
|
25
|
+
* `stables:write` (or the legacy `stables`), and never gets admin tools.
|
|
26
|
+
*/
|
|
27
|
+
export function grantFor(props, scope) {
|
|
28
|
+
if (props?.source === "api_key")
|
|
29
|
+
return FULL_ACCESS;
|
|
30
|
+
const write = scope.includes(WRITE_SCOPE) || scope.includes(LEGACY_SCOPE);
|
|
31
|
+
const read = write || scope.includes(READ_SCOPE);
|
|
32
|
+
return { read, write, admin: false };
|
|
33
|
+
}
|
|
34
|
+
/** Tool names a JSON-RPC body calls (one message or a batch). */
|
|
35
|
+
export async function calledTools(request) {
|
|
36
|
+
if (request.method !== "POST")
|
|
37
|
+
return [];
|
|
38
|
+
let body;
|
|
39
|
+
try {
|
|
40
|
+
body = await request.clone().json();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const messages = Array.isArray(body) ? body : [body];
|
|
46
|
+
return messages
|
|
47
|
+
.filter((m) => !!m && typeof m === "object" && m.method === "tools/call")
|
|
48
|
+
.map((m) => (typeof m.params?.name === "string" ? m.params.name : ""))
|
|
49
|
+
.filter(Boolean);
|
|
50
|
+
}
|
|
21
51
|
export function resourceFor(origin) {
|
|
22
52
|
return `${origin}/mcp`;
|
|
23
53
|
}
|
|
@@ -30,7 +60,7 @@ export function apiClientFor(apiKey, env) {
|
|
|
30
60
|
userAgent: `stables-mcp-server/${SERVER_VERSION} (hosted)`,
|
|
31
61
|
});
|
|
32
62
|
}
|
|
33
|
-
async function serveAuthorizedMcp(request, env, props) {
|
|
63
|
+
async function serveAuthorizedMcp(request, env, props, auth) {
|
|
34
64
|
const client = props?.apiKey ? apiClientFor(props.apiKey, env) : null;
|
|
35
65
|
if (!client) {
|
|
36
66
|
return withCors(json({
|
|
@@ -38,7 +68,20 @@ async function serveAuthorizedMcp(request, env, props) {
|
|
|
38
68
|
message: "This connection carries no usable Stables API key. Disconnect and connect again.",
|
|
39
69
|
}, 401));
|
|
40
70
|
}
|
|
41
|
-
|
|
71
|
+
const grant = grantFor(props, auth?.scope ?? []);
|
|
72
|
+
if (!grant.read) {
|
|
73
|
+
return withCors(json({ error: "insufficient_scope", message: "This connection has no access." }, 403));
|
|
74
|
+
}
|
|
75
|
+
// A read-only connection still lists the write tools, so the client knows
|
|
76
|
+
// they exist; calling one answers 403 insufficient_scope naming the write
|
|
77
|
+
// scope, which MCP clients answer by asking the person for more access.
|
|
78
|
+
if (!grant.write && auth) {
|
|
79
|
+
const writes = (await calledTools(request)).filter((name) => TOOL_POLICY[name]?.access === "write");
|
|
80
|
+
if (writes.length > 0) {
|
|
81
|
+
return withCors(insufficientScope(auth, [READ_SCOPE, WRITE_SCOPE], `${writes.join(", ")} changes your Stables account. Reconnect and allow "Read and make changes" to use it.`));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return withCors(await serveMcp(request, client, { grant }));
|
|
42
85
|
}
|
|
43
86
|
const providers = new Map();
|
|
44
87
|
/** One provider per public origin; metadata and token audiences are bound to it. */
|
|
@@ -51,8 +94,8 @@ export function providerFor(origin) {
|
|
|
51
94
|
apiRoute: "/mcp",
|
|
52
95
|
apiHandler: {
|
|
53
96
|
fetch(request, env, ctx) {
|
|
54
|
-
const props = ctx
|
|
55
|
-
return serveAuthorizedMcp(request, env, props);
|
|
97
|
+
const { props, auth } = ctx;
|
|
98
|
+
return serveAuthorizedMcp(request, env, props, auth);
|
|
56
99
|
},
|
|
57
100
|
},
|
|
58
101
|
defaultHandler: {
|
|
@@ -85,7 +128,11 @@ export function providerFor(origin) {
|
|
|
85
128
|
statusCode: 401,
|
|
86
129
|
});
|
|
87
130
|
}
|
|
88
|
-
const props = {
|
|
131
|
+
const props = {
|
|
132
|
+
source: "api_key",
|
|
133
|
+
apiKey: token,
|
|
134
|
+
environment: environmentForKey(token),
|
|
135
|
+
};
|
|
89
136
|
return { props, audience: resource };
|
|
90
137
|
},
|
|
91
138
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"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"}
|
package/build/oauth/types.d.ts
CHANGED
|
@@ -9,13 +9,24 @@
|
|
|
9
9
|
* is never kept.
|
|
10
10
|
*/
|
|
11
11
|
import type { OAuthHelpers } from "@cloudflare/workers-oauth-provider";
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Scopes. `stables:read` is what any connection gets; `stables:write` lets the
|
|
14
|
+
* agent change things and move money, and is granted only when the person
|
|
15
|
+
* ticks "make changes" on the consent page. Grants made before these scopes
|
|
16
|
+
* existed carry `stables`, which keeps meaning read and write.
|
|
17
|
+
*/
|
|
18
|
+
export declare const READ_SCOPE = "stables:read";
|
|
19
|
+
export declare const WRITE_SCOPE = "stables:write";
|
|
20
|
+
export declare const LEGACY_SCOPE = "stables";
|
|
21
|
+
/** The baseline a client should request first (RFC 9728 scopes_supported). */
|
|
22
|
+
export declare const SCOPE = "stables:read";
|
|
14
23
|
export declare const SUPPORTED_SCOPES: string[];
|
|
15
24
|
export type StablesEnvironment = "sandbox" | "production";
|
|
16
25
|
/** What a grant carries; handlers read it as ctx.props. */
|
|
17
26
|
export interface GrantProps {
|
|
18
27
|
apiKey: string;
|
|
28
|
+
/** "api_key" when the caller presented its own key: full access, as before. */
|
|
29
|
+
source?: "oauth" | "api_key";
|
|
19
30
|
environment: StablesEnvironment;
|
|
20
31
|
apiKeyId?: string;
|
|
21
32
|
email?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/oauth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/oauth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,UAAU,iBAAiB,CAAC;AACzC,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAC3C,eAAO,MAAM,YAAY,YAAY,CAAC;AACtC,8EAA8E;AAC9E,eAAO,MAAM,KAAK,iBAAa,CAAC;AAChC,eAAO,MAAM,gBAAgB,UAA4D,CAAC;AAE1F,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,CAAC;AAE1D,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC"}
|
package/build/oauth/types.js
CHANGED
|
@@ -8,7 +8,16 @@
|
|
|
8
8
|
* props, so every later MCP request is served with it and the Auth0 token
|
|
9
9
|
* is never kept.
|
|
10
10
|
*/
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Scopes. `stables:read` is what any connection gets; `stables:write` lets the
|
|
13
|
+
* agent change things and move money, and is granted only when the person
|
|
14
|
+
* ticks "make changes" on the consent page. Grants made before these scopes
|
|
15
|
+
* existed carry `stables`, which keeps meaning read and write.
|
|
16
|
+
*/
|
|
17
|
+
export const READ_SCOPE = "stables:read";
|
|
18
|
+
export const WRITE_SCOPE = "stables:write";
|
|
19
|
+
export const LEGACY_SCOPE = "stables";
|
|
20
|
+
/** The baseline a client should request first (RFC 9728 scopes_supported). */
|
|
21
|
+
export const SCOPE = READ_SCOPE;
|
|
22
|
+
export const SUPPORTED_SCOPES = [READ_SCOPE, WRITE_SCOPE, "offline_access", LEGACY_SCOPE];
|
|
14
23
|
//# sourceMappingURL=types.js.map
|
package/build/oauth/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/oauth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/oauth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAC3C,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AACtC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAAC;AAChC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC"}
|
package/build/server.d.ts
CHANGED
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
import type { StablesApiClient } from "./lib/stables-client.js";
|
|
9
|
+
import { type ToolGrant } from "./tool-policy.js";
|
|
9
10
|
import { SERVER_VERSION } from "./version.js";
|
|
10
11
|
export declare const SERVER_NAME = "stables-mcp-server";
|
|
11
12
|
export { SERVER_VERSION };
|
|
12
|
-
export
|
|
13
|
+
export interface ServerOptions {
|
|
14
|
+
/**
|
|
15
|
+
* What this connection may do. Write tools stay listed for a read-only
|
|
16
|
+
* connection (so a client can ask the person for more access when it needs
|
|
17
|
+
* it); admin tools are removed when not granted. Defaults to everything,
|
|
18
|
+
* which is what an API-key caller and the local stdio server get.
|
|
19
|
+
*/
|
|
20
|
+
grant?: ToolGrant;
|
|
21
|
+
}
|
|
22
|
+
export declare function createStablesMcpServer(client: StablesApiClient, options?: ServerOptions): McpServer;
|
|
13
23
|
//# sourceMappingURL=server.d.ts.map
|
package/build/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,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAuB,MAAM,yCAAyC,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAapG,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,aAAkB,GAC1B,SAAS,CA0CX"}
|
package/build/server.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* through here, so the tool surface is identical however the server is reached.
|
|
6
6
|
*/
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { FULL_ACCESS, TOOL_POLICY, allows, annotationsFor } from "./tool-policy.js";
|
|
8
9
|
import { registerCustomerTools } from "./tools/customers.js";
|
|
9
10
|
import { registerQuoteTools } from "./tools/quotes.js";
|
|
10
11
|
import { registerTransferTools } from "./tools/transfers.js";
|
|
@@ -19,12 +20,21 @@ import { registerDocumentTools } from "./tools/documents.js";
|
|
|
19
20
|
import { SERVER_VERSION } from "./version.js";
|
|
20
21
|
export const SERVER_NAME = "stables-mcp-server";
|
|
21
22
|
export { SERVER_VERSION };
|
|
22
|
-
export function createStablesMcpServer(client) {
|
|
23
|
+
export function createStablesMcpServer(client, options = {}) {
|
|
24
|
+
const grant = options.grant ?? FULL_ACCESS;
|
|
23
25
|
const server = new McpServer({
|
|
24
26
|
name: SERVER_NAME,
|
|
25
27
|
version: SERVER_VERSION,
|
|
26
28
|
description: "Stables fiat-to-crypto API for AI agents - manage customers, quotes, transfers, and virtual accounts",
|
|
27
29
|
});
|
|
30
|
+
// Capture every tool as it registers, so each gets its label below.
|
|
31
|
+
const registered = new Map();
|
|
32
|
+
const register = server.tool.bind(server);
|
|
33
|
+
server.tool = (...args) => {
|
|
34
|
+
const tool = register(...args);
|
|
35
|
+
registered.set(String(args[0]), tool);
|
|
36
|
+
return tool;
|
|
37
|
+
};
|
|
28
38
|
registerCustomerTools(server, client);
|
|
29
39
|
registerQuoteTools(server, client);
|
|
30
40
|
registerTransferTools(server, client);
|
|
@@ -36,6 +46,15 @@ export function createStablesMcpServer(client) {
|
|
|
36
46
|
registerComplianceTools(server, client);
|
|
37
47
|
registerDocumentTools(server, client);
|
|
38
48
|
registerSandboxTools(server, client);
|
|
49
|
+
for (const [name, tool] of registered) {
|
|
50
|
+
const policy = TOOL_POLICY[name];
|
|
51
|
+
if (!policy) {
|
|
52
|
+
throw new Error(`Tool "${name}" has no entry in TOOL_POLICY (src/tool-policy.ts)`);
|
|
53
|
+
}
|
|
54
|
+
tool.update({ title: policy.title, annotations: annotationsFor(policy) });
|
|
55
|
+
if (policy.access === "admin" && !allows(grant, "admin"))
|
|
56
|
+
tool.disable();
|
|
57
|
+
}
|
|
39
58
|
return server;
|
|
40
59
|
}
|
|
41
60
|
//# sourceMappingURL=server.js.map
|
package/build/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,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every tool may do, in one place.
|
|
3
|
+
*
|
|
4
|
+
* - `read` tools only read. They are labelled read-only, so MCP clients run
|
|
5
|
+
* them without asking.
|
|
6
|
+
* - `write` tools change something in the account, and some move money.
|
|
7
|
+
* They are labelled destructive, so clients such as Claude ask the person
|
|
8
|
+
* to confirm each call, and an OAuth connection can only use them when the
|
|
9
|
+
* person granted "make changes" (scope `stables:write`).
|
|
10
|
+
* - `admin` tools manage API keys. An agent connected through OAuth never
|
|
11
|
+
* gets them: it could otherwise mint itself credentials outside the grant.
|
|
12
|
+
* A caller authenticating with its own API key keeps them.
|
|
13
|
+
*
|
|
14
|
+
* Every registered tool must appear here; createStablesMcpServer refuses to
|
|
15
|
+
* start otherwise, so a new tool cannot ship unlabelled.
|
|
16
|
+
*/
|
|
17
|
+
import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
|
|
18
|
+
export type ToolAccess = "read" | "write" | "admin";
|
|
19
|
+
interface ToolPolicy {
|
|
20
|
+
access: ToolAccess;
|
|
21
|
+
title: string;
|
|
22
|
+
/** Repeating the same call has no further effect (gets, updates, deletes). */
|
|
23
|
+
idempotent?: boolean;
|
|
24
|
+
/** Reaches beyond the Stables account: pays out to a third party, calls a URL. */
|
|
25
|
+
openWorld?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const TOOL_POLICY: Record<string, ToolPolicy>;
|
|
28
|
+
/**
|
|
29
|
+
* MCP annotations for a tool. Reads are read-only; every write is marked
|
|
30
|
+
* destructive so clients confirm it with the person, which is the
|
|
31
|
+
* human-in-the-loop step money-moving tools need.
|
|
32
|
+
*/
|
|
33
|
+
export declare function annotationsFor(policy: ToolPolicy): ToolAnnotations;
|
|
34
|
+
export declare function accessOf(toolName: string): ToolAccess | undefined;
|
|
35
|
+
/** What a connection may call: write implies read; admin implies write. */
|
|
36
|
+
export interface ToolGrant {
|
|
37
|
+
read: boolean;
|
|
38
|
+
write: boolean;
|
|
39
|
+
admin: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare const FULL_ACCESS: ToolGrant;
|
|
42
|
+
export declare function allows(grant: ToolGrant, access: ToolAccess): boolean;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=tool-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-policy.d.ts","sourceRoot":"","sources":["../src/tool-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAE1E,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEpD,UAAU,UAAU;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kFAAkF;IAClF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAUD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAuElD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,eAAe,CASlE;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEjE;AAED,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,eAAO,MAAM,WAAW,EAAE,SAAoD,CAAC;AAE/E,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAEpE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every tool may do, in one place.
|
|
3
|
+
*
|
|
4
|
+
* - `read` tools only read. They are labelled read-only, so MCP clients run
|
|
5
|
+
* them without asking.
|
|
6
|
+
* - `write` tools change something in the account, and some move money.
|
|
7
|
+
* They are labelled destructive, so clients such as Claude ask the person
|
|
8
|
+
* to confirm each call, and an OAuth connection can only use them when the
|
|
9
|
+
* person granted "make changes" (scope `stables:write`).
|
|
10
|
+
* - `admin` tools manage API keys. An agent connected through OAuth never
|
|
11
|
+
* gets them: it could otherwise mint itself credentials outside the grant.
|
|
12
|
+
* A caller authenticating with its own API key keeps them.
|
|
13
|
+
*
|
|
14
|
+
* Every registered tool must appear here; createStablesMcpServer refuses to
|
|
15
|
+
* start otherwise, so a new tool cannot ship unlabelled.
|
|
16
|
+
*/
|
|
17
|
+
const read = (title) => ({ access: "read", title, idempotent: true });
|
|
18
|
+
const write = (title, extra = {}) => ({
|
|
19
|
+
access: "write",
|
|
20
|
+
title,
|
|
21
|
+
...extra,
|
|
22
|
+
});
|
|
23
|
+
const admin = (title) => ({ access: "admin", title });
|
|
24
|
+
export const TOOL_POLICY = {
|
|
25
|
+
// Customers
|
|
26
|
+
list_customers: read("List customers"),
|
|
27
|
+
get_customer: read("Get customer"),
|
|
28
|
+
create_customer: write("Create customer"),
|
|
29
|
+
update_customer: write("Update customer", { idempotent: true }),
|
|
30
|
+
update_customer_metadata: write("Update customer metadata", { idempotent: true }),
|
|
31
|
+
create_customer_onboarding_link: write("Create customer onboarding link"),
|
|
32
|
+
get_verification_link: write("Create verification link"),
|
|
33
|
+
// Quotes and transfers
|
|
34
|
+
create_quote: write("Create quote"),
|
|
35
|
+
get_quote: read("Get quote"),
|
|
36
|
+
validate_payment_method: read("Validate payment method"),
|
|
37
|
+
create_transfer: write("Create transfer (moves money)", { openWorld: true }),
|
|
38
|
+
get_transfer: read("Get transfer"),
|
|
39
|
+
list_transfers: read("List transfers"),
|
|
40
|
+
// Payment routes (virtual accounts)
|
|
41
|
+
create_virtual_account: write("Create payment route"),
|
|
42
|
+
list_virtual_accounts: read("List payment routes"),
|
|
43
|
+
update_virtual_account: write("Update payment route", { idempotent: true }),
|
|
44
|
+
update_route_destination: write("Change payment route destination", { idempotent: true }),
|
|
45
|
+
get_virtual_account_history: read("Get payment route history"),
|
|
46
|
+
list_route_whitelist: read("List payment route allowed senders"),
|
|
47
|
+
add_route_whitelist_account: write("Add payment route allowed sender"),
|
|
48
|
+
update_route_whitelist_account: write("Update payment route allowed sender", {
|
|
49
|
+
idempotent: true,
|
|
50
|
+
}),
|
|
51
|
+
register_route_payid: write("Register PayID on payment route"),
|
|
52
|
+
// Balances
|
|
53
|
+
get_balance: read("Get balance"),
|
|
54
|
+
get_balance_wallet: read("Get balance wallet"),
|
|
55
|
+
create_balance_wallet: write("Create balance wallet"),
|
|
56
|
+
list_balance_activity: read("List balance activity"),
|
|
57
|
+
list_pending_balance_deposits: read("List pending balance deposits"),
|
|
58
|
+
list_whitelisted_wallets: read("List allowed wallets"),
|
|
59
|
+
// Entitlements and compliance
|
|
60
|
+
list_available_entitlements: read("List available entitlements"),
|
|
61
|
+
request_entitlements: write("Request entitlements"),
|
|
62
|
+
submit_entitlement_requirements: write("Submit entitlement requirements"),
|
|
63
|
+
list_rfis: read("List information requests"),
|
|
64
|
+
list_customer_rfis: read("List customer information requests"),
|
|
65
|
+
get_rfi: read("Get information request"),
|
|
66
|
+
get_rfi_evidence_form: read("Get information request form"),
|
|
67
|
+
submit_rfi_evidence: write("Submit information request evidence"),
|
|
68
|
+
get_kyc_capabilities: read("Get KYC capabilities"),
|
|
69
|
+
// Documents
|
|
70
|
+
add_document: write("Add document"),
|
|
71
|
+
list_documents: read("List documents"),
|
|
72
|
+
get_document_download_url: read("Get document download link"),
|
|
73
|
+
delete_document: write("Delete document", { idempotent: true }),
|
|
74
|
+
// Webhooks
|
|
75
|
+
create_webhook: write("Create webhook", { openWorld: true }),
|
|
76
|
+
list_webhooks: read("List webhooks"),
|
|
77
|
+
delete_webhook: write("Delete webhook", { idempotent: true }),
|
|
78
|
+
list_webhook_deliveries: read("List webhook deliveries"),
|
|
79
|
+
// API keys
|
|
80
|
+
list_api_keys: read("List API keys"),
|
|
81
|
+
get_api_key: read("Get API key"),
|
|
82
|
+
create_api_key: admin("Create API key"),
|
|
83
|
+
revoke_api_key: admin("Revoke API key"),
|
|
84
|
+
// Sandbox
|
|
85
|
+
simulate_route_deposit: write("Simulate payment route deposit (sandbox)"),
|
|
86
|
+
simulate_transfer_deposit: write("Simulate transfer deposit (sandbox)"),
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* MCP annotations for a tool. Reads are read-only; every write is marked
|
|
90
|
+
* destructive so clients confirm it with the person, which is the
|
|
91
|
+
* human-in-the-loop step money-moving tools need.
|
|
92
|
+
*/
|
|
93
|
+
export function annotationsFor(policy) {
|
|
94
|
+
const readOnly = policy.access === "read";
|
|
95
|
+
return {
|
|
96
|
+
title: policy.title,
|
|
97
|
+
readOnlyHint: readOnly,
|
|
98
|
+
destructiveHint: !readOnly,
|
|
99
|
+
idempotentHint: readOnly || policy.idempotent === true,
|
|
100
|
+
openWorldHint: policy.openWorld === true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function accessOf(toolName) {
|
|
104
|
+
return TOOL_POLICY[toolName]?.access;
|
|
105
|
+
}
|
|
106
|
+
export const FULL_ACCESS = { read: true, write: true, admin: true };
|
|
107
|
+
export function allows(grant, access) {
|
|
108
|
+
return grant[access];
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=tool-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-policy.js","sourceRoot":"","sources":["../src/tool-policy.ts"],"names":[],"mappings":"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"}
|
package/build/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SERVER_VERSION = "2.
|
|
1
|
+
export declare const SERVER_VERSION = "2.6.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/build/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stables-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
|
+
"mcpName": "money.stables/mcp",
|
|
4
5
|
"description": "MCP server for the Stables fiat-to-crypto API, hosted at mcp.stables.money or run locally - enables AI agents to manage customers, quotes, transfers and payment routes",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "build/index.js",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"check:release": "node scripts/check-release-state.mjs",
|
|
35
36
|
"docs:reference": "node scripts/generate-tool-reference.mjs > docs/tool-reference.md",
|
|
36
37
|
"version:sync": "node scripts/write-version.mjs",
|
|
37
|
-
"version": "npm run version:sync && git add src/version.ts"
|
|
38
|
+
"version": "npm run version:sync && git add src/version.ts server.json"
|
|
38
39
|
},
|
|
39
40
|
"keywords": [
|
|
40
41
|
"mcp",
|