@identikey/coding-mcp 2.0.5 → 2.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/README.md +108 -103
- package/build/common/apiClient.d.ts +1 -1
- package/build/common/apiClient.d.ts.map +1 -1
- package/build/common/apiClient.js +31 -49
- package/build/core/CommandDispatcher.d.ts +3 -3
- package/build/core/CommandDispatcher.d.ts.map +1 -1
- package/build/core/CommandDispatcher.js +42 -32
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/build/personas/charles/index.d.ts +1 -1
- package/build/personas/charles/index.d.ts.map +1 -1
- package/build/personas/charles/index.js +107 -62
- package/build/personas/router.d.ts.map +1 -1
- package/build/personas/router.js +33 -0
- package/build/personas/sterling/index.d.ts +14 -0
- package/build/personas/sterling/index.d.ts.map +1 -0
- package/build/personas/sterling/index.js +128 -0
- package/build/personas/xavier/index.js +2 -2
- package/build/prompts/architectPrompts.d.ts +1 -1
- package/build/prompts/architectPrompts.d.ts.map +1 -1
- package/build/prompts/architectPrompts.js +56 -53
- package/build/tools/architect.d.ts +6 -12
- package/build/tools/architect.d.ts.map +1 -1
- package/build/tools/ask.d.ts +4 -20
- package/build/tools/ask.d.ts.map +1 -1
- package/build/tools/codeReview.d.ts +1 -5
- package/build/tools/codeReview.d.ts.map +1 -1
- package/build/tools/codeadvice.d.ts +6 -10
- package/build/tools/codeadvice.d.ts.map +1 -1
- package/build/tools/discover.d.ts +11 -8
- package/build/tools/discover.d.ts.map +1 -1
- package/build/tools/discover.js +20 -5
- package/build/tools/persona.d.ts +29 -28
- package/build/tools/persona.d.ts.map +1 -1
- package/build/tools/researcher.d.ts +23 -20
- package/build/tools/researcher.d.ts.map +1 -1
- package/build/tools/screenshot.d.ts +1 -9
- package/build/tools/screenshot.d.ts.map +1 -1
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -1,157 +1,162 @@
|
|
|
1
|
+
# @identikey/coding-mcp
|
|
1
2
|
|
|
3
|
+
MCP server with expert AI personas for architecture reviews, code advice, and research. Runs as a tool server in Cursor, Windsurf, or any MCP-compatible client.
|
|
2
4
|
|
|
3
|
-
##
|
|
4
|
-
folks can use it in their MCP config like:
|
|
5
|
+
## Quick Start
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
- **Command**: `npx`
|
|
8
|
-
- **Args**: `-y`, `@identikey/coding-mcp`
|
|
7
|
+
Add to your MCP config (e.g., `.cursor/mcp.json`):
|
|
9
8
|
|
|
10
|
-
Or in `.cursor/mcp.json`:
|
|
11
9
|
```json
|
|
12
10
|
{
|
|
13
11
|
"mcpServers": {
|
|
14
12
|
"coding-mcp": {
|
|
15
13
|
"command": "npx",
|
|
16
|
-
"args": ["-y", "@identikey/coding-mcp"]
|
|
14
|
+
"args": ["-y", "@identikey/coding-mcp"],
|
|
15
|
+
"env": {
|
|
16
|
+
"XAI_API_KEY": "your-xai-key",
|
|
17
|
+
"OPENAI_API_KEY": "your-openai-key"
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
Or via Cursor Settings → MCP → Add Server.
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
### Environment Variables
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
| Variable | Required | Description |
|
|
29
|
+
| ---------------- | -------- | ---------------------------------------------------- |
|
|
30
|
+
| `XAI_API_KEY` | Yes\* | xAI/Grok API key ([get one](https://console.x.ai)) |
|
|
31
|
+
| `OPENAI_API_KEY` | Yes\* | OpenAI API key (for GPT-5 reasoning) |
|
|
32
|
+
| `AI_PROVIDER` | No | Default provider: `xai` or `openai` (default: `xai`) |
|
|
33
|
+
| `XAI_MODEL` | No | xAI model override (default: `grok-4.1`) |
|
|
34
|
+
| `OPENAI_MODEL` | No | OpenAI model override (default: `gpt-5.2`) |
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
- **Ask**: Natural language queries automatically routed to the best expert
|
|
30
|
-
- **Discover**: Explore available expert personas and their specialties
|
|
31
|
-
- **Persona**: Direct access to specific expert personas
|
|
32
|
-
- **Screenshot**: Capture screenshots from URLs
|
|
33
|
-
- **Architect**: Comprehensive architectural code reviews
|
|
34
|
-
- **Code Review**: Git diff analysis and improvement suggestions
|
|
36
|
+
\*At least one API key required. The server auto-selects providers based on task type—xAI for quick advice, OpenAI for deep reasoning.
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
### Using bunx
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"coding-mcp": {
|
|
44
|
+
"command": "bunx",
|
|
45
|
+
"args": ["@identikey/coding-mcp"],
|
|
46
|
+
"env": {
|
|
47
|
+
"XAI_API_KEY": "your-xai-key"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
## Tools
|
|
49
55
|
|
|
50
|
-
###
|
|
56
|
+
### `ask`
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
- **Charles**: Distinguished British architect with dry wit
|
|
54
|
-
- **Ada**: Pragmatic performance engineer, metrics-focused
|
|
58
|
+
Natural language queries auto-routed to the best expert persona. Just ask—it figures out who should answer.
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
```
|
|
61
|
+
"How should I structure this React app?" → routes to Iris (frontend)
|
|
62
|
+
"Is this auth implementation secure?" → routes to Sentinel (security)
|
|
63
|
+
"Review this API design" → routes to Atlas (backend)
|
|
64
|
+
```
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
### `architect`
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
Deep architectural review with reasoning. Pass code + task description, get structured analysis.
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
### `code-review`
|
|
63
71
|
|
|
64
|
-
|
|
72
|
+
Git diff analysis. Point it at a repo, get review of changes vs main branch.
|
|
65
73
|
|
|
66
|
-
###
|
|
74
|
+
### `code-advice`
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
Quick, focused guidance on specific problems. Lower latency than full architect review.
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
export const OPENAI_API_KEY = "your_key_here";
|
|
72
|
-
// Add any other keys you need
|
|
73
|
-
```
|
|
78
|
+
### `researcher`
|
|
74
79
|
|
|
75
|
-
|
|
80
|
+
Multi-source research with citations. Searches across Google, arXiv, GitHub, StackExchange, etc.
|
|
76
81
|
|
|
77
|
-
###
|
|
82
|
+
### `persona`
|
|
78
83
|
|
|
79
|
-
|
|
80
|
-
npm install
|
|
81
|
-
# or
|
|
82
|
-
yarn install
|
|
83
|
-
```
|
|
84
|
+
Direct access to a specific expert. Skip auto-routing when you know who you want.
|
|
84
85
|
|
|
85
|
-
###
|
|
86
|
+
### `discover`
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
npm run build
|
|
89
|
-
```
|
|
88
|
+
List available personas and their specialties.
|
|
90
89
|
|
|
91
|
-
###
|
|
90
|
+
### `screenshot`
|
|
92
91
|
|
|
93
|
-
|
|
92
|
+
Capture screenshots from URLs for UI review.
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
2. Go to `Cursor Settings > Features > MCP`
|
|
97
|
-
3. Click `+ Add New MCP Server`
|
|
98
|
-
4. Fill out the form:
|
|
99
|
-
- **Name**: AI Development Assistant
|
|
100
|
-
- **Type**: stdio
|
|
101
|
-
- **Command**: `node /path/to/your/project/dist/index.js`
|
|
94
|
+
## Personas
|
|
102
95
|
|
|
103
|
-
|
|
96
|
+
| Persona | Focus | Style |
|
|
97
|
+
| ------------ | ------------------------ | -------------------------------------------------- |
|
|
98
|
+
| **Charles** | Pragmatic architecture | Anti-enterprise, ships fast, calls out YAGNI |
|
|
99
|
+
| **Sterling** | Enterprise systems | Zero-downtime, compliance, multi-team coordination |
|
|
100
|
+
| **Ada** | Algorithms & performance | Big-O, profiling, optimization |
|
|
101
|
+
| **Atlas** | Backend & APIs | Contract-first, database design, caching |
|
|
102
|
+
| **Hermes** | DevOps & SRE | CI/CD, observability, Kubernetes |
|
|
103
|
+
| **Sentinel** | Security | Threat modeling, auth, compliance |
|
|
104
|
+
| **Iris** | Frontend & UX | Accessibility, design systems, React/Vue |
|
|
105
|
+
| **Xavier** | MVP development | KISS, ship it, avoid yak shaving |
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
## Development
|
|
106
108
|
|
|
107
|
-
|
|
109
|
+
```bash
|
|
110
|
+
# Install deps
|
|
111
|
+
bun install
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
# Build
|
|
114
|
+
bun run build
|
|
110
115
|
|
|
111
|
-
|
|
116
|
+
# Test
|
|
117
|
+
bun test
|
|
112
118
|
|
|
113
|
-
|
|
119
|
+
# Run locally (for testing)
|
|
120
|
+
bun run start
|
|
121
|
+
```
|
|
114
122
|
|
|
115
|
-
|
|
116
|
-
- "Help me architect a new feature"
|
|
117
|
-
- "Analyze this UI screenshot"
|
|
123
|
+
### Local MCP Config
|
|
118
124
|
|
|
119
|
-
|
|
125
|
+
For development, point to your local build:
|
|
120
126
|
|
|
121
|
-
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"coding-mcp-dev": {
|
|
131
|
+
"command": "node",
|
|
132
|
+
"args": ["/path/to/coding-mcp/build/index.js"],
|
|
133
|
+
"env": {
|
|
134
|
+
"XAI_API_KEY": "your-key"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
122
140
|
|
|
123
|
-
|
|
141
|
+
### Project Structure
|
|
124
142
|
|
|
125
143
|
```
|
|
126
144
|
src/
|
|
127
|
-
├──
|
|
128
|
-
|
|
129
|
-
│ ├──
|
|
130
|
-
│
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
├── index.ts # MCP server entry
|
|
146
|
+
├── common/
|
|
147
|
+
│ ├── apiClient.ts # Unified AI provider client
|
|
148
|
+
│ ├── providerConfig.ts # Env vars, provider selection
|
|
149
|
+
│ └── ...
|
|
150
|
+
├── personas/
|
|
151
|
+
│ ├── charles/ # Each persona has its own module
|
|
152
|
+
│ ├── sterling/
|
|
153
|
+
│ └── ...
|
|
154
|
+
└── tools/
|
|
155
|
+
├── ask.ts # Smart routing
|
|
156
|
+
├── architect.ts # Deep review
|
|
157
|
+
└── ...
|
|
134
158
|
```
|
|
135
159
|
|
|
136
|
-
##
|
|
137
|
-
|
|
138
|
-
Contributions welcome! Please feel free to submit a Pull Request.
|
|
139
|
-
|
|
140
|
-
## 📝 License
|
|
141
|
-
|
|
142
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
143
|
-
|
|
144
|
-
## 🐛 Issues & Support
|
|
145
|
-
|
|
146
|
-
Found a bug or need help? Open an issue with:
|
|
147
|
-
|
|
148
|
-
1. What you were trying to do
|
|
149
|
-
2. What happened instead
|
|
150
|
-
3. Steps to reproduce
|
|
151
|
-
4. Your environment details
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
I'll be honest though, this is a tutorial demo, and not a production-ready tool so I likely won't be fixing issues. But feel free to fork it and make it your own!
|
|
160
|
+
## License
|
|
156
161
|
|
|
157
|
-
|
|
162
|
+
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/common/apiClient.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/common/apiClient.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAW7B,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,eAAe,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;IACjE,eAAe,EAAE,eAAe,CAAC;IACjC,QAAQ,EAAE,UAAU,CAAC;CACtB;AAiBD,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B1E"}
|
|
@@ -1,68 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified AI provider client using Vercel AI SDK
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
4
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
5
5
|
import { xai } from "@ai-sdk/xai";
|
|
6
6
|
import { generateText } from "ai";
|
|
7
|
-
import { OPENAI_API_KEY, validateProvider } from "./providerConfig.js";
|
|
7
|
+
import { OPENAI_API_KEY, validateProvider, } from "./providerConfig.js";
|
|
8
8
|
import { formatTokenInfo } from "./tokenFormatter.js";
|
|
9
9
|
import { buildUserPrompt } from "./promptBuilder.js";
|
|
10
|
-
|
|
10
|
+
// Model defaults with env overrides
|
|
11
|
+
const XAI_MODEL = process.env.XAI_MODEL || "grok-4.1";
|
|
12
|
+
const OPENAI_MODEL = process.env.OPENAI_MODEL || "gpt-5.2";
|
|
13
|
+
// Provider clients
|
|
14
|
+
const openai = createOpenAI({ apiKey: OPENAI_API_KEY });
|
|
15
|
+
const providers = {
|
|
16
|
+
xai: {
|
|
17
|
+
model: () => xai(XAI_MODEL),
|
|
18
|
+
mapOptions: (effort) => ({
|
|
19
|
+
xai: { reasoningEffort: effort },
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
openai: {
|
|
23
|
+
model: () => openai(OPENAI_MODEL),
|
|
24
|
+
mapOptions: (effort) => ({
|
|
25
|
+
openai: { reasoningEffort: effort },
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
export async function callAIProvider(config) {
|
|
30
|
+
validateProvider(config.provider);
|
|
31
|
+
const provider = providers[config.provider];
|
|
32
|
+
if (!provider) {
|
|
33
|
+
throw new Error(`Unsupported provider: ${config.provider}`);
|
|
34
|
+
}
|
|
11
35
|
const userPrompt = buildUserPrompt({
|
|
12
36
|
task: config.task,
|
|
13
37
|
code: config.code,
|
|
14
38
|
analysisType: config.analysisType,
|
|
15
39
|
});
|
|
16
40
|
const result = await generateText({
|
|
17
|
-
model:
|
|
41
|
+
model: provider.model(),
|
|
18
42
|
messages: [
|
|
19
43
|
{ role: "system", content: config.systemPrompt },
|
|
20
44
|
{ role: "user", content: userPrompt },
|
|
21
45
|
],
|
|
22
|
-
|
|
46
|
+
providerOptions: provider.mapOptions(config.reasoningEffort),
|
|
23
47
|
});
|
|
24
|
-
const tokenInfo = formatTokenInfo(
|
|
48
|
+
const tokenInfo = formatTokenInfo(config.provider, result.usage, config.reasoningEffort);
|
|
25
49
|
return result.text + tokenInfo;
|
|
26
50
|
}
|
|
27
|
-
async function callOpenAIProvider(config) {
|
|
28
|
-
const openai = new OpenAI({
|
|
29
|
-
apiKey: OPENAI_API_KEY,
|
|
30
|
-
});
|
|
31
|
-
const userPrompt = buildUserPrompt({
|
|
32
|
-
task: config.task,
|
|
33
|
-
code: config.code,
|
|
34
|
-
analysisType: config.analysisType,
|
|
35
|
-
});
|
|
36
|
-
const response = await openai.chat.completions.create({
|
|
37
|
-
model: "gpt-5",
|
|
38
|
-
messages: [
|
|
39
|
-
{ role: "system", content: config.systemPrompt },
|
|
40
|
-
{ role: "user", content: userPrompt },
|
|
41
|
-
],
|
|
42
|
-
reasoning_effort: config.reasoningEffort, // GPT-5 supports this
|
|
43
|
-
});
|
|
44
|
-
const assistantMessage = response.choices?.[0]?.message?.content ?? "No response from model.";
|
|
45
|
-
const usage = {
|
|
46
|
-
totalTokens: response.usage?.total_tokens,
|
|
47
|
-
reasoning_tokens: response.usage?.reasoning_tokens,
|
|
48
|
-
};
|
|
49
|
-
const tokenInfo = formatTokenInfo("openai", usage, config.reasoningEffort);
|
|
50
|
-
return assistantMessage + tokenInfo;
|
|
51
|
-
}
|
|
52
|
-
export async function callAIProvider(config) {
|
|
53
|
-
validateProvider(config.provider);
|
|
54
|
-
if (config.provider === "xai") {
|
|
55
|
-
// xAI doesn't support reasoning_effort, so create config without it
|
|
56
|
-
const xaiConfig = {
|
|
57
|
-
...config,
|
|
58
|
-
reasoningEffort: undefined // Remove for xAI
|
|
59
|
-
};
|
|
60
|
-
return callXaiProvider(xaiConfig);
|
|
61
|
-
}
|
|
62
|
-
else if (config.provider === "openai") {
|
|
63
|
-
return callOpenAIProvider(config);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
throw new Error(`Unsupported provider: ${config.provider}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Routes MCP requests to appropriate tool commands with structured error handling
|
|
4
4
|
*/
|
|
5
5
|
import { CallToolRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
import { MCPToolResponse } from
|
|
7
|
-
import { ToolRegistry } from
|
|
8
|
-
import { type EventBus } from
|
|
6
|
+
import { MCPToolResponse } from "./ToolCommand.js";
|
|
7
|
+
import { ToolRegistry } from "./ToolRegistry.js";
|
|
8
|
+
import { type EventBus } from "../infra/eventBus.js";
|
|
9
9
|
export interface DispatcherConfig {
|
|
10
10
|
/** Default execution timeout in milliseconds */
|
|
11
11
|
defaultTimeout?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandDispatcher.d.ts","sourceRoot":"","sources":["../../src/core/CommandDispatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EASL,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAG/D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oCAAoC;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"CommandDispatcher.d.ts","sourceRoot":"","sources":["../../src/core/CommandDispatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EASL,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAG/D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oCAAoC;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,gBAAgB,CAGpB;IACJ,OAAO,CAAC,gBAAgB,CAAK;gBAG3B,QAAQ,EAAE,YAAY,EACtB,gBAAgB,CAAC,EAAE,QAAQ,EAC3B,MAAM,GAAE,gBAAqB;IAW/B;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAwFlE;;OAEG;YACW,kBAAkB;IAwEhC;;OAEG;YACW,WAAW;IAczB;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,mBAAmB,IAAI,WAAW,CAChC,MAAM,EACN;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CACxC;IAID;;OAEG;IACH,QAAQ,IAAI;QACV,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;KACnB;IAWD;;OAEG;IACH,MAAM,CAAC,MAAM,CACX,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,gBAAgB,GACxB,iBAAiB;CAGrB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,gBAAgB,GACxB,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAGxD"}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Command Dispatcher - Replaces the monolithic switch statement
|
|
3
3
|
* Routes MCP requests to appropriate tool commands with structured error handling
|
|
4
4
|
*/
|
|
5
|
-
import { ToolNotFoundError, ToolValidationError, ToolExecutionError, ToolTimeoutError, ToolError } from
|
|
6
|
-
import { eventBus } from
|
|
7
|
-
import { ZodError } from
|
|
5
|
+
import { ToolNotFoundError, ToolValidationError, ToolExecutionError, ToolTimeoutError, ToolError, } from "./ToolCommand.js";
|
|
6
|
+
import { eventBus } from "../infra/eventBus.js";
|
|
7
|
+
import { ZodError } from "zod";
|
|
8
8
|
export class CommandDispatcher {
|
|
9
9
|
registry;
|
|
10
10
|
eventBus;
|
|
@@ -17,7 +17,7 @@ export class CommandDispatcher {
|
|
|
17
17
|
this.config = {
|
|
18
18
|
defaultTimeout: config.defaultTimeout || 30000, // 30 seconds
|
|
19
19
|
enableTracing: config.enableTracing ?? true,
|
|
20
|
-
maxConcurrentExecutions: config.maxConcurrentExecutions || 10
|
|
20
|
+
maxConcurrentExecutions: config.maxConcurrentExecutions || 10,
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -30,7 +30,7 @@ export class CommandDispatcher {
|
|
|
30
30
|
try {
|
|
31
31
|
// Check concurrent execution limit
|
|
32
32
|
if (this.activeExecutions.size >= this.config.maxConcurrentExecutions) {
|
|
33
|
-
throw new ToolError(`Maximum concurrent executions (${this.config.maxConcurrentExecutions}) reached`,
|
|
33
|
+
throw new ToolError(`Maximum concurrent executions (${this.config.maxConcurrentExecutions}) reached`, "RESOURCE_ERROR", toolName);
|
|
34
34
|
}
|
|
35
35
|
// Get the tool command
|
|
36
36
|
const tool = this.registry.get(toolName);
|
|
@@ -40,10 +40,10 @@ export class CommandDispatcher {
|
|
|
40
40
|
// Track active execution
|
|
41
41
|
this.activeExecutions.set(requestId, { toolName, startTime });
|
|
42
42
|
// Emit execution start event
|
|
43
|
-
this.eventBus.emit(
|
|
43
|
+
this.eventBus.emit("tool:execute:start", {
|
|
44
44
|
name: toolName,
|
|
45
45
|
requestId,
|
|
46
|
-
args
|
|
46
|
+
args,
|
|
47
47
|
});
|
|
48
48
|
// Execute the tool with timeout
|
|
49
49
|
const result = await this.executeWithTimeout(tool, args, requestId, startTime);
|
|
@@ -51,18 +51,19 @@ export class CommandDispatcher {
|
|
|
51
51
|
this.activeExecutions.delete(requestId);
|
|
52
52
|
// Emit execution end event
|
|
53
53
|
const executionTime = Date.now() - startTime;
|
|
54
|
-
this.eventBus.emit(
|
|
54
|
+
this.eventBus.emit("tool:execute:end", {
|
|
55
55
|
name: toolName,
|
|
56
56
|
requestId,
|
|
57
57
|
success: result.success,
|
|
58
|
-
executionTime
|
|
58
|
+
executionTime,
|
|
59
59
|
});
|
|
60
60
|
// Return MCP-compatible response
|
|
61
61
|
if (result.success && result.result) {
|
|
62
62
|
return this.formatMCPResponse(result.result);
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
throw result.error ||
|
|
65
|
+
throw (result.error ||
|
|
66
|
+
new ToolExecutionError(toolName, "Unknown execution error"));
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
catch (error) {
|
|
@@ -71,18 +72,18 @@ export class CommandDispatcher {
|
|
|
71
72
|
// Convert to ToolError if not already
|
|
72
73
|
const toolError = this.normalizeError(error, toolName);
|
|
73
74
|
// Emit error event
|
|
74
|
-
this.eventBus.emit(
|
|
75
|
+
this.eventBus.emit("tool:error", {
|
|
75
76
|
name: toolName,
|
|
76
77
|
error: toolError,
|
|
77
|
-
requestId
|
|
78
|
+
requestId,
|
|
78
79
|
});
|
|
79
80
|
// Emit execution end event with failure
|
|
80
81
|
const executionTime = Date.now() - startTime;
|
|
81
|
-
this.eventBus.emit(
|
|
82
|
+
this.eventBus.emit("tool:execute:end", {
|
|
82
83
|
name: toolName,
|
|
83
84
|
requestId,
|
|
84
85
|
success: false,
|
|
85
|
-
executionTime
|
|
86
|
+
executionTime,
|
|
86
87
|
});
|
|
87
88
|
// Return error response in MCP format
|
|
88
89
|
return this.formatErrorResponse(toolError);
|
|
@@ -100,19 +101,22 @@ export class CommandDispatcher {
|
|
|
100
101
|
}
|
|
101
102
|
catch (error) {
|
|
102
103
|
if (error instanceof ZodError) {
|
|
103
|
-
throw new ToolValidationError(tool.name, `Invalid arguments: ${error.
|
|
104
|
+
throw new ToolValidationError(tool.name, `Invalid arguments: ${error.issues
|
|
105
|
+
.map((e) => `${e.path.join(".")}: ${e.message}`)
|
|
106
|
+
.join(", ")}`, error);
|
|
104
107
|
}
|
|
105
|
-
throw new ToolValidationError(tool.name,
|
|
108
|
+
throw new ToolValidationError(tool.name, "Failed to validate arguments", error);
|
|
106
109
|
}
|
|
107
110
|
// Create execution context
|
|
108
111
|
const context = {
|
|
109
112
|
eventBus: this.eventBus,
|
|
110
113
|
requestId,
|
|
111
114
|
startTime,
|
|
112
|
-
config: tool.metadata?.constraints
|
|
115
|
+
config: tool.metadata?.constraints,
|
|
113
116
|
};
|
|
114
117
|
// Determine timeout (tool-specific or default)
|
|
115
|
-
const timeout = tool.metadata?.constraints?.maxExecutionTime ||
|
|
118
|
+
const timeout = tool.metadata?.constraints?.maxExecutionTime ||
|
|
119
|
+
this.config.defaultTimeout;
|
|
116
120
|
// Execute with timeout
|
|
117
121
|
const result = await this.withTimeout(tool.execute(validatedArgs, context), timeout, tool.name);
|
|
118
122
|
return {
|
|
@@ -122,8 +126,8 @@ export class CommandDispatcher {
|
|
|
122
126
|
metadata: {
|
|
123
127
|
toolName: tool.name,
|
|
124
128
|
version: tool.version,
|
|
125
|
-
requestId
|
|
126
|
-
}
|
|
129
|
+
requestId,
|
|
130
|
+
},
|
|
127
131
|
};
|
|
128
132
|
}
|
|
129
133
|
catch (error) {
|
|
@@ -134,8 +138,8 @@ export class CommandDispatcher {
|
|
|
134
138
|
metadata: {
|
|
135
139
|
toolName: tool.name,
|
|
136
140
|
version: tool.version,
|
|
137
|
-
requestId
|
|
138
|
-
}
|
|
141
|
+
requestId,
|
|
142
|
+
},
|
|
139
143
|
};
|
|
140
144
|
}
|
|
141
145
|
}
|
|
@@ -172,10 +176,14 @@ export class CommandDispatcher {
|
|
|
172
176
|
}
|
|
173
177
|
// Convert to MCP format
|
|
174
178
|
return {
|
|
175
|
-
content: [
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
176
181
|
type: "text",
|
|
177
|
-
text: typeof result ===
|
|
178
|
-
|
|
182
|
+
text: typeof result === "string"
|
|
183
|
+
? result
|
|
184
|
+
: JSON.stringify(result, null, 2),
|
|
185
|
+
},
|
|
186
|
+
],
|
|
179
187
|
};
|
|
180
188
|
}
|
|
181
189
|
/**
|
|
@@ -183,22 +191,24 @@ export class CommandDispatcher {
|
|
|
183
191
|
*/
|
|
184
192
|
formatErrorResponse(error) {
|
|
185
193
|
const errorMessage = this.config.enableTracing
|
|
186
|
-
? `${error.message}\n\nError Code: ${error.code}\nTool: ${error.toolName ||
|
|
194
|
+
? `${error.message}\n\nError Code: ${error.code}\nTool: ${error.toolName || "unknown"}`
|
|
187
195
|
: error.message;
|
|
188
196
|
return {
|
|
189
|
-
content: [
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
190
199
|
type: "text",
|
|
191
|
-
text: `Error: ${errorMessage}
|
|
192
|
-
}
|
|
200
|
+
text: `Error: ${errorMessage}`,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
193
203
|
};
|
|
194
204
|
}
|
|
195
205
|
/**
|
|
196
206
|
* Check if result is already in MCP response format
|
|
197
207
|
*/
|
|
198
208
|
isMCPResponse(result) {
|
|
199
|
-
return (typeof result ===
|
|
209
|
+
return (typeof result === "object" &&
|
|
200
210
|
result !== null &&
|
|
201
|
-
|
|
211
|
+
"content" in result &&
|
|
202
212
|
Array.isArray(result.content));
|
|
203
213
|
}
|
|
204
214
|
/**
|
|
@@ -223,7 +233,7 @@ export class CommandDispatcher {
|
|
|
223
233
|
activeExecutions: this.activeExecutions.size,
|
|
224
234
|
totalExecutions: this.executionCounter,
|
|
225
235
|
averageExecutionTime: 0, // Would need history tracking
|
|
226
|
-
errorRate: 0 // Would need error tracking
|
|
236
|
+
errorRate: 0, // Would need error tracking
|
|
227
237
|
};
|
|
228
238
|
}
|
|
229
239
|
/**
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAiEA,OAAO,6BAA6B,CAAC;AACrC,OAAO,yBAAyB,CAAC;AACjC,OAAO,4BAA4B,CAAC;AACpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,4BAA4B,CAAC;AACpC,OAAO,8BAA8B,CAAC;AACtC,OAAO,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAiEA,OAAO,6BAA6B,CAAC;AACrC,OAAO,8BAA8B,CAAC;AACtC,OAAO,yBAAyB,CAAC;AACjC,OAAO,4BAA4B,CAAC;AACpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,4BAA4B,CAAC;AACpC,OAAO,8BAA8B,CAAC;AACtC,OAAO,0BAA0B,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { askToolName, askToolDescription, AskToolSchema, runAskTool, } from "./t
|
|
|
12
12
|
import { discoverToolName, discoverToolDescription, DiscoverToolSchema, runDiscoverTool, } from "./tools/discover.js";
|
|
13
13
|
// Import personas to auto-register
|
|
14
14
|
import "./personas/charles/index.js";
|
|
15
|
+
import "./personas/sterling/index.js";
|
|
15
16
|
import "./personas/ada/index.js";
|
|
16
17
|
import "./personas/xavier/index.js";
|
|
17
18
|
import "./personas/atlas/index.js";
|
|
@@ -32,7 +33,7 @@ import "./personas/iris/index.js";
|
|
|
32
33
|
// 1. Create an MCP server instance
|
|
33
34
|
const server = new Server({
|
|
34
35
|
name: "cursor-tools",
|
|
35
|
-
version: "2.0
|
|
36
|
+
version: "2.1.0",
|
|
36
37
|
}, {
|
|
37
38
|
capabilities: {
|
|
38
39
|
tools: {},
|
|
@@ -258,6 +259,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
258
259
|
type: "string",
|
|
259
260
|
enum: [
|
|
260
261
|
"architecture",
|
|
262
|
+
"enterprise",
|
|
261
263
|
"algorithms",
|
|
262
264
|
"security",
|
|
263
265
|
"frontend",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Charles - A thoughtful, witty British architect with high reasoning capabilities
|
|
3
3
|
* Personality layer over GPT-5-class models
|
|
4
4
|
*/
|
|
5
|
-
import { BasePersona, PersonaContext } from
|
|
5
|
+
import { BasePersona, PersonaContext } from "../types.js";
|
|
6
6
|
export declare class CharlesPersona extends BasePersona {
|
|
7
7
|
constructor();
|
|
8
8
|
enhanceSystemPrompt(basePrompt: string, context: PersonaContext): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/personas/charles/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/personas/charles/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAyDzE,qBAAa,cAAe,SAAQ,WAAW;;IAU7C,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IA8ExE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IA2BtE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IAwBlE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IAe/D,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,uBAAuB;IA2B/B,OAAO,CAAC,sBAAsB;CAW/B;AAID,QAAA,MAAM,OAAO,gBAAuB,CAAC;AAGrC,eAAe,OAAO,CAAC"}
|