@zauso-ai/capstan-agent 0.1.2
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/a2a.d.ts +65 -0
- package/dist/a2a.d.ts.map +1 -0
- package/dist/a2a.js +173 -0
- package/dist/a2a.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +9 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +123 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp.d.ts +41 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +107 -0
- package/dist/mcp.js.map +1 -0
- package/dist/openapi.d.ts +9 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +218 -0
- package/dist/openapi.js.map +1 -0
- package/dist/registry.d.ts +59 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +77 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
package/dist/a2a.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AgentConfig, RouteRegistryEntry } from "./types.js";
|
|
2
|
+
/** Agent Card served at `/.well-known/agent.json`. */
|
|
3
|
+
export interface A2AAgentCard {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
url: string;
|
|
7
|
+
version: string;
|
|
8
|
+
capabilities: {
|
|
9
|
+
streaming?: boolean;
|
|
10
|
+
pushNotifications?: boolean;
|
|
11
|
+
};
|
|
12
|
+
skills: Array<{
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
inputSchema?: Record<string, unknown>;
|
|
17
|
+
outputSchema?: Record<string, unknown>;
|
|
18
|
+
}>;
|
|
19
|
+
authentication?: {
|
|
20
|
+
schemes: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** A2A task representing a unit of work submitted to an agent. */
|
|
24
|
+
export interface A2ATask {
|
|
25
|
+
id: string;
|
|
26
|
+
status: "submitted" | "working" | "input-required" | "completed" | "failed" | "canceled";
|
|
27
|
+
skill: string;
|
|
28
|
+
input?: unknown;
|
|
29
|
+
output?: unknown;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/** JSON-RPC response envelope. */
|
|
33
|
+
interface A2AJsonRpcResponse {
|
|
34
|
+
jsonrpc: "2.0";
|
|
35
|
+
id?: string | number | null;
|
|
36
|
+
result?: unknown;
|
|
37
|
+
error?: {
|
|
38
|
+
code: number;
|
|
39
|
+
message: string;
|
|
40
|
+
data?: unknown;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate an A2A Agent Card from the agent configuration and registered
|
|
45
|
+
* routes. Each route is mapped to an A2A "skill".
|
|
46
|
+
*/
|
|
47
|
+
export declare function generateA2AAgentCard(config: AgentConfig, routes: RouteRegistryEntry[]): A2AAgentCard;
|
|
48
|
+
/**
|
|
49
|
+
* Create an A2A handler that processes JSON-RPC requests according to
|
|
50
|
+
* Google's Agent-to-Agent protocol.
|
|
51
|
+
*
|
|
52
|
+
* Supported methods:
|
|
53
|
+
* - `tasks/send` — create a task, execute the matching skill, return result
|
|
54
|
+
* - `tasks/get` — retrieve the current status of a task
|
|
55
|
+
* - `agent/card` — return the agent card
|
|
56
|
+
*
|
|
57
|
+
* Tasks are tracked in an in-memory Map so callers can query status after
|
|
58
|
+
* submission.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createA2AHandler(config: AgentConfig, routes: RouteRegistryEntry[], executeRoute: (method: string, path: string, input: unknown) => Promise<unknown>): {
|
|
61
|
+
handleRequest: (body: unknown) => Promise<A2AJsonRpcResponse>;
|
|
62
|
+
getAgentCard: () => A2AAgentCard;
|
|
63
|
+
};
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=a2a.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a.d.ts","sourceRoot":"","sources":["../src/a2a.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAOlE,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,CAAC;IACF,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACxC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE;QACf,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,kEAAkE;AAClE,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EACF,WAAW,GACX,SAAS,GACT,gBAAgB,GAChB,WAAW,GACX,QAAQ,GACR,UAAU,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAUD,kCAAkC;AAClC,UAAU,kBAAkB;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D;AAkBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,kBAAkB,EAAE,GAC3B,YAAY,CAkCd;AA4BD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,kBAAkB,EAAE,EAC5B,YAAY,EAAE,CACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,OAAO,CAAC,GACpB;IACD,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9D,YAAY,EAAE,MAAM,YAAY,CAAC;CAClC,CA8HA"}
|
package/dist/a2a.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { routeToToolName } from "./mcp.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Agent Card generation
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Derive a human-readable skill name from a tool ID.
|
|
7
|
+
*
|
|
8
|
+
* "get_tickets" -> "Get Tickets"
|
|
9
|
+
*/
|
|
10
|
+
function humanizeToolName(toolName) {
|
|
11
|
+
return toolName
|
|
12
|
+
.split("_")
|
|
13
|
+
.map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w))
|
|
14
|
+
.join(" ");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate an A2A Agent Card from the agent configuration and registered
|
|
18
|
+
* routes. Each route is mapped to an A2A "skill".
|
|
19
|
+
*/
|
|
20
|
+
export function generateA2AAgentCard(config, routes) {
|
|
21
|
+
const skills = routes.map((route) => {
|
|
22
|
+
const id = routeToToolName(route.method, route.path);
|
|
23
|
+
return {
|
|
24
|
+
id,
|
|
25
|
+
name: route.description ?? humanizeToolName(id),
|
|
26
|
+
...(route.description !== undefined
|
|
27
|
+
? { description: route.description }
|
|
28
|
+
: {}),
|
|
29
|
+
...(route.inputSchema !== undefined
|
|
30
|
+
? { inputSchema: route.inputSchema }
|
|
31
|
+
: {}),
|
|
32
|
+
...(route.outputSchema !== undefined
|
|
33
|
+
? { outputSchema: route.outputSchema }
|
|
34
|
+
: {}),
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
name: config.name,
|
|
39
|
+
...(config.description !== undefined
|
|
40
|
+
? { description: config.description }
|
|
41
|
+
: {}),
|
|
42
|
+
url: config.baseUrl ?? "http://localhost:3000",
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
capabilities: {
|
|
45
|
+
streaming: false,
|
|
46
|
+
pushNotifications: false,
|
|
47
|
+
},
|
|
48
|
+
skills,
|
|
49
|
+
authentication: {
|
|
50
|
+
schemes: ["bearer"],
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// A2A Handler
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/** Generate a unique task ID. */
|
|
58
|
+
function generateTaskId() {
|
|
59
|
+
const timestamp = Date.now().toString(36);
|
|
60
|
+
const random = Math.random().toString(36).slice(2, 10);
|
|
61
|
+
return `task_${timestamp}_${random}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a skill ID to the corresponding route's method and path.
|
|
65
|
+
*/
|
|
66
|
+
function resolveSkill(skillId, routes) {
|
|
67
|
+
for (const route of routes) {
|
|
68
|
+
if (routeToToolName(route.method, route.path) === skillId) {
|
|
69
|
+
return { method: route.method, path: route.path };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create an A2A handler that processes JSON-RPC requests according to
|
|
76
|
+
* Google's Agent-to-Agent protocol.
|
|
77
|
+
*
|
|
78
|
+
* Supported methods:
|
|
79
|
+
* - `tasks/send` — create a task, execute the matching skill, return result
|
|
80
|
+
* - `tasks/get` — retrieve the current status of a task
|
|
81
|
+
* - `agent/card` — return the agent card
|
|
82
|
+
*
|
|
83
|
+
* Tasks are tracked in an in-memory Map so callers can query status after
|
|
84
|
+
* submission.
|
|
85
|
+
*/
|
|
86
|
+
export function createA2AHandler(config, routes, executeRoute) {
|
|
87
|
+
const tasks = new Map();
|
|
88
|
+
const agentCard = generateA2AAgentCard(config, routes);
|
|
89
|
+
function errorResponse(id, code, message, data) {
|
|
90
|
+
return {
|
|
91
|
+
jsonrpc: "2.0",
|
|
92
|
+
id: id ?? null,
|
|
93
|
+
error: { code, message, ...(data !== undefined ? { data } : {}) },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function successResponse(id, result) {
|
|
97
|
+
return {
|
|
98
|
+
jsonrpc: "2.0",
|
|
99
|
+
id: id ?? null,
|
|
100
|
+
result,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function handleTasksSend(reqId, params) {
|
|
104
|
+
const skillId = params["skill"];
|
|
105
|
+
if (!skillId) {
|
|
106
|
+
return errorResponse(reqId, -32602, "Missing required parameter: skill");
|
|
107
|
+
}
|
|
108
|
+
const resolved = resolveSkill(skillId, routes);
|
|
109
|
+
if (!resolved) {
|
|
110
|
+
return errorResponse(reqId, -32602, `Unknown skill: ${skillId}`);
|
|
111
|
+
}
|
|
112
|
+
const taskId = generateTaskId();
|
|
113
|
+
const task = {
|
|
114
|
+
id: taskId,
|
|
115
|
+
status: "submitted",
|
|
116
|
+
skill: skillId,
|
|
117
|
+
input: params["input"],
|
|
118
|
+
};
|
|
119
|
+
tasks.set(taskId, task);
|
|
120
|
+
// Transition to working.
|
|
121
|
+
task.status = "working";
|
|
122
|
+
try {
|
|
123
|
+
const result = await executeRoute(resolved.method, resolved.path, params["input"]);
|
|
124
|
+
task.status = "completed";
|
|
125
|
+
task.output = result;
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
task.status = "failed";
|
|
129
|
+
task.error =
|
|
130
|
+
err instanceof Error ? err.message : "Unknown error during execution";
|
|
131
|
+
}
|
|
132
|
+
return successResponse(reqId, task);
|
|
133
|
+
}
|
|
134
|
+
function handleTasksGet(reqId, params) {
|
|
135
|
+
const taskId = params["id"];
|
|
136
|
+
if (!taskId) {
|
|
137
|
+
return errorResponse(reqId, -32602, "Missing required parameter: id");
|
|
138
|
+
}
|
|
139
|
+
const task = tasks.get(taskId);
|
|
140
|
+
if (!task) {
|
|
141
|
+
return errorResponse(reqId, -32602, `Task not found: ${taskId}`);
|
|
142
|
+
}
|
|
143
|
+
return successResponse(reqId, task);
|
|
144
|
+
}
|
|
145
|
+
async function handleRequest(body) {
|
|
146
|
+
// Validate JSON-RPC envelope.
|
|
147
|
+
if (body === null ||
|
|
148
|
+
typeof body !== "object" ||
|
|
149
|
+
!("method" in body)) {
|
|
150
|
+
return errorResponse(null, -32600, "Invalid JSON-RPC request");
|
|
151
|
+
}
|
|
152
|
+
const rpc = body;
|
|
153
|
+
if (rpc.jsonrpc !== "2.0") {
|
|
154
|
+
return errorResponse(rpc.id, -32600, "Invalid JSON-RPC version");
|
|
155
|
+
}
|
|
156
|
+
const params = rpc.params ?? {};
|
|
157
|
+
switch (rpc.method) {
|
|
158
|
+
case "tasks/send":
|
|
159
|
+
return handleTasksSend(rpc.id, params);
|
|
160
|
+
case "tasks/get":
|
|
161
|
+
return handleTasksGet(rpc.id, params);
|
|
162
|
+
case "agent/card":
|
|
163
|
+
return successResponse(rpc.id, agentCard);
|
|
164
|
+
default:
|
|
165
|
+
return errorResponse(rpc.id, -32601, `Method not found: ${rpc.method}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
handleRequest,
|
|
170
|
+
getAgentCard: () => agentCard,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=a2a.js.map
|
package/dist/a2a.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a.js","sourceRoot":"","sources":["../src/a2a.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { generateAgentManifest } from "./manifest.js";
|
|
2
|
+
export { createMcpServer, serveMcpStdio, routeToToolName } from "./mcp.js";
|
|
3
|
+
export { generateOpenApiSpec } from "./openapi.js";
|
|
4
|
+
export { generateA2AAgentCard, createA2AHandler, } from "./a2a.js";
|
|
5
|
+
export type { A2AAgentCard, A2ATask } from "./a2a.js";
|
|
6
|
+
export { CapabilityRegistry } from "./registry.js";
|
|
7
|
+
export type { AgentManifest, RouteRegistryEntry, AgentConfig } from "./types.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { generateAgentManifest } from "./manifest.js";
|
|
2
|
+
export { createMcpServer, serveMcpStdio, routeToToolName } from "./mcp.js";
|
|
3
|
+
export { generateOpenApiSpec } from "./openapi.js";
|
|
4
|
+
export { generateA2AAgentCard, createA2AHandler, } from "./a2a.js";
|
|
5
|
+
export { CapabilityRegistry } from "./registry.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentConfig, AgentManifest, RouteRegistryEntry } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the Capstan agent manifest — a JSON document that describes
|
|
4
|
+
* all API capabilities of the application for AI agent consumption.
|
|
5
|
+
*
|
|
6
|
+
* This is served at `/.well-known/capstan.json`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateAgentManifest(config: AgentConfig, routes: RouteRegistryEntry[]): AgentManifest;
|
|
9
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAmFjF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,kBAAkB,EAAE,GAC3B,aAAa,CA8Cf"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive a camelCase capability key from an HTTP method and URL path.
|
|
3
|
+
*
|
|
4
|
+
* Examples:
|
|
5
|
+
* GET /tickets -> "listTickets"
|
|
6
|
+
* GET /tickets/:id -> "getTicket"
|
|
7
|
+
* POST /tickets -> "createTicket"
|
|
8
|
+
* PUT /tickets/:id -> "updateTicket"
|
|
9
|
+
* DELETE /tickets/:id -> "deleteTicket"
|
|
10
|
+
* PATCH /tickets/:id -> "patchTicket"
|
|
11
|
+
*/
|
|
12
|
+
function deriveCapabilityKey(method, path) {
|
|
13
|
+
// Extract the meaningful path segments, stripping parameter placeholders
|
|
14
|
+
const segments = path
|
|
15
|
+
.split("/")
|
|
16
|
+
.filter((s) => s.length > 0 && !s.startsWith(":") && !s.startsWith("{"));
|
|
17
|
+
const hasParam = path.includes(":") || path.includes("{");
|
|
18
|
+
// Build the base noun from the path segments
|
|
19
|
+
const noun = segments.map((s) => capitalize(s)).join("");
|
|
20
|
+
const upperMethod = method.toUpperCase();
|
|
21
|
+
if (upperMethod === "GET" && !hasParam) {
|
|
22
|
+
// Collection read: GET /tickets -> listTickets
|
|
23
|
+
return `list${noun}`;
|
|
24
|
+
}
|
|
25
|
+
if (upperMethod === "GET" && hasParam) {
|
|
26
|
+
// Single resource read: GET /tickets/:id -> getTicket
|
|
27
|
+
return `get${singularize(noun)}`;
|
|
28
|
+
}
|
|
29
|
+
if (upperMethod === "POST") {
|
|
30
|
+
return `create${singularize(noun)}`;
|
|
31
|
+
}
|
|
32
|
+
if (upperMethod === "PUT") {
|
|
33
|
+
return `update${singularize(noun)}`;
|
|
34
|
+
}
|
|
35
|
+
if (upperMethod === "DELETE") {
|
|
36
|
+
return `delete${singularize(noun)}`;
|
|
37
|
+
}
|
|
38
|
+
if (upperMethod === "PATCH") {
|
|
39
|
+
return `patch${singularize(noun)}`;
|
|
40
|
+
}
|
|
41
|
+
// Fallback: method + noun
|
|
42
|
+
return `${method.toLowerCase()}${noun}`;
|
|
43
|
+
}
|
|
44
|
+
/** Simple singularization: strip trailing "s" if present. */
|
|
45
|
+
function singularize(word) {
|
|
46
|
+
if (word.endsWith("ies")) {
|
|
47
|
+
return word.slice(0, -3) + "y";
|
|
48
|
+
}
|
|
49
|
+
if (word.endsWith("ses") || word.endsWith("xes") || word.endsWith("zes")) {
|
|
50
|
+
return word.slice(0, -2);
|
|
51
|
+
}
|
|
52
|
+
if (word.endsWith("s") && !word.endsWith("ss")) {
|
|
53
|
+
return word.slice(0, -1);
|
|
54
|
+
}
|
|
55
|
+
return word;
|
|
56
|
+
}
|
|
57
|
+
/** Capitalize the first letter of a string. */
|
|
58
|
+
function capitalize(s) {
|
|
59
|
+
if (s.length === 0)
|
|
60
|
+
return s;
|
|
61
|
+
return s[0].toUpperCase() + s.slice(1);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a capability key to a human-readable title.
|
|
65
|
+
*
|
|
66
|
+
* "listTickets" -> "List Tickets"
|
|
67
|
+
*/
|
|
68
|
+
function humanize(key) {
|
|
69
|
+
// Insert spaces before uppercase letters and capitalize each word
|
|
70
|
+
const words = key.replace(/([A-Z])/g, " $1").trim();
|
|
71
|
+
return words[0].toUpperCase() + words.slice(1);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate the Capstan agent manifest — a JSON document that describes
|
|
75
|
+
* all API capabilities of the application for AI agent consumption.
|
|
76
|
+
*
|
|
77
|
+
* This is served at `/.well-known/capstan.json`.
|
|
78
|
+
*/
|
|
79
|
+
export function generateAgentManifest(config, routes) {
|
|
80
|
+
const capabilities = routes.map((route) => {
|
|
81
|
+
const key = deriveCapabilityKey(route.method, route.path);
|
|
82
|
+
return {
|
|
83
|
+
key,
|
|
84
|
+
title: route.description ?? humanize(key),
|
|
85
|
+
...(route.description !== undefined ? { description: route.description } : {}),
|
|
86
|
+
mode: route.capability ?? "read",
|
|
87
|
+
...(route.resource !== undefined ? { resource: route.resource } : {}),
|
|
88
|
+
endpoint: {
|
|
89
|
+
method: route.method.toUpperCase(),
|
|
90
|
+
path: route.path,
|
|
91
|
+
...(route.inputSchema !== undefined ? { inputSchema: route.inputSchema } : {}),
|
|
92
|
+
...(route.outputSchema !== undefined
|
|
93
|
+
? { outputSchema: route.outputSchema }
|
|
94
|
+
: {}),
|
|
95
|
+
},
|
|
96
|
+
...(route.policy !== undefined ? { policy: route.policy } : {}),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
const manifest = {
|
|
100
|
+
capstan: "1.0",
|
|
101
|
+
name: config.name,
|
|
102
|
+
...(config.description !== undefined ? { description: config.description } : {}),
|
|
103
|
+
...(config.baseUrl !== undefined ? { baseUrl: config.baseUrl } : {}),
|
|
104
|
+
authentication: {
|
|
105
|
+
schemes: [
|
|
106
|
+
{
|
|
107
|
+
type: "bearer",
|
|
108
|
+
name: "API Key",
|
|
109
|
+
header: "Authorization",
|
|
110
|
+
description: "Bearer token for authenticating API requests. Include as: Authorization: Bearer <token>",
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
resources: config.resources ?? [],
|
|
115
|
+
capabilities,
|
|
116
|
+
mcp: {
|
|
117
|
+
endpoint: "/.well-known/mcp",
|
|
118
|
+
transport: "stdio",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
return manifest;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { AgentConfig, RouteRegistryEntry } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Convert an HTTP method + URL path into a snake_case MCP tool name.
|
|
5
|
+
*
|
|
6
|
+
* Examples:
|
|
7
|
+
* GET /tickets -> "get_tickets"
|
|
8
|
+
* POST /tickets -> "post_tickets"
|
|
9
|
+
* GET /tickets/:id -> "get_tickets_by_id"
|
|
10
|
+
* PUT /tickets/:id -> "put_tickets_by_id"
|
|
11
|
+
* DELETE /orgs/:orgId/members/:memberId -> "delete_orgs_by_orgId_members_by_memberId"
|
|
12
|
+
*/
|
|
13
|
+
export declare function routeToToolName(method: string, path: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Create an MCP server that exposes all Capstan API routes as MCP tools.
|
|
16
|
+
*
|
|
17
|
+
* Each API route is registered as an MCP tool. Tool arguments sent by the
|
|
18
|
+
* client are forwarded to the `executeRoute` callback so the actual Capstan
|
|
19
|
+
* handler can process them.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Application configuration.
|
|
22
|
+
* @param routes - Registered API routes.
|
|
23
|
+
* @param executeRoute - Callback that invokes the actual route handler.
|
|
24
|
+
* @returns The McpServer instance and a helper to inspect tool definitions.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createMcpServer(config: AgentConfig, routes: RouteRegistryEntry[], executeRoute: (method: string, path: string, input: unknown) => Promise<unknown>): {
|
|
27
|
+
server: McpServer;
|
|
28
|
+
getToolDefinitions: () => Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
inputSchema: unknown;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Connect an MCP server to stdio transport and start serving.
|
|
36
|
+
*
|
|
37
|
+
* This is the standard way to run a Capstan MCP server as a subprocess
|
|
38
|
+
* that communicates over stdin/stdout.
|
|
39
|
+
*/
|
|
40
|
+
export declare function serveMcpStdio(server: McpServer): Promise<void>;
|
|
41
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBpE;AAYD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,kBAAkB,EAAE,EAC5B,YAAY,EAAE,CACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,OAAO,CAAC,GACpB;IACD,MAAM,EAAE,SAAS,CAAC;IAClB,kBAAkB,EAAE,MAAM,KAAK,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC,CAAC;CACJ,CAyDA;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Convert an HTTP method + URL path into a snake_case MCP tool name.
|
|
6
|
+
*
|
|
7
|
+
* Examples:
|
|
8
|
+
* GET /tickets -> "get_tickets"
|
|
9
|
+
* POST /tickets -> "post_tickets"
|
|
10
|
+
* GET /tickets/:id -> "get_tickets_by_id"
|
|
11
|
+
* PUT /tickets/:id -> "put_tickets_by_id"
|
|
12
|
+
* DELETE /orgs/:orgId/members/:memberId -> "delete_orgs_by_orgId_members_by_memberId"
|
|
13
|
+
*/
|
|
14
|
+
export function routeToToolName(method, path) {
|
|
15
|
+
const prefix = method.toLowerCase();
|
|
16
|
+
const segments = path.split("/").filter((s) => s.length > 0);
|
|
17
|
+
const parts = [];
|
|
18
|
+
for (const segment of segments) {
|
|
19
|
+
if (segment.startsWith(":")) {
|
|
20
|
+
// Dynamic parameter: :id -> "by_id"
|
|
21
|
+
parts.push("by_" + segment.slice(1));
|
|
22
|
+
}
|
|
23
|
+
else if (segment.startsWith("{") && segment.endsWith("}")) {
|
|
24
|
+
// OpenAPI-style parameter: {id} -> "by_id"
|
|
25
|
+
parts.push("by_" + segment.slice(1, -1));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
parts.push(segment);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return `${prefix}_${parts.join("_")}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a tool description from a route.
|
|
35
|
+
*/
|
|
36
|
+
function buildToolDescription(route) {
|
|
37
|
+
if (route.description) {
|
|
38
|
+
return route.description;
|
|
39
|
+
}
|
|
40
|
+
return `${route.method.toUpperCase()} ${route.path}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create an MCP server that exposes all Capstan API routes as MCP tools.
|
|
44
|
+
*
|
|
45
|
+
* Each API route is registered as an MCP tool. Tool arguments sent by the
|
|
46
|
+
* client are forwarded to the `executeRoute` callback so the actual Capstan
|
|
47
|
+
* handler can process them.
|
|
48
|
+
*
|
|
49
|
+
* @param config - Application configuration.
|
|
50
|
+
* @param routes - Registered API routes.
|
|
51
|
+
* @param executeRoute - Callback that invokes the actual route handler.
|
|
52
|
+
* @returns The McpServer instance and a helper to inspect tool definitions.
|
|
53
|
+
*/
|
|
54
|
+
export function createMcpServer(config, routes, executeRoute) {
|
|
55
|
+
const server = new McpServer({
|
|
56
|
+
name: config.name,
|
|
57
|
+
version: "1.0.0",
|
|
58
|
+
});
|
|
59
|
+
const toolDefinitions = [];
|
|
60
|
+
// A permissive Zod schema that accepts any object and passes all
|
|
61
|
+
// properties through. This lets the MCP SDK forward client-supplied
|
|
62
|
+
// arguments to our handler while avoiding the need to convert each
|
|
63
|
+
// route's JSON Schema into a Zod type at registration time.
|
|
64
|
+
const passthroughShape = { _input: z.unknown().optional() };
|
|
65
|
+
for (const route of routes) {
|
|
66
|
+
const toolName = routeToToolName(route.method, route.path);
|
|
67
|
+
const description = buildToolDescription(route);
|
|
68
|
+
// Record the definition for introspection
|
|
69
|
+
toolDefinitions.push({
|
|
70
|
+
name: toolName,
|
|
71
|
+
description,
|
|
72
|
+
inputSchema: route.inputSchema ?? { type: "object", properties: {} },
|
|
73
|
+
});
|
|
74
|
+
// Register the tool with the MCP server.
|
|
75
|
+
//
|
|
76
|
+
// We use the `tool(name, description, paramsSchema, callback)` overload
|
|
77
|
+
// with a minimal Zod shape so the SDK invokes `callback(args, extra)`.
|
|
78
|
+
// The `passthroughShape` ensures the SDK parses the incoming arguments
|
|
79
|
+
// as an object and hands them to us — we then forward them to the
|
|
80
|
+
// actual route handler via `executeRoute`.
|
|
81
|
+
server.tool(toolName, description, passthroughShape, async (args) => {
|
|
82
|
+
// Forward all arguments (minus our synthetic _input marker) to the
|
|
83
|
+
// route handler. Agents will send the actual input properties
|
|
84
|
+
// directly in the tool arguments object.
|
|
85
|
+
const input = Object.keys(args).length > 0 ? args : undefined;
|
|
86
|
+
const result = await executeRoute(route.method, route.path, input);
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
server,
|
|
94
|
+
getToolDefinitions: () => [...toolDefinitions],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Connect an MCP server to stdio transport and start serving.
|
|
99
|
+
*
|
|
100
|
+
* This is the standard way to run a Capstan MCP server as a subprocess
|
|
101
|
+
* that communicates over stdin/stdout.
|
|
102
|
+
*/
|
|
103
|
+
export async function serveMcpStdio(server) {
|
|
104
|
+
const transport = new StdioServerTransport();
|
|
105
|
+
await server.connect(transport);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentConfig, RouteRegistryEntry } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate an OpenAPI 3.1.0 specification from the agent configuration and
|
|
4
|
+
* registered routes.
|
|
5
|
+
*
|
|
6
|
+
* The returned object is a plain JSON-serializable OpenAPI document.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateOpenApiSpec(config: AgentConfig, routes: RouteRegistryEntry[]): Record<string, unknown>;
|
|
9
|
+
//# sourceMappingURL=openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgLlE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,kBAAkB,EAAE,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8EzB"}
|
package/dist/openapi.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP methods where the request body carries the input payload.
|
|
3
|
+
*/
|
|
4
|
+
const BODY_METHODS = new Set(["POST", "PUT", "PATCH"]);
|
|
5
|
+
/**
|
|
6
|
+
* Convert a Capstan route path (Express/Hono-style) to an OpenAPI path.
|
|
7
|
+
*
|
|
8
|
+
* /tickets/:id -> /tickets/{id}
|
|
9
|
+
*/
|
|
10
|
+
function toOpenApiPath(path) {
|
|
11
|
+
return path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, "{$1}");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract path parameter names from a route path.
|
|
15
|
+
*
|
|
16
|
+
* /tickets/:id -> ["id"]
|
|
17
|
+
* /orgs/:orgId/members/:memberId -> ["orgId", "memberId"]
|
|
18
|
+
*/
|
|
19
|
+
function extractPathParams(path) {
|
|
20
|
+
const params = [];
|
|
21
|
+
const regex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
22
|
+
let match;
|
|
23
|
+
while ((match = regex.exec(path)) !== null) {
|
|
24
|
+
params.push(match[1]);
|
|
25
|
+
}
|
|
26
|
+
return params;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build OpenAPI parameter objects for path parameters.
|
|
30
|
+
*/
|
|
31
|
+
function buildPathParameters(pathParams) {
|
|
32
|
+
return pathParams.map((name) => ({
|
|
33
|
+
name,
|
|
34
|
+
in: "path",
|
|
35
|
+
required: true,
|
|
36
|
+
schema: { type: "string" },
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build OpenAPI query parameter objects from a JSON Schema input definition.
|
|
41
|
+
*
|
|
42
|
+
* For GET and DELETE requests, input properties are sent as query parameters.
|
|
43
|
+
*/
|
|
44
|
+
function buildQueryParameters(inputSchema, pathParams) {
|
|
45
|
+
if (!inputSchema)
|
|
46
|
+
return [];
|
|
47
|
+
const properties = (inputSchema["properties"] ?? {});
|
|
48
|
+
const required = new Set(inputSchema["required"] ?? []);
|
|
49
|
+
const pathParamSet = new Set(pathParams);
|
|
50
|
+
return Object.entries(properties)
|
|
51
|
+
.filter(([name]) => !pathParamSet.has(name))
|
|
52
|
+
.map(([name, schema]) => ({
|
|
53
|
+
name,
|
|
54
|
+
in: "query",
|
|
55
|
+
required: required.has(name),
|
|
56
|
+
schema,
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build an OpenAPI operation object for a single route.
|
|
61
|
+
*/
|
|
62
|
+
function buildOperation(route, pathParams) {
|
|
63
|
+
const upperMethod = route.method.toUpperCase();
|
|
64
|
+
const operation = {};
|
|
65
|
+
// Operation ID derived from method + path (including param markers for uniqueness)
|
|
66
|
+
const allSegments = route.path.split("/").filter((s) => s.length > 0);
|
|
67
|
+
const idParts = [];
|
|
68
|
+
for (const seg of allSegments) {
|
|
69
|
+
if (seg.startsWith(":")) {
|
|
70
|
+
idParts.push("By" + seg[1].toUpperCase() + seg.slice(2));
|
|
71
|
+
}
|
|
72
|
+
else if (seg.startsWith("{") && seg.endsWith("}")) {
|
|
73
|
+
const name = seg.slice(1, -1);
|
|
74
|
+
idParts.push("By" + name[0].toUpperCase() + name.slice(1));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
idParts.push(seg[0].toUpperCase() + seg.slice(1));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
operation["operationId"] = upperMethod.toLowerCase() + idParts.join("");
|
|
81
|
+
if (route.description) {
|
|
82
|
+
operation["summary"] = route.description;
|
|
83
|
+
}
|
|
84
|
+
// Tags: use the resource name if available, otherwise derive from first path segment
|
|
85
|
+
const staticSegments = allSegments.filter((s) => !s.startsWith(":") && !s.startsWith("{"));
|
|
86
|
+
if (route.resource) {
|
|
87
|
+
operation["tags"] = [route.resource];
|
|
88
|
+
}
|
|
89
|
+
else if (staticSegments.length > 0) {
|
|
90
|
+
operation["tags"] = [staticSegments[0]];
|
|
91
|
+
}
|
|
92
|
+
// Parameters: path params + query params for non-body methods
|
|
93
|
+
const parameters = [
|
|
94
|
+
...buildPathParameters(pathParams),
|
|
95
|
+
];
|
|
96
|
+
if (!BODY_METHODS.has(upperMethod)) {
|
|
97
|
+
parameters.push(...buildQueryParameters(route.inputSchema, pathParams));
|
|
98
|
+
}
|
|
99
|
+
if (parameters.length > 0) {
|
|
100
|
+
operation["parameters"] = parameters;
|
|
101
|
+
}
|
|
102
|
+
// Request body for POST/PUT/PATCH
|
|
103
|
+
if (BODY_METHODS.has(upperMethod) && route.inputSchema) {
|
|
104
|
+
operation["requestBody"] = {
|
|
105
|
+
required: true,
|
|
106
|
+
content: {
|
|
107
|
+
"application/json": {
|
|
108
|
+
schema: route.inputSchema,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Responses
|
|
114
|
+
const responses = {};
|
|
115
|
+
if (route.outputSchema) {
|
|
116
|
+
responses["200"] = {
|
|
117
|
+
description: "Successful response",
|
|
118
|
+
content: {
|
|
119
|
+
"application/json": {
|
|
120
|
+
schema: route.outputSchema,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
responses["200"] = {
|
|
127
|
+
description: "Successful response",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
responses["401"] = {
|
|
131
|
+
description: "Unauthorized — missing or invalid authentication",
|
|
132
|
+
};
|
|
133
|
+
if (route.policy) {
|
|
134
|
+
responses["403"] = {
|
|
135
|
+
description: `Forbidden — policy "${route.policy}" denied access`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
operation["responses"] = responses;
|
|
139
|
+
// Security requirement
|
|
140
|
+
operation["security"] = [{ bearerAuth: [] }];
|
|
141
|
+
return operation;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Generate an OpenAPI 3.1.0 specification from the agent configuration and
|
|
145
|
+
* registered routes.
|
|
146
|
+
*
|
|
147
|
+
* The returned object is a plain JSON-serializable OpenAPI document.
|
|
148
|
+
*/
|
|
149
|
+
export function generateOpenApiSpec(config, routes) {
|
|
150
|
+
// Build paths
|
|
151
|
+
const paths = {};
|
|
152
|
+
for (const route of routes) {
|
|
153
|
+
const openApiPath = toOpenApiPath(route.path);
|
|
154
|
+
const method = route.method.toLowerCase();
|
|
155
|
+
const pathParams = extractPathParams(route.path);
|
|
156
|
+
if (!paths[openApiPath]) {
|
|
157
|
+
paths[openApiPath] = {};
|
|
158
|
+
}
|
|
159
|
+
paths[openApiPath][method] = buildOperation(route, pathParams);
|
|
160
|
+
}
|
|
161
|
+
// Build component schemas from resources
|
|
162
|
+
const schemas = {};
|
|
163
|
+
if (config.resources) {
|
|
164
|
+
for (const resource of config.resources) {
|
|
165
|
+
const properties = {};
|
|
166
|
+
const required = [];
|
|
167
|
+
for (const [fieldName, fieldDef] of Object.entries(resource.fields)) {
|
|
168
|
+
const prop = { type: fieldDef.type };
|
|
169
|
+
if (fieldDef.enum) {
|
|
170
|
+
prop["enum"] = fieldDef.enum;
|
|
171
|
+
}
|
|
172
|
+
properties[fieldName] = prop;
|
|
173
|
+
if (fieldDef.required) {
|
|
174
|
+
required.push(fieldName);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const schema = {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties,
|
|
180
|
+
};
|
|
181
|
+
if (required.length > 0) {
|
|
182
|
+
schema["required"] = required;
|
|
183
|
+
}
|
|
184
|
+
if (resource.description) {
|
|
185
|
+
schema["description"] = resource.description;
|
|
186
|
+
}
|
|
187
|
+
schemas[resource.key] = schema;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Assemble the spec
|
|
191
|
+
const spec = {
|
|
192
|
+
openapi: "3.1.0",
|
|
193
|
+
info: {
|
|
194
|
+
title: config.name,
|
|
195
|
+
...(config.description !== undefined
|
|
196
|
+
? { description: config.description }
|
|
197
|
+
: {}),
|
|
198
|
+
version: "0.1.0",
|
|
199
|
+
},
|
|
200
|
+
...(config.baseUrl !== undefined
|
|
201
|
+
? { servers: [{ url: config.baseUrl }] }
|
|
202
|
+
: {}),
|
|
203
|
+
paths,
|
|
204
|
+
components: {
|
|
205
|
+
securitySchemes: {
|
|
206
|
+
bearerAuth: {
|
|
207
|
+
type: "http",
|
|
208
|
+
scheme: "bearer",
|
|
209
|
+
bearerFormat: "JWT",
|
|
210
|
+
description: "Bearer token for authenticating API requests",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
...(Object.keys(schemas).length > 0 ? { schemas } : {}),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
return spec;
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AgentConfig, AgentManifest, RouteRegistryEntry } from "./types.js";
|
|
2
|
+
import type { A2AAgentCard } from "./a2a.js";
|
|
3
|
+
/**
|
|
4
|
+
* Unified capability registry — the central abstraction for Capstan's
|
|
5
|
+
* multi-protocol adapter layer.
|
|
6
|
+
*
|
|
7
|
+
* Register routes once, then project them to any supported protocol surface:
|
|
8
|
+
*
|
|
9
|
+
* - **Capstan manifest** (`/.well-known/capstan.json`)
|
|
10
|
+
* - **OpenAPI 3.1** (`/openapi.json`)
|
|
11
|
+
* - **MCP** (Model Context Protocol tools)
|
|
12
|
+
* - **A2A** (Google Agent-to-Agent protocol)
|
|
13
|
+
*
|
|
14
|
+
* One registry, four projections.
|
|
15
|
+
*/
|
|
16
|
+
export declare class CapabilityRegistry {
|
|
17
|
+
private routes;
|
|
18
|
+
private config;
|
|
19
|
+
constructor(config: AgentConfig);
|
|
20
|
+
/** Register a single route entry. */
|
|
21
|
+
register(route: RouteRegistryEntry): void;
|
|
22
|
+
/** Register multiple route entries at once. */
|
|
23
|
+
registerAll(routes: RouteRegistryEntry[]): void;
|
|
24
|
+
/** Get all registered routes (read-only view). */
|
|
25
|
+
getRoutes(): readonly RouteRegistryEntry[];
|
|
26
|
+
/** Get the agent configuration. */
|
|
27
|
+
getConfig(): Readonly<AgentConfig>;
|
|
28
|
+
/** Project to Capstan native agent manifest. */
|
|
29
|
+
toManifest(): AgentManifest;
|
|
30
|
+
/** Project to OpenAPI 3.1 specification. */
|
|
31
|
+
toOpenApi(): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Project to MCP server.
|
|
34
|
+
*
|
|
35
|
+
* @param executeRoute - Callback that invokes the actual route handler
|
|
36
|
+
* given an HTTP method, path, and input payload.
|
|
37
|
+
* @returns The McpServer instance and a helper to list tool definitions.
|
|
38
|
+
*/
|
|
39
|
+
toMcp(executeRoute: (method: string, path: string, input: unknown) => Promise<unknown>): {
|
|
40
|
+
server: InstanceType<typeof import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
|
|
41
|
+
getToolDefinitions: () => Array<{
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
inputSchema: unknown;
|
|
45
|
+
}>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Project to A2A agent card and JSON-RPC handler.
|
|
49
|
+
*
|
|
50
|
+
* @param executeRoute - Callback that invokes the actual route handler
|
|
51
|
+
* given an HTTP method, path, and input payload.
|
|
52
|
+
* @returns The A2A request handler and agent card accessor.
|
|
53
|
+
*/
|
|
54
|
+
toA2A(executeRoute: (method: string, path: string, input: unknown) => Promise<unknown>): {
|
|
55
|
+
handleRequest: (body: unknown) => Promise<unknown>;
|
|
56
|
+
getAgentCard: () => A2AAgentCard;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAM7C;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAQ/B,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAIzC,+CAA+C;IAC/C,WAAW,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAM/C,kDAAkD;IAClD,SAAS,IAAI,SAAS,kBAAkB,EAAE;IAI1C,mCAAmC;IACnC,SAAS,IAAI,QAAQ,CAAC,WAAW,CAAC;IAQlC,gDAAgD;IAChD,UAAU,IAAI,aAAa;IAI3B,4CAA4C;IAC5C,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIpC;;;;;;OAMG;IACH,KAAK,CACH,YAAY,EAAE,CACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,OAAO,CAAC,GACpB;QACD,MAAM,EAAE,YAAY,CAAC,cAAc,yCAAyC,EAAE,SAAS,CAAC,CAAC;QACzF,kBAAkB,EAAE,MAAM,KAAK,CAAC;YAC9B,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,WAAW,EAAE,OAAO,CAAC;SACtB,CAAC,CAAC;KACJ;IAID;;;;;;OAMG;IACH,KAAK,CACH,YAAY,EAAE,CACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,OAAO,CAAC,GACpB;QACD,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACnD,YAAY,EAAE,MAAM,YAAY,CAAC;KAClC;CAGF"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { generateAgentManifest } from "./manifest.js";
|
|
2
|
+
import { generateOpenApiSpec } from "./openapi.js";
|
|
3
|
+
import { createMcpServer } from "./mcp.js";
|
|
4
|
+
import { createA2AHandler } from "./a2a.js";
|
|
5
|
+
/**
|
|
6
|
+
* Unified capability registry — the central abstraction for Capstan's
|
|
7
|
+
* multi-protocol adapter layer.
|
|
8
|
+
*
|
|
9
|
+
* Register routes once, then project them to any supported protocol surface:
|
|
10
|
+
*
|
|
11
|
+
* - **Capstan manifest** (`/.well-known/capstan.json`)
|
|
12
|
+
* - **OpenAPI 3.1** (`/openapi.json`)
|
|
13
|
+
* - **MCP** (Model Context Protocol tools)
|
|
14
|
+
* - **A2A** (Google Agent-to-Agent protocol)
|
|
15
|
+
*
|
|
16
|
+
* One registry, four projections.
|
|
17
|
+
*/
|
|
18
|
+
export class CapabilityRegistry {
|
|
19
|
+
routes = [];
|
|
20
|
+
config;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
}
|
|
24
|
+
// -------------------------------------------------------------------------
|
|
25
|
+
// Registration
|
|
26
|
+
// -------------------------------------------------------------------------
|
|
27
|
+
/** Register a single route entry. */
|
|
28
|
+
register(route) {
|
|
29
|
+
this.routes.push(route);
|
|
30
|
+
}
|
|
31
|
+
/** Register multiple route entries at once. */
|
|
32
|
+
registerAll(routes) {
|
|
33
|
+
for (const route of routes) {
|
|
34
|
+
this.routes.push(route);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Get all registered routes (read-only view). */
|
|
38
|
+
getRoutes() {
|
|
39
|
+
return this.routes;
|
|
40
|
+
}
|
|
41
|
+
/** Get the agent configuration. */
|
|
42
|
+
getConfig() {
|
|
43
|
+
return this.config;
|
|
44
|
+
}
|
|
45
|
+
// -------------------------------------------------------------------------
|
|
46
|
+
// Projections
|
|
47
|
+
// -------------------------------------------------------------------------
|
|
48
|
+
/** Project to Capstan native agent manifest. */
|
|
49
|
+
toManifest() {
|
|
50
|
+
return generateAgentManifest(this.config, this.routes);
|
|
51
|
+
}
|
|
52
|
+
/** Project to OpenAPI 3.1 specification. */
|
|
53
|
+
toOpenApi() {
|
|
54
|
+
return generateOpenApiSpec(this.config, this.routes);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Project to MCP server.
|
|
58
|
+
*
|
|
59
|
+
* @param executeRoute - Callback that invokes the actual route handler
|
|
60
|
+
* given an HTTP method, path, and input payload.
|
|
61
|
+
* @returns The McpServer instance and a helper to list tool definitions.
|
|
62
|
+
*/
|
|
63
|
+
toMcp(executeRoute) {
|
|
64
|
+
return createMcpServer(this.config, this.routes, executeRoute);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Project to A2A agent card and JSON-RPC handler.
|
|
68
|
+
*
|
|
69
|
+
* @param executeRoute - Callback that invokes the actual route handler
|
|
70
|
+
* given an HTTP method, path, and input payload.
|
|
71
|
+
* @returns The A2A request handler and agent card accessor.
|
|
72
|
+
*/
|
|
73
|
+
toA2A(executeRoute) {
|
|
74
|
+
return createA2AHandler(this.config, this.routes, executeRoute);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,kBAAkB;IACrB,MAAM,GAAyB,EAAE,CAAC;IAClC,MAAM,CAAc;IAE5B,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,4EAA4E;IAC5E,eAAe;IACf,4EAA4E;IAE5E,qCAAqC;IACrC,QAAQ,CAAC,KAAyB;QAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,+CAA+C;IAC/C,WAAW,CAAC,MAA4B;QACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,mCAAmC;IACnC,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,4EAA4E;IAC5E,cAAc;IACd,4EAA4E;IAE5E,gDAAgD;IAChD,UAAU;QACR,OAAO,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAED,4CAA4C;IAC5C,SAAS;QACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CACH,YAIqB;QASrB,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CACH,YAIqB;QAKrB,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Agent manifest describing all capabilities of a Capstan application for AI consumption. */
|
|
2
|
+
export interface AgentManifest {
|
|
3
|
+
/** Manifest format version, e.g. "1.0". */
|
|
4
|
+
capstan: string;
|
|
5
|
+
/** Application name. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Optional human-readable description of the application. */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Base URL where the application is served. */
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** Authentication schemes the application accepts. */
|
|
12
|
+
authentication: {
|
|
13
|
+
schemes: Array<{
|
|
14
|
+
type: "bearer";
|
|
15
|
+
name: string;
|
|
16
|
+
header: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
/** Domain resources the application manages. */
|
|
21
|
+
resources: Array<{
|
|
22
|
+
key: string;
|
|
23
|
+
title: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
fields: Record<string, {
|
|
26
|
+
type: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
enum?: string[];
|
|
29
|
+
}>;
|
|
30
|
+
}>;
|
|
31
|
+
/** API capabilities (tools) exposed by the application. */
|
|
32
|
+
capabilities: Array<{
|
|
33
|
+
key: string;
|
|
34
|
+
title: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
mode: "read" | "write" | "external";
|
|
37
|
+
resource?: string;
|
|
38
|
+
endpoint: {
|
|
39
|
+
method: string;
|
|
40
|
+
path: string;
|
|
41
|
+
inputSchema?: Record<string, unknown>;
|
|
42
|
+
outputSchema?: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
policy?: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** MCP server configuration, if enabled. */
|
|
47
|
+
mcp?: {
|
|
48
|
+
endpoint: string;
|
|
49
|
+
transport: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** An entry in the route registry used to generate agent surfaces. */
|
|
53
|
+
export interface RouteRegistryEntry {
|
|
54
|
+
method: string;
|
|
55
|
+
path: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
capability?: "read" | "write" | "external";
|
|
58
|
+
resource?: string;
|
|
59
|
+
policy?: string;
|
|
60
|
+
inputSchema?: Record<string, unknown>;
|
|
61
|
+
outputSchema?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
/** Configuration for the agent surface layer. */
|
|
64
|
+
export interface AgentConfig {
|
|
65
|
+
name: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
baseUrl?: string;
|
|
68
|
+
resources?: Array<{
|
|
69
|
+
key: string;
|
|
70
|
+
title: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
fields: Record<string, {
|
|
73
|
+
type: string;
|
|
74
|
+
required?: boolean;
|
|
75
|
+
enum?: string[];
|
|
76
|
+
}>;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,cAAc,EAAE;QACd,OAAO,EAAE,KAAK,CAAC;YACb,IAAI,EAAE,QAAQ,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;IACF,gDAAgD;IAChD,SAAS,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CACtD,CAAC;KACH,CAAC,CAAC;IACH,2DAA2D;IAC3D,YAAY,EAAE,KAAK,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE;YACR,MAAM,EAAE,MAAM,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACxC,CAAC;QACF,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,4CAA4C;IAC5C,GAAG,CAAC,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CACtD,CAAC;KACH,CAAC,CAAC;CACJ"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zauso-ai/capstan-agent",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
19
|
+
},
|
|
20
|
+
"description": "Multi-protocol agent surface for Capstan — MCP server, A2A adapter, OpenAPI, manifest",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/barry3406/capstan.git",
|
|
27
|
+
"directory": "packages/agent"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "barry3406",
|
|
31
|
+
"homepage": "https://github.com/barry3406/capstan",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"capstan",
|
|
34
|
+
"ai-agent",
|
|
35
|
+
"full-stack",
|
|
36
|
+
"framework",
|
|
37
|
+
"mcp",
|
|
38
|
+
"a2a",
|
|
39
|
+
"typescript"
|
|
40
|
+
],
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|