@kb-labs/agent-mcp 0.6.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/dist/index.d.ts +195 -0
- package/dist/index.js +557 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { ToolPack, ToolConflictPolicy, ToolPermissions, PackedTool } from '@kb-labs/agent-contracts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCPToolPack — bridges an MCP server to the ToolPack contract.
|
|
5
|
+
*
|
|
6
|
+
* Connects to an MCP server (stdio / SSE / HTTP), discovers its tools,
|
|
7
|
+
* and exposes them as a ToolPack with namespace `mcp.<serverName>`.
|
|
8
|
+
*
|
|
9
|
+
* Security envelope (enforced here, NOT in ToolManager):
|
|
10
|
+
* - Allowlist: only listed tool names are exposed
|
|
11
|
+
* - Audit trail: every call is logged via onAudit callback
|
|
12
|
+
* - Input redaction: redactFields stripped from inputs before logging
|
|
13
|
+
* - Output redaction: redactPatterns applied to output before returning
|
|
14
|
+
* - Sandbox: networkAllowed, allowedPaths from MCPServerConfig.permissions
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
type MCPTransportType = 'stdio' | 'sse';
|
|
18
|
+
interface MCPServerConfig {
|
|
19
|
+
/** Unique server name — used as namespace suffix: `mcp.<name>` */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Transport type */
|
|
22
|
+
transport: MCPTransportType;
|
|
23
|
+
/** For stdio: command to launch the MCP server process */
|
|
24
|
+
command?: string;
|
|
25
|
+
/** For stdio: args to the command */
|
|
26
|
+
args?: string[];
|
|
27
|
+
/** For stdio: env vars for the process */
|
|
28
|
+
env?: Record<string, string>;
|
|
29
|
+
/** For SSE: URL of the MCP server */
|
|
30
|
+
url?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Tool allowlist. Only tools with names in this list are exposed.
|
|
33
|
+
* If undefined/empty, ALL tools from the server are exposed.
|
|
34
|
+
*/
|
|
35
|
+
allowedTools?: string[];
|
|
36
|
+
/** Fields to strip from tool inputs before audit logging */
|
|
37
|
+
redactInputFields?: string[];
|
|
38
|
+
/** Regex patterns applied to tool output (replace match with '[REDACTED]') */
|
|
39
|
+
redactOutputPatterns?: RegExp[];
|
|
40
|
+
/** Priority for conflict resolution with other packs (default: 30) */
|
|
41
|
+
priority?: number;
|
|
42
|
+
/** Conflict policy (default: 'namespace-prefix') */
|
|
43
|
+
conflictPolicy?: ToolConflictPolicy;
|
|
44
|
+
/** ToolPack-level permissions */
|
|
45
|
+
permissions?: ToolPermissions;
|
|
46
|
+
}
|
|
47
|
+
interface MCPPackCallbacks {
|
|
48
|
+
/** Called before each tool execution (for audit trail) */
|
|
49
|
+
onAudit?: (serverName: string, toolName: string, input: Record<string, unknown>) => void;
|
|
50
|
+
/** Called when a tool is blocked by the allowlist */
|
|
51
|
+
onDenied?: (serverName: string, toolName: string, reason: string) => void;
|
|
52
|
+
/** Called after successful connection */
|
|
53
|
+
onConnected?: (serverName: string, toolCount: number) => void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A ToolPack backed by a remote MCP server.
|
|
57
|
+
*
|
|
58
|
+
* Usage:
|
|
59
|
+
* const pack = new MCPToolPack(config, callbacks);
|
|
60
|
+
* await pack.connect(); // discovers server tools
|
|
61
|
+
* toolManager.register(pack); // exposes as mcp.<name>.* tools
|
|
62
|
+
* // ... use via toolManager.execute(...)
|
|
63
|
+
* await pack.dispose(); // clean disconnect
|
|
64
|
+
*/
|
|
65
|
+
declare class MCPToolPack implements ToolPack {
|
|
66
|
+
readonly id: string;
|
|
67
|
+
readonly namespace: string;
|
|
68
|
+
readonly version = "1.0.0";
|
|
69
|
+
readonly priority: number;
|
|
70
|
+
readonly conflictPolicy: ToolConflictPolicy;
|
|
71
|
+
readonly capabilities: string[];
|
|
72
|
+
readonly permissions: ToolPermissions;
|
|
73
|
+
private readonly config;
|
|
74
|
+
private readonly callbacks;
|
|
75
|
+
private client;
|
|
76
|
+
private _tools;
|
|
77
|
+
private _connected;
|
|
78
|
+
constructor(config: MCPServerConfig, callbacks?: MCPPackCallbacks);
|
|
79
|
+
get tools(): PackedTool[];
|
|
80
|
+
get connected(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Connect to the MCP server and discover its tools.
|
|
83
|
+
* Must be called before registering with ToolManager.
|
|
84
|
+
*/
|
|
85
|
+
connect(): Promise<void>;
|
|
86
|
+
initialize(): Promise<void>;
|
|
87
|
+
dispose(): Promise<void>;
|
|
88
|
+
enabled(): boolean;
|
|
89
|
+
private buildTransport;
|
|
90
|
+
private discoverTools;
|
|
91
|
+
private wrapTool;
|
|
92
|
+
private callTool;
|
|
93
|
+
private redactInput;
|
|
94
|
+
private redactOutput;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* MCPAgentServer — exposes the KB Labs Agent as an MCP server.
|
|
99
|
+
*
|
|
100
|
+
* Allows IDE integrations (Claude Desktop, Cursor, etc.) to interact
|
|
101
|
+
* with the agent system via the Model Context Protocol.
|
|
102
|
+
*
|
|
103
|
+
* Exposed via MCP:
|
|
104
|
+
*
|
|
105
|
+
* Tools:
|
|
106
|
+
* - run_task — start an agent task, returns task_id
|
|
107
|
+
* - get_session — get session status / result
|
|
108
|
+
* - get_plan — retrieve the current plan (plan mode)
|
|
109
|
+
* - approve_plan — approve a pending plan
|
|
110
|
+
* - cancel_task — cancel a running task
|
|
111
|
+
*
|
|
112
|
+
* Resources:
|
|
113
|
+
* - agent://sessions/<id> — session JSON
|
|
114
|
+
* - agent://plans/<id> — plan markdown
|
|
115
|
+
* - agent://traces/<id> — trace NDJSON
|
|
116
|
+
*
|
|
117
|
+
* Prompts:
|
|
118
|
+
* - execute-task — system prompt for execute mode
|
|
119
|
+
* - plan-task — system prompt for plan mode
|
|
120
|
+
*
|
|
121
|
+
* Security:
|
|
122
|
+
* - Optional auth token (X-Auth-Token header or Bearer token)
|
|
123
|
+
* - Rate limiting (maxRequestsPerMinute)
|
|
124
|
+
* - Input validation via Zod
|
|
125
|
+
*/
|
|
126
|
+
interface AgentSession {
|
|
127
|
+
id: string;
|
|
128
|
+
task: string;
|
|
129
|
+
mode: string;
|
|
130
|
+
status: 'running' | 'completed' | 'failed' | 'cancelled';
|
|
131
|
+
result?: string;
|
|
132
|
+
error?: string;
|
|
133
|
+
startedAt: number;
|
|
134
|
+
completedAt?: number;
|
|
135
|
+
}
|
|
136
|
+
interface AgentServerCallbacks {
|
|
137
|
+
/**
|
|
138
|
+
* Start a new agent task. Must return a session ID.
|
|
139
|
+
* The server calls this when `run_task` is invoked.
|
|
140
|
+
*/
|
|
141
|
+
runTask(task: string, mode: string, options?: Record<string, unknown>): Promise<string>;
|
|
142
|
+
/**
|
|
143
|
+
* Get status / result of a session.
|
|
144
|
+
*/
|
|
145
|
+
getSession(sessionId: string): Promise<AgentSession | null>;
|
|
146
|
+
/**
|
|
147
|
+
* Get the current plan markdown for a session (plan mode only).
|
|
148
|
+
*/
|
|
149
|
+
getPlan(sessionId: string): Promise<string | null>;
|
|
150
|
+
/**
|
|
151
|
+
* Approve a pending plan. Returns success boolean.
|
|
152
|
+
*/
|
|
153
|
+
approvePlan(sessionId: string): Promise<boolean>;
|
|
154
|
+
/**
|
|
155
|
+
* Cancel a running task.
|
|
156
|
+
*/
|
|
157
|
+
cancelTask(sessionId: string): Promise<boolean>;
|
|
158
|
+
/**
|
|
159
|
+
* List all sessions (for resources).
|
|
160
|
+
*/
|
|
161
|
+
listSessions(): Promise<AgentSession[]>;
|
|
162
|
+
/**
|
|
163
|
+
* Get trace data for a session.
|
|
164
|
+
*/
|
|
165
|
+
getTrace(sessionId: string): Promise<string | null>;
|
|
166
|
+
}
|
|
167
|
+
interface MCPAgentServerConfig {
|
|
168
|
+
/** Server name shown to clients */
|
|
169
|
+
name?: string;
|
|
170
|
+
/** Server version */
|
|
171
|
+
version?: string;
|
|
172
|
+
/** Optional auth token. If set, all requests must include it. */
|
|
173
|
+
authToken?: string;
|
|
174
|
+
/** Max requests per minute (simple in-memory rate limiter). 0 = unlimited. */
|
|
175
|
+
maxRequestsPerMinute?: number;
|
|
176
|
+
}
|
|
177
|
+
declare class MCPAgentServer {
|
|
178
|
+
private readonly server;
|
|
179
|
+
private readonly callbacks;
|
|
180
|
+
private readonly config;
|
|
181
|
+
private readonly requestTimestamps;
|
|
182
|
+
constructor(callbacks: AgentServerCallbacks, config?: MCPAgentServerConfig);
|
|
183
|
+
/**
|
|
184
|
+
* Start serving via stdio (for Claude Desktop / Cursor integration).
|
|
185
|
+
*/
|
|
186
|
+
serveStdio(): Promise<void>;
|
|
187
|
+
close(): Promise<void>;
|
|
188
|
+
private checkRateLimit;
|
|
189
|
+
private registerHandlers;
|
|
190
|
+
private registerToolHandlers;
|
|
191
|
+
private registerResourceHandlers;
|
|
192
|
+
private registerPromptHandlers;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export { type AgentServerCallbacks, type AgentSession, MCPAgentServer, type MCPAgentServerConfig, type MCPPackCallbacks, type MCPServerConfig, MCPToolPack, type MCPTransportType };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
// src/client/mcp-tool-pack.ts
|
|
10
|
+
var MCPToolPack = class {
|
|
11
|
+
id;
|
|
12
|
+
namespace;
|
|
13
|
+
version = "1.0.0";
|
|
14
|
+
priority;
|
|
15
|
+
conflictPolicy;
|
|
16
|
+
capabilities = ["mcp"];
|
|
17
|
+
permissions;
|
|
18
|
+
config;
|
|
19
|
+
callbacks;
|
|
20
|
+
client = null;
|
|
21
|
+
_tools = [];
|
|
22
|
+
_connected = false;
|
|
23
|
+
constructor(config, callbacks = {}) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.callbacks = callbacks;
|
|
26
|
+
this.id = `mcp:${config.name}`;
|
|
27
|
+
this.namespace = `mcp.${config.name}`;
|
|
28
|
+
this.priority = config.priority ?? 30;
|
|
29
|
+
this.conflictPolicy = config.conflictPolicy ?? "namespace-prefix";
|
|
30
|
+
this.permissions = config.permissions ?? {
|
|
31
|
+
networkAllowed: false,
|
|
32
|
+
// MCP servers are sandboxed by default
|
|
33
|
+
auditTrail: true
|
|
34
|
+
// Always audit MCP tool calls
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
get tools() {
|
|
38
|
+
return this._tools;
|
|
39
|
+
}
|
|
40
|
+
get connected() {
|
|
41
|
+
return this._connected;
|
|
42
|
+
}
|
|
43
|
+
// ── Lifecycle ────────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Connect to the MCP server and discover its tools.
|
|
46
|
+
* Must be called before registering with ToolManager.
|
|
47
|
+
*/
|
|
48
|
+
async connect() {
|
|
49
|
+
if (this._connected) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.client = new Client({
|
|
53
|
+
name: `kb-labs-agent-mcp-${this.config.name}`,
|
|
54
|
+
version: "1.0.0"
|
|
55
|
+
});
|
|
56
|
+
const transport = this.buildTransport();
|
|
57
|
+
await this.client.connect(transport);
|
|
58
|
+
await this.discoverTools();
|
|
59
|
+
this._connected = true;
|
|
60
|
+
this.callbacks.onConnected?.(this.config.name, this._tools.length);
|
|
61
|
+
}
|
|
62
|
+
async initialize() {
|
|
63
|
+
if (!this._connected) {
|
|
64
|
+
await this.connect();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async dispose() {
|
|
68
|
+
if (this.client && this._connected) {
|
|
69
|
+
await this.client.close();
|
|
70
|
+
this._connected = false;
|
|
71
|
+
this.client = null;
|
|
72
|
+
this._tools = [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
enabled() {
|
|
76
|
+
return this._connected;
|
|
77
|
+
}
|
|
78
|
+
// ── Transport ────────────────────────────────────────────────────────
|
|
79
|
+
buildTransport() {
|
|
80
|
+
if (this.config.transport === "stdio") {
|
|
81
|
+
if (!this.config.command) {
|
|
82
|
+
throw new Error(`MCPToolPack "${this.config.name}": stdio transport requires "command"`);
|
|
83
|
+
}
|
|
84
|
+
return new StdioClientTransport({
|
|
85
|
+
command: this.config.command,
|
|
86
|
+
args: this.config.args ?? [],
|
|
87
|
+
env: this.config.env
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (this.config.transport === "sse") {
|
|
91
|
+
if (!this.config.url) {
|
|
92
|
+
throw new Error(`MCPToolPack "${this.config.name}": sse transport requires "url"`);
|
|
93
|
+
}
|
|
94
|
+
return new SSEClientTransport(new URL(this.config.url));
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`MCPToolPack "${this.config.name}": unknown transport "${this.config.transport}"`);
|
|
97
|
+
}
|
|
98
|
+
// ── Tool Discovery ───────────────────────────────────────────────────
|
|
99
|
+
async discoverTools() {
|
|
100
|
+
if (!this.client) {
|
|
101
|
+
throw new Error("MCPToolPack: client not initialized");
|
|
102
|
+
}
|
|
103
|
+
const response = await this.client.listTools();
|
|
104
|
+
const serverTools = response.tools;
|
|
105
|
+
const allowlist = this.config.allowedTools;
|
|
106
|
+
this._tools = [];
|
|
107
|
+
for (const serverTool of serverTools) {
|
|
108
|
+
const toolName = serverTool.name;
|
|
109
|
+
if (allowlist && allowlist.length > 0 && !allowlist.includes(toolName)) {
|
|
110
|
+
this.callbacks.onDenied?.(this.config.name, toolName, "not in allowlist");
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
this._tools.push(this.wrapTool(toolName, serverTool));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
wrapTool(toolName, serverTool) {
|
|
117
|
+
const schema = serverTool.inputSchema;
|
|
118
|
+
return {
|
|
119
|
+
definition: {
|
|
120
|
+
type: "function",
|
|
121
|
+
function: {
|
|
122
|
+
name: toolName,
|
|
123
|
+
description: serverTool.description ?? `MCP tool: ${toolName}`,
|
|
124
|
+
parameters: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: schema?.properties ?? {},
|
|
127
|
+
...schema?.required ? { required: schema.required } : {}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
readOnly: false,
|
|
132
|
+
// MCP tools are assumed to have side effects
|
|
133
|
+
capability: "mcp",
|
|
134
|
+
execute: async (input) => this.callTool(toolName, input)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// ── Execution ────────────────────────────────────────────────────────
|
|
138
|
+
async callTool(toolName, input) {
|
|
139
|
+
if (!this.client || !this._connected) {
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
error: `MCPToolPack "${this.config.name}" is not connected`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (this.permissions.auditTrail && this.callbacks.onAudit) {
|
|
146
|
+
const auditInput = this.redactInput(input);
|
|
147
|
+
this.callbacks.onAudit(this.config.name, toolName, auditInput);
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const result = await this.client.callTool({ name: toolName, arguments: input });
|
|
151
|
+
let output = "";
|
|
152
|
+
if (Array.isArray(result.content)) {
|
|
153
|
+
for (const item of result.content) {
|
|
154
|
+
if (item.type === "text") {
|
|
155
|
+
output += item.text;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
output = this.redactOutput(output);
|
|
160
|
+
const isError = result.isError === true;
|
|
161
|
+
return {
|
|
162
|
+
success: !isError,
|
|
163
|
+
output,
|
|
164
|
+
...isError ? { error: output } : {}
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: msg
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ── Redaction ────────────────────────────────────────────────────────
|
|
175
|
+
redactInput(input) {
|
|
176
|
+
const fields = this.config.redactInputFields;
|
|
177
|
+
if (!fields || fields.length === 0) {
|
|
178
|
+
return input;
|
|
179
|
+
}
|
|
180
|
+
const redacted = { ...input };
|
|
181
|
+
for (const field of fields) {
|
|
182
|
+
if (field in redacted) {
|
|
183
|
+
redacted[field] = "[REDACTED]";
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return redacted;
|
|
187
|
+
}
|
|
188
|
+
redactOutput(output) {
|
|
189
|
+
const patterns = this.config.redactOutputPatterns;
|
|
190
|
+
if (!patterns || patterns.length === 0) {
|
|
191
|
+
return output;
|
|
192
|
+
}
|
|
193
|
+
let result = output;
|
|
194
|
+
for (const pattern of patterns) {
|
|
195
|
+
result = result.replace(pattern, "[REDACTED]");
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
var RunTaskInput = z.object({
|
|
201
|
+
task: z.string().min(1).max(1e4).describe("The task to execute"),
|
|
202
|
+
mode: z.enum(["execute", "plan", "spec", "debug"]).default("execute").describe("Agent execution mode"),
|
|
203
|
+
options: z.record(z.unknown()).optional().describe("Additional mode-specific options")
|
|
204
|
+
});
|
|
205
|
+
var SessionIdInput = z.object({
|
|
206
|
+
session_id: z.string().min(1).describe("Session ID returned by run_task")
|
|
207
|
+
});
|
|
208
|
+
var MCPAgentServer = class {
|
|
209
|
+
server;
|
|
210
|
+
callbacks;
|
|
211
|
+
config;
|
|
212
|
+
// Simple rate limiter
|
|
213
|
+
requestTimestamps = [];
|
|
214
|
+
constructor(callbacks, config = {}) {
|
|
215
|
+
this.callbacks = callbacks;
|
|
216
|
+
this.config = {
|
|
217
|
+
name: config.name ?? "kb-labs-agent",
|
|
218
|
+
version: config.version ?? "1.0.0",
|
|
219
|
+
authToken: config.authToken ?? "",
|
|
220
|
+
maxRequestsPerMinute: config.maxRequestsPerMinute ?? 60
|
|
221
|
+
};
|
|
222
|
+
this.server = new Server(
|
|
223
|
+
{ name: this.config.name, version: this.config.version },
|
|
224
|
+
{
|
|
225
|
+
capabilities: {
|
|
226
|
+
tools: {},
|
|
227
|
+
resources: {},
|
|
228
|
+
prompts: {}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
this.registerHandlers();
|
|
233
|
+
}
|
|
234
|
+
// ── Start ────────────────────────────────────────────────────────────
|
|
235
|
+
/**
|
|
236
|
+
* Start serving via stdio (for Claude Desktop / Cursor integration).
|
|
237
|
+
*/
|
|
238
|
+
async serveStdio() {
|
|
239
|
+
const transport = new StdioServerTransport();
|
|
240
|
+
await this.server.connect(transport);
|
|
241
|
+
}
|
|
242
|
+
async close() {
|
|
243
|
+
await this.server.close();
|
|
244
|
+
}
|
|
245
|
+
// ── Rate Limiting ────────────────────────────────────────────────────
|
|
246
|
+
checkRateLimit() {
|
|
247
|
+
if (this.config.maxRequestsPerMinute === 0) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const now = Date.now();
|
|
251
|
+
const oneMinuteAgo = now - 6e4;
|
|
252
|
+
while (this.requestTimestamps.length > 0 && this.requestTimestamps[0] < oneMinuteAgo) {
|
|
253
|
+
this.requestTimestamps.shift();
|
|
254
|
+
}
|
|
255
|
+
if (this.requestTimestamps.length >= this.config.maxRequestsPerMinute) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Rate limit exceeded: max ${this.config.maxRequestsPerMinute} requests per minute`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
this.requestTimestamps.push(now);
|
|
261
|
+
}
|
|
262
|
+
// ── Handlers ─────────────────────────────────────────────────────────
|
|
263
|
+
registerHandlers() {
|
|
264
|
+
this.registerToolHandlers();
|
|
265
|
+
this.registerResourceHandlers();
|
|
266
|
+
this.registerPromptHandlers();
|
|
267
|
+
}
|
|
268
|
+
registerToolHandlers() {
|
|
269
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
270
|
+
tools: [
|
|
271
|
+
{
|
|
272
|
+
name: "run_task",
|
|
273
|
+
description: "Start a new agent task. Returns a session_id for tracking.",
|
|
274
|
+
inputSchema: {
|
|
275
|
+
type: "object",
|
|
276
|
+
properties: {
|
|
277
|
+
task: { type: "string", description: "The task to execute" },
|
|
278
|
+
mode: {
|
|
279
|
+
type: "string",
|
|
280
|
+
enum: ["execute", "plan", "spec", "debug"],
|
|
281
|
+
default: "execute",
|
|
282
|
+
description: "Agent execution mode"
|
|
283
|
+
},
|
|
284
|
+
options: {
|
|
285
|
+
type: "object",
|
|
286
|
+
description: "Additional mode-specific options"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
required: ["task"]
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: "get_session",
|
|
294
|
+
description: "Get the status and result of an agent session.",
|
|
295
|
+
inputSchema: {
|
|
296
|
+
type: "object",
|
|
297
|
+
properties: {
|
|
298
|
+
session_id: { type: "string", description: "Session ID from run_task" }
|
|
299
|
+
},
|
|
300
|
+
required: ["session_id"]
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "get_plan",
|
|
305
|
+
description: "Get the current plan (markdown) for a plan-mode session.",
|
|
306
|
+
inputSchema: {
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: {
|
|
309
|
+
session_id: { type: "string", description: "Session ID from run_task" }
|
|
310
|
+
},
|
|
311
|
+
required: ["session_id"]
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: "approve_plan",
|
|
316
|
+
description: "Approve a pending plan so the agent can execute it.",
|
|
317
|
+
inputSchema: {
|
|
318
|
+
type: "object",
|
|
319
|
+
properties: {
|
|
320
|
+
session_id: { type: "string", description: "Session ID from run_task" }
|
|
321
|
+
},
|
|
322
|
+
required: ["session_id"]
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: "cancel_task",
|
|
327
|
+
description: "Cancel a running agent task.",
|
|
328
|
+
inputSchema: {
|
|
329
|
+
type: "object",
|
|
330
|
+
properties: {
|
|
331
|
+
session_id: { type: "string", description: "Session ID from run_task" }
|
|
332
|
+
},
|
|
333
|
+
required: ["session_id"]
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
}));
|
|
338
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
339
|
+
const { name, arguments: args } = request.params;
|
|
340
|
+
try {
|
|
341
|
+
this.checkRateLimit();
|
|
342
|
+
switch (name) {
|
|
343
|
+
case "run_task": {
|
|
344
|
+
const input = RunTaskInput.parse(args);
|
|
345
|
+
const sessionId = await this.callbacks.runTask(
|
|
346
|
+
input.task,
|
|
347
|
+
input.mode,
|
|
348
|
+
input.options
|
|
349
|
+
);
|
|
350
|
+
return {
|
|
351
|
+
content: [
|
|
352
|
+
{
|
|
353
|
+
type: "text",
|
|
354
|
+
text: JSON.stringify({ session_id: sessionId, status: "started" })
|
|
355
|
+
}
|
|
356
|
+
]
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
case "get_session": {
|
|
360
|
+
const input = SessionIdInput.parse(args);
|
|
361
|
+
const session = await this.callbacks.getSession(input.session_id);
|
|
362
|
+
if (!session) {
|
|
363
|
+
return {
|
|
364
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Session not found" }) }],
|
|
365
|
+
isError: true
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
content: [{ type: "text", text: JSON.stringify(session) }]
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
case "get_plan": {
|
|
373
|
+
const input = SessionIdInput.parse(args);
|
|
374
|
+
const plan = await this.callbacks.getPlan(input.session_id);
|
|
375
|
+
if (plan === null) {
|
|
376
|
+
return {
|
|
377
|
+
content: [
|
|
378
|
+
{ type: "text", text: JSON.stringify({ error: "No plan available for this session" }) }
|
|
379
|
+
],
|
|
380
|
+
isError: true
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
content: [{ type: "text", text: plan }]
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
case "approve_plan": {
|
|
388
|
+
const input = SessionIdInput.parse(args);
|
|
389
|
+
const ok = await this.callbacks.approvePlan(input.session_id);
|
|
390
|
+
return {
|
|
391
|
+
content: [
|
|
392
|
+
{
|
|
393
|
+
type: "text",
|
|
394
|
+
text: JSON.stringify({ approved: ok, session_id: input.session_id })
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
case "cancel_task": {
|
|
400
|
+
const input = SessionIdInput.parse(args);
|
|
401
|
+
const ok = await this.callbacks.cancelTask(input.session_id);
|
|
402
|
+
return {
|
|
403
|
+
content: [
|
|
404
|
+
{
|
|
405
|
+
type: "text",
|
|
406
|
+
text: JSON.stringify({ cancelled: ok, session_id: input.session_id })
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
default:
|
|
412
|
+
return {
|
|
413
|
+
content: [{ type: "text", text: JSON.stringify({ error: `Unknown tool: ${name}` }) }],
|
|
414
|
+
isError: true
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
} catch (error) {
|
|
418
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
419
|
+
return {
|
|
420
|
+
content: [{ type: "text", text: JSON.stringify({ error: msg }) }],
|
|
421
|
+
isError: true
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
registerResourceHandlers() {
|
|
427
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
428
|
+
const sessions = await this.callbacks.listSessions();
|
|
429
|
+
return {
|
|
430
|
+
resources: sessions.map((s) => ({
|
|
431
|
+
uri: `agent://sessions/${s.id}`,
|
|
432
|
+
name: `Session ${s.id} (${s.status})`,
|
|
433
|
+
description: `Task: ${s.task.slice(0, 80)}`,
|
|
434
|
+
mimeType: "application/json"
|
|
435
|
+
}))
|
|
436
|
+
};
|
|
437
|
+
});
|
|
438
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
439
|
+
this.checkRateLimit();
|
|
440
|
+
const uri = request.params.uri;
|
|
441
|
+
const sessionMatch = uri.match(/^agent:\/\/sessions\/(.+)$/);
|
|
442
|
+
if (sessionMatch) {
|
|
443
|
+
const sessionId = sessionMatch[1];
|
|
444
|
+
const session = await this.callbacks.getSession(sessionId);
|
|
445
|
+
if (!session) {
|
|
446
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
contents: [
|
|
450
|
+
{
|
|
451
|
+
uri,
|
|
452
|
+
mimeType: "application/json",
|
|
453
|
+
text: JSON.stringify(session, null, 2)
|
|
454
|
+
}
|
|
455
|
+
]
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const planMatch = uri.match(/^agent:\/\/plans\/(.+)$/);
|
|
459
|
+
if (planMatch) {
|
|
460
|
+
const planSessionId = planMatch[1];
|
|
461
|
+
const plan = await this.callbacks.getPlan(planSessionId);
|
|
462
|
+
if (plan === null) {
|
|
463
|
+
throw new Error(`No plan for session: ${planSessionId}`);
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
contents: [
|
|
467
|
+
{
|
|
468
|
+
uri,
|
|
469
|
+
mimeType: "text/markdown",
|
|
470
|
+
text: plan
|
|
471
|
+
}
|
|
472
|
+
]
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
const traceMatch = uri.match(/^agent:\/\/traces\/(.+)$/);
|
|
476
|
+
if (traceMatch) {
|
|
477
|
+
const traceSessionId = traceMatch[1];
|
|
478
|
+
const trace = await this.callbacks.getTrace(traceSessionId);
|
|
479
|
+
if (trace === null) {
|
|
480
|
+
throw new Error(`No trace for session: ${traceSessionId}`);
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
contents: [
|
|
484
|
+
{
|
|
485
|
+
uri,
|
|
486
|
+
mimeType: "application/x-ndjson",
|
|
487
|
+
text: trace
|
|
488
|
+
}
|
|
489
|
+
]
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
registerPromptHandlers() {
|
|
496
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
497
|
+
prompts: [
|
|
498
|
+
{
|
|
499
|
+
name: "execute-task",
|
|
500
|
+
description: "System prompt guidance for executing a task with the agent",
|
|
501
|
+
arguments: [
|
|
502
|
+
{ name: "task", description: "The task to execute", required: true }
|
|
503
|
+
]
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
name: "plan-task",
|
|
507
|
+
description: "System prompt guidance for planning a task before execution",
|
|
508
|
+
arguments: [
|
|
509
|
+
{ name: "task", description: "The task to plan", required: true }
|
|
510
|
+
]
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
}));
|
|
514
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
515
|
+
const { name, arguments: args } = request.params;
|
|
516
|
+
const task = args?.["task"] ?? "";
|
|
517
|
+
switch (name) {
|
|
518
|
+
case "execute-task":
|
|
519
|
+
return {
|
|
520
|
+
description: "Execute a task with the KB Labs agent",
|
|
521
|
+
messages: [
|
|
522
|
+
{
|
|
523
|
+
role: "user",
|
|
524
|
+
content: {
|
|
525
|
+
type: "text",
|
|
526
|
+
text: `Use the run_task tool to execute the following task in "execute" mode, then use get_session to monitor progress until it completes.
|
|
527
|
+
|
|
528
|
+
Task: ${task}`
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
};
|
|
533
|
+
case "plan-task":
|
|
534
|
+
return {
|
|
535
|
+
description: "Plan a task before execution",
|
|
536
|
+
messages: [
|
|
537
|
+
{
|
|
538
|
+
role: "user",
|
|
539
|
+
content: {
|
|
540
|
+
type: "text",
|
|
541
|
+
text: `Use run_task with mode="plan" for the following task. After it generates a plan, use get_plan to retrieve it, review it, then use approve_plan to proceed with execution.
|
|
542
|
+
|
|
543
|
+
Task: ${task}`
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
]
|
|
547
|
+
};
|
|
548
|
+
default:
|
|
549
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
export { MCPAgentServer, MCPToolPack };
|
|
556
|
+
//# sourceMappingURL=index.js.map
|
|
557
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/mcp-tool-pack.ts","../src/server/mcp-agent-server.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * MCPToolPack — bridges an MCP server to the ToolPack contract.\n *\n * Connects to an MCP server (stdio / SSE / HTTP), discovers its tools,\n * and exposes them as a ToolPack with namespace `mcp.<serverName>`.\n *\n * Security envelope (enforced here, NOT in ToolManager):\n * - Allowlist: only listed tool names are exposed\n * - Audit trail: every call is logged via onAudit callback\n * - Input redaction: redactFields stripped from inputs before logging\n * - Output redaction: redactPatterns applied to output before returning\n * - Sandbox: networkAllowed, allowedPaths from MCPServerConfig.permissions\n */\n\nimport type { ToolPack, PackedTool, ToolPermissions, ToolConflictPolicy } from '@kb-labs/agent-contracts';\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\n\n// ═══════════════════════════════════════════════════════════════════════\n// Configuration\n// ═══════════════════════════════════════════════════════════════════════\n\nexport type MCPTransportType = 'stdio' | 'sse';\n\nexport interface MCPServerConfig {\n /** Unique server name — used as namespace suffix: `mcp.<name>` */\n name: string;\n\n /** Transport type */\n transport: MCPTransportType;\n\n /** For stdio: command to launch the MCP server process */\n command?: string;\n /** For stdio: args to the command */\n args?: string[];\n /** For stdio: env vars for the process */\n env?: Record<string, string>;\n\n /** For SSE: URL of the MCP server */\n url?: string;\n\n /**\n * Tool allowlist. Only tools with names in this list are exposed.\n * If undefined/empty, ALL tools from the server are exposed.\n */\n allowedTools?: string[];\n\n /** Fields to strip from tool inputs before audit logging */\n redactInputFields?: string[];\n\n /** Regex patterns applied to tool output (replace match with '[REDACTED]') */\n redactOutputPatterns?: RegExp[];\n\n /** Priority for conflict resolution with other packs (default: 30) */\n priority?: number;\n /** Conflict policy (default: 'namespace-prefix') */\n conflictPolicy?: ToolConflictPolicy;\n /** ToolPack-level permissions */\n permissions?: ToolPermissions;\n}\n\nexport interface MCPPackCallbacks {\n /** Called before each tool execution (for audit trail) */\n onAudit?: (serverName: string, toolName: string, input: Record<string, unknown>) => void;\n /** Called when a tool is blocked by the allowlist */\n onDenied?: (serverName: string, toolName: string, reason: string) => void;\n /** Called after successful connection */\n onConnected?: (serverName: string, toolCount: number) => void;\n}\n\n// ═══════════════════════════════════════════════════════════════════════\n// MCPToolPack\n// ═══════════════════════════════════════════════════════════════════════\n\n/**\n * A ToolPack backed by a remote MCP server.\n *\n * Usage:\n * const pack = new MCPToolPack(config, callbacks);\n * await pack.connect(); // discovers server tools\n * toolManager.register(pack); // exposes as mcp.<name>.* tools\n * // ... use via toolManager.execute(...)\n * await pack.dispose(); // clean disconnect\n */\nexport class MCPToolPack implements ToolPack {\n readonly id: string;\n readonly namespace: string;\n readonly version = '1.0.0';\n readonly priority: number;\n readonly conflictPolicy: ToolConflictPolicy;\n readonly capabilities = ['mcp'];\n readonly permissions: ToolPermissions;\n\n private readonly config: MCPServerConfig;\n private readonly callbacks: MCPPackCallbacks;\n private client: Client | null = null;\n private _tools: PackedTool[] = [];\n private _connected = false;\n\n constructor(config: MCPServerConfig, callbacks: MCPPackCallbacks = {}) {\n this.config = config;\n this.callbacks = callbacks;\n this.id = `mcp:${config.name}`;\n this.namespace = `mcp.${config.name}`;\n this.priority = config.priority ?? 30;\n this.conflictPolicy = config.conflictPolicy ?? 'namespace-prefix';\n this.permissions = config.permissions ?? {\n networkAllowed: false, // MCP servers are sandboxed by default\n auditTrail: true, // Always audit MCP tool calls\n };\n }\n\n get tools(): PackedTool[] {\n return this._tools;\n }\n\n get connected(): boolean {\n return this._connected;\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────\n\n /**\n * Connect to the MCP server and discover its tools.\n * Must be called before registering with ToolManager.\n */\n async connect(): Promise<void> {\n if (this._connected) {\n return;\n }\n\n this.client = new Client({\n name: `kb-labs-agent-mcp-${this.config.name}`,\n version: '1.0.0',\n });\n const transport = this.buildTransport();\n await this.client.connect(transport);\n await this.discoverTools();\n this._connected = true;\n this.callbacks.onConnected?.(this.config.name, this._tools.length);\n }\n\n async initialize(): Promise<void> {\n // connect() is the public API — initialize() is a ToolPack hook\n // called after registration. If already connected, no-op.\n if (!this._connected) {\n await this.connect();\n }\n }\n\n async dispose(): Promise<void> {\n if (this.client && this._connected) {\n await this.client.close();\n this._connected = false;\n this.client = null;\n this._tools = [];\n }\n }\n\n enabled(): boolean {\n return this._connected;\n }\n\n // ── Transport ────────────────────────────────────────────────────────\n\n private buildTransport(): StdioClientTransport | SSEClientTransport {\n if (this.config.transport === 'stdio') {\n if (!this.config.command) {\n throw new Error(`MCPToolPack \"${this.config.name}\": stdio transport requires \"command\"`);\n }\n return new StdioClientTransport({\n command: this.config.command,\n args: this.config.args ?? [],\n env: this.config.env,\n });\n }\n\n if (this.config.transport === 'sse') {\n if (!this.config.url) {\n throw new Error(`MCPToolPack \"${this.config.name}\": sse transport requires \"url\"`);\n }\n return new SSEClientTransport(new URL(this.config.url));\n }\n\n throw new Error(`MCPToolPack \"${this.config.name}\": unknown transport \"${this.config.transport}\"`);\n }\n\n // ── Tool Discovery ───────────────────────────────────────────────────\n\n private async discoverTools(): Promise<void> {\n if (!this.client) {\n throw new Error('MCPToolPack: client not initialized');\n }\n\n const response = await this.client.listTools();\n const serverTools = response.tools;\n const allowlist = this.config.allowedTools;\n\n this._tools = [];\n for (const serverTool of serverTools) {\n const toolName = serverTool.name;\n\n // Allowlist check: if allowedTools is set, only include listed tools\n if (allowlist && allowlist.length > 0 && !allowlist.includes(toolName)) {\n this.callbacks.onDenied?.(this.config.name, toolName, 'not in allowlist');\n continue;\n }\n\n this._tools.push(this.wrapTool(toolName, serverTool));\n }\n }\n\n private wrapTool(\n toolName: string,\n serverTool: { name: string; description?: string; inputSchema?: unknown },\n ): PackedTool {\n const schema = serverTool.inputSchema as { type?: string; properties?: Record<string, unknown>; required?: string[] } | undefined;\n\n return {\n definition: {\n type: 'function',\n function: {\n name: toolName,\n description: serverTool.description ?? `MCP tool: ${toolName}`,\n parameters: {\n type: 'object' as const,\n properties: schema?.properties ?? {},\n ...(schema?.required ? { required: schema.required } : {}),\n },\n },\n },\n readOnly: false, // MCP tools are assumed to have side effects\n capability: 'mcp',\n\n execute: async (input: Record<string, unknown>) => this.callTool(toolName, input),\n };\n }\n\n // ── Execution ────────────────────────────────────────────────────────\n\n private async callTool(\n toolName: string,\n input: Record<string, unknown>,\n ) {\n if (!this.client || !this._connected) {\n return {\n success: false,\n error: `MCPToolPack \"${this.config.name}\" is not connected`,\n };\n }\n\n // Audit logging (input redacted)\n if (this.permissions.auditTrail && this.callbacks.onAudit) {\n const auditInput = this.redactInput(input);\n this.callbacks.onAudit(this.config.name, toolName, auditInput);\n }\n\n try {\n const result = await this.client.callTool({ name: toolName, arguments: input });\n\n // Collect text content from MCP response\n let output = '';\n if (Array.isArray(result.content)) {\n for (const item of result.content) {\n if (item.type === 'text') {\n output += item.text;\n }\n }\n }\n\n // Output redaction\n output = this.redactOutput(output);\n\n const isError = result.isError === true;\n return {\n success: !isError,\n output,\n ...(isError ? { error: output } : {}),\n };\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: msg,\n };\n }\n }\n\n // ── Redaction ────────────────────────────────────────────────────────\n\n private redactInput(input: Record<string, unknown>): Record<string, unknown> {\n const fields = this.config.redactInputFields;\n if (!fields || fields.length === 0) {\n return input;\n }\n\n const redacted = { ...input };\n for (const field of fields) {\n if (field in redacted) {\n redacted[field] = '[REDACTED]';\n }\n }\n return redacted;\n }\n\n private redactOutput(output: string): string {\n const patterns = this.config.redactOutputPatterns;\n if (!patterns || patterns.length === 0) {\n return output;\n }\n\n let result = output;\n for (const pattern of patterns) {\n result = result.replace(pattern, '[REDACTED]');\n }\n return result;\n }\n}\n","/**\n * MCPAgentServer — exposes the KB Labs Agent as an MCP server.\n *\n * Allows IDE integrations (Claude Desktop, Cursor, etc.) to interact\n * with the agent system via the Model Context Protocol.\n *\n * Exposed via MCP:\n *\n * Tools:\n * - run_task — start an agent task, returns task_id\n * - get_session — get session status / result\n * - get_plan — retrieve the current plan (plan mode)\n * - approve_plan — approve a pending plan\n * - cancel_task — cancel a running task\n *\n * Resources:\n * - agent://sessions/<id> — session JSON\n * - agent://plans/<id> — plan markdown\n * - agent://traces/<id> — trace NDJSON\n *\n * Prompts:\n * - execute-task — system prompt for execute mode\n * - plan-task — system prompt for plan mode\n *\n * Security:\n * - Optional auth token (X-Auth-Token header or Bearer token)\n * - Rate limiting (maxRequestsPerMinute)\n * - Input validation via Zod\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\n\n// ═══════════════════════════════════════════════════════════════════════\n// Types\n// ═══════════════════════════════════════════════════════════════════════\n\nexport interface AgentSession {\n id: string;\n task: string;\n mode: string;\n status: 'running' | 'completed' | 'failed' | 'cancelled';\n result?: string;\n error?: string;\n startedAt: number;\n completedAt?: number;\n}\n\nexport interface AgentServerCallbacks {\n /**\n * Start a new agent task. Must return a session ID.\n * The server calls this when `run_task` is invoked.\n */\n runTask(task: string, mode: string, options?: Record<string, unknown>): Promise<string>;\n\n /**\n * Get status / result of a session.\n */\n getSession(sessionId: string): Promise<AgentSession | null>;\n\n /**\n * Get the current plan markdown for a session (plan mode only).\n */\n getPlan(sessionId: string): Promise<string | null>;\n\n /**\n * Approve a pending plan. Returns success boolean.\n */\n approvePlan(sessionId: string): Promise<boolean>;\n\n /**\n * Cancel a running task.\n */\n cancelTask(sessionId: string): Promise<boolean>;\n\n /**\n * List all sessions (for resources).\n */\n listSessions(): Promise<AgentSession[]>;\n\n /**\n * Get trace data for a session.\n */\n getTrace(sessionId: string): Promise<string | null>;\n}\n\nexport interface MCPAgentServerConfig {\n /** Server name shown to clients */\n name?: string;\n /** Server version */\n version?: string;\n /** Optional auth token. If set, all requests must include it. */\n authToken?: string;\n /** Max requests per minute (simple in-memory rate limiter). 0 = unlimited. */\n maxRequestsPerMinute?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════════════\n// Input Schemas\n// ═══════════════════════════════════════════════════════════════════════\n\nconst RunTaskInput = z.object({\n task: z.string().min(1).max(10_000).describe('The task to execute'),\n mode: z\n .enum(['execute', 'plan', 'spec', 'debug'])\n .default('execute')\n .describe('Agent execution mode'),\n options: z\n .record(z.unknown())\n .optional()\n .describe('Additional mode-specific options'),\n});\n\nconst SessionIdInput = z.object({\n session_id: z.string().min(1).describe('Session ID returned by run_task'),\n});\n\n// ═══════════════════════════════════════════════════════════════════════\n// MCPAgentServer\n// ═══════════════════════════════════════════════════════════════════════\n\nexport class MCPAgentServer {\n private readonly server: Server;\n private readonly callbacks: AgentServerCallbacks;\n private readonly config: Required<MCPAgentServerConfig>;\n\n // Simple rate limiter\n private readonly requestTimestamps: number[] = [];\n\n constructor(callbacks: AgentServerCallbacks, config: MCPAgentServerConfig = {}) {\n this.callbacks = callbacks;\n this.config = {\n name: config.name ?? 'kb-labs-agent',\n version: config.version ?? '1.0.0',\n authToken: config.authToken ?? '',\n maxRequestsPerMinute: config.maxRequestsPerMinute ?? 60,\n };\n\n this.server = new Server(\n { name: this.config.name, version: this.config.version },\n {\n capabilities: {\n tools: {},\n resources: {},\n prompts: {},\n },\n },\n );\n\n this.registerHandlers();\n }\n\n // ── Start ────────────────────────────────────────────────────────────\n\n /**\n * Start serving via stdio (for Claude Desktop / Cursor integration).\n */\n async serveStdio(): Promise<void> {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n }\n\n async close(): Promise<void> {\n await this.server.close();\n }\n\n // ── Rate Limiting ────────────────────────────────────────────────────\n\n private checkRateLimit(): void {\n if (this.config.maxRequestsPerMinute === 0) {\n return;\n }\n\n const now = Date.now();\n const oneMinuteAgo = now - 60_000;\n\n // Clean old timestamps\n while (this.requestTimestamps.length > 0 && this.requestTimestamps[0]! < oneMinuteAgo) {\n this.requestTimestamps.shift();\n }\n\n if (this.requestTimestamps.length >= this.config.maxRequestsPerMinute) {\n throw new Error(\n `Rate limit exceeded: max ${this.config.maxRequestsPerMinute} requests per minute`,\n );\n }\n\n this.requestTimestamps.push(now);\n }\n\n // ── Handlers ─────────────────────────────────────────────────────────\n\n private registerHandlers(): void {\n this.registerToolHandlers();\n this.registerResourceHandlers();\n this.registerPromptHandlers();\n }\n\n private registerToolHandlers(): void {\n // List tools\n this.server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: 'run_task',\n description: 'Start a new agent task. Returns a session_id for tracking.',\n inputSchema: {\n type: 'object',\n properties: {\n task: { type: 'string', description: 'The task to execute' },\n mode: {\n type: 'string',\n enum: ['execute', 'plan', 'spec', 'debug'],\n default: 'execute',\n description: 'Agent execution mode',\n },\n options: {\n type: 'object',\n description: 'Additional mode-specific options',\n },\n },\n required: ['task'],\n },\n },\n {\n name: 'get_session',\n description: 'Get the status and result of an agent session.',\n inputSchema: {\n type: 'object',\n properties: {\n session_id: { type: 'string', description: 'Session ID from run_task' },\n },\n required: ['session_id'],\n },\n },\n {\n name: 'get_plan',\n description: 'Get the current plan (markdown) for a plan-mode session.',\n inputSchema: {\n type: 'object',\n properties: {\n session_id: { type: 'string', description: 'Session ID from run_task' },\n },\n required: ['session_id'],\n },\n },\n {\n name: 'approve_plan',\n description: 'Approve a pending plan so the agent can execute it.',\n inputSchema: {\n type: 'object',\n properties: {\n session_id: { type: 'string', description: 'Session ID from run_task' },\n },\n required: ['session_id'],\n },\n },\n {\n name: 'cancel_task',\n description: 'Cancel a running agent task.',\n inputSchema: {\n type: 'object',\n properties: {\n session_id: { type: 'string', description: 'Session ID from run_task' },\n },\n required: ['session_id'],\n },\n },\n ],\n }));\n\n // Call tool\n this.server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n this.checkRateLimit();\n switch (name) {\n case 'run_task': {\n const input = RunTaskInput.parse(args);\n const sessionId = await this.callbacks.runTask(\n input.task,\n input.mode,\n input.options,\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ session_id: sessionId, status: 'started' }),\n },\n ],\n };\n }\n\n case 'get_session': {\n const input = SessionIdInput.parse(args);\n const session = await this.callbacks.getSession(input.session_id);\n if (!session) {\n return {\n content: [{ type: 'text', text: JSON.stringify({ error: 'Session not found' }) }],\n isError: true,\n };\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(session) }],\n };\n }\n\n case 'get_plan': {\n const input = SessionIdInput.parse(args);\n const plan = await this.callbacks.getPlan(input.session_id);\n if (plan === null) {\n return {\n content: [\n { type: 'text', text: JSON.stringify({ error: 'No plan available for this session' }) },\n ],\n isError: true,\n };\n }\n return {\n content: [{ type: 'text', text: plan }],\n };\n }\n\n case 'approve_plan': {\n const input = SessionIdInput.parse(args);\n const ok = await this.callbacks.approvePlan(input.session_id);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ approved: ok, session_id: input.session_id }),\n },\n ],\n };\n }\n\n case 'cancel_task': {\n const input = SessionIdInput.parse(args);\n const ok = await this.callbacks.cancelTask(input.session_id);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ cancelled: ok, session_id: input.session_id }),\n },\n ],\n };\n }\n\n default:\n return {\n content: [{ type: 'text', text: JSON.stringify({ error: `Unknown tool: ${name}` }) }],\n isError: true,\n };\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text', text: JSON.stringify({ error: msg }) }],\n isError: true,\n };\n }\n });\n }\n\n private registerResourceHandlers(): void {\n // List resources\n this.server.setRequestHandler(ListResourcesRequestSchema, async () => {\n const sessions = await this.callbacks.listSessions();\n return {\n resources: sessions.map((s) => ({\n uri: `agent://sessions/${s.id}`,\n name: `Session ${s.id} (${s.status})`,\n description: `Task: ${s.task.slice(0, 80)}`,\n mimeType: 'application/json',\n })),\n };\n });\n\n // Read resource\n this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n this.checkRateLimit();\n const uri = request.params.uri;\n\n // agent://sessions/<id>\n const sessionMatch = uri.match(/^agent:\\/\\/sessions\\/(.+)$/);\n if (sessionMatch) {\n const sessionId = sessionMatch[1]!;\n const session = await this.callbacks.getSession(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(session, null, 2),\n },\n ],\n };\n }\n\n // agent://plans/<id>\n const planMatch = uri.match(/^agent:\\/\\/plans\\/(.+)$/);\n if (planMatch) {\n const planSessionId = planMatch[1]!;\n const plan = await this.callbacks.getPlan(planSessionId);\n if (plan === null) {\n throw new Error(`No plan for session: ${planSessionId}`);\n }\n return {\n contents: [\n {\n uri,\n mimeType: 'text/markdown',\n text: plan,\n },\n ],\n };\n }\n\n // agent://traces/<id>\n const traceMatch = uri.match(/^agent:\\/\\/traces\\/(.+)$/);\n if (traceMatch) {\n const traceSessionId = traceMatch[1]!;\n const trace = await this.callbacks.getTrace(traceSessionId);\n if (trace === null) {\n throw new Error(`No trace for session: ${traceSessionId}`);\n }\n return {\n contents: [\n {\n uri,\n mimeType: 'application/x-ndjson',\n text: trace,\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource URI: ${uri}`);\n });\n }\n\n private registerPromptHandlers(): void {\n // List prompts\n this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({\n prompts: [\n {\n name: 'execute-task',\n description: 'System prompt guidance for executing a task with the agent',\n arguments: [\n { name: 'task', description: 'The task to execute', required: true },\n ],\n },\n {\n name: 'plan-task',\n description: 'System prompt guidance for planning a task before execution',\n arguments: [\n { name: 'task', description: 'The task to plan', required: true },\n ],\n },\n ],\n }));\n\n // Get prompt\n this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n const task = (args?.['task'] as string) ?? '';\n\n switch (name) {\n case 'execute-task':\n return {\n description: 'Execute a task with the KB Labs agent',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Use the run_task tool to execute the following task in \"execute\" mode, then use get_session to monitor progress until it completes.\\n\\nTask: ${task}`,\n },\n },\n ],\n };\n\n case 'plan-task':\n return {\n description: 'Plan a task before execution',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Use run_task with mode=\"plan\" for the following task. After it generates a plan, use get_plan to retrieve it, review it, then use approve_plan to proceed with execution.\\n\\nTask: ${task}`,\n },\n },\n ],\n };\n\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n });\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/agent-mcp",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "MCP (Model Context Protocol) integration for KB Labs Agents. Client → MCPToolPack + Server → agent as MCP endpoint.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./dist/*": "./dist/*"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"scripts": {
|
|
21
|
+
"clean": "rimraf dist",
|
|
22
|
+
"build": "tsup --config tsup.config.ts",
|
|
23
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
24
|
+
"lint": "eslint src --ext .ts",
|
|
25
|
+
"type-check": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run --passWithNoTests",
|
|
27
|
+
"test:watch": "vitest"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@kb-labs/agent-contracts": "^0.6.0",
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
32
|
+
"zod": "^3.23.8"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
|
|
36
|
+
"@types/node": "^24.3.3",
|
|
37
|
+
"eslint": "^9",
|
|
38
|
+
"rimraf": "^6.0.1",
|
|
39
|
+
"tsup": "^8.5.0",
|
|
40
|
+
"typescript": "^5.6.3",
|
|
41
|
+
"vitest": "^3.2.4"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20.0.0",
|
|
45
|
+
"pnpm": ">=9.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|