@dexto/server 1.2.5

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.
Files changed (174) hide show
  1. package/LICENSE +44 -0
  2. package/dist/a2a/adapters/index.cjs +42 -0
  3. package/dist/a2a/adapters/index.d.ts +10 -0
  4. package/dist/a2a/adapters/index.d.ts.map +1 -0
  5. package/dist/a2a/adapters/index.js +12 -0
  6. package/dist/a2a/adapters/message.cjs +193 -0
  7. package/dist/a2a/adapters/message.d.ts +50 -0
  8. package/dist/a2a/adapters/message.d.ts.map +1 -0
  9. package/dist/a2a/adapters/message.js +167 -0
  10. package/dist/a2a/adapters/state.cjs +57 -0
  11. package/dist/a2a/adapters/state.d.ts +36 -0
  12. package/dist/a2a/adapters/state.d.ts.map +1 -0
  13. package/dist/a2a/adapters/state.js +32 -0
  14. package/dist/a2a/adapters/task-view.cjs +85 -0
  15. package/dist/a2a/adapters/task-view.d.ts +58 -0
  16. package/dist/a2a/adapters/task-view.d.ts.map +1 -0
  17. package/dist/a2a/adapters/task-view.js +60 -0
  18. package/dist/a2a/index.cjs +51 -0
  19. package/dist/a2a/index.d.ts +15 -0
  20. package/dist/a2a/index.d.ts.map +1 -0
  21. package/dist/a2a/index.js +30 -0
  22. package/dist/a2a/jsonrpc/index.cjs +38 -0
  23. package/dist/a2a/jsonrpc/index.d.ts +11 -0
  24. package/dist/a2a/jsonrpc/index.d.ts.map +1 -0
  25. package/dist/a2a/jsonrpc/index.js +10 -0
  26. package/dist/a2a/jsonrpc/methods.cjs +183 -0
  27. package/dist/a2a/jsonrpc/methods.d.ts +110 -0
  28. package/dist/a2a/jsonrpc/methods.d.ts.map +1 -0
  29. package/dist/a2a/jsonrpc/methods.js +159 -0
  30. package/dist/a2a/jsonrpc/server.cjs +199 -0
  31. package/dist/a2a/jsonrpc/server.d.ts +100 -0
  32. package/dist/a2a/jsonrpc/server.d.ts.map +1 -0
  33. package/dist/a2a/jsonrpc/server.js +175 -0
  34. package/dist/a2a/jsonrpc/types.cjs +47 -0
  35. package/dist/a2a/jsonrpc/types.d.ts +91 -0
  36. package/dist/a2a/jsonrpc/types.d.ts.map +1 -0
  37. package/dist/a2a/jsonrpc/types.js +21 -0
  38. package/dist/a2a/types.cjs +16 -0
  39. package/dist/a2a/types.d.ts +250 -0
  40. package/dist/a2a/types.d.ts.map +1 -0
  41. package/dist/a2a/types.js +0 -0
  42. package/dist/approval/approval-coordinator.cjs +87 -0
  43. package/dist/approval/approval-coordinator.d.ts +52 -0
  44. package/dist/approval/approval-coordinator.d.ts.map +1 -0
  45. package/dist/approval/approval-coordinator.js +63 -0
  46. package/dist/approval/manual-approval-handler.cjs +100 -0
  47. package/dist/approval/manual-approval-handler.d.ts +32 -0
  48. package/dist/approval/manual-approval-handler.d.ts.map +1 -0
  49. package/dist/approval/manual-approval-handler.js +76 -0
  50. package/dist/events/a2a-sse-subscriber.cjs +271 -0
  51. package/dist/events/a2a-sse-subscriber.d.ts +94 -0
  52. package/dist/events/a2a-sse-subscriber.d.ts.map +1 -0
  53. package/dist/events/a2a-sse-subscriber.js +247 -0
  54. package/dist/events/types.cjs +16 -0
  55. package/dist/events/types.d.ts +15 -0
  56. package/dist/events/types.d.ts.map +1 -0
  57. package/dist/events/types.js +0 -0
  58. package/dist/events/webhook-subscriber.cjs +301 -0
  59. package/dist/events/webhook-subscriber.d.ts +64 -0
  60. package/dist/events/webhook-subscriber.d.ts.map +1 -0
  61. package/dist/events/webhook-subscriber.js +269 -0
  62. package/dist/events/webhook-types.cjs +16 -0
  63. package/dist/events/webhook-types.d.ts +91 -0
  64. package/dist/events/webhook-types.d.ts.map +1 -0
  65. package/dist/events/webhook-types.js +0 -0
  66. package/dist/hono/__tests__/test-fixtures.cjs +236 -0
  67. package/dist/hono/__tests__/test-fixtures.d.ts +65 -0
  68. package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -0
  69. package/dist/hono/__tests__/test-fixtures.js +197 -0
  70. package/dist/hono/index.cjs +166 -0
  71. package/dist/hono/index.d.ts +2783 -0
  72. package/dist/hono/index.d.ts.map +1 -0
  73. package/dist/hono/index.js +141 -0
  74. package/dist/hono/middleware/auth.cjs +75 -0
  75. package/dist/hono/middleware/auth.d.ts +3 -0
  76. package/dist/hono/middleware/auth.d.ts.map +1 -0
  77. package/dist/hono/middleware/auth.js +51 -0
  78. package/dist/hono/middleware/cors.cjs +57 -0
  79. package/dist/hono/middleware/cors.d.ts +9 -0
  80. package/dist/hono/middleware/cors.d.ts.map +1 -0
  81. package/dist/hono/middleware/cors.js +33 -0
  82. package/dist/hono/middleware/error.cjs +131 -0
  83. package/dist/hono/middleware/error.d.ts +5 -0
  84. package/dist/hono/middleware/error.d.ts.map +1 -0
  85. package/dist/hono/middleware/error.js +105 -0
  86. package/dist/hono/middleware/redaction.cjs +45 -0
  87. package/dist/hono/middleware/redaction.d.ts +4 -0
  88. package/dist/hono/middleware/redaction.d.ts.map +1 -0
  89. package/dist/hono/middleware/redaction.js +20 -0
  90. package/dist/hono/node/index.cjs +139 -0
  91. package/dist/hono/node/index.d.ts +19 -0
  92. package/dist/hono/node/index.d.ts.map +1 -0
  93. package/dist/hono/node/index.js +115 -0
  94. package/dist/hono/routes/a2a-jsonrpc.cjs +119 -0
  95. package/dist/hono/routes/a2a-jsonrpc.d.ts +46 -0
  96. package/dist/hono/routes/a2a-jsonrpc.d.ts.map +1 -0
  97. package/dist/hono/routes/a2a-jsonrpc.js +95 -0
  98. package/dist/hono/routes/a2a-tasks.cjs +315 -0
  99. package/dist/hono/routes/a2a-tasks.d.ts +530 -0
  100. package/dist/hono/routes/a2a-tasks.d.ts.map +1 -0
  101. package/dist/hono/routes/a2a-tasks.js +291 -0
  102. package/dist/hono/routes/a2a.cjs +36 -0
  103. package/dist/hono/routes/a2a.d.ts +4 -0
  104. package/dist/hono/routes/a2a.d.ts.map +1 -0
  105. package/dist/hono/routes/a2a.js +12 -0
  106. package/dist/hono/routes/agents.cjs +735 -0
  107. package/dist/hono/routes/agents.d.ts +650 -0
  108. package/dist/hono/routes/agents.d.ts.map +1 -0
  109. package/dist/hono/routes/agents.js +711 -0
  110. package/dist/hono/routes/approvals.cjs +125 -0
  111. package/dist/hono/routes/approvals.d.ts +89 -0
  112. package/dist/hono/routes/approvals.d.ts.map +1 -0
  113. package/dist/hono/routes/approvals.js +101 -0
  114. package/dist/hono/routes/greeting.cjs +60 -0
  115. package/dist/hono/routes/greeting.d.ts +19 -0
  116. package/dist/hono/routes/greeting.d.ts.map +1 -0
  117. package/dist/hono/routes/greeting.js +36 -0
  118. package/dist/hono/routes/health.cjs +45 -0
  119. package/dist/hono/routes/health.d.ts +17 -0
  120. package/dist/hono/routes/health.d.ts.map +1 -0
  121. package/dist/hono/routes/health.js +21 -0
  122. package/dist/hono/routes/llm.cjs +298 -0
  123. package/dist/hono/routes/llm.d.ts +294 -0
  124. package/dist/hono/routes/llm.d.ts.map +1 -0
  125. package/dist/hono/routes/llm.js +287 -0
  126. package/dist/hono/routes/mcp.cjs +356 -0
  127. package/dist/hono/routes/mcp.d.ts +246 -0
  128. package/dist/hono/routes/mcp.d.ts.map +1 -0
  129. package/dist/hono/routes/mcp.js +332 -0
  130. package/dist/hono/routes/memory.cjs +192 -0
  131. package/dist/hono/routes/memory.d.ts +146 -0
  132. package/dist/hono/routes/memory.d.ts.map +1 -0
  133. package/dist/hono/routes/memory.js +168 -0
  134. package/dist/hono/routes/messages.cjs +320 -0
  135. package/dist/hono/routes/messages.d.ts +163 -0
  136. package/dist/hono/routes/messages.d.ts.map +1 -0
  137. package/dist/hono/routes/messages.js +296 -0
  138. package/dist/hono/routes/prompts.cjs +228 -0
  139. package/dist/hono/routes/prompts.d.ts +150 -0
  140. package/dist/hono/routes/prompts.d.ts.map +1 -0
  141. package/dist/hono/routes/prompts.js +204 -0
  142. package/dist/hono/routes/resources.cjs +110 -0
  143. package/dist/hono/routes/resources.d.ts +76 -0
  144. package/dist/hono/routes/resources.d.ts.map +1 -0
  145. package/dist/hono/routes/resources.js +86 -0
  146. package/dist/hono/routes/search.cjs +109 -0
  147. package/dist/hono/routes/search.d.ts +137 -0
  148. package/dist/hono/routes/search.d.ts.map +1 -0
  149. package/dist/hono/routes/search.js +85 -0
  150. package/dist/hono/routes/sessions.cjs +366 -0
  151. package/dist/hono/routes/sessions.d.ts +229 -0
  152. package/dist/hono/routes/sessions.d.ts.map +1 -0
  153. package/dist/hono/routes/sessions.js +342 -0
  154. package/dist/hono/routes/webhooks.cjs +228 -0
  155. package/dist/hono/routes/webhooks.d.ts +127 -0
  156. package/dist/hono/routes/webhooks.d.ts.map +1 -0
  157. package/dist/hono/routes/webhooks.js +204 -0
  158. package/dist/hono/schemas/responses.cjs +276 -0
  159. package/dist/hono/schemas/responses.d.ts +1418 -0
  160. package/dist/hono/schemas/responses.d.ts.map +1 -0
  161. package/dist/hono/schemas/responses.js +227 -0
  162. package/dist/hono/types.cjs +16 -0
  163. package/dist/hono/types.d.ts +6 -0
  164. package/dist/hono/types.d.ts.map +1 -0
  165. package/dist/hono/types.js +0 -0
  166. package/dist/index.cjs +38 -0
  167. package/dist/index.d.ts +11 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +9 -0
  170. package/dist/mcp/mcp-handler.cjs +145 -0
  171. package/dist/mcp/mcp-handler.d.ts +14 -0
  172. package/dist/mcp/mcp-handler.d.ts.map +1 -0
  173. package/dist/mcp/mcp-handler.js +118 -0
  174. package/package.json +59 -0
