@happykiller/sunny-mcp 0.2.5 → 0.2.6
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/safety/target.js
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
// refuse d'écrire sans `--write`. Il ne protège pas contre un attaquant — il
|
|
4
4
|
// protège contre soi-même, un soir où l'on croit viser le local.
|
|
5
5
|
const HOTES_LOCAUX = new Set([
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
"localhost",
|
|
7
|
+
"127.0.0.1",
|
|
8
|
+
"::1",
|
|
9
|
+
"[::1]",
|
|
10
|
+
"0.0.0.0",
|
|
11
11
|
]);
|
|
12
12
|
/** Le mot de passe est volontairement long et non devinable : on ne le pose pas
|
|
13
13
|
* par distraction, contrairement à `true` ou `1`. */
|
|
14
|
-
export const AVEU_PROD =
|
|
14
|
+
export const AVEU_PROD = "yes-i-know";
|
|
15
15
|
export class TargetRefusedError extends Error {
|
|
16
|
-
code =
|
|
16
|
+
code = "TARGET_REFUSED";
|
|
17
17
|
}
|
|
18
18
|
export function resolveTarget(rawUrl, aveu) {
|
|
19
19
|
let url;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { McpServer } from
|
|
2
|
-
import type { Appelant, ToolCatalog, ToolContext } from
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { Appelant, ToolCatalog, ToolContext } from "../tools/defineTool.js";
|
|
3
|
+
import type { Target } from "../safety/target.js";
|
|
3
4
|
/**
|
|
4
5
|
* Contexte des outils : une valeur fixe, ou une fabrique appelée à CHAQUE
|
|
5
6
|
* requête.
|
|
@@ -14,6 +15,16 @@ export interface CreateServerOptions {
|
|
|
14
15
|
version: string;
|
|
15
16
|
catalog: ToolCatalog;
|
|
16
17
|
ctx: ToolContext | FabriqueContexte;
|
|
18
|
+
/**
|
|
19
|
+
* Cible visée, quand `ctx` est une FABRIQUE.
|
|
20
|
+
*
|
|
21
|
+
* Les descriptions sont figées à l'enregistrement, alors qu'une fabrique ne
|
|
22
|
+
* rend son contexte qu'à l'arrivée d'une requête : la cible était donc
|
|
23
|
+
* inconnue au moment de décider du préfixe, et les outils destructifs
|
|
24
|
+
* perdaient silencieusement leur avertissement `[PRODUCTION]` — sur le seul
|
|
25
|
+
* transport où plusieurs personnes agissent à distance. Constaté en recette.
|
|
26
|
+
*/
|
|
27
|
+
target?: Target;
|
|
17
28
|
}
|
|
18
29
|
export declare function createMcpServer(opts: CreateServerOptions): McpServer;
|
|
19
30
|
//# sourceMappingURL=createMcpServer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMcpServer.d.ts","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"createMcpServer.d.ts","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,QAAQ,GAAG,SAAS,KAC3B,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAExC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,GAAG,EAAE,WAAW,GAAG,gBAAgB,CAAC;IACpC;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS,CAsFpE"}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
// src/server/createMcpServer.ts
|
|
2
|
-
import { McpServer } from
|
|
3
|
-
import { ok, fail } from
|
|
4
|
-
import { GraphQLCallError } from
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { ok, fail } from "./contract.js";
|
|
4
|
+
import { GraphQLCallError } from "../graphql/errors.js";
|
|
5
5
|
/** Préfixe apposé en clair sur les outils écrivant en production : la seule
|
|
6
6
|
* chose que l'agent lit avant d'agir, c'est la description. */
|
|
7
|
-
const PREFIXE_PROD =
|
|
7
|
+
const PREFIXE_PROD = "[PRODUCTION] ";
|
|
8
8
|
export function createMcpServer(opts) {
|
|
9
9
|
const { catalog } = opts;
|
|
10
10
|
const server = new McpServer({ name: opts.name, version: opts.version });
|
|
11
|
-
const resoudreContexte = async (appelant) => typeof opts.ctx ===
|
|
12
|
-
// La cible
|
|
13
|
-
//
|
|
14
|
-
|
|
11
|
+
const resoudreContexte = async (appelant) => typeof opts.ctx === "function" ? opts.ctx(appelant) : opts.ctx;
|
|
12
|
+
// La cible ne dépend pas de l'appelant : on la lit une fois, pour décider des
|
|
13
|
+
// descriptions à l'enregistrement. Avec une fabrique, elle doit être fournie
|
|
14
|
+
// à part — sans quoi le préfixe ne serait jamais posé.
|
|
15
|
+
const cible = typeof opts.ctx === "function" ? opts.target : opts.target ?? opts.ctx.target;
|
|
15
16
|
const noms = new Set();
|
|
16
17
|
for (const tool of catalog) {
|
|
17
18
|
if (noms.has(tool.name)) {
|
|
18
19
|
throw new Error(`Outil déclaré deux fois : ${tool.name}`);
|
|
19
20
|
}
|
|
20
21
|
noms.add(tool.name);
|
|
21
|
-
const description =
|
|
22
|
+
const description = cible?.isProd === true && tool.requiresWrite
|
|
22
23
|
? PREFIXE_PROD + tool.description
|
|
23
24
|
: tool.description;
|
|
24
25
|
server.registerTool(tool.name, {
|
|
@@ -40,10 +41,10 @@ export function createMcpServer(opts) {
|
|
|
40
41
|
const contexte = await resoudreContexte(appelant);
|
|
41
42
|
if (tool.requiresWrite && !contexte.allowWrites) {
|
|
42
43
|
// Refus AVANT toute requête : rien ne part sur le réseau.
|
|
43
|
-
return fail(
|
|
44
|
+
return fail("WRITES_DISABLED", {
|
|
44
45
|
tool: tool.name,
|
|
45
46
|
target: contexte.target.url,
|
|
46
|
-
hint:
|
|
47
|
+
hint: "Poser SUNNY_MCP_ALLOW_WRITES=true pour autoriser les écritures.",
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
try {
|
|
@@ -65,7 +66,7 @@ export function createMcpServer(opts) {
|
|
|
65
66
|
if (e instanceof GraphQLCallError) {
|
|
66
67
|
return fail(e.code, { ...e.details, tool: tool.name });
|
|
67
68
|
}
|
|
68
|
-
return fail(e?.code ??
|
|
69
|
+
return fail(e?.code ?? "TOOL_FAILED", {
|
|
69
70
|
message: e?.message ?? String(e),
|
|
70
71
|
tool: tool.name,
|
|
71
72
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMcpServer.js","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"createMcpServer.js","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happykiller/sunny-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Socle MCP partagé : transport, session GraphQL, registre d'outils et garde-fous, pour exposer le back-office d'un produit aux agents.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": {
|