@deimoscloud/coreai 0.1.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/.prettierrc +9 -0
- package/AGENT_SPEC.md +347 -0
- package/ARCHITECTURE.md +547 -0
- package/DRAFT_PRD.md +1440 -0
- package/IMPLEMENTATION_PLAN.md +256 -0
- package/PRODUCT.md +473 -0
- package/README.md +303 -0
- package/WORKFLOWS.md +295 -0
- package/agents/_templates/ic-engineer.md +185 -0
- package/agents/_templates/reviewer.md +182 -0
- package/agents/backend-engineer.yaml +72 -0
- package/agents/devops-engineer.yaml +72 -0
- package/agents/engineering-manager.yaml +70 -0
- package/agents/examples/android-engineer.md +302 -0
- package/agents/examples/backend-engineer.md +320 -0
- package/agents/examples/devops-engineer.md +742 -0
- package/agents/examples/engineering-manager.md +469 -0
- package/agents/examples/frontend-engineer.md +58 -0
- package/agents/examples/product-manager.md +315 -0
- package/agents/examples/qa-engineer.md +371 -0
- package/agents/examples/security-engineer.md +525 -0
- package/agents/examples/solutions-architect.md +351 -0
- package/agents/examples/wearos-engineer.md +359 -0
- package/agents/frontend-engineer.yaml +72 -0
- package/commands/core/check-inbox.md +34 -0
- package/commands/core/delegate.md +30 -0
- package/commands/core/git-commit.md +144 -0
- package/commands/core/pr-create.md +193 -0
- package/commands/core/review.md +56 -0
- package/commands/core/sprint-status.md +65 -0
- package/commands/optional/docs-update.md +200 -0
- package/commands/optional/jira-create.md +200 -0
- package/commands/optional/jira-transition.md +184 -0
- package/commands/optional/worktree-cleanup.md +167 -0
- package/commands/optional/worktree-setup.md +110 -0
- package/dist/cli/index.js +4037 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +2978 -0
- package/dist/index.js +3867 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +29 -0
- package/jest.config.js +22 -0
- package/knowledge-library/README.md +118 -0
- package/knowledge-library/android-engineer/context/current.txt +42 -0
- package/knowledge-library/android-engineer/control/decisions.txt +9 -0
- package/knowledge-library/android-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/android-engineer/control/objectives.txt +26 -0
- package/knowledge-library/android-engineer/history/.gitkeep +0 -0
- package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/architecture.txt +61 -0
- package/knowledge-library/backend-engineer/context/current.txt +42 -0
- package/knowledge-library/backend-engineer/control/decisions.txt +9 -0
- package/knowledge-library/backend-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/backend-engineer/control/objectives.txt +26 -0
- package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/context.txt +52 -0
- package/knowledge-library/devops-engineer/context/current.txt +42 -0
- package/knowledge-library/devops-engineer/control/decisions.txt +9 -0
- package/knowledge-library/devops-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/devops-engineer/control/objectives.txt +26 -0
- package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/context/current.txt +40 -0
- package/knowledge-library/engineering-manager/control/decisions.txt +9 -0
- package/knowledge-library/engineering-manager/control/objectives.txt +27 -0
- package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
- package/knowledge-library/prd.txt +81 -0
- package/knowledge-library/product-manager/context/current.txt +42 -0
- package/knowledge-library/product-manager/control/decisions.txt +9 -0
- package/knowledge-library/product-manager/control/dependencies.txt +19 -0
- package/knowledge-library/product-manager/control/objectives.txt +26 -0
- package/knowledge-library/product-manager/history/.gitkeep +0 -0
- package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/product-manager/tech/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/context/current.txt +42 -0
- package/knowledge-library/qa-engineer/control/decisions.txt +9 -0
- package/knowledge-library/qa-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/qa-engineer/control/objectives.txt +26 -0
- package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/security-engineer/context/current.txt +42 -0
- package/knowledge-library/security-engineer/control/decisions.txt +9 -0
- package/knowledge-library/security-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/security-engineer/control/objectives.txt +26 -0
- package/knowledge-library/security-engineer/history/.gitkeep +0 -0
- package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/context/current.txt +42 -0
- package/knowledge-library/solutions-architect/control/decisions.txt +9 -0
- package/knowledge-library/solutions-architect/control/dependencies.txt +19 -0
- package/knowledge-library/solutions-architect/control/objectives.txt +26 -0
- package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/context/current.txt +42 -0
- package/knowledge-library/wearos-engineer/control/decisions.txt +9 -0
- package/knowledge-library/wearos-engineer/control/dependencies.txt +19 -0
- package/knowledge-library/wearos-engineer/control/objectives.txt +26 -0
- package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
- package/package.json +66 -0
- package/schemas/agent.schema.json +171 -0
- package/schemas/coreai.config.schema.json +257 -0
- package/scripts/add-agent.sh +323 -0
- package/scripts/install.sh +354 -0
- package/src/adapters/factory.test.ts +386 -0
- package/src/adapters/factory.ts +305 -0
- package/src/adapters/index.ts +113 -0
- package/src/adapters/interfaces.ts +268 -0
- package/src/adapters/mcp/client.test.ts +130 -0
- package/src/adapters/mcp/client.ts +451 -0
- package/src/adapters/mcp/discovery.test.ts +315 -0
- package/src/adapters/mcp/discovery.ts +340 -0
- package/src/adapters/mcp/index.ts +66 -0
- package/src/adapters/mcp/mapper.test.ts +218 -0
- package/src/adapters/mcp/mapper.ts +536 -0
- package/src/adapters/mcp/registry.test.ts +433 -0
- package/src/adapters/mcp/registry.ts +550 -0
- package/src/adapters/mcp/types.ts +258 -0
- package/src/adapters/native/filesystem.test.ts +350 -0
- package/src/adapters/native/filesystem.ts +393 -0
- package/src/adapters/native/github.test.ts +173 -0
- package/src/adapters/native/github.ts +627 -0
- package/src/adapters/native/index.ts +22 -0
- package/src/adapters/native/selector.test.ts +224 -0
- package/src/adapters/native/selector.ts +150 -0
- package/src/adapters/types.ts +270 -0
- package/src/agents/compiler.test.ts +399 -0
- package/src/agents/compiler.ts +359 -0
- package/src/agents/index.ts +36 -0
- package/src/agents/loader.test.ts +319 -0
- package/src/agents/loader.ts +143 -0
- package/src/agents/resolver.test.ts +282 -0
- package/src/agents/resolver.ts +262 -0
- package/src/agents/types.ts +87 -0
- package/src/cache/index.ts +38 -0
- package/src/cache/interfaces.ts +283 -0
- package/src/cache/manager.test.ts +266 -0
- package/src/cache/manager.ts +388 -0
- package/src/cache/provider.test.ts +485 -0
- package/src/cache/provider.ts +745 -0
- package/src/cache/types.test.ts +192 -0
- package/src/cache/types.ts +313 -0
- package/src/cli/commands/build.test.ts +248 -0
- package/src/cli/commands/build.ts +244 -0
- package/src/cli/commands/cache.test.ts +221 -0
- package/src/cli/commands/cache.ts +229 -0
- package/src/cli/commands/index.ts +63 -0
- package/src/cli/commands/init.test.ts +173 -0
- package/src/cli/commands/init.ts +296 -0
- package/src/cli/commands/skills.test.ts +272 -0
- package/src/cli/commands/skills.ts +348 -0
- package/src/cli/commands/status.test.ts +392 -0
- package/src/cli/commands/status.ts +332 -0
- package/src/cli/commands/sync.test.ts +213 -0
- package/src/cli/commands/sync.ts +251 -0
- package/src/cli/commands/validate.test.ts +216 -0
- package/src/cli/commands/validate.ts +340 -0
- package/src/cli/index.test.ts +190 -0
- package/src/cli/index.ts +493 -0
- package/src/commands/context.test.ts +163 -0
- package/src/commands/context.ts +111 -0
- package/src/commands/index.ts +56 -0
- package/src/commands/loader.test.ts +273 -0
- package/src/commands/loader.ts +355 -0
- package/src/commands/registry.test.ts +384 -0
- package/src/commands/registry.ts +248 -0
- package/src/commands/runner.test.ts +297 -0
- package/src/commands/runner.ts +222 -0
- package/src/commands/types.ts +361 -0
- package/src/config/index.ts +19 -0
- package/src/config/loader.test.ts +262 -0
- package/src/config/loader.ts +188 -0
- package/src/config/types.ts +154 -0
- package/src/context/index.ts +14 -0
- package/src/context/loader.test.ts +334 -0
- package/src/context/loader.ts +357 -0
- package/src/index.test.ts +13 -0
- package/src/index.ts +244 -0
- package/src/knowledge-library/index.ts +44 -0
- package/src/knowledge-library/manager.test.ts +536 -0
- package/src/knowledge-library/manager.ts +804 -0
- package/src/knowledge-library/types.ts +432 -0
- package/src/skills/generator.test.ts +602 -0
- package/src/skills/generator.ts +491 -0
- package/src/skills/index.ts +27 -0
- package/src/skills/templates.ts +520 -0
- package/src/skills/types.ts +251 -0
- package/templates/completion-report.md +72 -0
- package/templates/feedback.md +56 -0
- package/templates/project-files/CLAUDE.md.template +109 -0
- package/templates/project-files/coreai.json.example +47 -0
- package/templates/project-files/mcp.json.template +20 -0
- package/templates/review-complete.md +64 -0
- package/templates/review-request.md +67 -0
- package/templates/task-assignment.md +51 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +26 -0
- package/tsup.config.ts +23 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for managing MCP server connections.
|
|
5
|
+
* Handles discovery, connection lifecycle, and provides access to connected servers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import type { McpServerDefinition, McpServerInfo, McpTool, McpResource } from './types.js';
|
|
10
|
+
import { McpError } from './types.js';
|
|
11
|
+
import type { McpClientOptions } from './client.js';
|
|
12
|
+
import { McpClient } from './client.js';
|
|
13
|
+
import type { DiscoveryOptions } from './discovery.js';
|
|
14
|
+
import { discoverMcpServers } from './discovery.js';
|
|
15
|
+
import type { ToolMapping } from './mapper.js';
|
|
16
|
+
import { getMappingsForServer, groupMappingsByAdapter } from './mapper.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Registry entry for a server
|
|
20
|
+
*/
|
|
21
|
+
export interface ServerEntry {
|
|
22
|
+
/**
|
|
23
|
+
* Server definition from config
|
|
24
|
+
*/
|
|
25
|
+
definition: McpServerDefinition;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* MCP client instance (null if not connected)
|
|
29
|
+
*/
|
|
30
|
+
client: McpClient | null;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Current connection status
|
|
34
|
+
*/
|
|
35
|
+
status: ServerStatus;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Server info (available after connection)
|
|
39
|
+
*/
|
|
40
|
+
info: McpServerInfo | null;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Available tools (cached after connection)
|
|
44
|
+
*/
|
|
45
|
+
tools: McpTool[];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Available resources (cached after connection)
|
|
49
|
+
*/
|
|
50
|
+
resources: McpResource[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Tool mappings for adapter interfaces
|
|
54
|
+
*/
|
|
55
|
+
mappings: ToolMapping[];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Last error if connection failed
|
|
59
|
+
*/
|
|
60
|
+
lastError: Error | null;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Timestamp of last connection attempt
|
|
64
|
+
*/
|
|
65
|
+
lastAttempt: Date | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Server connection status
|
|
70
|
+
*/
|
|
71
|
+
export type ServerStatus = 'disconnected' | 'connecting' | 'connected' | 'error' | 'disabled';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Registry events
|
|
75
|
+
*/
|
|
76
|
+
export interface RegistryEvents {
|
|
77
|
+
/**
|
|
78
|
+
* Emitted when a server connects
|
|
79
|
+
*/
|
|
80
|
+
serverConnected: (name: string, info: McpServerInfo) => void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Emitted when a server disconnects
|
|
84
|
+
*/
|
|
85
|
+
serverDisconnected: (name: string) => void;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Emitted when a server connection fails
|
|
89
|
+
*/
|
|
90
|
+
serverError: (name: string, error: Error) => void;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Emitted when server list changes
|
|
94
|
+
*/
|
|
95
|
+
serversChanged: (servers: string[]) => void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Options for the registry
|
|
100
|
+
*/
|
|
101
|
+
export interface RegistryOptions {
|
|
102
|
+
/**
|
|
103
|
+
* Client options to use for all connections
|
|
104
|
+
*/
|
|
105
|
+
clientOptions?: McpClientOptions;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Discovery options
|
|
109
|
+
*/
|
|
110
|
+
discoveryOptions?: DiscoveryOptions;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Whether to auto-connect on discovery
|
|
114
|
+
*/
|
|
115
|
+
autoConnect?: boolean;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Maximum retry attempts for failed connections
|
|
119
|
+
*/
|
|
120
|
+
maxRetries?: number;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Delay between retries in milliseconds
|
|
124
|
+
*/
|
|
125
|
+
retryDelay?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const DEFAULT_OPTIONS: Required<RegistryOptions> = {
|
|
129
|
+
clientOptions: {},
|
|
130
|
+
discoveryOptions: {},
|
|
131
|
+
autoConnect: false,
|
|
132
|
+
maxRetries: 3,
|
|
133
|
+
retryDelay: 1000,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* MCP Server Registry
|
|
138
|
+
*
|
|
139
|
+
* Manages MCP server connections and provides centralized access to
|
|
140
|
+
* connected servers, their tools, and adapter mappings.
|
|
141
|
+
*/
|
|
142
|
+
export class McpRegistry extends EventEmitter {
|
|
143
|
+
private servers = new Map<string, ServerEntry>();
|
|
144
|
+
private options: Required<RegistryOptions>;
|
|
145
|
+
|
|
146
|
+
constructor(options?: RegistryOptions) {
|
|
147
|
+
super();
|
|
148
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Discover and register MCP servers from config files
|
|
153
|
+
*/
|
|
154
|
+
async discover(): Promise<string[]> {
|
|
155
|
+
const definitions = discoverMcpServers(this.options.discoveryOptions);
|
|
156
|
+
const registered: string[] = [];
|
|
157
|
+
|
|
158
|
+
for (const definition of definitions) {
|
|
159
|
+
if (!this.servers.has(definition.name)) {
|
|
160
|
+
this.registerServer(definition);
|
|
161
|
+
registered.push(definition.name);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (registered.length > 0) {
|
|
166
|
+
this.emit('serversChanged', this.getServerNames());
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (this.options.autoConnect) {
|
|
170
|
+
await this.connectAll();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return registered;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Register a server definition manually
|
|
178
|
+
*/
|
|
179
|
+
registerServer(definition: McpServerDefinition): void {
|
|
180
|
+
if (this.servers.has(definition.name)) {
|
|
181
|
+
throw new McpError(
|
|
182
|
+
`Server "${definition.name}" is already registered`,
|
|
183
|
+
'invalid_config',
|
|
184
|
+
definition.name
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const entry: ServerEntry = {
|
|
189
|
+
definition,
|
|
190
|
+
client: null,
|
|
191
|
+
status: definition.enabled === false ? 'disabled' : 'disconnected',
|
|
192
|
+
info: null,
|
|
193
|
+
tools: [],
|
|
194
|
+
resources: [],
|
|
195
|
+
mappings: [],
|
|
196
|
+
lastError: null,
|
|
197
|
+
lastAttempt: null,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
this.servers.set(definition.name, entry);
|
|
201
|
+
this.emit('serversChanged', this.getServerNames());
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Unregister a server
|
|
206
|
+
*/
|
|
207
|
+
async unregisterServer(name: string): Promise<void> {
|
|
208
|
+
const entry = this.servers.get(name);
|
|
209
|
+
if (!entry) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (entry.status === 'connected' && entry.client) {
|
|
214
|
+
await entry.client.disconnect();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.servers.delete(name);
|
|
218
|
+
this.emit('serversChanged', this.getServerNames());
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Connect to a specific server
|
|
223
|
+
*/
|
|
224
|
+
async connect(name: string): Promise<McpServerInfo> {
|
|
225
|
+
const entry = this.servers.get(name);
|
|
226
|
+
if (!entry) {
|
|
227
|
+
throw new McpError(`Server "${name}" is not registered`, 'server_not_found', name);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (entry.status === 'disabled') {
|
|
231
|
+
throw new McpError(`Server "${name}" is disabled`, 'invalid_config', name);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (entry.status === 'connected' && entry.info) {
|
|
235
|
+
return entry.info;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return this.doConnect(entry);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Disconnect from a specific server
|
|
243
|
+
*/
|
|
244
|
+
async disconnect(name: string): Promise<void> {
|
|
245
|
+
const entry = this.servers.get(name);
|
|
246
|
+
if (!entry) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (entry.client) {
|
|
251
|
+
await entry.client.disconnect();
|
|
252
|
+
entry.client = null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
entry.status = entry.definition.enabled === false ? 'disabled' : 'disconnected';
|
|
256
|
+
entry.info = null;
|
|
257
|
+
entry.tools = [];
|
|
258
|
+
entry.resources = [];
|
|
259
|
+
entry.mappings = [];
|
|
260
|
+
|
|
261
|
+
this.emit('serverDisconnected', name);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Connect to all registered servers
|
|
266
|
+
*/
|
|
267
|
+
async connectAll(): Promise<Map<string, McpServerInfo | Error>> {
|
|
268
|
+
const results = new Map<string, McpServerInfo | Error>();
|
|
269
|
+
|
|
270
|
+
const promises = Array.from(this.servers.entries())
|
|
271
|
+
.filter(([, entry]) => entry.status !== 'disabled')
|
|
272
|
+
.map(async ([name]) => {
|
|
273
|
+
try {
|
|
274
|
+
const info = await this.connect(name);
|
|
275
|
+
results.set(name, info);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
results.set(name, error instanceof Error ? error : new Error(String(error)));
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await Promise.all(promises);
|
|
282
|
+
return results;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Disconnect from all servers
|
|
287
|
+
*/
|
|
288
|
+
async disconnectAll(): Promise<void> {
|
|
289
|
+
const promises = Array.from(this.servers.keys()).map((name) => this.disconnect(name));
|
|
290
|
+
await Promise.all(promises);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Get a connected client by server name
|
|
295
|
+
*/
|
|
296
|
+
getClient(name: string): McpClient | null {
|
|
297
|
+
const entry = this.servers.get(name);
|
|
298
|
+
return entry?.client ?? null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get server entry by name
|
|
303
|
+
*/
|
|
304
|
+
getServer(name: string): ServerEntry | undefined {
|
|
305
|
+
return this.servers.get(name);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get all registered server names
|
|
310
|
+
*/
|
|
311
|
+
getServerNames(): string[] {
|
|
312
|
+
return Array.from(this.servers.keys());
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get all connected server names
|
|
317
|
+
*/
|
|
318
|
+
getConnectedServers(): string[] {
|
|
319
|
+
return Array.from(this.servers.entries())
|
|
320
|
+
.filter(([, entry]) => entry.status === 'connected')
|
|
321
|
+
.map(([name]) => name);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get all server entries
|
|
326
|
+
*/
|
|
327
|
+
getAllServers(): Map<string, ServerEntry> {
|
|
328
|
+
return new Map(this.servers);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get tools from a connected server
|
|
333
|
+
*/
|
|
334
|
+
getTools(name: string): McpTool[] {
|
|
335
|
+
const entry = this.servers.get(name);
|
|
336
|
+
return entry?.tools ?? [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get all tools from all connected servers
|
|
341
|
+
*/
|
|
342
|
+
getAllTools(): Map<string, McpTool[]> {
|
|
343
|
+
const result = new Map<string, McpTool[]>();
|
|
344
|
+
for (const [name, entry] of this.servers) {
|
|
345
|
+
if (entry.status === 'connected' && entry.tools.length > 0) {
|
|
346
|
+
result.set(name, entry.tools);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Get tool mappings for a server
|
|
354
|
+
*/
|
|
355
|
+
getMappings(name: string): ToolMapping[] {
|
|
356
|
+
const entry = this.servers.get(name);
|
|
357
|
+
return entry?.mappings ?? [];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get all mappings grouped by adapter type
|
|
362
|
+
*/
|
|
363
|
+
getAllMappingsByAdapter(): Map<string, Map<string, ToolMapping[]>> {
|
|
364
|
+
const result = new Map<string, Map<string, ToolMapping[]>>();
|
|
365
|
+
|
|
366
|
+
for (const [serverName, entry] of this.servers) {
|
|
367
|
+
if (entry.mappings.length > 0) {
|
|
368
|
+
const grouped = groupMappingsByAdapter(entry.mappings);
|
|
369
|
+
for (const [adapterType, mappings] of grouped) {
|
|
370
|
+
let adapterMap = result.get(adapterType);
|
|
371
|
+
if (!adapterMap) {
|
|
372
|
+
adapterMap = new Map();
|
|
373
|
+
result.set(adapterType, adapterMap);
|
|
374
|
+
}
|
|
375
|
+
adapterMap.set(serverName, mappings);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Find servers that provide a specific adapter type
|
|
385
|
+
*/
|
|
386
|
+
findServersForAdapter(
|
|
387
|
+
adapterType: 'issue_tracker' | 'git' | 'documentation' | 'state'
|
|
388
|
+
): string[] {
|
|
389
|
+
const servers: string[] = [];
|
|
390
|
+
|
|
391
|
+
for (const [name, entry] of this.servers) {
|
|
392
|
+
if (entry.status === 'connected') {
|
|
393
|
+
const hasAdapter = entry.mappings.some((m) => m.adapterType === adapterType);
|
|
394
|
+
if (hasAdapter) {
|
|
395
|
+
servers.push(name);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return servers;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Call a tool on a connected server
|
|
405
|
+
*/
|
|
406
|
+
async callTool(
|
|
407
|
+
serverName: string,
|
|
408
|
+
toolName: string,
|
|
409
|
+
args?: Record<string, unknown>
|
|
410
|
+
): Promise<unknown> {
|
|
411
|
+
const entry = this.servers.get(serverName);
|
|
412
|
+
if (!entry) {
|
|
413
|
+
throw new McpError(
|
|
414
|
+
`Server "${serverName}" is not registered`,
|
|
415
|
+
'server_not_found',
|
|
416
|
+
serverName
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (entry.status !== 'connected' || !entry.client) {
|
|
421
|
+
throw new McpError(
|
|
422
|
+
`Server "${serverName}" is not connected`,
|
|
423
|
+
'connection_closed',
|
|
424
|
+
serverName
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return entry.client.callTool(toolName, args);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Get registry status summary
|
|
433
|
+
*/
|
|
434
|
+
getStatus(): RegistryStatus {
|
|
435
|
+
const servers: Record<string, ServerStatusSummary> = {};
|
|
436
|
+
|
|
437
|
+
for (const [name, entry] of this.servers) {
|
|
438
|
+
const summary: ServerStatusSummary = {
|
|
439
|
+
status: entry.status,
|
|
440
|
+
toolCount: entry.tools.length,
|
|
441
|
+
resourceCount: entry.resources.length,
|
|
442
|
+
mappingCount: entry.mappings.length,
|
|
443
|
+
};
|
|
444
|
+
if (entry.lastError?.message) {
|
|
445
|
+
summary.lastError = entry.lastError.message;
|
|
446
|
+
}
|
|
447
|
+
servers[name] = summary;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
totalServers: this.servers.size,
|
|
452
|
+
connectedServers: this.getConnectedServers().length,
|
|
453
|
+
servers,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Internal: perform connection with retries
|
|
459
|
+
*/
|
|
460
|
+
private async doConnect(entry: ServerEntry, attempt = 1): Promise<McpServerInfo> {
|
|
461
|
+
const name = entry.definition.name;
|
|
462
|
+
entry.status = 'connecting';
|
|
463
|
+
entry.lastAttempt = new Date();
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
// Create client if needed
|
|
467
|
+
if (!entry.client) {
|
|
468
|
+
entry.client = new McpClient(name, entry.definition.config, this.options.clientOptions);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Connect
|
|
472
|
+
await entry.client.connect();
|
|
473
|
+
|
|
474
|
+
// Get server info
|
|
475
|
+
const info = entry.client.getServerInfo();
|
|
476
|
+
if (!info) {
|
|
477
|
+
throw new McpError(`Failed to get server info for "${name}"`, 'protocol_error', name);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Cache tools and resources
|
|
481
|
+
if (info.capabilities?.tools) {
|
|
482
|
+
entry.tools = await entry.client.listTools();
|
|
483
|
+
}
|
|
484
|
+
if (info.capabilities?.resources) {
|
|
485
|
+
entry.resources = await entry.client.listResources();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Generate mappings
|
|
489
|
+
entry.mappings = getMappingsForServer(name, entry.tools);
|
|
490
|
+
|
|
491
|
+
// Update status
|
|
492
|
+
entry.status = 'connected';
|
|
493
|
+
entry.info = info;
|
|
494
|
+
entry.lastError = null;
|
|
495
|
+
|
|
496
|
+
this.emit('serverConnected', name, info);
|
|
497
|
+
return info;
|
|
498
|
+
} catch (error) {
|
|
499
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
500
|
+
entry.lastError = err;
|
|
501
|
+
|
|
502
|
+
// Retry if we haven't exceeded max retries
|
|
503
|
+
if (attempt < this.options.maxRetries) {
|
|
504
|
+
await this.delay(this.options.retryDelay);
|
|
505
|
+
return this.doConnect(entry, attempt + 1);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Mark as error status
|
|
509
|
+
entry.status = 'error';
|
|
510
|
+
entry.client = null;
|
|
511
|
+
|
|
512
|
+
this.emit('serverError', name, err);
|
|
513
|
+
throw err;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Internal: delay helper
|
|
519
|
+
*/
|
|
520
|
+
private delay(ms: number): Promise<void> {
|
|
521
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Server status summary
|
|
527
|
+
*/
|
|
528
|
+
export interface ServerStatusSummary {
|
|
529
|
+
status: ServerStatus;
|
|
530
|
+
toolCount: number;
|
|
531
|
+
resourceCount: number;
|
|
532
|
+
mappingCount: number;
|
|
533
|
+
lastError?: string;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Registry status
|
|
538
|
+
*/
|
|
539
|
+
export interface RegistryStatus {
|
|
540
|
+
totalServers: number;
|
|
541
|
+
connectedServers: number;
|
|
542
|
+
servers: Record<string, ServerStatusSummary>;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Create a new registry with default options
|
|
547
|
+
*/
|
|
548
|
+
export function createRegistry(options?: RegistryOptions): McpRegistry {
|
|
549
|
+
return new McpRegistry(options);
|
|
550
|
+
}
|