@elliotding/ai-agent-mcp 0.1.25 → 0.1.27

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 (53) hide show
  1. package/package.json +4 -1
  2. package/.prompt-cache/cmd-cmd-client-sdk-ai-hub-generate-testcase.md +0 -101
  3. package/.prompt-cache/cmd-cmd-client-sdk-ai-hub-submit_zct_job.md +0 -158
  4. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-conf-status.md +0 -311
  5. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-sdk-log.md +0 -64
  6. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-zmb-log-errors.md +0 -84
  7. package/ai-resource-telemetry.json +0 -40
  8. package/src/api/cached-client.ts +0 -144
  9. package/src/api/client.ts +0 -697
  10. package/src/auth/index.ts +0 -11
  11. package/src/auth/middleware.ts +0 -244
  12. package/src/auth/permissions.ts +0 -323
  13. package/src/auth/token-validator.ts +0 -292
  14. package/src/cache/cache-manager.ts +0 -243
  15. package/src/cache/index.ts +0 -6
  16. package/src/cache/redis-client.ts +0 -249
  17. package/src/config/constants.ts +0 -33
  18. package/src/config/index.ts +0 -269
  19. package/src/filesystem/manager.ts +0 -235
  20. package/src/git/multi-source-manager.ts +0 -654
  21. package/src/git/operations.ts +0 -93
  22. package/src/index.ts +0 -157
  23. package/src/monitoring/health.ts +0 -132
  24. package/src/prompts/cache.ts +0 -140
  25. package/src/prompts/generator.ts +0 -143
  26. package/src/prompts/index.ts +0 -20
  27. package/src/prompts/manager.ts +0 -718
  28. package/src/resources/index.ts +0 -13
  29. package/src/resources/loader.ts +0 -563
  30. package/src/server/http.ts +0 -549
  31. package/src/server.ts +0 -206
  32. package/src/session/manager.ts +0 -296
  33. package/src/telemetry/index.ts +0 -10
  34. package/src/telemetry/manager.ts +0 -419
  35. package/src/tools/index.ts +0 -13
  36. package/src/tools/manage-subscription.ts +0 -388
  37. package/src/tools/registry.ts +0 -97
  38. package/src/tools/resolve-prompt-content.ts +0 -113
  39. package/src/tools/search-resources.ts +0 -185
  40. package/src/tools/sync-resources.ts +0 -829
  41. package/src/tools/track-usage.ts +0 -113
  42. package/src/tools/uninstall-resource.ts +0 -199
  43. package/src/tools/upload-resource.ts +0 -431
  44. package/src/transport/sse.ts +0 -308
  45. package/src/types/errors.ts +0 -146
  46. package/src/types/index.ts +0 -7
  47. package/src/types/mcp.ts +0 -61
  48. package/src/types/resources.ts +0 -141
  49. package/src/types/tools.ts +0 -305
  50. package/src/utils/cursor-paths.ts +0 -135
  51. package/src/utils/log-cleaner.ts +0 -92
  52. package/src/utils/logger.ts +0 -333
  53. package/src/utils/validation.ts +0 -262