@@ -0,0 +1,246 @@
1
+ import { OpenAPIHono } from '@hono/zod-openapi';
2
+ import type { DextoAgent } from '@dexto/core';
3
+ export declare function createMcpRouter(getAgent: () => DextoAgent): OpenAPIHono<import("hono").Env, {
4
+ "/mcp/servers": {
5
+ $post: {
6
+ input: {
7
+ json: {
8
+ config: {
9
+ type: "stdio";
10
+ command: string;
11
+ timeout?: number | undefined;
12
+ args?: string[] | undefined;
13
+ env?: Record<string, string> | undefined;
14
+ connectionMode?: "strict" | "lenient" | undefined;
15
+ } | {
16
+ type: "sse";
17
+ url: string;
18
+ timeout?: number | undefined;
19
+ connectionMode?: "strict" | "lenient" | undefined;
20
+ headers?: Record<string, string> | undefined;
21
+ } | {
22
+ type: "http";
23
+ url: string;
24
+ timeout?: number | undefined;
25
+ connectionMode?: "strict" | "lenient" | undefined;
26
+ headers?: Record<string, string> | undefined;
27
+ };
28
+ name: string;
29
+ persistToAgent?: boolean | undefined;
30
+ };
31
+ };
32
+ output: {
33
+ status: string;
34
+ name: string;
35
+ };
36
+ outputFormat: "json";
37
+ status: 200;
38
+ };
39
+ };
40
+ } & {
41
+ "/mcp/servers": {
42
+ $get: {
43
+ input: {};
44
+ output: {
45
+ servers: {
46
+ status: "error" | "connected" | "disconnected";
47
+ id: string;
48
+ name: string;
49
+ }[];
50
+ };
51
+ outputFormat: "json";
52
+ status: 200;
53
+ };
54
+ };
55
+ } & {
56
+ "/mcp/servers/:serverId/tools": {
57
+ $get: {
58
+ input: {
59
+ param: {
60
+ serverId: string;
61
+ };
62
+ };
63
+ output: {};
64
+ outputFormat: string;
65
+ status: 404;
66
+ } | {
67
+ input: {
68
+ param: {
69
+ serverId: string;
70
+ };
71
+ };
72
+ output: {
73
+ tools: {
74
+ description: string;
75
+ id: string;
76
+ name: string;
77
+ inputSchema?: {
78
+ [x: string]: import("hono/utils/types").JSONValue;
79
+ type?: "object" | undefined;
80
+ properties?: {
81
+ [x: string]: {
82
+ [x: string]: import("hono/utils/types").JSONValue;
83
+ description?: string | undefined;
84
+ default?: any;
85
+ type?: "string" | "number" | "boolean" | "object" | "integer" | "array" | undefined;
86
+ enum?: (string | number | boolean)[] | undefined;
87
+ };
88
+ } | undefined;
89
+ required?: string[] | undefined;
90
+ } | undefined;
91
+ }[];
92
+ };
93
+ outputFormat: "json";
94
+ status: 200;
95
+ };
96
+ };
97
+ } & {
98
+ "/mcp/servers/:serverId": {
99
+ $delete: {
100
+ input: {
101
+ param: {
102
+ serverId: string;
103
+ };
104
+ };
105
+ output: {};
106
+ outputFormat: string;
107
+ status: 404;
108
+ } | {
109
+ input: {
110
+ param: {
111
+ serverId: string;
112
+ };
113
+ };
114
+ output: {
115
+ status: "disconnected";
116
+ id: string;
117
+ };
118
+ outputFormat: "json";
119
+ status: 200;
120
+ };
121
+ };
122
+ } & {
123
+ "/mcp/servers/:serverId/restart": {
124
+ $post: {
125
+ input: {
126
+ param: {
127
+ serverId: string;
128
+ };
129
+ };
130
+ output: {};
131
+ outputFormat: string;
132
+ status: 404;
133
+ } | {
134
+ input: {
135
+ param: {
136
+ serverId: string;
137
+ };
138
+ };
139
+ output: {
140
+ status: "restarted";
141
+ id: string;
142
+ };
143
+ outputFormat: "json";
144
+ status: 200;
145
+ };
146
+ };
147
+ } & {
148
+ "/mcp/servers/:serverId/tools/:toolName/execute": {
149
+ $post: {
150
+ input: {
151
+ param: {
152
+ serverId: string;
153
+ toolName: string;
154
+ };
155
+ } & {
156
+ json: Record<string, unknown>;
157
+ };
158
+ output: {};
159
+ outputFormat: string;
160
+ status: 404;
161
+ } | {
162
+ input: {
163
+ param: {
164
+ serverId: string;
165
+ toolName: string;
166
+ };
167
+ } & {
168
+ json: Record<string, unknown>;
169
+ };
170
+ output: {
171
+ success: boolean;
172
+ data?: any;
173
+ error?: string | undefined;
174
+ };
175
+ outputFormat: "json";
176
+ status: 200;
177
+ };
178
+ };
179
+ } & {
180
+ "/mcp/servers/:serverId/resources": {
181
+ $get: {
182
+ input: {
183
+ param: {
184
+ serverId: string;
185
+ };
186
+ };
187
+ output: {};
188
+ outputFormat: string;
189
+ status: 404;
190
+ } | {
191
+ input: {
192
+ param: {
193
+ serverId: string;
194
+ };
195
+ };
196
+ output: {
197
+ success: boolean;
198
+ resources: {
199
+ uri: string;
200
+ source: "mcp" | "internal";
201
+ description?: string | undefined;
202
+ mimeType?: string | undefined;
203
+ name?: string | undefined;
204
+ metadata?: {
205
+ [x: string]: import("hono/utils/types").JSONValue;
206
+ } | undefined;
207
+ serverName?: string | undefined;
208
+ size?: number | undefined;
209
+ lastModified?: string | undefined;
210
+ }[];
211
+ };
212
+ outputFormat: "json";
213
+ status: 200;
214
+ };
215
+ };
216
+ } & {
217
+ "/mcp/servers/:serverId/resources/:resourceId/content": {
218
+ $get: {
219
+ input: {
220
+ param: {
221
+ serverId: string;
222
+ resourceId: string;
223
+ };
224
+ };
225
+ output: {};
226
+ outputFormat: string;
227
+ status: 404;
228
+ } | {
229
+ input: {
230
+ param: {
231
+ serverId: string;
232
+ resourceId: string;
233
+ };
234
+ };
235
+ output: {
236
+ data: {
237
+ content?: any;
238
+ };
239
+ success: boolean;
240
+ };
241
+ outputFormat: "json";
242
+ status: 200;
243
+ };
244
+ };
245
+ }, "/">;
246
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/hono/routes/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0I9C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4SzD"}
@@ -0,0 +1,332 @@
1
+ import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
2
+ import { logger, McpServerConfigSchema } from "@dexto/core";
3
+ import { updateAgentConfigFile } from "@dexto/agent-management";
4
+ import { ResourceSchema } from "../schemas/responses.js";
5
+ const McpServerRequestSchema = z.object({
6
+ name: z.string().min(1, "Server name is required").describe("A unique name for the server"),
7
+ config: McpServerConfigSchema.describe("The server configuration object"),
8
+ persistToAgent: z.boolean().optional().describe("If true, saves the server to agent configuration file")
9
+ }).describe("Request body for adding or updating an MCP server");
10
+ const ExecuteToolBodySchema = z.record(z.unknown()).describe(
11
+ "Tool execution parameters as JSON object. The specific fields depend on the tool being executed and are defined by the tool's inputSchema."
12
+ );
13
+ const ServerStatusResponseSchema = z.object({
14
+ status: z.string().describe("Connection status"),
15
+ name: z.string().describe("Server name")
16
+ }).strict().describe("Server status response");
17
+ const ServerInfoSchema = z.object({
18
+ id: z.string().describe("Server identifier"),
19
+ name: z.string().describe("Server name"),
20
+ status: z.enum(["connected", "error", "disconnected"]).describe("Server status")
21
+ }).strict().describe("MCP server information");
22
+ const ServersListResponseSchema = z.object({
23
+ servers: z.array(ServerInfoSchema).describe("Array of server information")
24
+ }).strict().describe("List of MCP servers");
25
+ const JsonSchemaProperty = z.object({
26
+ type: z.enum(["string", "number", "integer", "boolean", "object", "array"]).optional().describe("Property type"),
27
+ description: z.string().optional().describe("Property description"),
28
+ enum: z.array(z.union([z.string(), z.number(), z.boolean()])).optional().describe("Enum values"),
29
+ default: z.any().optional().describe("Default value")
30
+ }).passthrough().describe("JSON Schema property definition");
31
+ const ToolInputSchema = z.object({
32
+ type: z.literal("object").optional().describe('Schema type, always "object" when present'),
33
+ properties: z.record(JsonSchemaProperty).optional().describe("Property definitions"),
34
+ required: z.array(z.string()).optional().describe("Required property names")
35
+ }).passthrough().describe("JSON Schema for tool input parameters");
36
+ const ToolInfoSchema = z.object({
37
+ id: z.string().describe("Tool identifier"),
38
+ name: z.string().describe("Tool name"),
39
+ description: z.string().describe("Tool description"),
40
+ inputSchema: ToolInputSchema.optional().describe("JSON Schema for tool input parameters")
41
+ }).strict().describe("Tool information");
42
+ const ToolsListResponseSchema = z.object({
43
+ tools: z.array(ToolInfoSchema).describe("Array of available tools")
44
+ }).strict().describe("List of tools from MCP server");
45
+ const DisconnectResponseSchema = z.object({
46
+ status: z.literal("disconnected").describe("Disconnection status"),
47
+ id: z.string().describe("Server identifier")
48
+ }).strict().describe("Server disconnection response");
49
+ const RestartResponseSchema = z.object({
50
+ status: z.literal("restarted").describe("Restart status"),
51
+ id: z.string().describe("Server identifier")
52
+ }).strict().describe("Server restart response");
53
+ const ToolExecutionResponseSchema = z.object({
54
+ success: z.boolean().describe("Whether tool execution succeeded"),
55
+ data: z.any().optional().describe("Tool execution result data"),
56
+ error: z.string().optional().describe("Error message if execution failed")
57
+ }).strict().describe("Tool execution response");
58
+ const ResourcesListResponseSchema = z.object({
59
+ success: z.boolean().describe("Success indicator"),
60
+ resources: z.array(ResourceSchema).describe("Array of available resources")
61
+ }).strict().describe("List of resources from MCP server");
62
+ const ResourceContentSchema = z.object({
63
+ content: z.any().describe("Resource content data")
64
+ }).strict().describe("Resource content wrapper");
65
+ const ResourceContentResponseSchema = z.object({
66
+ success: z.boolean().describe("Success indicator"),
67
+ data: ResourceContentSchema.describe("Resource content")
68
+ }).strict().describe("Resource content response");
69
+ function createMcpRouter(getAgent) {
70
+ const app = new OpenAPIHono();
71
+ const addServerRoute = createRoute({
72
+ method: "post",
73
+ path: "/mcp/servers",
74
+ summary: "Add MCP Server",
75
+ description: "Connects a new MCP server dynamically",
76
+ tags: ["mcp"],
77
+ request: { body: { content: { "application/json": { schema: McpServerRequestSchema } } } },
78
+ responses: {
79
+ 200: {
80
+ description: "Server connected",
81
+ content: { "application/json": { schema: ServerStatusResponseSchema } }
82
+ }
83
+ }
84
+ });
85
+ const listServersRoute = createRoute({
86
+ method: "get",
87
+ path: "/mcp/servers",
88
+ summary: "List MCP Servers",
89
+ description: "Gets a list of all connected and failed MCP servers",
90
+ tags: ["mcp"],
91
+ responses: {
92
+ 200: {
93
+ description: "Servers list",
94
+ content: { "application/json": { schema: ServersListResponseSchema } }
95
+ }
96
+ }
97
+ });
98
+ const toolsRoute = createRoute({
99
+ method: "get",
100
+ path: "/mcp/servers/{serverId}/tools",
101
+ summary: "List Server Tools",
102
+ description: "Retrieves the list of tools available on a specific MCP server",
103
+ tags: ["mcp"],
104
+ request: {
105
+ params: z.object({ serverId: z.string().describe("The ID of the MCP server") })
106
+ },
107
+ responses: {
108
+ 200: {
109
+ description: "Tools list",
110
+ content: { "application/json": { schema: ToolsListResponseSchema } }
111
+ },
112
+ 404: { description: "Not found" }
113
+ }
114
+ });
115
+ const deleteServerRoute = createRoute({
116
+ method: "delete",
117
+ path: "/mcp/servers/{serverId}",
118
+ summary: "Remove MCP Server",
119
+ description: "Disconnects and removes an MCP server",
120
+ tags: ["mcp"],
121
+ request: {
122
+ params: z.object({ serverId: z.string().describe("The ID of the MCP server") })
123
+ },
124
+ responses: {
125
+ 200: {
126
+ description: "Disconnected",
127
+ content: { "application/json": { schema: DisconnectResponseSchema } }
128
+ },
129
+ 404: { description: "Not found" }
130
+ }
131
+ });
132
+ const restartServerRoute = createRoute({
133
+ method: "post",
134
+ path: "/mcp/servers/{serverId}/restart",
135
+ summary: "Restart MCP Server",
136
+ description: "Restarts a connected MCP server",
137
+ tags: ["mcp"],
138
+ request: {
139
+ params: z.object({ serverId: z.string().describe("The ID of the MCP server") })
140
+ },
141
+ responses: {
142
+ 200: {
143
+ description: "Server restarted",
144
+ content: { "application/json": { schema: RestartResponseSchema } }
145
+ },
146
+ 404: { description: "Not found" }
147
+ }
148
+ });
149
+ const execToolRoute = createRoute({
150
+ method: "post",
151
+ path: "/mcp/servers/{serverId}/tools/{toolName}/execute",
152
+ summary: "Execute MCP Tool",
153
+ description: "Executes a tool on an MCP server directly",
154
+ tags: ["mcp"],
155
+ request: {
156
+ params: z.object({
157
+ serverId: z.string().describe("The ID of the MCP server"),
158
+ toolName: z.string().describe("The name of the tool to execute")
159
+ }),
160
+ body: { content: { "application/json": { schema: ExecuteToolBodySchema } } }
161
+ },
162
+ responses: {
163
+ 200: {
164
+ description: "Tool executed",
165
+ content: { "application/json": { schema: ToolExecutionResponseSchema } }
166
+ },
167
+ 404: { description: "Not found" }
168
+ }
169
+ });
170
+ const listResourcesRoute = createRoute({
171
+ method: "get",
172
+ path: "/mcp/servers/{serverId}/resources",
173
+ summary: "List Server Resources",
174
+ description: "Retrieves all resources available from a specific MCP server",
175
+ tags: ["mcp"],
176
+ request: {
177
+ params: z.object({ serverId: z.string().describe("The ID of the MCP server") })
178
+ },
179
+ responses: {
180
+ 200: {
181
+ description: "Server resources",
182
+ content: { "application/json": { schema: ResourcesListResponseSchema } }
183
+ },
184
+ 404: { description: "Not found" }
185
+ }
186
+ });
187
+ const getResourceContentRoute = createRoute({
188
+ method: "get",
189
+ path: "/mcp/servers/{serverId}/resources/{resourceId}/content",
190
+ summary: "Read Server Resource Content",
191
+ description: "Reads content from a specific resource on an MCP server. This endpoint automatically constructs the qualified URI format (mcp:serverId:resourceId)",
192
+ tags: ["mcp"],
193
+ request: {
194
+ params: z.object({
195
+ serverId: z.string().describe("The ID of the MCP server"),
196
+ resourceId: z.string().min(1, "Resource ID is required").transform((encoded) => decodeURIComponent(encoded)).describe("The URI-encoded resource identifier on that server")
197
+ })
198
+ },
199
+ responses: {
200
+ 200: {
201
+ description: "Resource content",
202
+ content: { "application/json": { schema: ResourceContentResponseSchema } }
203
+ },
204
+ 404: { description: "Not found" }
205
+ }
206
+ });
207
+ return app.openapi(addServerRoute, async (ctx) => {
208
+ const agent = getAgent();
209
+ const { name, config, persistToAgent } = ctx.req.valid("json");
210
+ await agent.connectMcpServer(name, config);
211
+ logger.info(`Successfully connected to new server '${name}' via API request.`);
212
+ if (persistToAgent === true) {
213
+ try {
214
+ const currentConfig = agent.getEffectiveConfig();
215
+ const updates = {
216
+ mcpServers: {
217
+ ...currentConfig.mcpServers || {},
218
+ [name]: config
219
+ }
220
+ };
221
+ const newConfig = await updateAgentConfigFile(
222
+ agent.getAgentFilePath(),
223
+ updates
224
+ );
225
+ const reloadResult = await agent.reload(newConfig);
226
+ if (reloadResult.restarted) {
227
+ logger.info(
228
+ `Agent restarted to apply changes: ${reloadResult.changesApplied.join(", ")}`
229
+ );
230
+ }
231
+ logger.info(`Saved server '${name}' to agent configuration file`);
232
+ } catch (saveError) {
233
+ const errorMessage = saveError instanceof Error ? saveError.message : String(saveError);
234
+ logger.warn(
235
+ `Failed to save server '${name}' to agent config: ${errorMessage}`,
236
+ {
237
+ error: saveError
238
+ }
239
+ );
240
+ }
241
+ }
242
+ return ctx.json({ status: "connected", name }, 200);
243
+ }).openapi(listServersRoute, async (ctx) => {
244
+ const agent = getAgent();
245
+ const clientsMap = agent.getMcpClients();
246
+ const failedConnections = agent.getMcpFailedConnections();
247
+ const servers = [];
248
+ for (const name of clientsMap.keys()) {
249
+ servers.push({ id: name, name, status: "connected" });
250
+ }
251
+ for (const name of Object.keys(failedConnections)) {
252
+ servers.push({ id: name, name, status: "error" });
253
+ }
254
+ return ctx.json({ servers });
255
+ }).openapi(toolsRoute, async (ctx) => {
256
+ const agent = getAgent();
257
+ const { serverId } = ctx.req.valid("param");
258
+ const client = agent.getMcpClients().get(serverId);
259
+ if (!client) {
260
+ return ctx.json({ error: `Server '${serverId}' not found` }, 404);
261
+ }
262
+ const toolsMap = await client.getTools();
263
+ const tools = Object.entries(toolsMap).map(([toolName, toolDef]) => ({
264
+ id: toolName,
265
+ name: toolName,
266
+ description: toolDef.description || "",
267
+ inputSchema: toolDef.parameters
268
+ }));
269
+ return ctx.json({ tools });
270
+ }).openapi(deleteServerRoute, async (ctx) => {
271
+ const agent = getAgent();
272
+ const { serverId } = ctx.req.valid("param");
273
+ const clientExists = agent.getMcpClients().has(serverId) || agent.getMcpFailedConnections()[serverId];
274
+ if (!clientExists) {
275
+ return ctx.json({ error: `Server '${serverId}' not found.` }, 404);
276
+ }
277
+ await agent.removeMcpServer(serverId);
278
+ return ctx.json({ status: "disconnected", id: serverId });
279
+ }).openapi(restartServerRoute, async (ctx) => {
280
+ const agent = getAgent();
281
+ const { serverId } = ctx.req.valid("param");
282
+ logger.info(`Received request to POST /api/mcp/servers/${serverId}/restart`);
283
+ const clientExists = agent.getMcpClients().has(serverId);
284
+ if (!clientExists) {
285
+ logger.warn(`Attempted to restart non-existent server: ${serverId}`);
286
+ return ctx.json({ error: `Server '${serverId}' not found.` }, 404);
287
+ }
288
+ await agent.restartMcpServer(serverId);
289
+ return ctx.json({ status: "restarted", id: serverId });
290
+ }).openapi(execToolRoute, async (ctx) => {
291
+ const agent = getAgent();
292
+ const { serverId, toolName } = ctx.req.valid("param");
293
+ const body = ctx.req.valid("json");
294
+ const client = agent.getMcpClients().get(serverId);
295
+ if (!client) {
296
+ return ctx.json({ success: false, error: `Server '${serverId}' not found` }, 404);
297
+ }
298
+ try {
299
+ const rawResult = await client.callTool(toolName, body);
300
+ return ctx.json({ success: true, data: rawResult });
301
+ } catch (error) {
302
+ const errorMessage = error instanceof Error ? error.message : String(error);
303
+ logger.error(
304
+ `Tool execution failed for '${toolName}' on server '${serverId}': ${errorMessage}`,
305
+ { error }
306
+ );
307
+ return ctx.json({ success: false, error: errorMessage }, 200);
308
+ }
309
+ }).openapi(listResourcesRoute, async (ctx) => {
310
+ const agent = getAgent();
311
+ const { serverId } = ctx.req.valid("param");
312
+ const client = agent.getMcpClients().get(serverId);
313
+ if (!client) {
314
+ return ctx.json({ error: `Server '${serverId}' not found` }, 404);
315
+ }
316
+ const resources = await agent.listResourcesForServer(serverId);
317
+ return ctx.json({ success: true, resources });
318
+ }).openapi(getResourceContentRoute, async (ctx) => {
319
+ const agent = getAgent();
320
+ const { serverId, resourceId } = ctx.req.valid("param");
321
+ const client = agent.getMcpClients().get(serverId);
322
+ if (!client) {
323
+ return ctx.json({ error: `Server '${serverId}' not found` }, 404);
324
+ }
325
+ const qualifiedUri = `mcp:${serverId}:${resourceId}`;
326
+ const content = await agent.readResource(qualifiedUri);
327
+ return ctx.json({ success: true, data: { content } });
328
+ });
329
+ }
330
+ export {
331
+ createMcpRouter
332
+ };