@webbula/mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -0
- package/dist/api/enums.d.ts +80 -0
- package/dist/api/enums.js +230 -0
- package/dist/api/enums.js.map +1 -0
- package/dist/api/types.d.ts +163 -0
- package/dist/api/types.js +8 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/webbula-client.d.ts +116 -0
- package/dist/api/webbula-client.js +249 -0
- package/dist/api/webbula-client.js.map +1 -0
- package/dist/config.d.ts +70 -0
- package/dist/config.js +90 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/server/http.d.ts +4 -0
- package/dist/server/http.js +76 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/stdio.d.ts +12 -0
- package/dist/server/stdio.js +30 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/tools/download-results.d.ts +35 -0
- package/dist/tools/download-results.js +62 -0
- package/dist/tools/download-results.js.map +1 -0
- package/dist/tools/errors.d.ts +10 -0
- package/dist/tools/errors.js +16 -0
- package/dist/tools/errors.js.map +1 -0
- package/dist/tools/file-status.d.ts +35 -0
- package/dist/tools/file-status.js +54 -0
- package/dist/tools/file-status.js.map +1 -0
- package/dist/tools/get-credits.d.ts +31 -0
- package/dist/tools/get-credits.js +47 -0
- package/dist/tools/get-credits.js.map +1 -0
- package/dist/tools/hygiene-check.d.ts +49 -0
- package/dist/tools/hygiene-check.js +84 -0
- package/dist/tools/hygiene-check.js.map +1 -0
- package/dist/tools/persona-append.d.ts +62 -0
- package/dist/tools/persona-append.js +123 -0
- package/dist/tools/persona-append.js.map +1 -0
- package/dist/tools/register.d.ts +15 -0
- package/dist/tools/register.js +23 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/upload-file.d.ts +58 -0
- package/dist/tools/upload-file.js +119 -0
- package/dist/tools/upload-file.js.map +1 -0
- package/dist/tools/validate-lead.d.ts +102 -0
- package/dist/tools/validate-lead.js +192 -0
- package/dist/tools/validate-lead.js.map +1 -0
- package/dist/tools/verify-email.d.ts +41 -0
- package/dist/tools/verify-email.js +74 -0
- package/dist/tools/verify-email.js.map +1 -0
- package/dist/trust.d.ts +28 -0
- package/dist/trust.js +23 -0
- package/dist/trust.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local stdio transport bootstrap — the `webbula-mcp` npm binary (constitution
|
|
3
|
+
* principle IV). Builds an `McpServer`, registers the shared tool set via
|
|
4
|
+
* `registerTools()`, and connects it over stdio. The tool definitions and the
|
|
5
|
+
* Webbula client are transport-agnostic, so the same `registerTools()` also
|
|
6
|
+
* serves the HTTP transport.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
/** Build a fully-registered MCP server instance (shared shape across transports). */
|
|
10
|
+
export declare function buildMcpServer(): McpServer;
|
|
11
|
+
/** Connect the MCP server over stdio and start listening. */
|
|
12
|
+
export declare function startStdioServer(): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local stdio transport bootstrap — the `webbula-mcp` npm binary (constitution
|
|
3
|
+
* principle IV). Builds an `McpServer`, registers the shared tool set via
|
|
4
|
+
* `registerTools()`, and connects it over stdio. The tool definitions and the
|
|
5
|
+
* Webbula client are transport-agnostic, so the same `registerTools()` also
|
|
6
|
+
* serves the HTTP transport.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { createWebbulaClient } from "../api/webbula-client.js";
|
|
11
|
+
import { SERVER_NAME, SERVER_VERSION } from "../config.js";
|
|
12
|
+
import { registerTools } from "../tools/register.js";
|
|
13
|
+
/** Build a fully-registered MCP server instance (shared shape across transports). */
|
|
14
|
+
export function buildMcpServer() {
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: SERVER_NAME,
|
|
17
|
+
version: SERVER_VERSION,
|
|
18
|
+
});
|
|
19
|
+
registerTools(server, createWebbulaClient());
|
|
20
|
+
return server;
|
|
21
|
+
}
|
|
22
|
+
/** Connect the MCP server over stdio and start listening. */
|
|
23
|
+
export async function startStdioServer() {
|
|
24
|
+
const server = buildMcpServer();
|
|
25
|
+
const transport = new StdioServerTransport();
|
|
26
|
+
await server.connect(transport);
|
|
27
|
+
// Logs go to stderr so they never corrupt the stdio JSON-RPC stream on stdout.
|
|
28
|
+
console.error(`${SERVER_NAME} v${SERVER_VERSION} stdio transport ready`);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/server/stdio.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,qFAAqF;AACrF,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IACH,aAAa,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,+EAA+E;IAC/E,OAAO,CAAC,KAAK,CAAC,GAAG,WAAW,KAAK,cAAc,wBAAwB,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `download_results` — download a result file from a completed batch task
|
|
3
|
+
* (spec 003 US3). Maps to `GET /api/v5/task/get_file` and returns the file
|
|
4
|
+
* content unchanged (contracts/download_results.md).
|
|
5
|
+
*
|
|
6
|
+
* The bytes are passed through unmodified — text files (`.csv`/`.txt`) as text,
|
|
7
|
+
* binary files (`.xls`/`.xlsx`) base64-encoded so they survive the text channel.
|
|
8
|
+
* The wrapper never parses rows or decodes verdict flags (principle I, SC-003).
|
|
9
|
+
* A JSON error body from the upstream is mapped to a structured error by the
|
|
10
|
+
* client, never returned as content (FR-007).
|
|
11
|
+
*/
|
|
12
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { type WebbulaClient } from "../api/webbula-client.js";
|
|
15
|
+
export declare const DOWNLOAD_RESULTS_NAME = "download_results";
|
|
16
|
+
export declare const DOWNLOAD_RESULTS_DESCRIPTION: string;
|
|
17
|
+
/**
|
|
18
|
+
* Documented result filenames (OpenAPI `get_file` enum + the v4.2.22 guide's
|
|
19
|
+
* `parse_errors.csv`). Used for a friendly pre-flight error; the canonical set
|
|
20
|
+
* for a given task is what `file_status.files` reports.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ALLOWED_RESULT_FILES: readonly ["insert.csv", "_report.xls", "parse_errors.csv"];
|
|
23
|
+
export declare const downloadResultsInputShape: {
|
|
24
|
+
readonly package_name: z.ZodString;
|
|
25
|
+
readonly filename: z.ZodString;
|
|
26
|
+
};
|
|
27
|
+
export interface ResultFile {
|
|
28
|
+
filename: string;
|
|
29
|
+
encoding: "text" | "base64";
|
|
30
|
+
content: string;
|
|
31
|
+
}
|
|
32
|
+
/** Validate the requested filename against the documented set (FR-006). */
|
|
33
|
+
export declare function assertAllowedFilename(filename: string): void;
|
|
34
|
+
/** Register `download_results` against the MCP server. */
|
|
35
|
+
export declare function registerDownloadResults(server: McpServer, client: WebbulaClient): void;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { WebbulaApiError } from "../api/webbula-client.js";
|
|
3
|
+
import { toToolError } from "./errors.js";
|
|
4
|
+
export const DOWNLOAD_RESULTS_NAME = "download_results";
|
|
5
|
+
export const DOWNLOAD_RESULTS_DESCRIPTION = "Download a result file from a completed batch task. Provide the package_name " +
|
|
6
|
+
"and a filename reported by file_status (e.g. insert.csv for cleaned records, " +
|
|
7
|
+
"_report.xls for the summary). Returns the file content unchanged — text files " +
|
|
8
|
+
"as text, binary files base64-encoded.";
|
|
9
|
+
/**
|
|
10
|
+
* Documented result filenames (OpenAPI `get_file` enum + the v4.2.22 guide's
|
|
11
|
+
* `parse_errors.csv`). Used for a friendly pre-flight error; the canonical set
|
|
12
|
+
* for a given task is what `file_status.files` reports.
|
|
13
|
+
*/
|
|
14
|
+
export const ALLOWED_RESULT_FILES = [
|
|
15
|
+
"insert.csv",
|
|
16
|
+
"_report.xls",
|
|
17
|
+
"parse_errors.csv",
|
|
18
|
+
];
|
|
19
|
+
export const downloadResultsInputShape = {
|
|
20
|
+
package_name: z.string().describe("The task handle from upload_file."),
|
|
21
|
+
filename: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe("A result filename reported by file_status (e.g. insert.csv, _report.xls)."),
|
|
24
|
+
};
|
|
25
|
+
/** Text result extensions are returned as-is; everything else is base64. */
|
|
26
|
+
function encodingFor(filename) {
|
|
27
|
+
const lower = filename.toLowerCase();
|
|
28
|
+
return lower.endsWith(".csv") || lower.endsWith(".txt") ? "text" : "base64";
|
|
29
|
+
}
|
|
30
|
+
/** Validate the requested filename against the documented set (FR-006). */
|
|
31
|
+
export function assertAllowedFilename(filename) {
|
|
32
|
+
if (!ALLOWED_RESULT_FILES.includes(filename)) {
|
|
33
|
+
throw new WebbulaApiError("validation", `Unknown result file — request one listed by file_status (${ALLOWED_RESULT_FILES.join(", ")})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Register `download_results` against the MCP server. */
|
|
37
|
+
export function registerDownloadResults(server, client) {
|
|
38
|
+
server.registerTool(DOWNLOAD_RESULTS_NAME, {
|
|
39
|
+
title: "Download a batch result file",
|
|
40
|
+
description: DOWNLOAD_RESULTS_DESCRIPTION,
|
|
41
|
+
inputSchema: downloadResultsInputShape,
|
|
42
|
+
}, async ({ package_name, filename }) => {
|
|
43
|
+
try {
|
|
44
|
+
assertAllowedFilename(filename);
|
|
45
|
+
const { bytes } = await client.getResultFile({ package_name, filename });
|
|
46
|
+
const encoding = encodingFor(filename);
|
|
47
|
+
const result = {
|
|
48
|
+
filename,
|
|
49
|
+
encoding,
|
|
50
|
+
content: encoding === "text" ? bytes.toString("utf8") : bytes.toString("base64"),
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
54
|
+
structuredContent: result,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return toToolError(error);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=download-results.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download-results.js","sourceRoot":"","sources":["../../src/tools/download-results.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAsB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,4BAA4B,GACvC,+EAA+E;IAC/E,+EAA+E;IAC/E,gFAAgF;IAChF,uCAAuC,CAAC;AAE1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,aAAa;IACb,kBAAkB;CACV,CAAC;AAEX,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IACtE,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,CAAC,2EAA2E,CAAC;CAChF,CAAC;AAQX,4EAA4E;AAC5E,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9E,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,QAAiD,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,eAAe,CACvB,YAAY,EACZ,4DAA4D,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,uBAAuB,CAAC,MAAiB,EAAE,MAAqB;IAC9E,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EAAE,4BAA4B;QACzC,WAAW,EAAE,yBAAyB;KACvC,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YAChC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC;YACzE,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,MAAM,GAAe;gBACzB,QAAQ;gBACR,QAAQ;gBACR,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACjF,CAAC;YACF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAA4C;aAChE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ToolErrorResult {
|
|
2
|
+
isError: true;
|
|
3
|
+
content: Array<{
|
|
4
|
+
type: "text";
|
|
5
|
+
text: string;
|
|
6
|
+
}>;
|
|
7
|
+
/** Matches the SDK's `CallToolResult` open shape. */
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export declare function toToolError(error: unknown): ToolErrorResult;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn any thrown error into a structured MCP tool error (`isError: true`),
|
|
3
|
+
* never a fabricated success and never leaking the API key (constitution
|
|
4
|
+
* principle V). `WebbulaApiError` messages are already safe to surface verbatim;
|
|
5
|
+
* unknown errors are reported generically.
|
|
6
|
+
*/
|
|
7
|
+
import { WebbulaApiError } from "../api/webbula-client.js";
|
|
8
|
+
export function toToolError(error) {
|
|
9
|
+
const message = error instanceof WebbulaApiError
|
|
10
|
+
? error.message
|
|
11
|
+
: error instanceof Error
|
|
12
|
+
? `Unexpected error: ${error.message}`
|
|
13
|
+
: "Unexpected error";
|
|
14
|
+
return { isError: true, content: [{ type: "text", text: message }] };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/tools/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAS3D,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,MAAM,OAAO,GACX,KAAK,YAAY,eAAe;QAC9B,CAAC,CAAC,KAAK,CAAC,OAAO;QACf,CAAC,CAAC,KAAK,YAAY,KAAK;YACtB,CAAC,CAAC,qBAAqB,KAAK,CAAC,OAAO,EAAE;YACtC,CAAC,CAAC,kBAAkB,CAAC;IAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `file_status` — check a batch task's status (spec 003 US2). Maps to
|
|
3
|
+
* `GET /api/v5/task/info` and reshapes `BatchTaskResponse` into a
|
|
4
|
+
* `BatchTaskStatus` (contracts/file_status.md).
|
|
5
|
+
*
|
|
6
|
+
* `status` is the upstream value verbatim; `status_label` + `terminal` are a
|
|
7
|
+
* STATIC `TASK_STATUS` lookup (`api/enums.ts`), omitted for an undocumented
|
|
8
|
+
* status (FR-005, principle I). `files` is surfaced whenever the upstream
|
|
9
|
+
* returns it.
|
|
10
|
+
*/
|
|
11
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import type { BatchTaskResponse } from "../api/types.js";
|
|
14
|
+
import type { WebbulaClient } from "../api/webbula-client.js";
|
|
15
|
+
export declare const FILE_STATUS_NAME = "file_status";
|
|
16
|
+
export declare const FILE_STATUS_DESCRIPTION: string;
|
|
17
|
+
export declare const fileStatusInputShape: {
|
|
18
|
+
readonly package_name: z.ZodString;
|
|
19
|
+
};
|
|
20
|
+
export interface BatchTaskStatus {
|
|
21
|
+
package_name?: string;
|
|
22
|
+
/** Upstream status token, verbatim. */
|
|
23
|
+
status?: string;
|
|
24
|
+
/** Human-readable label for `status`; omitted for an undocumented status. */
|
|
25
|
+
status_label?: string;
|
|
26
|
+
/** Whether the status is terminal; omitted for an undocumented status. */
|
|
27
|
+
terminal?: boolean;
|
|
28
|
+
/** Result files available for download (when the upstream reports them). */
|
|
29
|
+
files?: string[];
|
|
30
|
+
transaction?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Reshape the upstream `BatchTaskResponse`, enriching the status (FR-005). */
|
|
33
|
+
export declare function toBatchTaskStatus(response: BatchTaskResponse): BatchTaskStatus;
|
|
34
|
+
/** Register `file_status` against the MCP server. */
|
|
35
|
+
export declare function registerFileStatus(server: McpServer, client: WebbulaClient): void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TASK_STATUS } from "../api/enums.js";
|
|
3
|
+
import { toToolError } from "./errors.js";
|
|
4
|
+
export const FILE_STATUS_NAME = "file_status";
|
|
5
|
+
export const FILE_STATUS_DESCRIPTION = "Check the status of a batch task by its package_name. Returns the current " +
|
|
6
|
+
"stage (preparing → prepared → running → finished → completed, or canceled) " +
|
|
7
|
+
"with a human-readable label and whether it is terminal, plus — once completed " +
|
|
8
|
+
"— the list of result files ready to download. Poll this after upload_file " +
|
|
9
|
+
"until the task is terminal.";
|
|
10
|
+
export const fileStatusInputShape = {
|
|
11
|
+
package_name: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The task handle returned by upload_file."),
|
|
14
|
+
};
|
|
15
|
+
/** Reshape the upstream `BatchTaskResponse`, enriching the status (FR-005). */
|
|
16
|
+
export function toBatchTaskStatus(response) {
|
|
17
|
+
const out = {};
|
|
18
|
+
if (typeof response.package_name === "string")
|
|
19
|
+
out.package_name = response.package_name;
|
|
20
|
+
if (typeof response.status === "string") {
|
|
21
|
+
out.status = response.status;
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(TASK_STATUS, response.status)) {
|
|
23
|
+
const info = TASK_STATUS[response.status];
|
|
24
|
+
out.status_label = info.label;
|
|
25
|
+
out.terminal = info.terminal;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(response.files))
|
|
29
|
+
out.files = response.files;
|
|
30
|
+
if (typeof response.transaction === "string")
|
|
31
|
+
out.transaction = response.transaction;
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Register `file_status` against the MCP server. */
|
|
35
|
+
export function registerFileStatus(server, client) {
|
|
36
|
+
server.registerTool(FILE_STATUS_NAME, {
|
|
37
|
+
title: "Check a batch task's status",
|
|
38
|
+
description: FILE_STATUS_DESCRIPTION,
|
|
39
|
+
inputSchema: fileStatusInputShape,
|
|
40
|
+
}, async ({ package_name }) => {
|
|
41
|
+
try {
|
|
42
|
+
const response = await client.taskInfo(package_name);
|
|
43
|
+
const result = toBatchTaskStatus(response);
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
46
|
+
structuredContent: result,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return toToolError(error);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=file-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-status.js","sourceRoot":"","sources":["../../src/tools/file-status.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,uBAAuB,GAClC,4EAA4E;IAC5E,6EAA6E;IAC7E,gFAAgF;IAChF,4EAA4E;IAC5E,6BAA6B,CAAC;AAEhC,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,CAAC,0CAA0C,CAAC;CAC/C,CAAC;AAeX,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB,CAAC,QAA2B;IAC3D,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,IAAI,OAAO,QAAQ,CAAC,YAAY,KAAK,QAAQ;QAC3C,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;IAC3C,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxC,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC7B,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACvE,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1C,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC9D,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,QAAQ;QAAE,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;IACrF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAqB;IACzE,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,6BAA6B;QACpC,WAAW,EAAE,uBAAuB;QACpC,WAAW,EAAE,oBAAoB;KAClC,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;QACzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YACrD,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC3C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAA4C;aAChE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `get_credits` — read the account's remaining credit balance (spec US3). Maps
|
|
3
|
+
* to `GET /api/v5/account/info?mode=short` and reshapes `CreditsRemaining[]`
|
|
4
|
+
* into a `CreditBalance` (contracts/get_credits.md).
|
|
5
|
+
*
|
|
6
|
+
* `unlimited` is `true` when the upstream scenario reports `limited === false`
|
|
7
|
+
* (FR-003). `mode=short` keeps the API token out of the response; the wrapper
|
|
8
|
+
* also drops `key` defensively (constitution principle V).
|
|
9
|
+
*/
|
|
10
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import type { AccountInfoResponse } from "../api/types.js";
|
|
12
|
+
import type { WebbulaClient } from "../api/webbula-client.js";
|
|
13
|
+
export declare const GET_CREDITS_NAME = "get_credits";
|
|
14
|
+
export declare const GET_CREDITS_DESCRIPTION: string;
|
|
15
|
+
/** This tool takes no parameters. */
|
|
16
|
+
export declare const getCreditsInputShape: {};
|
|
17
|
+
export interface CreditScenario {
|
|
18
|
+
service?: string;
|
|
19
|
+
scenario?: string;
|
|
20
|
+
records?: number;
|
|
21
|
+
/** `true` when the upstream scenario is not metered (`limited === false`). */
|
|
22
|
+
unlimited: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface CreditBalance {
|
|
25
|
+
login?: string;
|
|
26
|
+
scenarios: CreditScenario[];
|
|
27
|
+
}
|
|
28
|
+
/** Reshape the upstream account info into the agent-facing balance. */
|
|
29
|
+
export declare function toCreditBalance(response: AccountInfoResponse): CreditBalance;
|
|
30
|
+
/** Register `get_credits` against the MCP server. */
|
|
31
|
+
export declare function registerGetCredits(server: McpServer, client: WebbulaClient): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { toToolError } from "./errors.js";
|
|
2
|
+
export const GET_CREDITS_NAME = "get_credits";
|
|
3
|
+
export const GET_CREDITS_DESCRIPTION = "Check the Webbula account's remaining credit balance before running a larger " +
|
|
4
|
+
"job. Returns remaining credits per billing scenario, with an explicit " +
|
|
5
|
+
'"unlimited" flag for accounts that are not metered. Does not consume ' +
|
|
6
|
+
"verification credits.";
|
|
7
|
+
/** This tool takes no parameters. */
|
|
8
|
+
export const getCreditsInputShape = {};
|
|
9
|
+
/** Reshape the upstream account info into the agent-facing balance. */
|
|
10
|
+
export function toCreditBalance(response) {
|
|
11
|
+
const scenarios = (response.credits_remaining ?? []).map((entry) => {
|
|
12
|
+
const scenario = { unlimited: entry.limited === false };
|
|
13
|
+
if (entry.service !== undefined)
|
|
14
|
+
scenario.service = entry.service;
|
|
15
|
+
if (entry.scenario !== undefined)
|
|
16
|
+
scenario.scenario = entry.scenario;
|
|
17
|
+
if (entry.records !== undefined)
|
|
18
|
+
scenario.records = entry.records;
|
|
19
|
+
return scenario;
|
|
20
|
+
});
|
|
21
|
+
const out = { scenarios };
|
|
22
|
+
if (response.login !== undefined)
|
|
23
|
+
out.login = response.login;
|
|
24
|
+
// `key` is intentionally never copied across (principle V).
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
/** Register `get_credits` against the MCP server. */
|
|
28
|
+
export function registerGetCredits(server, client) {
|
|
29
|
+
server.registerTool(GET_CREDITS_NAME, {
|
|
30
|
+
title: "Check remaining credits",
|
|
31
|
+
description: GET_CREDITS_DESCRIPTION,
|
|
32
|
+
inputSchema: getCreditsInputShape,
|
|
33
|
+
}, async () => {
|
|
34
|
+
try {
|
|
35
|
+
const response = await client.accountInfo();
|
|
36
|
+
const result = toCreditBalance(response);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
39
|
+
structuredContent: result,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return toToolError(error);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=get-credits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-credits.js","sourceRoot":"","sources":["../../src/tools/get-credits.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,uBAAuB,GAClC,+EAA+E;IAC/E,wEAAwE;IACxE,uEAAuE;IACvE,uBAAuB,CAAC;AAE1B,qCAAqC;AACrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAW,CAAC;AAehD,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,QAA6B;IAC3D,MAAM,SAAS,GAAqB,CAAC,QAAQ,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,GAAG,CACxE,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,QAAQ,GAAmB,EAAE,SAAS,EAAE,KAAK,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QACxE,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAAE,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAClE,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;YAAE,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QACrE,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAAE,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAClE,OAAO,QAAQ,CAAC;IAClB,CAAC,CACF,CAAC;IACF,MAAM,GAAG,GAAkB,EAAE,SAAS,EAAE,CAAC;IACzC,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;QAAE,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC7D,4DAA4D;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAqB;IACzE,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,uBAAuB;QACpC,WAAW,EAAE,oBAAoB;KAClC,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACzC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAA4C;aAChE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hygiene_check` — full hygiene on a list of addresses (spec US2). Maps to
|
|
3
|
+
* `POST /api/v5/task/express` with `emails[]` and reshapes each `EmailResult`
|
|
4
|
+
* into a `HygieneResult` (contracts/hygiene_check.md), passing through the
|
|
5
|
+
* top-level `profile`, `transaction`, and `credits_remaining`.
|
|
6
|
+
*
|
|
7
|
+
* Like `verify_email`, every classification is upstream-verbatim and the `trust`
|
|
8
|
+
* block is assembled only from present upstream fields (principles I and II).
|
|
9
|
+
*/
|
|
10
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import type { EmailResult, ExpressEmailResponseV5 } from "../api/types.js";
|
|
13
|
+
import type { WebbulaClient } from "../api/webbula-client.js";
|
|
14
|
+
import { type TrustMetadata } from "../trust.js";
|
|
15
|
+
export declare const HYGIENE_CHECK_NAME = "hygiene_check";
|
|
16
|
+
export declare const HYGIENE_CHECK_DESCRIPTION: string;
|
|
17
|
+
/** Zod raw shape for the tool input (validated before any upstream call). */
|
|
18
|
+
export declare const hygieneCheckInputShape: {
|
|
19
|
+
readonly emails: z.ZodArray<z.ZodString, "many">;
|
|
20
|
+
readonly profile: z.ZodOptional<z.ZodString>;
|
|
21
|
+
};
|
|
22
|
+
export interface HygieneResult {
|
|
23
|
+
email: string;
|
|
24
|
+
corrected?: string;
|
|
25
|
+
/** Upstream classification token, verbatim. */
|
|
26
|
+
result: string;
|
|
27
|
+
/** Human-readable label for `result`; omitted for unknown tokens. */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** Documented risk level for `result`; omitted for unknown tokens. */
|
|
30
|
+
risk?: string;
|
|
31
|
+
/** Documented description for `result`; omitted for unknown tokens. */
|
|
32
|
+
description?: string;
|
|
33
|
+
activity_first_seen?: string;
|
|
34
|
+
activity_most_recent_seen?: string;
|
|
35
|
+
activity_trajectory?: string;
|
|
36
|
+
trust?: TrustMetadata;
|
|
37
|
+
}
|
|
38
|
+
export interface HygieneCheckResult {
|
|
39
|
+
profile?: string;
|
|
40
|
+
transaction?: string;
|
|
41
|
+
credits_remaining?: number;
|
|
42
|
+
results: HygieneResult[];
|
|
43
|
+
}
|
|
44
|
+
/** Reshape one upstream `EmailResult` into a `HygieneResult`. */
|
|
45
|
+
export declare function toHygieneResult(result: EmailResult): HygieneResult;
|
|
46
|
+
/** Reshape the full express response into the tool's output. */
|
|
47
|
+
export declare function toHygieneCheckResult(response: ExpressEmailResponseV5): HygieneCheckResult;
|
|
48
|
+
/** Register `hygiene_check` against the MCP server. */
|
|
49
|
+
export declare function registerHygieneCheck(server: McpServer, client: WebbulaClient): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { lookupEmailVerdict } from "../api/enums.js";
|
|
3
|
+
import { WEBBULA_HYGIENE_PROFILE, WEBBULA_MAX_EMAILS } from "../config.js";
|
|
4
|
+
import { assembleTrust } from "../trust.js";
|
|
5
|
+
import { toToolError } from "./errors.js";
|
|
6
|
+
export const HYGIENE_CHECK_NAME = "hygiene_check";
|
|
7
|
+
export const HYGIENE_CHECK_DESCRIPTION = "Run Webbula's full email hygiene analysis on one or more addresses. For each " +
|
|
8
|
+
"email you get its classification, activity history (first/last seen, " +
|
|
9
|
+
"trajectory), a corrected form when a typo is detected, and a trust block. Use " +
|
|
10
|
+
"this when you need the full picture — threats, spam-trap/complainer risk, and " +
|
|
11
|
+
`provenance — not just a yes/no. Accepts 1..${WEBBULA_MAX_EMAILS} addresses per call.`;
|
|
12
|
+
/** Zod raw shape for the tool input (validated before any upstream call). */
|
|
13
|
+
export const hygieneCheckInputShape = {
|
|
14
|
+
emails: z
|
|
15
|
+
.array(z.string().email())
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(WEBBULA_MAX_EMAILS)
|
|
18
|
+
.describe(`The email addresses to check (1..${WEBBULA_MAX_EMAILS}). Larger lists belong in the batch flow.`),
|
|
19
|
+
profile: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Optional Webbula hygiene profile name. Defaults to the server's configured profile."),
|
|
23
|
+
};
|
|
24
|
+
/** Reshape one upstream `EmailResult` into a `HygieneResult`. */
|
|
25
|
+
export function toHygieneResult(result) {
|
|
26
|
+
const out = { email: result.email, result: result.result };
|
|
27
|
+
if (result.corrected !== undefined)
|
|
28
|
+
out.corrected = result.corrected;
|
|
29
|
+
// Static lookup of the documented label/risk/description (api/enums.ts);
|
|
30
|
+
// unknown tokens leave them omitted (principle I — no guessing).
|
|
31
|
+
const verdict = lookupEmailVerdict(result.result);
|
|
32
|
+
if (verdict !== undefined) {
|
|
33
|
+
out.label = verdict.label;
|
|
34
|
+
out.risk = verdict.risk;
|
|
35
|
+
out.description = verdict.description;
|
|
36
|
+
}
|
|
37
|
+
if (result.activity_first_seen !== undefined)
|
|
38
|
+
out.activity_first_seen = result.activity_first_seen;
|
|
39
|
+
if (result.activity_most_recent_seen !== undefined)
|
|
40
|
+
out.activity_most_recent_seen = result.activity_most_recent_seen;
|
|
41
|
+
if (result.activity_trajectory !== undefined)
|
|
42
|
+
out.activity_trajectory = result.activity_trajectory;
|
|
43
|
+
const trust = assembleTrust(result);
|
|
44
|
+
if (trust !== undefined)
|
|
45
|
+
out.trust = trust;
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** Reshape the full express response into the tool's output. */
|
|
49
|
+
export function toHygieneCheckResult(response) {
|
|
50
|
+
const out = {
|
|
51
|
+
results: (response.emails ?? []).map(toHygieneResult),
|
|
52
|
+
};
|
|
53
|
+
if (response.profile !== undefined)
|
|
54
|
+
out.profile = response.profile;
|
|
55
|
+
if (response.transaction !== undefined)
|
|
56
|
+
out.transaction = response.transaction;
|
|
57
|
+
if (response.credits_remaining !== undefined)
|
|
58
|
+
out.credits_remaining = response.credits_remaining;
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** Register `hygiene_check` against the MCP server. */
|
|
62
|
+
export function registerHygieneCheck(server, client) {
|
|
63
|
+
server.registerTool(HYGIENE_CHECK_NAME, {
|
|
64
|
+
title: "Hygiene check a list of emails",
|
|
65
|
+
description: HYGIENE_CHECK_DESCRIPTION,
|
|
66
|
+
inputSchema: hygieneCheckInputShape,
|
|
67
|
+
}, async ({ emails, profile }) => {
|
|
68
|
+
try {
|
|
69
|
+
const response = await client.expressHygieneV5({
|
|
70
|
+
emails,
|
|
71
|
+
profile: profile ?? WEBBULA_HYGIENE_PROFILE,
|
|
72
|
+
});
|
|
73
|
+
const result = toHygieneCheckResult(response);
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
76
|
+
structuredContent: result,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return toToolError(error);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=hygiene-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hygiene-check.js","sourceRoot":"","sources":["../../src/tools/hygiene-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persona data-append tools (feature 006): `append_email`, `append_telephone`,
|
|
3
|
+
* `append_postal`, `append_automotive`. Each maps to `POST {persona}/v1/append`
|
|
4
|
+
* with a fixed `filter` selecting the data point to resolve, and reshapes the
|
|
5
|
+
* persona response into one agent-facing `AppendResult`.
|
|
6
|
+
*
|
|
7
|
+
* The four tools share one PII input shape and differ only by their `filter`.
|
|
8
|
+
* The wrapper forwards exactly the PII the caller supplied and passes the
|
|
9
|
+
* appended `data` through verbatim — it never invents PII or infers a match
|
|
10
|
+
* (constitution principle I). A no-match is reported as `matched: false`, not a
|
|
11
|
+
* fabricated value; transport/auth/upstream failures surface as structured
|
|
12
|
+
* errors (principle V).
|
|
13
|
+
*/
|
|
14
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import type { PersonaAppendResponse } from "../api/types.js";
|
|
17
|
+
import { type PersonaFilter, type PersonaScope, type WebbulaClient } from "../api/webbula-client.js";
|
|
18
|
+
/** The PII attributes that can serve as a match key (at least one required). */
|
|
19
|
+
export declare const APPEND_MATCH_KEYS: readonly ["first_name", "last_name", "email", "address", "city", "state", "zip5", "phone"];
|
|
20
|
+
/** Zod raw shape shared by all four append tools (validated before any call). */
|
|
21
|
+
export declare const appendInputShape: {
|
|
22
|
+
readonly first_name: z.ZodOptional<z.ZodString>;
|
|
23
|
+
readonly last_name: z.ZodOptional<z.ZodString>;
|
|
24
|
+
readonly email: z.ZodOptional<z.ZodString>;
|
|
25
|
+
readonly address: z.ZodOptional<z.ZodString>;
|
|
26
|
+
readonly city: z.ZodOptional<z.ZodString>;
|
|
27
|
+
readonly state: z.ZodOptional<z.ZodString>;
|
|
28
|
+
readonly zip5: z.ZodOptional<z.ZodString>;
|
|
29
|
+
readonly phone: z.ZodOptional<z.ZodString>;
|
|
30
|
+
readonly scope: z.ZodOptional<z.ZodEnum<["individual", "household", "both"]>>;
|
|
31
|
+
};
|
|
32
|
+
/** Parsed, validated append input (one optional field per match key + scope). */
|
|
33
|
+
export type AppendInput = {
|
|
34
|
+
[K in (typeof APPEND_MATCH_KEYS)[number]]?: string;
|
|
35
|
+
} & {
|
|
36
|
+
scope?: PersonaScope;
|
|
37
|
+
};
|
|
38
|
+
/** Agent-facing append result — the appended data passed through verbatim. */
|
|
39
|
+
export interface AppendResult {
|
|
40
|
+
/** Which data point was requested. */
|
|
41
|
+
filter: PersonaFilter;
|
|
42
|
+
/** The identity-resolution scope used for the lookup. */
|
|
43
|
+
scope: PersonaScope;
|
|
44
|
+
/** True when the persona endpoint resolved a match with data. */
|
|
45
|
+
matched: boolean;
|
|
46
|
+
/** The appended field(s), verbatim from the upstream `data` block. */
|
|
47
|
+
data?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
/** Reshape a persona response into the agent-facing result (no fabrication). */
|
|
50
|
+
export declare function toAppendResult(filter: PersonaFilter, scope: PersonaScope, response: PersonaAppendResponse): AppendResult;
|
|
51
|
+
/** Definition of one append tool — its name, filter, and human-facing text. */
|
|
52
|
+
interface AppendToolSpec {
|
|
53
|
+
name: string;
|
|
54
|
+
title: string;
|
|
55
|
+
filter: PersonaFilter;
|
|
56
|
+
description: string;
|
|
57
|
+
}
|
|
58
|
+
/** The four append tools (CSV rows 22–25). */
|
|
59
|
+
export declare const APPEND_TOOLS: readonly AppendToolSpec[];
|
|
60
|
+
/** Register all four persona append tools against the MCP server. */
|
|
61
|
+
export declare function registerPersonaAppend(server: McpServer, client: WebbulaClient): void;
|
|
62
|
+
export {};
|