@@ -1,113 +0,0 @@
1
- /**
2
- * track_usage Tool
3
- *
4
- * Records an AI Resource invocation for telemetry purposes.
5
- *
6
- * This tool is automatically invoked by the AI at the start of every
7
- * Command or Skill execution. The Prompt content generated by
8
- * PromptGenerator prepends a system instruction that asks the AI to
9
- * call `track_usage` before doing anything else, so that the server
10
- * can record the usage even though Cursor does not call `prompts/get`
11
- * when a slash command is selected.
12
- *
13
- * The tool is intentionally lightweight:
14
- * - No external API calls.
15
- * - Fire-and-forget write to the local telemetry file.
16
- * - Always returns a success response so the AI continues normally.
17
- */
18
-
19
- import { logger } from '../utils/logger';
20
- import { telemetry } from '../telemetry/index.js';
21
- import type { ToolResult } from '../types/tools';
22
-
23
- export interface TrackUsageParams {
24
- resource_id: string;
25
- resource_type: 'command' | 'skill';
26
- resource_name: string;
27
- /** Automatically injected by the MCP server from the SSE token. */
28
- user_token?: string;
29
- /** Optional Jira Issue ID for usage correlation (e.g. "PROJ-12345"). */
30
- jira_id?: string;
31
- }
32
-
33
- export async function trackUsage(params: unknown): Promise<ToolResult<{ recorded: boolean }>> {
34
- const p = params as TrackUsageParams;
35
-
36
- const resourceId = p.resource_id ?? '';
37
- const resourceType = p.resource_type ?? 'command';
38
- const resourceName = p.resource_name ?? '';
39
- const userToken = p.user_token ?? '';
40
- const jiraId = typeof p.jira_id === 'string' && p.jira_id.trim() !== ''
41
- ? p.jira_id.trim()
42
- : undefined;
43
-
44
- if (!resourceId || !userToken) {
45
- // Missing required fields — log and return without recording so the AI
46
- // is not blocked. This should not happen in normal operation.
47
- logger.warn(
48
- { resourceId, userToken: !!userToken },
49
- 'track_usage called with missing resource_id or user_token — skipping',
50
- );
51
- return { success: true, data: { recorded: false } };
52
- }
53
-
54
- // Await the write to ensure the event is persisted before the periodic flush
55
- // timer fires and clears pending_events. File write latency is negligible
56
- // (< 1 ms) so this does not meaningfully delay the tool response.
57
- await telemetry
58
- .recordInvocation(resourceId, resourceType, resourceName, userToken, jiraId)
59
- .catch((err) => {
60
- logger.warn({ resourceId, error: (err as Error).message }, 'track_usage: telemetry write failed (non-critical)');
61
- });
62
-
63
- logger.info(
64
- { resourceId, resourceType, resourceName, jiraId: jiraId ?? '(none)' },
65
- 'track_usage: invocation recorded',
66
- );
67
-
68
- return { success: true, data: { recorded: true } };
69
- }
70
-
71
- export const trackUsageTool = {
72
- name: 'track_usage',
73
- description:
74
- 'Record the invocation of an AI Resource (Command or Skill) for telemetry. ' +
75
- 'MUST be called at the very beginning of every Command or Skill execution, ' +
76
- 'before performing any other action. ' +
77
- 'The resource_id, resource_type, and resource_name are provided in the prompt header — ' +
78
- 'copy them exactly as given. ' +
79
- 'user_token is injected automatically by the server; do NOT ask the user for it. ' +
80
- 'jira_id is optional — only include it if the user explicitly mentions a Jira issue number.',
81
- inputSchema: {
82
- type: 'object' as const,
83
- properties: {
84
- resource_id: {
85
- type: 'string',
86
- description: 'Canonical resource ID as shown in the prompt header (e.g. "cmd-client-sdk-ai-hub-generate-testcase").',
87
- },
88
- resource_type: {
89
- type: 'string',
90
- enum: ['command', 'skill'],
91
- description: 'Resource type: "command" or "skill".',
92
- },
93
- resource_name: {
94
- type: 'string',
95
- description: 'Human-readable resource name as shown in the prompt header (e.g. "generate-testcase").',
96
- },
97
- user_token: {
98
- type: 'string',
99
- description:
100
- 'DO NOT set this field — it is automatically injected by the MCP server from ' +
101
- 'the authenticated SSE connection.',
102
- },
103
- jira_id: {
104
- type: 'string',
105
- description:
106
- 'Optional Jira Issue ID for usage correlation (e.g. "PROJ-12345"). ' +
107
- 'Only include if the user explicitly mentioned a Jira issue in this conversation.',
108
- },
109
- },
110
- required: ['resource_id', 'resource_type', 'resource_name'],
111
- },
112
- handler: trackUsage,
113
- };
@@ -1,199 +0,0 @@
1
- /**
2
- * uninstall_resource Tool
3
- * Uninstall a resource from local filesystem and clean up related configuration.
4
- *
5
- * For MCP resources this also removes the mcpServers entry from ~/.cursor/mcp.json.
6
- * For directory-based resources (skill, mcp) the entire install directory is removed.
7
- */
8
-
9
- import { logger, logToolCall } from '../utils/logger';
10
- import { apiClient } from '../api/client';
11
- import { getCursorTypeDirForClient, getCursorRootDirForClient } from '../utils/cursor-paths.js';
12
- import { MCPServerError, createValidationError } from '../types/errors';
13
- import type { UninstallResourceParams, UninstallResourceResult, LocalAction, ToolResult } from '../types/tools';
14
- import { promptManager } from '../prompts/index.js';
15
-
16
-
17
- export async function uninstallResource(params: unknown): Promise<ToolResult<UninstallResourceResult>> {
18
- const startTime = Date.now();
19
- const typedParams = params as UninstallResourceParams;
20
-
21
- logger.info({ tool: 'uninstall_resource', params }, 'uninstall_resource called');
22
-
23
- try {
24
- const pattern = typedParams.resource_id_or_name;
25
- const removeFromAccount = typedParams.remove_from_account || false;
26
-
27
- const removedResources: Array<{ id: string; name: string; path: string }> = [];
28
- let subscriptionRemoved = false;
29
-
30
- // ── Command / Skill: unregister MCP Prompt + delete cache ─────────────
31
- // Match registered prompt names that contain the pattern.
32
- const matchedPromptNames = promptManager.promptNames(typedParams.user_token ?? '').filter(
33
- (name) => name === pattern || name.includes(pattern),
34
- );
35
-
36
- if (matchedPromptNames.length > 0) {
37
- for (const promptName of matchedPromptNames) {
38
- // Prompt name format: <team>/<type>/<resource_name>
39
- const parts = promptName.split('/');
40
- const team = parts[0] ?? 'general';
41
- const resourceType = parts[1] as 'command' | 'skill' | undefined;
42
- const resourceName = parts.slice(2).join('/') || promptName;
43
-
44
- // Find the resource_id from the registered prompt (best-effort via name).
45
- // For unsubscription, we pass the promptName as id if no better source.
46
- const resourceId = pattern.startsWith('cmd-') || pattern.startsWith('skill-')
47
- ? pattern
48
- : promptName;
49
-
50
- // Unregister from the in-memory prompt registry only.
51
- // The server-side .prompt-cache/ files are intentionally NOT deleted here —
52
- // they are shared across all users and will be regenerated on the next git pull.
53
- promptManager.unregisterPrompt(resourceId, resourceType ?? 'command', resourceName, typedParams.user_token ?? '');
54
-
55
- removedResources.push({ id: resourceId, name: resourceName, path: `[MCP Prompt: ${promptName}]` });
56
- logger.info({ promptName, team, resourceType, resourceName }, 'MCP Prompt unregistered via uninstall');
57
- }
58
-
59
- // Remove from server subscription if requested
60
- if (removeFromAccount) {
61
- for (const r of removedResources) {
62
- try {
63
- await apiClient.unsubscribe(r.id);
64
- subscriptionRemoved = true;
65
- } catch (err) {
66
- logger.warn({ resourceId: r.id, err }, 'Failed to unsubscribe Command/Skill Prompt from account');
67
- }
68
- }
69
- }
70
-
71
- // Return early — Command/Skill resources have no local filesystem footprint.
72
- const result: UninstallResourceResult = {
73
- success: true,
74
- removed_resources: removedResources,
75
- subscription_removed: subscriptionRemoved,
76
- message: [
77
- `Successfully unregistered ${removedResources.length} MCP Prompt${removedResources.length > 1 ? 's' : ''}.`,
78
- subscriptionRemoved ? 'Subscription removed from account.' : null,
79
- ].filter(Boolean).join(' '),
80
- };
81
- const duration = Date.now() - startTime;
82
- logToolCall('uninstall_resource', 'user-id', params as Record<string, unknown>, duration);
83
- return { success: true, data: result };
84
- }
85
-
86
- // ── Rule / MCP: return LocalAction instructions for the AI to execute ────
87
- // The MCP server may be running remotely; we must NOT touch the server's
88
- // own filesystem. Instead we return delete/remove instructions so the AI
89
- // Agent performs them on the user's LOCAL machine.
90
- logger.debug({ pattern, resourceType: typedParams.resource_type }, 'Building local uninstall actions for Rule/MCP resource...');
91
-
92
- const localActions: LocalAction[] = [];
93
- // Use client-side tilde-based paths; the MCP server may be running remotely
94
- // and its os.homedir() would resolve to the server's home, not the user's.
95
- const mcpJsonPath = `${getCursorRootDirForClient()}/mcp.json`;
96
-
97
- // When resource_type is provided, only emit the relevant actions.
98
- // When unknown, emit both (AI skips missing files gracefully).
99
- const knownType = typedParams.resource_type;
100
- const isRule = !knownType || knownType === 'rule';
101
- const isMcp = !knownType || knownType === 'mcp';
102
-
103
- if (isRule) {
104
- // Rule: delete ~/.cursor/rules/<pattern>.mdc and .md variants.
105
- const rulesDir = getCursorTypeDirForClient('rule');
106
- for (const ext of ['.mdc', '.md']) {
107
- const filePath = `${rulesDir}/${pattern}${ext}`;
108
- localActions.push({ action: 'delete_file', path: filePath });
109
- removedResources.push({ id: pattern, name: pattern, path: filePath });
110
- }
111
- }
112
-
113
- if (isMcp) {
114
- // MCP: delete install directory (Format A — may not exist for remote-URL MCPs)
115
- // and remove the mcpServers entry from mcp.json.
116
- const mcpDir = getCursorTypeDirForClient('mcp');
117
- const mcpInstallDir = `${mcpDir}/${pattern}`;
118
- localActions.push({ action: 'delete_file', path: mcpInstallDir, recursive: true });
119
- localActions.push({ action: 'remove_mcp_json_entry', mcp_json_path: mcpJsonPath, server_name: pattern });
120
- removedResources.push({ id: pattern, name: pattern, path: mcpInstallDir });
121
- }
122
-
123
- if (removedResources.length === 0 && localActions.length === 0) {
124
- throw createValidationError(
125
- pattern,
126
- 'resource_id_or_name',
127
- 'No installed Rule or MCP resources found matching pattern. Use search_resources to find available resources'
128
- );
129
- }
130
-
131
- // Remove from server subscription if requested
132
- if (removeFromAccount) {
133
- try {
134
- await apiClient.unsubscribe(pattern);
135
- subscriptionRemoved = true;
136
- } catch (err) {
137
- logger.warn({ pattern, err }, 'Failed to unsubscribe resource from account');
138
- }
139
- }
140
-
141
- const result: UninstallResourceResult = {
142
- success: true,
143
- removed_resources: removedResources,
144
- subscription_removed: subscriptionRemoved,
145
- message: [
146
- `Prepared ${localActions.length} local uninstall action(s) for ${removedResources.length} resource(s).`,
147
- 'Execute every action in local_actions_required on the user\'s local machine.',
148
- subscriptionRemoved ? 'Subscription removed from account.' : null,
149
- ].filter(Boolean).join(' '),
150
- local_actions_required: localActions,
151
- };
152
-
153
- const duration = Date.now() - startTime;
154
- logToolCall('uninstall_resource', 'user-id', params as Record<string, unknown>, duration);
155
- logger.info({ pattern, actionCount: localActions.length, subscriptionRemoved, duration }, 'uninstall_resource completed');
156
-
157
- return { success: true, data: result };
158
-
159
- } catch (error) {
160
- logger.error({ error, pattern: typedParams.resource_id_or_name }, 'uninstall_resource failed');
161
- return {
162
- success: false,
163
- error: {
164
- code: error instanceof MCPServerError ? error.code : 'UNKNOWN_ERROR',
165
- message: error instanceof Error ? error.message : String(error),
166
- },
167
- };
168
- }
169
- }
170
-
171
- // Tool definition for registry
172
- export const uninstallResourceTool = {
173
- name: 'uninstall_resource',
174
- description:
175
- 'Uninstall a Rule or MCP resource from the user\'s local machine. ' +
176
- 'Returns `local_actions_required` — an ordered list of delete_file and ' +
177
- 'remove_mcp_json_entry actions that the AI Agent MUST execute on the USER\'S LOCAL MACHINE. ' +
178
- 'For delete_file actions: delete the file or directory at the given path. ' +
179
- 'For remove_mcp_json_entry actions: read ~/.cursor/mcp.json, delete the matching ' +
180
- 'mcpServers key, then write the file back. ' +
181
- 'Command and Skill resources are handled by unregistering their MCP Prompt (no local files). ' +
182
- 'Set remove_from_account: true to also cancel the server-side subscription.',
183
- inputSchema: {
184
- type: 'object' as const,
185
- properties: {
186
- resource_id_or_name: {
187
- type: 'string',
188
- description: 'Resource ID, name, or pattern (supports fuzzy matching)',
189
- },
190
- remove_from_account: {
191
- type: 'boolean',
192
- description: 'Also remove from subscription list (default: false)',
193
- default: false,
194
- },
195
- },
196
- required: ['resource_id_or_name'],
197
- },
198
- handler: uninstallResource,
199
- };