@vallum/mcp-server 0.0.1-mcp.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 +66 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +86 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.js +66 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +16 -0
- package/dist/stdio.d.ts +22 -0
- package/dist/stdio.js +69 -0
- package/dist/tools.d.ts +39 -0
- package/dist/tools.js +100 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @vallum/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP tool facade for Vallum sponsored IOTA actions.
|
|
4
|
+
|
|
5
|
+
This package exposes tool descriptors and a local callable server facade that
|
|
6
|
+
routes sponsored actions through the Vallum SDK and policy gateway. It
|
|
7
|
+
does not directly call IOTA, Gas Station, or transaction submission APIs.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
For the npm prerelease, install:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @vallum/mcp-server@next
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Current Status
|
|
18
|
+
|
|
19
|
+
This source package builds both:
|
|
20
|
+
|
|
21
|
+
- a programmatic MCP-shaped facade; and
|
|
22
|
+
- a stdio CLI bin, `vallum-mcp`, for local MCP hosts.
|
|
23
|
+
|
|
24
|
+
The CLI reads gateway configuration from the MCP server process environment
|
|
25
|
+
and routes tool calls through the Vallum SDK and policy gateway. It does not
|
|
26
|
+
directly call IOTA, Gas Station, or transaction submission APIs.
|
|
27
|
+
|
|
28
|
+
The already-published `0.0.0-prerelease` package predates this runnable bin.
|
|
29
|
+
The runnable MCP package is published as
|
|
30
|
+
`@vallum/mcp-server@0.0.1-mcp.0` on the npm `next` dist-tag.
|
|
31
|
+
Registry install plus local stdio execution is covered by
|
|
32
|
+
`npm run smoke:npm-registry-mcp-stdio-consumer`.
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
Run the stdio server from a package install or local tarball consumer:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
VALLUM_GATEWAY_URL=http://127.0.0.1:8787 \
|
|
40
|
+
VALLUM_API_KEY=replace-with-server-side-secret \
|
|
41
|
+
npm exec -- vallum-mcp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use placeholders in MCP host configuration files. Do not commit real
|
|
45
|
+
`VALLUM_API_KEY` values.
|
|
46
|
+
|
|
47
|
+
The programmatic facade remains available:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createIotaMcpServer } from "@vallum/mcp-server";
|
|
51
|
+
|
|
52
|
+
const server = createIotaMcpServer({
|
|
53
|
+
gatewayBaseUrl: process.env.VALLUM_GATEWAY_URL!,
|
|
54
|
+
apiKey: process.env.VALLUM_API_KEY!,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const tools = server.listTools();
|
|
58
|
+
const result = await server.callTool("iota.request_sponsored_transaction", {
|
|
59
|
+
manifest,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Keep `VALLUM_API_KEY`, Gas Station bearer tokens, sponsor keys, raw
|
|
64
|
+
transaction bytes, and user signatures server-side. See
|
|
65
|
+
https://github.com/0xCozart/agentic-gaskit/blob/main/docs/vallum/package-integration-guide.md
|
|
66
|
+
for the full package map and configuration boundary.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface VallumMcpCliIo {
|
|
3
|
+
readonly stdout: Pick<NodeJS.WriteStream, "write">;
|
|
4
|
+
readonly stderr: Pick<NodeJS.WriteStream, "write">;
|
|
5
|
+
}
|
|
6
|
+
export declare function runVallumMcpCli(args: readonly string[], env: Record<string, string | undefined>, io: VallumMcpCliIo): Promise<number>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
5
|
+
import { VallumMcpConfigError, parseVallumMcpConfig, redactVallumMcpConfig, } from "./config.js";
|
|
6
|
+
import { startVallumMcpStdioServer } from "./stdio.js";
|
|
7
|
+
export async function runVallumMcpCli(args, env, io) {
|
|
8
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
9
|
+
io.stdout.write(usage());
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
if (args.includes("--version")) {
|
|
13
|
+
io.stdout.write(`${packageJson.version}\n`);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
if (args.some((arg) => arg.startsWith("--") && arg !== "--check-config")) {
|
|
17
|
+
io.stderr.write("Unknown option. Run vallum-mcp --help for usage.\n");
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const config = parseVallumMcpConfig(env, { packageVersion: packageJson.version });
|
|
22
|
+
if (args.includes("--check-config")) {
|
|
23
|
+
io.stdout.write(`${JSON.stringify(redactVallumMcpConfig(config), null, 2)}\n`);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
const session = await startVallumMcpStdioServer(config);
|
|
27
|
+
installShutdownHandlers(session.close);
|
|
28
|
+
await session.closed;
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
io.stderr.write(`${formatCliError(error)}\n`);
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function installShutdownHandlers(close) {
|
|
37
|
+
const shutdown = () => {
|
|
38
|
+
void close();
|
|
39
|
+
};
|
|
40
|
+
process.once("SIGINT", shutdown);
|
|
41
|
+
process.once("SIGTERM", shutdown);
|
|
42
|
+
}
|
|
43
|
+
function usage() {
|
|
44
|
+
return `Usage: vallum-mcp [--help] [--version] [--check-config]
|
|
45
|
+
|
|
46
|
+
Runs the Vallum MCP server. Configuration is read from the MCP server process environment.
|
|
47
|
+
|
|
48
|
+
Required environment:
|
|
49
|
+
VALLUM_GATEWAY_URL Vallum-compatible policy gateway base URL.
|
|
50
|
+
VALLUM_API_KEY Gateway app credential.
|
|
51
|
+
|
|
52
|
+
Optional environment:
|
|
53
|
+
VALLUM_MCP_SERVER_NAME MCP server name, defaults to vallum.
|
|
54
|
+
VALLUM_MCP_SERVER_VERSION MCP server version, defaults to package version.
|
|
55
|
+
VALLUM_MCP_LOG_LEVEL silent, error, warn, info, or debug. Defaults to error.
|
|
56
|
+
|
|
57
|
+
Flags:
|
|
58
|
+
--help Print this help text without reading configuration.
|
|
59
|
+
--version Print the package version without reading configuration.
|
|
60
|
+
--check-config Validate configuration and print redacted status.
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
function formatCliError(error) {
|
|
64
|
+
if (error instanceof VallumMcpConfigError) {
|
|
65
|
+
return `Configuration error: ${error.message}`;
|
|
66
|
+
}
|
|
67
|
+
return "Vallum MCP failed before startup.";
|
|
68
|
+
}
|
|
69
|
+
if (isDirectCliExecution()) {
|
|
70
|
+
const exitCode = await runVallumMcpCli(process.argv.slice(2), process.env, {
|
|
71
|
+
stdout: process.stdout,
|
|
72
|
+
stderr: process.stderr,
|
|
73
|
+
});
|
|
74
|
+
process.exitCode = exitCode;
|
|
75
|
+
}
|
|
76
|
+
function isDirectCliExecution() {
|
|
77
|
+
const entrypoint = process.argv[1];
|
|
78
|
+
if (!entrypoint)
|
|
79
|
+
return false;
|
|
80
|
+
try {
|
|
81
|
+
return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(entrypoint);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const VALLUM_GATEWAY_URL_ENV = "VALLUM_GATEWAY_URL";
|
|
2
|
+
export declare const VALLUM_API_KEY_ENV = "VALLUM_API_KEY";
|
|
3
|
+
export declare const VALLUM_MCP_SERVER_NAME_ENV = "VALLUM_MCP_SERVER_NAME";
|
|
4
|
+
export declare const VALLUM_MCP_SERVER_VERSION_ENV = "VALLUM_MCP_SERVER_VERSION";
|
|
5
|
+
export declare const VALLUM_MCP_LOG_LEVEL_ENV = "VALLUM_MCP_LOG_LEVEL";
|
|
6
|
+
export type VallumMcpLogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
7
|
+
export interface VallumMcpConfig {
|
|
8
|
+
readonly gatewayBaseUrl: string;
|
|
9
|
+
readonly apiKey: string;
|
|
10
|
+
readonly serverName: string;
|
|
11
|
+
readonly serverVersion: string;
|
|
12
|
+
readonly logLevel: VallumMcpLogLevel;
|
|
13
|
+
}
|
|
14
|
+
export interface VallumMcpConfigOptions {
|
|
15
|
+
readonly packageVersion?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RedactedVallumMcpConfig {
|
|
18
|
+
readonly gatewayUrl: "configured";
|
|
19
|
+
readonly apiKey: "configured";
|
|
20
|
+
readonly serverName: string;
|
|
21
|
+
readonly serverVersion: string;
|
|
22
|
+
readonly logLevel: VallumMcpLogLevel;
|
|
23
|
+
}
|
|
24
|
+
export declare class VallumMcpConfigError extends Error {
|
|
25
|
+
readonly code = "VALLUM_MCP_CONFIG_ERROR";
|
|
26
|
+
constructor(message: string);
|
|
27
|
+
}
|
|
28
|
+
export declare function parseVallumMcpConfig(env: Record<string, string | undefined>, options?: VallumMcpConfigOptions): VallumMcpConfig;
|
|
29
|
+
export declare function redactVallumMcpConfig(config: VallumMcpConfig): RedactedVallumMcpConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const VALLUM_GATEWAY_URL_ENV = "VALLUM_GATEWAY_URL";
|
|
2
|
+
export const VALLUM_API_KEY_ENV = "VALLUM_API_KEY";
|
|
3
|
+
export const VALLUM_MCP_SERVER_NAME_ENV = "VALLUM_MCP_SERVER_NAME";
|
|
4
|
+
export const VALLUM_MCP_SERVER_VERSION_ENV = "VALLUM_MCP_SERVER_VERSION";
|
|
5
|
+
export const VALLUM_MCP_LOG_LEVEL_ENV = "VALLUM_MCP_LOG_LEVEL";
|
|
6
|
+
export class VallumMcpConfigError extends Error {
|
|
7
|
+
code = "VALLUM_MCP_CONFIG_ERROR";
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "VallumMcpConfigError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function parseVallumMcpConfig(env, options = {}) {
|
|
14
|
+
const gatewayBaseUrl = requiredEnv(env, VALLUM_GATEWAY_URL_ENV);
|
|
15
|
+
const apiKey = requiredEnv(env, VALLUM_API_KEY_ENV);
|
|
16
|
+
return {
|
|
17
|
+
gatewayBaseUrl: normalizeGatewayBaseUrl(gatewayBaseUrl),
|
|
18
|
+
apiKey,
|
|
19
|
+
serverName: optionalEnv(env, VALLUM_MCP_SERVER_NAME_ENV) ?? "vallum",
|
|
20
|
+
serverVersion: optionalEnv(env, VALLUM_MCP_SERVER_VERSION_ENV) ?? options.packageVersion ?? "0.0.0",
|
|
21
|
+
logLevel: parseLogLevel(optionalEnv(env, VALLUM_MCP_LOG_LEVEL_ENV)),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function redactVallumMcpConfig(config) {
|
|
25
|
+
return {
|
|
26
|
+
gatewayUrl: "configured",
|
|
27
|
+
apiKey: "configured",
|
|
28
|
+
serverName: config.serverName,
|
|
29
|
+
serverVersion: config.serverVersion,
|
|
30
|
+
logLevel: config.logLevel,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function requiredEnv(env, name) {
|
|
34
|
+
const value = optionalEnv(env, name);
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
throw new VallumMcpConfigError(`${name} is required.`);
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function optionalEnv(env, name) {
|
|
41
|
+
const value = env[name]?.trim();
|
|
42
|
+
return value ? value : undefined;
|
|
43
|
+
}
|
|
44
|
+
function normalizeGatewayBaseUrl(value) {
|
|
45
|
+
let url;
|
|
46
|
+
try {
|
|
47
|
+
url = new URL(value);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new VallumMcpConfigError(`${VALLUM_GATEWAY_URL_ENV} must be an absolute http(s) URL.`);
|
|
51
|
+
}
|
|
52
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
53
|
+
throw new VallumMcpConfigError(`${VALLUM_GATEWAY_URL_ENV} must be an absolute http(s) URL.`);
|
|
54
|
+
}
|
|
55
|
+
url.hash = "";
|
|
56
|
+
url.search = "";
|
|
57
|
+
return url.toString().replace(/\/$/, "");
|
|
58
|
+
}
|
|
59
|
+
function parseLogLevel(value) {
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return "error";
|
|
62
|
+
if (value === "silent" || value === "error" || value === "warn" || value === "info" || value === "debug") {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
throw new VallumMcpConfigError(`${VALLUM_MCP_LOG_LEVEL_ENV} must be one of silent, error, warn, info, or debug.`);
|
|
66
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IOTA_MCP_TOOLS, type IotaMcpToolCallResult } from "./tools.js";
|
|
2
|
+
export interface IotaMcpServerOptions {
|
|
3
|
+
readonly gatewayBaseUrl: string;
|
|
4
|
+
readonly apiKey: string;
|
|
5
|
+
readonly fetchImpl?: typeof fetch;
|
|
6
|
+
readonly now?: () => Date;
|
|
7
|
+
}
|
|
8
|
+
export interface IotaMcpServerFacade {
|
|
9
|
+
readonly listTools: () => typeof IOTA_MCP_TOOLS;
|
|
10
|
+
readonly callTool: (name: string, input: unknown) => Promise<IotaMcpToolCallResult>;
|
|
11
|
+
}
|
|
12
|
+
export declare function createIotaMcpServer(options: IotaMcpServerOptions): IotaMcpServerFacade;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IotaAgent } from "@vallum/sdk";
|
|
2
|
+
import { callIotaMcpTool, IOTA_MCP_TOOLS } from "./tools.js";
|
|
3
|
+
export function createIotaMcpServer(options) {
|
|
4
|
+
const agent = new IotaAgent({
|
|
5
|
+
gatewayBaseUrl: options.gatewayBaseUrl,
|
|
6
|
+
apiKey: options.apiKey,
|
|
7
|
+
fetchImpl: options.fetchImpl,
|
|
8
|
+
});
|
|
9
|
+
return {
|
|
10
|
+
listTools: () => IOTA_MCP_TOOLS,
|
|
11
|
+
callTool: (name, input) => callIotaMcpTool(name, input, {
|
|
12
|
+
agent,
|
|
13
|
+
now: options.now,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { type CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { type VallumMcpConfig } from "./config.js";
|
|
6
|
+
import { type IotaMcpServerOptions } from "./server.js";
|
|
7
|
+
import { type IotaMcpToolCallResult } from "./tools.js";
|
|
8
|
+
export interface VallumMcpProtocolServerOptions {
|
|
9
|
+
readonly fetchImpl?: IotaMcpServerOptions["fetchImpl"];
|
|
10
|
+
readonly now?: IotaMcpServerOptions["now"];
|
|
11
|
+
readonly stdin?: Readable;
|
|
12
|
+
readonly stdout?: Writable;
|
|
13
|
+
}
|
|
14
|
+
export interface VallumMcpStdioSession {
|
|
15
|
+
readonly server: Server;
|
|
16
|
+
readonly transport: StdioServerTransport;
|
|
17
|
+
readonly closed: Promise<void>;
|
|
18
|
+
readonly close: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createVallumMcpProtocolServer(config: VallumMcpConfig, options?: VallumMcpProtocolServerOptions): Server;
|
|
21
|
+
export declare function startVallumMcpStdioServer(config: VallumMcpConfig, options?: VallumMcpProtocolServerOptions): Promise<VallumMcpStdioSession>;
|
|
22
|
+
export declare function toMcpToolResult(result: IotaMcpToolCallResult): CallToolResult;
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { createIotaMcpServer } from "./server.js";
|
|
5
|
+
export function createVallumMcpProtocolServer(config, options = {}) {
|
|
6
|
+
const facade = createIotaMcpServer({
|
|
7
|
+
gatewayBaseUrl: config.gatewayBaseUrl,
|
|
8
|
+
apiKey: config.apiKey,
|
|
9
|
+
fetchImpl: options.fetchImpl,
|
|
10
|
+
now: options.now,
|
|
11
|
+
});
|
|
12
|
+
const server = new Server({
|
|
13
|
+
name: config.serverName,
|
|
14
|
+
version: config.serverVersion,
|
|
15
|
+
}, {
|
|
16
|
+
capabilities: {
|
|
17
|
+
tools: {},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
21
|
+
tools: facade.listTools().map(toMcpTool),
|
|
22
|
+
}));
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
24
|
+
const result = await facade.callTool(request.params.name, request.params.arguments ?? {});
|
|
25
|
+
return toMcpToolResult(result);
|
|
26
|
+
});
|
|
27
|
+
return server;
|
|
28
|
+
}
|
|
29
|
+
export async function startVallumMcpStdioServer(config, options = {}) {
|
|
30
|
+
const server = createVallumMcpProtocolServer(config, options);
|
|
31
|
+
const transport = new StdioServerTransport(options.stdin, options.stdout);
|
|
32
|
+
let closeStarted = false;
|
|
33
|
+
let resolveClosed;
|
|
34
|
+
const closed = new Promise((resolve) => {
|
|
35
|
+
resolveClosed = resolve;
|
|
36
|
+
});
|
|
37
|
+
server.onclose = resolveClosed;
|
|
38
|
+
await server.connect(transport);
|
|
39
|
+
return {
|
|
40
|
+
server,
|
|
41
|
+
transport,
|
|
42
|
+
closed,
|
|
43
|
+
close: async () => {
|
|
44
|
+
if (closeStarted)
|
|
45
|
+
return;
|
|
46
|
+
closeStarted = true;
|
|
47
|
+
await server.close();
|
|
48
|
+
resolveClosed();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function toMcpToolResult(result) {
|
|
53
|
+
return {
|
|
54
|
+
content: [...result.content],
|
|
55
|
+
structuredContent: result.structuredContent,
|
|
56
|
+
isError: result.isError,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function toMcpTool(descriptor) {
|
|
60
|
+
return {
|
|
61
|
+
name: descriptor.name,
|
|
62
|
+
title: descriptor.title,
|
|
63
|
+
description: descriptor.description,
|
|
64
|
+
inputSchema: cloneJsonObject(descriptor.inputSchema),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function cloneJsonObject(value) {
|
|
68
|
+
return JSON.parse(JSON.stringify(value));
|
|
69
|
+
}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IotaAgent } from "@vallum/sdk";
|
|
2
|
+
export declare const REQUEST_SPONSORED_TRANSACTION_TOOL = "iota.request_sponsored_transaction";
|
|
3
|
+
export declare const OPEN_ESCROW_TOOL = "iota.open_escrow";
|
|
4
|
+
export type IotaMcpToolName = typeof REQUEST_SPONSORED_TRANSACTION_TOOL | typeof OPEN_ESCROW_TOOL;
|
|
5
|
+
export interface IotaMcpToolDescriptor {
|
|
6
|
+
readonly name: IotaMcpToolName;
|
|
7
|
+
readonly title: string;
|
|
8
|
+
readonly description: string;
|
|
9
|
+
readonly inputSchema: JsonSchemaObject;
|
|
10
|
+
}
|
|
11
|
+
export interface JsonSchemaObject {
|
|
12
|
+
readonly type: "object";
|
|
13
|
+
readonly additionalProperties?: boolean;
|
|
14
|
+
readonly required?: readonly string[];
|
|
15
|
+
readonly properties: Record<string, JsonSchemaProperty>;
|
|
16
|
+
}
|
|
17
|
+
export type JsonSchemaProperty = {
|
|
18
|
+
readonly type: "object";
|
|
19
|
+
readonly description?: string;
|
|
20
|
+
readonly additionalProperties?: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
readonly type: "string";
|
|
23
|
+
readonly description?: string;
|
|
24
|
+
};
|
|
25
|
+
export interface IotaMcpToolCallResult {
|
|
26
|
+
readonly content: readonly [{
|
|
27
|
+
readonly type: "text";
|
|
28
|
+
readonly text: string;
|
|
29
|
+
}];
|
|
30
|
+
readonly structuredContent: Record<string, unknown>;
|
|
31
|
+
readonly isError: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface IotaMcpToolHandlerOptions {
|
|
34
|
+
readonly agent: Pick<IotaAgent, "requestSponsoredAction">;
|
|
35
|
+
readonly now?: () => Date;
|
|
36
|
+
}
|
|
37
|
+
export declare const IOTA_MCP_TOOLS: readonly IotaMcpToolDescriptor[];
|
|
38
|
+
export declare function callIotaMcpTool(name: string, input: unknown, options: IotaMcpToolHandlerOptions): Promise<IotaMcpToolCallResult>;
|
|
39
|
+
export declare function isIotaMcpToolName(name: string): name is IotaMcpToolName;
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { validateAgentTransactionManifest } from "@vallum/manifest";
|
|
2
|
+
export const REQUEST_SPONSORED_TRANSACTION_TOOL = "iota.request_sponsored_transaction";
|
|
3
|
+
export const OPEN_ESCROW_TOOL = "iota.open_escrow";
|
|
4
|
+
export const IOTA_MCP_TOOLS = [
|
|
5
|
+
{
|
|
6
|
+
name: REQUEST_SPONSORED_TRANSACTION_TOOL,
|
|
7
|
+
title: "Request sponsored IOTA transaction",
|
|
8
|
+
description: "Submit an Agent Transaction Manifest through the Vallum SDK and policy gateway.",
|
|
9
|
+
inputSchema: manifestToolInputSchema(),
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
name: OPEN_ESCROW_TOOL,
|
|
13
|
+
title: "Open sponsored escrow",
|
|
14
|
+
description: "Submit an escrow Agent Transaction Manifest through the Vallum SDK and policy gateway.",
|
|
15
|
+
inputSchema: manifestToolInputSchema(),
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
export async function callIotaMcpTool(name, input, options) {
|
|
19
|
+
if (!isIotaMcpToolName(name)) {
|
|
20
|
+
return errorResult("UNKNOWN_TOOL", `Unknown IOTA MCP tool: ${name}`);
|
|
21
|
+
}
|
|
22
|
+
const manifestResult = manifestInput(input, options.now);
|
|
23
|
+
if (!manifestResult.ok) {
|
|
24
|
+
return errorResult("INVALID_TOOL_INPUT", manifestResult.message);
|
|
25
|
+
}
|
|
26
|
+
const result = await options.agent.requestSponsoredAction({
|
|
27
|
+
manifest: manifestResult.manifest,
|
|
28
|
+
});
|
|
29
|
+
return successResult(result);
|
|
30
|
+
}
|
|
31
|
+
export function isIotaMcpToolName(name) {
|
|
32
|
+
return name === REQUEST_SPONSORED_TRANSACTION_TOOL || name === OPEN_ESCROW_TOOL;
|
|
33
|
+
}
|
|
34
|
+
function manifestToolInputSchema() {
|
|
35
|
+
return {
|
|
36
|
+
type: "object",
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
required: ["manifest"],
|
|
39
|
+
properties: {
|
|
40
|
+
manifest: {
|
|
41
|
+
type: "object",
|
|
42
|
+
description: "Agent Transaction Manifest to submit through the policy gateway.",
|
|
43
|
+
additionalProperties: true,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function manifestInput(input, now) {
|
|
49
|
+
const record = asRecord(input);
|
|
50
|
+
if (!record)
|
|
51
|
+
return { ok: false, message: "Tool input must be a JSON object." };
|
|
52
|
+
const manifest = asRecord(record.manifest);
|
|
53
|
+
if (!manifest)
|
|
54
|
+
return { ok: false, message: "Tool input must include a manifest object." };
|
|
55
|
+
const validation = validateAgentTransactionManifest(manifest, { now: now?.() });
|
|
56
|
+
if (!validation.ok)
|
|
57
|
+
return { ok: false, message: "Tool manifest failed validation." };
|
|
58
|
+
return { ok: true, manifest: validation.manifest };
|
|
59
|
+
}
|
|
60
|
+
function successResult(result) {
|
|
61
|
+
if (!result.approved) {
|
|
62
|
+
return {
|
|
63
|
+
isError: true,
|
|
64
|
+
content: [{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: result.decision.message,
|
|
67
|
+
}],
|
|
68
|
+
structuredContent: {
|
|
69
|
+
error: {
|
|
70
|
+
code: result.decision.reasonCode,
|
|
71
|
+
message: result.decision.message,
|
|
72
|
+
},
|
|
73
|
+
decision: result.decision,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
isError: false,
|
|
79
|
+
content: [{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: JSON.stringify(result),
|
|
82
|
+
}],
|
|
83
|
+
structuredContent: result,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function errorResult(code, message) {
|
|
87
|
+
return {
|
|
88
|
+
isError: true,
|
|
89
|
+
content: [{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: message,
|
|
92
|
+
}],
|
|
93
|
+
structuredContent: {
|
|
94
|
+
error: { code, message },
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function asRecord(value) {
|
|
99
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
100
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vallum/mcp-server",
|
|
3
|
+
"version": "0.0.1-mcp.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"vallum-mcp": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./config": {
|
|
16
|
+
"types": "./dist/config.d.ts",
|
|
17
|
+
"import": "./dist/config.js"
|
|
18
|
+
},
|
|
19
|
+
"./stdio": {
|
|
20
|
+
"types": "./dist/stdio.d.ts",
|
|
21
|
+
"import": "./dist/stdio.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
27
|
+
"@vallum/manifest": "0.0.0-prerelease",
|
|
28
|
+
"@vallum/sdk": "0.0.0-prerelease"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@vallum/policy-gateway": "0.0.0-prerelease"
|
|
32
|
+
},
|
|
33
|
+
"description": "MCP tool facade for Vallum sponsored IOTA actions.",
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/**/*.js",
|
|
36
|
+
"dist/**/*.d.ts",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -p tsconfig.build.json"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=20"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"tag": "next"
|
|
50
|
+
}
|
|
51
|
+
}
|