@yirifi-org/mcp-server 1.2.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/LICENSE +21 -0
- package/README.md +809 -0
- package/dist/client.d.ts +73 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +116 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +99 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/server-core.d.ts +73 -0
- package/dist/server-core.d.ts.map +1 -0
- package/dist/server-core.js +189 -0
- package/dist/server-core.js.map +1 -0
- package/dist/server-http.d.ts +17 -0
- package/dist/server-http.d.ts.map +1 -0
- package/dist/server-http.js +87 -0
- package/dist/server-http.js.map +1 -0
- package/dist/server-stdio.d.ts +13 -0
- package/dist/server-stdio.d.ts.map +1 -0
- package/dist/server-stdio.js +43 -0
- package/dist/server-stdio.js.map +1 -0
- package/dist/tools/executor.d.ts +24 -0
- package/dist/tools/executor.d.ts.map +1 -0
- package/dist/tools/executor.js +220 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/filter.d.ts +82 -0
- package/dist/tools/filter.d.ts.map +1 -0
- package/dist/tools/filter.js +176 -0
- package/dist/tools/filter.js.map +1 -0
- package/dist/tools/generator.d.ts +45 -0
- package/dist/tools/generator.d.ts.map +1 -0
- package/dist/tools/generator.js +97 -0
- package/dist/tools/generator.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP server core logic.
|
|
3
|
+
* Provides context creation and server setup for both STDIO and HTTP transports.
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { loadHttpSettings, loadSettings } from "./config.js";
|
|
8
|
+
import { executeTool } from "./tools/executor.js";
|
|
9
|
+
import { applyDeferLoading, filterTools, setToolCategories, } from "./tools/filter.js";
|
|
10
|
+
import { buildToolCategories, generateToolsFromSwagger, } from "./tools/generator.js";
|
|
11
|
+
/**
|
|
12
|
+
* Create MCP context with tools generated from swagger specs.
|
|
13
|
+
* This should be called once at startup and reused.
|
|
14
|
+
*
|
|
15
|
+
* @returns MCP context with generated tools
|
|
16
|
+
*/
|
|
17
|
+
export async function createMcpContext() {
|
|
18
|
+
// Load settings
|
|
19
|
+
const settings = loadSettings();
|
|
20
|
+
// Generate tools from swagger specifications
|
|
21
|
+
const allTools = await generateToolsFromSwagger(settings.yirifiBaseUrl);
|
|
22
|
+
// Build and set tool categories for filtering
|
|
23
|
+
const toolCategories = buildToolCategories(allTools);
|
|
24
|
+
setToolCategories(toolCategories);
|
|
25
|
+
// Apply tool filtering based on YIRIFI_TOOLS environment variable
|
|
26
|
+
const filteredTools = filterTools(allTools, settings.yirifiTools);
|
|
27
|
+
// Apply defer_loading to tools matching YIRIFI_DEFER_TOOLS patterns
|
|
28
|
+
const toolsWithDeferLoading = applyDeferLoading(filteredTools, settings.yirifiDeferTools);
|
|
29
|
+
// Create tool lookup map
|
|
30
|
+
const toolMap = new Map(allTools.map((t) => [t.name, t]));
|
|
31
|
+
// Log filtering info
|
|
32
|
+
if (settings.yirifiTools) {
|
|
33
|
+
console.error(`Tool filtering enabled: ${filteredTools.length}/${allTools.length} tools exposed`);
|
|
34
|
+
console.error(`YIRIFI_TOOLS pattern: ${settings.yirifiTools}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error(`Collected ${allTools.length} tools from swagger specs`);
|
|
38
|
+
}
|
|
39
|
+
if (settings.yirifiDeferTools) {
|
|
40
|
+
const deferredCount = toolsWithDeferLoading.filter((t) => t.defer_loading).length;
|
|
41
|
+
console.error(`YIRIFI_DEFER_TOOLS pattern: ${settings.yirifiDeferTools}`);
|
|
42
|
+
console.error(`Tools deferred: ${deferredCount} (immediate: ${toolsWithDeferLoading.length - deferredCount})`);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
settings,
|
|
46
|
+
yirifiBaseUrl: settings.yirifiBaseUrl,
|
|
47
|
+
allTools,
|
|
48
|
+
filteredTools: toolsWithDeferLoading,
|
|
49
|
+
toolMap,
|
|
50
|
+
toolCategories,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create HTTP MCP context with tools generated from swagger specs.
|
|
55
|
+
* This should be called once at startup and reused.
|
|
56
|
+
*
|
|
57
|
+
* @returns HTTP MCP context with generated tools
|
|
58
|
+
*/
|
|
59
|
+
export async function createHttpMcpContext() {
|
|
60
|
+
// Load HTTP settings (no API key required)
|
|
61
|
+
const settings = loadHttpSettings();
|
|
62
|
+
// Generate tools from swagger specifications
|
|
63
|
+
const allTools = await generateToolsFromSwagger(settings.yirifiBaseUrl);
|
|
64
|
+
// Build and set tool categories for filtering
|
|
65
|
+
const toolCategories = buildToolCategories(allTools);
|
|
66
|
+
setToolCategories(toolCategories);
|
|
67
|
+
// Apply tool filtering based on YIRIFI_TOOLS environment variable
|
|
68
|
+
const filteredTools = filterTools(allTools, settings.yirifiTools);
|
|
69
|
+
// Apply defer_loading to tools matching YIRIFI_DEFER_TOOLS patterns
|
|
70
|
+
const toolsWithDeferLoading = applyDeferLoading(filteredTools, settings.yirifiDeferTools);
|
|
71
|
+
// Create tool lookup map
|
|
72
|
+
const toolMap = new Map(allTools.map((t) => [t.name, t]));
|
|
73
|
+
// Log filtering info
|
|
74
|
+
if (settings.yirifiTools) {
|
|
75
|
+
console.error(`Tool filtering enabled: ${filteredTools.length}/${allTools.length} tools exposed`);
|
|
76
|
+
console.error(`YIRIFI_TOOLS pattern: ${settings.yirifiTools}`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.error(`Collected ${allTools.length} tools from swagger specs`);
|
|
80
|
+
}
|
|
81
|
+
if (settings.yirifiDeferTools) {
|
|
82
|
+
const deferredCount = toolsWithDeferLoading.filter((t) => t.defer_loading).length;
|
|
83
|
+
console.error(`YIRIFI_DEFER_TOOLS pattern: ${settings.yirifiDeferTools}`);
|
|
84
|
+
console.error(`Tools deferred: ${deferredCount} (immediate: ${toolsWithDeferLoading.length - deferredCount})`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
settings,
|
|
88
|
+
yirifiBaseUrl: settings.yirifiBaseUrl,
|
|
89
|
+
allTools,
|
|
90
|
+
filteredTools: toolsWithDeferLoading,
|
|
91
|
+
toolMap,
|
|
92
|
+
toolCategories,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create an MCP server with tool handlers.
|
|
97
|
+
*
|
|
98
|
+
* @param ctx - MCP context with tool data (either STDIO or HTTP context)
|
|
99
|
+
* @param client - YirifiClient for making API calls
|
|
100
|
+
* @returns Configured McpServer instance
|
|
101
|
+
*/
|
|
102
|
+
export function createMcpServer(ctx, client, executeOptions, requestToolFilter) {
|
|
103
|
+
const { filteredTools, toolMap } = ctx;
|
|
104
|
+
const allToolNames = Array.from(toolMap.keys());
|
|
105
|
+
const toolOptions = {
|
|
106
|
+
...executeOptions,
|
|
107
|
+
allToolNames,
|
|
108
|
+
};
|
|
109
|
+
// Apply per-request filter on top of env-level whitelist.
|
|
110
|
+
// Env filter is the operator's hard boundary; this narrows further per-client.
|
|
111
|
+
const exposedTools = requestToolFilter
|
|
112
|
+
? filterTools(filteredTools, requestToolFilter)
|
|
113
|
+
: filteredTools;
|
|
114
|
+
// Create MCP server instance with tools capability
|
|
115
|
+
const server = new McpServer({
|
|
116
|
+
name: "yirifi-mcp",
|
|
117
|
+
version: "1.0.0",
|
|
118
|
+
}, {
|
|
119
|
+
capabilities: {
|
|
120
|
+
tools: {},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
// Register list_tools handler
|
|
124
|
+
server.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
125
|
+
return {
|
|
126
|
+
tools: exposedTools.map((t) => {
|
|
127
|
+
const fullTool = toolMap.get(t.name);
|
|
128
|
+
const isReadOnly = fullTool ? fullTool._meta.method.toUpperCase() === "GET" : true;
|
|
129
|
+
return {
|
|
130
|
+
name: t.name,
|
|
131
|
+
description: t.description,
|
|
132
|
+
inputSchema: t.inputSchema,
|
|
133
|
+
defer_loading: t.defer_loading,
|
|
134
|
+
annotations: {
|
|
135
|
+
readOnlyHint: isReadOnly,
|
|
136
|
+
destructiveHint: false,
|
|
137
|
+
idempotentHint: isReadOnly,
|
|
138
|
+
openWorldHint: true,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
// Register call_tool handler - single generic handler for all tools
|
|
145
|
+
server.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
146
|
+
const { name, arguments: args } = request.params;
|
|
147
|
+
const tool = toolMap.get(name);
|
|
148
|
+
if (!tool) {
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
151
|
+
isError: true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const result = await executeTool(tool, args ?? {}, client, toolOptions);
|
|
156
|
+
return { content: result };
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
160
|
+
return {
|
|
161
|
+
content: [{ type: "text", text: `Error executing tool: ${errorMsg}` }],
|
|
162
|
+
isError: true,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
console.error("Tool handlers registered successfully");
|
|
167
|
+
return server;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Log server startup information.
|
|
171
|
+
*
|
|
172
|
+
* @param ctx - MCP context (either STDIO or HTTP context)
|
|
173
|
+
* @param transport - Transport type label
|
|
174
|
+
*/
|
|
175
|
+
export function logServerStartup(ctx, transport) {
|
|
176
|
+
const { yirifiBaseUrl, allTools, filteredTools } = ctx;
|
|
177
|
+
console.error(`Yirifi MCP Server starting (${transport})...`);
|
|
178
|
+
console.error(`Base URL: ${yirifiBaseUrl}`);
|
|
179
|
+
console.error(`Tools exposed: ${filteredTools.length}/${allTools.length}`);
|
|
180
|
+
const immediateTools = filteredTools.filter((t) => !t.defer_loading);
|
|
181
|
+
const deferredTools = filteredTools.filter((t) => t.defer_loading);
|
|
182
|
+
if (deferredTools.length > 0) {
|
|
183
|
+
console.error(` Immediate: ${immediateTools.length} | Deferred: ${deferredTools.length}`);
|
|
184
|
+
}
|
|
185
|
+
if (filteredTools.length > 0 && filteredTools.length < allTools.length) {
|
|
186
|
+
console.error(`Exposed tools: ${filteredTools.map((t) => t.name).join(", ")}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=server-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-core.js","sourceRoot":"","sources":["../src/server-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Yirifi MCP Server - Streamable HTTP Transport Entry Point.
|
|
4
|
+
*
|
|
5
|
+
* This server provides MCP tools for accessing Yirifi GRC Platform external APIs
|
|
6
|
+
* over HTTP. Tools are dynamically generated from OpenAPI/Swagger specifications.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node dist/server-http.js
|
|
10
|
+
* yarn dev:http
|
|
11
|
+
*
|
|
12
|
+
* Environment:
|
|
13
|
+
* PORT=8002 HTTP server port (default: 8002)
|
|
14
|
+
* YIRIFI_BASE_URL=... Yirifi API base URL
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=server-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.d.ts","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Yirifi MCP Server - Streamable HTTP Transport Entry Point.
|
|
4
|
+
*
|
|
5
|
+
* This server provides MCP tools for accessing Yirifi GRC Platform external APIs
|
|
6
|
+
* over HTTP. Tools are dynamically generated from OpenAPI/Swagger specifications.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node dist/server-http.js
|
|
10
|
+
* yarn dev:http
|
|
11
|
+
*
|
|
12
|
+
* Environment:
|
|
13
|
+
* PORT=8002 HTTP server port (default: 8002)
|
|
14
|
+
* YIRIFI_BASE_URL=... Yirifi API base URL
|
|
15
|
+
*/
|
|
16
|
+
import express from "express";
|
|
17
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
18
|
+
import { YirifiClient } from "./client.js";
|
|
19
|
+
import { createHttpMcpContext, createMcpServer, logServerStartup, } from "./server-core.js";
|
|
20
|
+
let ctx;
|
|
21
|
+
function getServer(apiKey, requestToolFilter) {
|
|
22
|
+
const client = new YirifiClient({
|
|
23
|
+
baseUrl: ctx.settings.yirifiBaseUrl,
|
|
24
|
+
apiKey: apiKey || "",
|
|
25
|
+
timeout: 30000,
|
|
26
|
+
});
|
|
27
|
+
return createMcpServer(ctx, client, {
|
|
28
|
+
maxResponseChars: ctx.settings.yirifiResponseMaxChars,
|
|
29
|
+
maxPaginationLimit: ctx.settings.yirifiMaxPaginationLimit,
|
|
30
|
+
}, requestToolFilter);
|
|
31
|
+
}
|
|
32
|
+
async function main() {
|
|
33
|
+
ctx = await createHttpMcpContext();
|
|
34
|
+
const port = Number(process.env.PORT) || 8002;
|
|
35
|
+
const app = express();
|
|
36
|
+
app.use(express.json());
|
|
37
|
+
// Root endpoint
|
|
38
|
+
app.get("/", (_req, res) => {
|
|
39
|
+
res.json({
|
|
40
|
+
name: "Yirifi MCP Server",
|
|
41
|
+
version: "1.0.0",
|
|
42
|
+
status: "ok",
|
|
43
|
+
tools: ctx.filteredTools.length,
|
|
44
|
+
endpoints: {
|
|
45
|
+
health: "GET /health",
|
|
46
|
+
mcp: "POST /mcp",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
// Health check endpoint
|
|
51
|
+
app.get("/health", (_req, res) => {
|
|
52
|
+
res.json({ status: "ok", tools: ctx.filteredTools.length });
|
|
53
|
+
});
|
|
54
|
+
app.post("/mcp", async (req, res) => {
|
|
55
|
+
try {
|
|
56
|
+
// Handle the MCP request
|
|
57
|
+
const apiKey = req.headers["api-key"];
|
|
58
|
+
const requestToolFilter = req.headers["yirifi-tools"];
|
|
59
|
+
const server = getServer(apiKey, requestToolFilter);
|
|
60
|
+
const transport = new StreamableHTTPServerTransport({
|
|
61
|
+
sessionIdGenerator: undefined,
|
|
62
|
+
});
|
|
63
|
+
res.on("close", () => {
|
|
64
|
+
console.log("Request closed");
|
|
65
|
+
transport.close();
|
|
66
|
+
server.close();
|
|
67
|
+
});
|
|
68
|
+
await server.connect(transport);
|
|
69
|
+
await transport.handleRequest(req, res, req.body);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("MCP error:", error);
|
|
73
|
+
if (!res.headersSent) {
|
|
74
|
+
res.status(500).json({ error: "Internal error" });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
app.listen(port, () => {
|
|
79
|
+
logServerStartup(ctx, `HTTP on port ${port}`);
|
|
80
|
+
console.error(`MCP endpoint: http://localhost:${port}/mcp`);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
main().catch((error) => {
|
|
84
|
+
console.error("Fatal error:", error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=server-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.js","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Yirifi MCP Server - STDIO Transport Entry Point.
|
|
4
|
+
*
|
|
5
|
+
* This server provides MCP tools for accessing Yirifi GRC Platform external APIs.
|
|
6
|
+
* Tools are dynamically generated from OpenAPI/Swagger specifications.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* YIRIFI_API_KEY=xxx node dist/server-stdio.js
|
|
10
|
+
* YIRIFI_API_KEY=xxx yarn dev
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=server-stdio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-stdio.d.ts","sourceRoot":"","sources":["../src/server-stdio.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Yirifi MCP Server - STDIO Transport Entry Point.
|
|
4
|
+
*
|
|
5
|
+
* This server provides MCP tools for accessing Yirifi GRC Platform external APIs.
|
|
6
|
+
* Tools are dynamically generated from OpenAPI/Swagger specifications.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* YIRIFI_API_KEY=xxx node dist/server-stdio.js
|
|
10
|
+
* YIRIFI_API_KEY=xxx yarn dev
|
|
11
|
+
*/
|
|
12
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
+
import { YirifiClient } from "./client.js";
|
|
14
|
+
import { createMcpContext, createMcpServer, logServerStartup } from "./server-core.js";
|
|
15
|
+
/**
|
|
16
|
+
* Main entry point for STDIO transport.
|
|
17
|
+
*/
|
|
18
|
+
async function main() {
|
|
19
|
+
// Create MCP context (loads settings, generates tools)
|
|
20
|
+
const ctx = await createMcpContext();
|
|
21
|
+
// Create Yirifi API client with API key from environment
|
|
22
|
+
const client = new YirifiClient({
|
|
23
|
+
baseUrl: ctx.settings.yirifiBaseUrl,
|
|
24
|
+
apiKey: ctx.settings.yirifiApiKey,
|
|
25
|
+
timeout: 30000,
|
|
26
|
+
});
|
|
27
|
+
// Create MCP server with handlers
|
|
28
|
+
const server = createMcpServer(ctx, client, {
|
|
29
|
+
maxResponseChars: ctx.settings.yirifiResponseMaxChars,
|
|
30
|
+
maxPaginationLimit: ctx.settings.yirifiMaxPaginationLimit,
|
|
31
|
+
});
|
|
32
|
+
// Create and connect STDIO transport
|
|
33
|
+
const transport = new StdioServerTransport();
|
|
34
|
+
await server.connect(transport);
|
|
35
|
+
// Log startup info
|
|
36
|
+
logServerStartup(ctx, "STDIO");
|
|
37
|
+
}
|
|
38
|
+
// Run the server
|
|
39
|
+
main().catch((error) => {
|
|
40
|
+
console.error("Fatal error:", error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=server-stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-stdio.js","sourceRoot":"","sources":["../src/server-stdio.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEvF;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,uDAAuD;IACvD,MAAM,GAAG,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAErC,yDAAyD;IACzD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;QAC9B,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,aAAa;QACnC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,YAAY;QACjC,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IAEH,kCAAkC;IAClC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE;QAC1C,gBAAgB,EAAE,GAAG,CAAC,QAAQ,CAAC,sBAAsB;QACrD,kBAAkB,EAAE,GAAG,CAAC,QAAQ,CAAC,wBAAwB;KAC1D,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,mBAAmB;IACnB,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,iBAAiB;AACjB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic tool executor.
|
|
3
|
+
* Executes any generated tool using its metadata and the YirifiClient.
|
|
4
|
+
*/
|
|
5
|
+
import type { TextContent } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import type { YirifiClient } from "../client.js";
|
|
7
|
+
import type { GeneratedTool } from "./generator.js";
|
|
8
|
+
/** Options for tool execution behavior. */
|
|
9
|
+
export interface ExecuteToolOptions {
|
|
10
|
+
maxResponseChars?: number;
|
|
11
|
+
maxPaginationLimit?: number;
|
|
12
|
+
allToolNames?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute a generated tool.
|
|
16
|
+
*
|
|
17
|
+
* @param tool - The generated tool definition with metadata
|
|
18
|
+
* @param args - Tool arguments from the MCP request
|
|
19
|
+
* @param client - YirifiClient instance for making API calls
|
|
20
|
+
* @param options - Execution options (truncation, pagination caps, etc.)
|
|
21
|
+
* @returns Formatted response content
|
|
22
|
+
*/
|
|
23
|
+
export declare function executeTool(tool: GeneratedTool, args: Record<string, unknown>, client: YirifiClient, options?: ExecuteToolOptions): Promise<TextContent[]>;
|
|
24
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQpD,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAmND;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,WAAW,EAAE,CAAC,CA8CxB"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic tool executor.
|
|
3
|
+
* Executes any generated tool using its metadata and the YirifiClient.
|
|
4
|
+
*/
|
|
5
|
+
import { YirifiApiError } from "../client.js";
|
|
6
|
+
const DEFAULT_MAX_RESPONSE_CHARS = 50_000;
|
|
7
|
+
const DEFAULT_MAX_PAGINATION_LIMIT = 50;
|
|
8
|
+
const PAGINATION_PARAM_NAMES = new Set(["limit", "per_page", "page_size", "size"]);
|
|
9
|
+
/**
|
|
10
|
+
* Build the request path by substituting path parameters.
|
|
11
|
+
*/
|
|
12
|
+
function buildPath(pathTemplate, args, executionParameters) {
|
|
13
|
+
let path = pathTemplate;
|
|
14
|
+
for (const param of executionParameters) {
|
|
15
|
+
if (param.in === "path" && args[param.name] !== undefined) {
|
|
16
|
+
path = path.replace(`{${param.name}}`, String(args[param.name]));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extract query parameters from arguments.
|
|
23
|
+
*/
|
|
24
|
+
function extractQueryParams(args, executionParameters) {
|
|
25
|
+
const queryParams = {};
|
|
26
|
+
for (const param of executionParameters) {
|
|
27
|
+
if (param.in === "query" && args[param.name] !== undefined) {
|
|
28
|
+
const value = args[param.name];
|
|
29
|
+
// Skip empty strings - they often cause API issues
|
|
30
|
+
if (value === "")
|
|
31
|
+
continue;
|
|
32
|
+
queryParams[param.name] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return queryParams;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Cap pagination parameters to prevent huge payloads.
|
|
39
|
+
*/
|
|
40
|
+
function capPaginationParams(queryParams, maxLimit) {
|
|
41
|
+
const cap = maxLimit ?? DEFAULT_MAX_PAGINATION_LIMIT;
|
|
42
|
+
const capped = { ...queryParams };
|
|
43
|
+
for (const paramName of PAGINATION_PARAM_NAMES) {
|
|
44
|
+
if (paramName in capped && typeof capped[paramName] === "number") {
|
|
45
|
+
const original = capped[paramName];
|
|
46
|
+
if (original > cap) {
|
|
47
|
+
console.error(`[guardrail] Capped ${paramName} from ${original} to ${cap}`);
|
|
48
|
+
capped[paramName] = cap;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return capped;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract request body from arguments.
|
|
56
|
+
*/
|
|
57
|
+
function extractRequestBody(args, executionParameters) {
|
|
58
|
+
const bodyParams = {};
|
|
59
|
+
for (const param of executionParameters) {
|
|
60
|
+
if (param.in === "body" && args[param.name] !== undefined) {
|
|
61
|
+
bodyParams[param.name] = args[param.name];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// If there's a 'requestBody' key, use it directly
|
|
65
|
+
if (args.requestBody !== undefined) {
|
|
66
|
+
return args.requestBody;
|
|
67
|
+
}
|
|
68
|
+
return Object.keys(bodyParams).length > 0 ? bodyParams : undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Truncate response text if it exceeds the character limit.
|
|
72
|
+
*/
|
|
73
|
+
function truncateResponse(text, maxChars) {
|
|
74
|
+
const limit = maxChars ?? DEFAULT_MAX_RESPONSE_CHARS;
|
|
75
|
+
if (text.length <= limit)
|
|
76
|
+
return text;
|
|
77
|
+
const truncated = text.slice(0, limit);
|
|
78
|
+
const note = `\n\n[TRUNCATED: Response was ${text.length.toLocaleString()} chars, showing first ${limit.toLocaleString()}. Use more specific filters or pagination to reduce response size.]`;
|
|
79
|
+
return truncated + note;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Format a successful API response with metadata envelope.
|
|
83
|
+
*/
|
|
84
|
+
function formatSuccessResponse(tool, data, maxResponseChars) {
|
|
85
|
+
const envelope = {
|
|
86
|
+
source: "yirifi-api",
|
|
87
|
+
tool: tool.name,
|
|
88
|
+
api: `${tool._meta.method.toUpperCase()} ${tool._meta.pathTemplate}`,
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
data,
|
|
91
|
+
};
|
|
92
|
+
const raw = JSON.stringify(envelope, null, 2);
|
|
93
|
+
const text = truncateResponse(raw, maxResponseChars);
|
|
94
|
+
return [{ type: "text", text }];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Format an error response with actionable hints for the LLM.
|
|
98
|
+
*/
|
|
99
|
+
function formatErrorResponse(tool, error, allToolNames) {
|
|
100
|
+
if (error instanceof YirifiApiError) {
|
|
101
|
+
const hints = [];
|
|
102
|
+
switch (error.status) {
|
|
103
|
+
case 400:
|
|
104
|
+
hints.push("Check that all required parameters are provided and correctly formatted.");
|
|
105
|
+
hints.push("Review the tool's inputSchema for valid parameter values.");
|
|
106
|
+
break;
|
|
107
|
+
case 401:
|
|
108
|
+
case 403:
|
|
109
|
+
hints.push("The API key may be invalid or lack permissions for this endpoint.");
|
|
110
|
+
hints.push("This is not a parameter issue - do not retry with different arguments.");
|
|
111
|
+
break;
|
|
112
|
+
case 404: {
|
|
113
|
+
hints.push("The requested resource was not found.");
|
|
114
|
+
const service = tool._category?.service;
|
|
115
|
+
if (service) {
|
|
116
|
+
const related = allToolNames
|
|
117
|
+
.filter((n) => n.startsWith(`${service}_`) && n !== tool.name)
|
|
118
|
+
.slice(0, 5);
|
|
119
|
+
if (related.length > 0) {
|
|
120
|
+
hints.push(`Related tools you could try: ${related.join(", ")}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
hints.push("If using an ID parameter, verify the ID exists by listing resources first.");
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 422:
|
|
127
|
+
hints.push("The request parameters failed validation.");
|
|
128
|
+
hints.push("Check parameter types and formats match what the API expects.");
|
|
129
|
+
break;
|
|
130
|
+
case 429:
|
|
131
|
+
hints.push("Rate limit exceeded. Wait before retrying this request.");
|
|
132
|
+
break;
|
|
133
|
+
case 500:
|
|
134
|
+
case 502:
|
|
135
|
+
case 503:
|
|
136
|
+
hints.push("The Yirifi API is experiencing issues. This is not a parameter problem.");
|
|
137
|
+
hints.push("Try again after a brief wait.");
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
hints.push("An unexpected error occurred.");
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
const envelope = {
|
|
144
|
+
source: "yirifi-api",
|
|
145
|
+
tool: tool.name,
|
|
146
|
+
api: `${tool._meta.method.toUpperCase()} ${tool._meta.pathTemplate}`,
|
|
147
|
+
error: {
|
|
148
|
+
status: error.status,
|
|
149
|
+
message: error.message,
|
|
150
|
+
hints,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
return [{ type: "text", text: JSON.stringify(envelope, null, 2) }];
|
|
154
|
+
}
|
|
155
|
+
// Non-API errors (network, timeout, etc.)
|
|
156
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
157
|
+
return [
|
|
158
|
+
{
|
|
159
|
+
type: "text",
|
|
160
|
+
text: JSON.stringify({
|
|
161
|
+
source: "yirifi-api",
|
|
162
|
+
tool: tool.name,
|
|
163
|
+
error: {
|
|
164
|
+
message: `Error executing ${tool.name}: ${errorMsg}`,
|
|
165
|
+
hints: ["This may be a network or timeout issue. Try again."],
|
|
166
|
+
},
|
|
167
|
+
}, null, 2),
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Execute a generated tool.
|
|
173
|
+
*
|
|
174
|
+
* @param tool - The generated tool definition with metadata
|
|
175
|
+
* @param args - Tool arguments from the MCP request
|
|
176
|
+
* @param client - YirifiClient instance for making API calls
|
|
177
|
+
* @param options - Execution options (truncation, pagination caps, etc.)
|
|
178
|
+
* @returns Formatted response content
|
|
179
|
+
*/
|
|
180
|
+
export async function executeTool(tool, args, client, options) {
|
|
181
|
+
const { _meta: meta } = tool;
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
const method = meta.method.toUpperCase();
|
|
184
|
+
const path = buildPath(meta.pathTemplate, args, meta.executionParameters);
|
|
185
|
+
console.error(`[tool:call] ${tool.name} -> ${method} ${path}`);
|
|
186
|
+
try {
|
|
187
|
+
// Extract and cap query parameters
|
|
188
|
+
const rawQueryParams = extractQueryParams(args, meta.executionParameters);
|
|
189
|
+
const queryParams = capPaginationParams(rawQueryParams, options?.maxPaginationLimit);
|
|
190
|
+
// Extract request body (for POST/PUT/PATCH)
|
|
191
|
+
const body = extractRequestBody(args, meta.executionParameters);
|
|
192
|
+
// Execute the request based on HTTP method
|
|
193
|
+
let data;
|
|
194
|
+
switch (method) {
|
|
195
|
+
case "GET":
|
|
196
|
+
data = await client.get(path, queryParams);
|
|
197
|
+
break;
|
|
198
|
+
case "POST":
|
|
199
|
+
data = await client.post(path, body, queryParams);
|
|
200
|
+
break;
|
|
201
|
+
case "PUT":
|
|
202
|
+
case "PATCH":
|
|
203
|
+
case "DELETE":
|
|
204
|
+
data = await client.request(method, path, queryParams, body);
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
208
|
+
}
|
|
209
|
+
const durationMs = Date.now() - startTime;
|
|
210
|
+
console.error(`[tool:ok] ${tool.name} -> ${method} ${path} (${durationMs}ms)`);
|
|
211
|
+
return formatSuccessResponse(tool, data, options?.maxResponseChars);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
const durationMs = Date.now() - startTime;
|
|
215
|
+
const status = error instanceof YirifiApiError ? error.status : "ERR";
|
|
216
|
+
console.error(`[tool:fail] ${tool.name} -> ${method} ${path} -> ${status} (${durationMs}ms)`);
|
|
217
|
+
return formatErrorResponse(tool, error, options?.allToolNames ?? []);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"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"}
|