@heyclaude/mcp 0.1.2 → 0.3.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/CHANGELOG.md +25 -0
- package/README.md +71 -11
- package/package.json +1 -1
- package/scripts/validate-endpoint.mjs +236 -12
- package/src/package-metadata.js +4 -7
- package/src/registry.d.ts +139 -0
- package/src/registry.js +2154 -61
- package/src/remote-proxy.d.ts +20 -0
- package/src/remote-proxy.js +155 -42
- package/src/schemas.d.ts +15 -0
- package/src/schemas.js +181 -1
- package/src/server.js +40 -1
- package/src/submissions.d.ts +14 -2
- package/src/submissions.js +464 -67
package/src/remote-proxy.d.ts
CHANGED
|
@@ -14,6 +14,26 @@ export function createRemoteMcpProxyServer(
|
|
|
14
14
|
timeoutMs: number;
|
|
15
15
|
}>;
|
|
16
16
|
|
|
17
|
+
export function createRemoteMcpProxyServerFromClient(
|
|
18
|
+
client: {
|
|
19
|
+
getServerCapabilities: () => Record<string, unknown> | undefined;
|
|
20
|
+
listTools: (...args: unknown[]) => Promise<{ tools: Array<unknown> }>;
|
|
21
|
+
callTool: (...args: unknown[]) => Promise<unknown>;
|
|
22
|
+
listResources?: (...args: unknown[]) => Promise<unknown>;
|
|
23
|
+
listResourceTemplates?: (...args: unknown[]) => Promise<unknown>;
|
|
24
|
+
readResource?: (...args: unknown[]) => Promise<unknown>;
|
|
25
|
+
listPrompts?: (...args: unknown[]) => Promise<unknown>;
|
|
26
|
+
getPrompt?: (...args: unknown[]) => Promise<unknown>;
|
|
27
|
+
close?: () => Promise<void>;
|
|
28
|
+
},
|
|
29
|
+
options?: RemoteProxyOptions,
|
|
30
|
+
): Promise<{
|
|
31
|
+
server: Server;
|
|
32
|
+
client: unknown;
|
|
33
|
+
endpointUrl: URL;
|
|
34
|
+
timeoutMs: number;
|
|
35
|
+
}>;
|
|
36
|
+
|
|
17
37
|
export function runRemoteStdioProxy(
|
|
18
38
|
options?: RemoteProxyOptions,
|
|
19
39
|
): Promise<void>;
|
package/src/remote-proxy.js
CHANGED
|
@@ -4,12 +4,17 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import {
|
|
6
6
|
CallToolRequestSchema,
|
|
7
|
+
GetPromptRequestSchema,
|
|
7
8
|
ListToolsRequestSchema,
|
|
9
|
+
ListPromptsRequestSchema,
|
|
10
|
+
ListResourcesRequestSchema,
|
|
11
|
+
ListResourceTemplatesRequestSchema,
|
|
12
|
+
ReadResourceRequestSchema,
|
|
8
13
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
14
|
|
|
10
15
|
import { normalizeEndpointUrl, normalizeTimeoutMs } from "./endpoint-url.js";
|
|
11
16
|
import { packageVersion } from "./package-metadata.js";
|
|
12
|
-
import {
|
|
17
|
+
import { MCP_PUBLIC_POLICY, READ_ONLY_TOOL_NAMES } from "./registry.js";
|
|
13
18
|
|
|
14
19
|
function toError(error) {
|
|
15
20
|
if (error instanceof Error) return error;
|
|
@@ -34,7 +39,11 @@ function createTimeoutFetch(timeoutMs) {
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
try {
|
|
37
|
-
return await fetch(url, {
|
|
42
|
+
return await fetch(url, {
|
|
43
|
+
...init,
|
|
44
|
+
redirect: "error",
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
});
|
|
38
47
|
} finally {
|
|
39
48
|
clearTimeout(timeout);
|
|
40
49
|
if (inputSignal) {
|
|
@@ -45,86 +54,146 @@ function createTimeoutFetch(timeoutMs) {
|
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
function invalidToolResult(name) {
|
|
57
|
+
const structuredContent = {
|
|
58
|
+
ok: false,
|
|
59
|
+
error: {
|
|
60
|
+
code: "invalid_request",
|
|
61
|
+
message: `Unknown or unsupported HeyClaude MCP tool: ${name}`,
|
|
62
|
+
},
|
|
63
|
+
policy: MCP_PUBLIC_POLICY,
|
|
64
|
+
};
|
|
48
65
|
return {
|
|
49
66
|
isError: true,
|
|
67
|
+
structuredContent,
|
|
50
68
|
content: [
|
|
51
69
|
{
|
|
52
70
|
type: "text",
|
|
53
|
-
text: JSON.stringify(
|
|
54
|
-
{
|
|
55
|
-
ok: false,
|
|
56
|
-
error: {
|
|
57
|
-
code: "invalid_request",
|
|
58
|
-
message: `Unknown or unsupported HeyClaude MCP tool: ${name}`,
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
null,
|
|
62
|
-
2,
|
|
63
|
-
),
|
|
71
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
64
72
|
},
|
|
65
73
|
],
|
|
66
74
|
};
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
function errorToolResult(error) {
|
|
78
|
+
const structuredContent = {
|
|
79
|
+
ok: false,
|
|
80
|
+
error: {
|
|
81
|
+
code: "remote_mcp_error",
|
|
82
|
+
message: safeErrorMessage(error),
|
|
83
|
+
},
|
|
84
|
+
policy: MCP_PUBLIC_POLICY,
|
|
85
|
+
};
|
|
70
86
|
return {
|
|
71
87
|
isError: true,
|
|
88
|
+
structuredContent,
|
|
72
89
|
content: [
|
|
73
90
|
{
|
|
74
91
|
type: "text",
|
|
75
|
-
text: JSON.stringify(
|
|
76
|
-
{
|
|
77
|
-
ok: false,
|
|
78
|
-
error: {
|
|
79
|
-
code: "remote_mcp_error",
|
|
80
|
-
message: safeErrorMessage(error),
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
null,
|
|
84
|
-
2,
|
|
85
|
-
),
|
|
92
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
86
93
|
},
|
|
87
94
|
],
|
|
88
95
|
};
|
|
89
96
|
}
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
function readOnlyToolDefinition(tool) {
|
|
99
|
+
if (!READ_ONLY_TOOL_NAMES.includes(tool?.name)) return null;
|
|
100
|
+
return {
|
|
101
|
+
...tool,
|
|
102
|
+
annotations: {
|
|
103
|
+
...(tool.annotations || {}),
|
|
104
|
+
readOnlyHint: true,
|
|
105
|
+
destructiveHint: false,
|
|
106
|
+
idempotentHint: true,
|
|
107
|
+
openWorldHint: false,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function parseTextToolPayload(result) {
|
|
113
|
+
const text = result?.content?.find((item) => item.type === "text")?.text;
|
|
114
|
+
if (!text) return null;
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(text);
|
|
117
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
118
|
+
? parsed
|
|
119
|
+
: null;
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function withPolicy(payload) {
|
|
126
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
127
|
+
return payload;
|
|
128
|
+
}
|
|
129
|
+
if (payload.policy) return payload;
|
|
130
|
+
return { ...payload, policy: MCP_PUBLIC_POLICY };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function normalizeForwardedToolResult(result) {
|
|
134
|
+
if (!result || typeof result !== "object") return result;
|
|
135
|
+
if (result.structuredContent) {
|
|
136
|
+
return {
|
|
137
|
+
...result,
|
|
138
|
+
structuredContent: withPolicy(result.structuredContent),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const parsed = parseTextToolPayload(result);
|
|
143
|
+
if (parsed) {
|
|
144
|
+
return {
|
|
145
|
+
...result,
|
|
146
|
+
structuredContent: withPolicy(parsed),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
...result,
|
|
152
|
+
structuredContent: {
|
|
153
|
+
ok: result.isError !== true,
|
|
154
|
+
policy: MCP_PUBLIC_POLICY,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function createRemoteMcpProxyServerFromClient(
|
|
160
|
+
client,
|
|
161
|
+
options = {},
|
|
162
|
+
) {
|
|
92
163
|
const endpointUrl = normalizeEndpointUrl(options.url);
|
|
93
164
|
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
165
|
+
const remoteCapabilities = client.getServerCapabilities() || {};
|
|
166
|
+
const remoteTools = await client.listTools(undefined, { timeout: timeoutMs });
|
|
167
|
+
const toolDefinitions = remoteTools.tools
|
|
168
|
+
.map(readOnlyToolDefinition)
|
|
169
|
+
.filter(Boolean);
|
|
170
|
+
const supportedToolNames = new Set(toolDefinitions.map((tool) => tool.name));
|
|
171
|
+
const capabilities = {
|
|
172
|
+
tools: {},
|
|
173
|
+
...(remoteCapabilities.resources ? { resources: {} } : {}),
|
|
174
|
+
...(remoteCapabilities.prompts ? { prompts: {} } : {}),
|
|
175
|
+
};
|
|
103
176
|
|
|
104
177
|
const server = new Server(
|
|
105
178
|
{
|
|
106
179
|
name: "heyclaude-registry",
|
|
107
180
|
version: packageVersion,
|
|
108
181
|
},
|
|
109
|
-
{
|
|
110
|
-
capabilities: {
|
|
111
|
-
tools: {},
|
|
112
|
-
},
|
|
113
|
-
},
|
|
182
|
+
{ capabilities },
|
|
114
183
|
);
|
|
115
184
|
|
|
116
185
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
117
|
-
tools:
|
|
186
|
+
tools: toolDefinitions,
|
|
118
187
|
}));
|
|
119
188
|
|
|
120
189
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
121
190
|
const name = request.params.name;
|
|
122
|
-
if (!
|
|
191
|
+
if (!supportedToolNames.has(name)) {
|
|
123
192
|
return invalidToolResult(name);
|
|
124
193
|
}
|
|
125
194
|
|
|
126
195
|
try {
|
|
127
|
-
|
|
196
|
+
const result = await client.callTool(
|
|
128
197
|
{
|
|
129
198
|
name,
|
|
130
199
|
arguments: request.params.arguments || {},
|
|
@@ -132,11 +201,37 @@ export async function createRemoteMcpProxyServer(options = {}) {
|
|
|
132
201
|
undefined,
|
|
133
202
|
{ timeout: timeoutMs },
|
|
134
203
|
);
|
|
204
|
+
return normalizeForwardedToolResult(result);
|
|
135
205
|
} catch (error) {
|
|
136
206
|
return errorToolResult(error);
|
|
137
207
|
}
|
|
138
208
|
});
|
|
139
209
|
|
|
210
|
+
if (remoteCapabilities.resources) {
|
|
211
|
+
server.setRequestHandler(ListResourcesRequestSchema, async (request) =>
|
|
212
|
+
client.listResources(request.params || {}, { timeout: timeoutMs }),
|
|
213
|
+
);
|
|
214
|
+
server.setRequestHandler(
|
|
215
|
+
ListResourceTemplatesRequestSchema,
|
|
216
|
+
async (request) =>
|
|
217
|
+
client.listResourceTemplates(request.params || {}, {
|
|
218
|
+
timeout: timeoutMs,
|
|
219
|
+
}),
|
|
220
|
+
);
|
|
221
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) =>
|
|
222
|
+
client.readResource(request.params || {}, { timeout: timeoutMs }),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (remoteCapabilities.prompts) {
|
|
227
|
+
server.setRequestHandler(ListPromptsRequestSchema, async (request) =>
|
|
228
|
+
client.listPrompts(request.params || {}, { timeout: timeoutMs }),
|
|
229
|
+
);
|
|
230
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) =>
|
|
231
|
+
client.getPrompt(request.params || {}, { timeout: timeoutMs }),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
140
235
|
server.onclose = () => {
|
|
141
236
|
client.close().catch(() => {});
|
|
142
237
|
};
|
|
@@ -144,6 +239,24 @@ export async function createRemoteMcpProxyServer(options = {}) {
|
|
|
144
239
|
return { server, client, endpointUrl, timeoutMs };
|
|
145
240
|
}
|
|
146
241
|
|
|
242
|
+
export async function createRemoteMcpProxyServer(options = {}) {
|
|
243
|
+
const endpointUrl = normalizeEndpointUrl(options.url);
|
|
244
|
+
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
245
|
+
const client = new Client({
|
|
246
|
+
name: "heyclaude-mcp-stdio-proxy",
|
|
247
|
+
version: packageVersion,
|
|
248
|
+
});
|
|
249
|
+
const remoteTransport = new StreamableHTTPClientTransport(endpointUrl, {
|
|
250
|
+
fetch: createTimeoutFetch(timeoutMs),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
await client.connect(remoteTransport, { timeout: timeoutMs });
|
|
254
|
+
return createRemoteMcpProxyServerFromClient(client, {
|
|
255
|
+
url: endpointUrl,
|
|
256
|
+
timeoutMs,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
147
260
|
export async function runRemoteStdioProxy(options = {}) {
|
|
148
261
|
const { server } = await createRemoteMcpProxyServer(options);
|
|
149
262
|
const transport = new StdioServerTransport();
|
package/src/schemas.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
|
|
3
3
|
export const SearchRegistryInputSchema: z.ZodType;
|
|
4
|
+
export const ServerInfoInputSchema: z.ZodType;
|
|
5
|
+
export const ListCategoryEntriesInputSchema: z.ZodType;
|
|
6
|
+
export const RecentUpdatesInputSchema: z.ZodType;
|
|
7
|
+
export const RelatedEntriesInputSchema: z.ZodType;
|
|
4
8
|
export const EntryDetailInputSchema: z.ZodType;
|
|
9
|
+
export const CopyableAssetInputSchema: z.ZodType;
|
|
10
|
+
export const CompareEntriesInputSchema: z.ZodType;
|
|
11
|
+
export const RegistryStatsInputSchema: z.ZodType;
|
|
12
|
+
export const ClientSetupInputSchema: z.ZodType;
|
|
5
13
|
export const CompatibilityInputSchema: z.ZodType;
|
|
6
14
|
export const InstallGuidanceInputSchema: z.ZodType;
|
|
7
15
|
export const PlatformAdapterInputSchema: z.ZodType;
|
|
@@ -12,9 +20,16 @@ export const ValidateSubmissionDraftInputSchema: z.ZodType;
|
|
|
12
20
|
export const SearchDuplicateEntriesInputSchema: z.ZodType;
|
|
13
21
|
export const BuildSubmissionUrlsInputSchema: z.ZodType;
|
|
14
22
|
export const CategorySubmissionGuidanceInputSchema: z.ZodType;
|
|
23
|
+
export const PrepareSubmissionDraftInputSchema: z.ZodType;
|
|
24
|
+
export const GetSubmissionExamplesInputSchema: z.ZodType;
|
|
25
|
+
export const ReviewSubmissionDraftInputSchema: z.ZodType;
|
|
26
|
+
export const SubmissionPolicyInputSchema: z.ZodType;
|
|
27
|
+
export const ExplainEntryTrustInputSchema: z.ZodType;
|
|
28
|
+
export const ReviewEntrySafetyInputSchema: z.ZodType;
|
|
15
29
|
export const TOOL_INPUT_SCHEMAS: Record<string, z.ZodType>;
|
|
16
30
|
|
|
17
31
|
export function jsonSchemaForTool(name: string): Record<string, unknown>;
|
|
32
|
+
export function jsonSchemaForToolOutput(name: string): Record<string, unknown>;
|
|
18
33
|
export function parseToolArguments(
|
|
19
34
|
name: string,
|
|
20
35
|
args?: Record<string, unknown>,
|
package/src/schemas.js
CHANGED
|
@@ -8,6 +8,17 @@ const pathPart = z
|
|
|
8
8
|
.regex(/^[a-z0-9-]+$/, "Use lowercase slug-safe path parts only.");
|
|
9
9
|
|
|
10
10
|
const platform = z.string().trim().min(1).max(80);
|
|
11
|
+
const trustBooleanFilter = z.enum(["all", "true", "false"]);
|
|
12
|
+
const downloadTrustFilter = z.enum(["all", "first-party", "external", "none"]);
|
|
13
|
+
const claimStatusFilter = z.enum(["all", "unclaimed", "pending", "verified"]);
|
|
14
|
+
const sourceStatusFilter = z.enum(["all", "available", "missing"]);
|
|
15
|
+
const clientName = z.enum([
|
|
16
|
+
"codex",
|
|
17
|
+
"claude-desktop",
|
|
18
|
+
"cursor",
|
|
19
|
+
"windsurf",
|
|
20
|
+
"remote-http",
|
|
21
|
+
]);
|
|
11
22
|
const submissionCategory = z.enum([
|
|
12
23
|
"agents",
|
|
13
24
|
"rules",
|
|
@@ -21,6 +32,17 @@ const submissionCategory = z.enum([
|
|
|
21
32
|
]);
|
|
22
33
|
const optionalText = z.string().trim().max(4000).optional();
|
|
23
34
|
const optionalLongText = z.string().trim().max(24000).optional();
|
|
35
|
+
const notesShape = z
|
|
36
|
+
.string()
|
|
37
|
+
.trim()
|
|
38
|
+
.refine((value) => {
|
|
39
|
+
const lines = value
|
|
40
|
+
.split(/\r?\n/)
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
return lines.length <= 8 && lines.every((line) => line.length <= 320);
|
|
44
|
+
}, "Use at most 8 non-empty lines, 320 characters per line.")
|
|
45
|
+
.optional();
|
|
24
46
|
const optionalTags = z
|
|
25
47
|
.union([
|
|
26
48
|
z.string().trim().max(1000),
|
|
@@ -61,6 +83,8 @@ export const SubmissionFieldsSchema = z
|
|
|
61
83
|
retrieval_sources: optionalLongText,
|
|
62
84
|
tested_platforms: optionalText,
|
|
63
85
|
prerequisites: optionalLongText,
|
|
86
|
+
safety_notes: notesShape,
|
|
87
|
+
privacy_notes: notesShape,
|
|
64
88
|
troubleshooting_section: optionalLongText,
|
|
65
89
|
installation_order: optionalText,
|
|
66
90
|
estimated_setup_time: optionalText,
|
|
@@ -73,6 +97,49 @@ export const SearchRegistryInputSchema = z
|
|
|
73
97
|
query: z.string().trim().max(240).optional(),
|
|
74
98
|
category: pathPart.optional(),
|
|
75
99
|
platform: platform.optional(),
|
|
100
|
+
hasSafetyNotes: trustBooleanFilter.optional(),
|
|
101
|
+
hasPrivacyNotes: trustBooleanFilter.optional(),
|
|
102
|
+
downloadTrust: downloadTrustFilter.optional(),
|
|
103
|
+
claimStatus: claimStatusFilter.optional(),
|
|
104
|
+
sourceStatus: sourceStatusFilter.optional(),
|
|
105
|
+
limit: z.number().int().min(1).max(25).optional(),
|
|
106
|
+
})
|
|
107
|
+
.strict();
|
|
108
|
+
|
|
109
|
+
export const PlanWorkflowToolboxInputSchema = z
|
|
110
|
+
.object({
|
|
111
|
+
goal: z.string().trim().min(2).max(240),
|
|
112
|
+
category: pathPart.optional(),
|
|
113
|
+
platform: platform.optional(),
|
|
114
|
+
limit: z.number().int().min(1).max(10).optional(),
|
|
115
|
+
})
|
|
116
|
+
.strict();
|
|
117
|
+
|
|
118
|
+
export const ServerInfoInputSchema = z.object({}).strict();
|
|
119
|
+
|
|
120
|
+
export const ListCategoryEntriesInputSchema = z
|
|
121
|
+
.object({
|
|
122
|
+
category: pathPart.optional(),
|
|
123
|
+
platform: platform.optional(),
|
|
124
|
+
tag: z.string().trim().min(1).max(80).optional(),
|
|
125
|
+
query: z.string().trim().max(240).optional(),
|
|
126
|
+
offset: z.number().int().min(0).max(5000).optional(),
|
|
127
|
+
limit: z.number().int().min(1).max(25).optional(),
|
|
128
|
+
})
|
|
129
|
+
.strict();
|
|
130
|
+
|
|
131
|
+
export const RecentUpdatesInputSchema = z
|
|
132
|
+
.object({
|
|
133
|
+
category: pathPart.optional(),
|
|
134
|
+
since: z.string().trim().min(4).max(40).optional(),
|
|
135
|
+
limit: z.number().int().min(1).max(25).optional(),
|
|
136
|
+
})
|
|
137
|
+
.strict();
|
|
138
|
+
|
|
139
|
+
export const RelatedEntriesInputSchema = z
|
|
140
|
+
.object({
|
|
141
|
+
category: pathPart,
|
|
142
|
+
slug: pathPart,
|
|
76
143
|
limit: z.number().int().min(1).max(25).optional(),
|
|
77
144
|
})
|
|
78
145
|
.strict();
|
|
@@ -84,6 +151,40 @@ export const EntryDetailInputSchema = z
|
|
|
84
151
|
})
|
|
85
152
|
.strict();
|
|
86
153
|
|
|
154
|
+
export const CopyableAssetInputSchema = z
|
|
155
|
+
.object({
|
|
156
|
+
category: pathPart,
|
|
157
|
+
slug: pathPart,
|
|
158
|
+
platform: platform.optional(),
|
|
159
|
+
})
|
|
160
|
+
.strict();
|
|
161
|
+
|
|
162
|
+
export const CompareEntriesInputSchema = z
|
|
163
|
+
.object({
|
|
164
|
+
entries: z
|
|
165
|
+
.array(
|
|
166
|
+
z
|
|
167
|
+
.object({
|
|
168
|
+
category: pathPart,
|
|
169
|
+
slug: pathPart,
|
|
170
|
+
})
|
|
171
|
+
.strict(),
|
|
172
|
+
)
|
|
173
|
+
.min(2)
|
|
174
|
+
.max(5),
|
|
175
|
+
platform: platform.optional(),
|
|
176
|
+
})
|
|
177
|
+
.strict();
|
|
178
|
+
|
|
179
|
+
export const RegistryStatsInputSchema = z.object({}).strict();
|
|
180
|
+
|
|
181
|
+
export const ClientSetupInputSchema = z
|
|
182
|
+
.object({
|
|
183
|
+
client: clientName.optional(),
|
|
184
|
+
endpointUrl: z.string().trim().url().max(500).optional(),
|
|
185
|
+
})
|
|
186
|
+
.strict();
|
|
187
|
+
|
|
87
188
|
export const CompatibilityInputSchema = z
|
|
88
189
|
.object({
|
|
89
190
|
category: pathPart.optional(),
|
|
@@ -135,7 +236,7 @@ export const SearchDuplicateEntriesInputSchema = z
|
|
|
135
236
|
export const BuildSubmissionUrlsInputSchema = z
|
|
136
237
|
.object({
|
|
137
238
|
fields: SubmissionFieldsSchema,
|
|
138
|
-
|
|
239
|
+
includePrBody: z.boolean().optional(),
|
|
139
240
|
})
|
|
140
241
|
.strict();
|
|
141
242
|
|
|
@@ -145,9 +246,63 @@ export const CategorySubmissionGuidanceInputSchema = z
|
|
|
145
246
|
})
|
|
146
247
|
.strict();
|
|
147
248
|
|
|
249
|
+
export const PrepareSubmissionDraftInputSchema = z
|
|
250
|
+
.object({
|
|
251
|
+
fields: SubmissionFieldsSchema,
|
|
252
|
+
})
|
|
253
|
+
.strict();
|
|
254
|
+
|
|
255
|
+
export const GetSubmissionExamplesInputSchema = z
|
|
256
|
+
.object({
|
|
257
|
+
category: submissionCategory.optional(),
|
|
258
|
+
})
|
|
259
|
+
.strict();
|
|
260
|
+
|
|
261
|
+
export const ReviewSubmissionDraftInputSchema = z
|
|
262
|
+
.object({
|
|
263
|
+
fields: SubmissionFieldsSchema,
|
|
264
|
+
duplicateLimit: z.number().int().min(1).max(10).optional(),
|
|
265
|
+
})
|
|
266
|
+
.strict();
|
|
267
|
+
|
|
268
|
+
export const SubmissionPolicyInputSchema = z.object({}).strict();
|
|
269
|
+
|
|
270
|
+
export const ExplainEntryTrustInputSchema = z
|
|
271
|
+
.object({
|
|
272
|
+
category: pathPart,
|
|
273
|
+
slug: pathPart,
|
|
274
|
+
})
|
|
275
|
+
.strict();
|
|
276
|
+
|
|
277
|
+
export const ReviewEntrySafetyInputSchema = z
|
|
278
|
+
.object({
|
|
279
|
+
entries: z
|
|
280
|
+
.array(
|
|
281
|
+
z
|
|
282
|
+
.object({
|
|
283
|
+
category: pathPart,
|
|
284
|
+
slug: pathPart,
|
|
285
|
+
})
|
|
286
|
+
.strict(),
|
|
287
|
+
)
|
|
288
|
+
.min(1)
|
|
289
|
+
.max(5),
|
|
290
|
+
platform: platform.optional(),
|
|
291
|
+
})
|
|
292
|
+
.strict();
|
|
293
|
+
|
|
148
294
|
export const TOOL_INPUT_SCHEMAS = {
|
|
149
295
|
search_registry: SearchRegistryInputSchema,
|
|
296
|
+
plan_workflow_toolbox: PlanWorkflowToolboxInputSchema,
|
|
297
|
+
server_info: ServerInfoInputSchema,
|
|
298
|
+
list_category_entries: ListCategoryEntriesInputSchema,
|
|
299
|
+
get_recent_updates: RecentUpdatesInputSchema,
|
|
300
|
+
get_related_entries: RelatedEntriesInputSchema,
|
|
150
301
|
get_entry_detail: EntryDetailInputSchema,
|
|
302
|
+
get_copyable_asset: CopyableAssetInputSchema,
|
|
303
|
+
compare_entries: CompareEntriesInputSchema,
|
|
304
|
+
get_registry_stats: RegistryStatsInputSchema,
|
|
305
|
+
get_client_setup: ClientSetupInputSchema,
|
|
151
306
|
get_compatibility: CompatibilityInputSchema,
|
|
152
307
|
get_install_guidance: InstallGuidanceInputSchema,
|
|
153
308
|
get_platform_adapter: PlatformAdapterInputSchema,
|
|
@@ -157,6 +312,12 @@ export const TOOL_INPUT_SCHEMAS = {
|
|
|
157
312
|
search_duplicate_entries: SearchDuplicateEntriesInputSchema,
|
|
158
313
|
build_submission_urls: BuildSubmissionUrlsInputSchema,
|
|
159
314
|
get_category_submission_guidance: CategorySubmissionGuidanceInputSchema,
|
|
315
|
+
prepare_submission_draft: PrepareSubmissionDraftInputSchema,
|
|
316
|
+
get_submission_examples: GetSubmissionExamplesInputSchema,
|
|
317
|
+
review_submission_draft: ReviewSubmissionDraftInputSchema,
|
|
318
|
+
get_submission_policy: SubmissionPolicyInputSchema,
|
|
319
|
+
explain_entry_trust: ExplainEntryTrustInputSchema,
|
|
320
|
+
review_entry_safety: ReviewEntrySafetyInputSchema,
|
|
160
321
|
};
|
|
161
322
|
|
|
162
323
|
function stripUnsupportedJsonSchemaFields(value) {
|
|
@@ -180,6 +341,25 @@ export function jsonSchemaForTool(name) {
|
|
|
180
341
|
return stripUnsupportedJsonSchemaFields(z.toJSONSchema(schema));
|
|
181
342
|
}
|
|
182
343
|
|
|
344
|
+
export function jsonSchemaForToolOutput(name) {
|
|
345
|
+
if (!TOOL_INPUT_SCHEMAS[name]) {
|
|
346
|
+
throw new Error(`Unknown HeyClaude MCP tool output schema: ${name}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
type: "object",
|
|
351
|
+
properties: {
|
|
352
|
+
ok: { type: "boolean" },
|
|
353
|
+
policy: {
|
|
354
|
+
type: "object",
|
|
355
|
+
additionalProperties: true,
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
required: ["ok"],
|
|
359
|
+
additionalProperties: true,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
183
363
|
export function parseToolArguments(name, args = {}) {
|
|
184
364
|
const schema = TOOL_INPUT_SCHEMAS[name];
|
|
185
365
|
if (!schema) {
|
package/src/server.js
CHANGED
|
@@ -2,11 +2,24 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import {
|
|
4
4
|
CallToolRequestSchema,
|
|
5
|
+
GetPromptRequestSchema,
|
|
6
|
+
ListPromptsRequestSchema,
|
|
7
|
+
ListResourcesRequestSchema,
|
|
8
|
+
ListResourceTemplatesRequestSchema,
|
|
5
9
|
ListToolsRequestSchema,
|
|
10
|
+
ReadResourceRequestSchema,
|
|
6
11
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
7
12
|
|
|
8
13
|
import { packageVersion } from "./package-metadata.js";
|
|
9
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
callRegistryTool,
|
|
16
|
+
getRegistryPrompt,
|
|
17
|
+
listRegistryPrompts,
|
|
18
|
+
listRegistryResources,
|
|
19
|
+
listRegistryResourceTemplates,
|
|
20
|
+
readRegistryResource,
|
|
21
|
+
TOOL_DEFINITIONS,
|
|
22
|
+
} from "./registry.js";
|
|
10
23
|
|
|
11
24
|
export function createHeyClaudeMcpServer(options = {}) {
|
|
12
25
|
const server = new Server(
|
|
@@ -16,6 +29,8 @@ export function createHeyClaudeMcpServer(options = {}) {
|
|
|
16
29
|
},
|
|
17
30
|
{
|
|
18
31
|
capabilities: {
|
|
32
|
+
prompts: {},
|
|
33
|
+
resources: {},
|
|
19
34
|
tools: {},
|
|
20
35
|
},
|
|
21
36
|
},
|
|
@@ -33,6 +48,10 @@ export function createHeyClaudeMcpServer(options = {}) {
|
|
|
33
48
|
);
|
|
34
49
|
return {
|
|
35
50
|
isError: result.ok === false,
|
|
51
|
+
structuredContent:
|
|
52
|
+
result && typeof result === "object" && !Array.isArray(result)
|
|
53
|
+
? result
|
|
54
|
+
: { result },
|
|
36
55
|
content: [
|
|
37
56
|
{
|
|
38
57
|
type: "text",
|
|
@@ -42,6 +61,26 @@ export function createHeyClaudeMcpServer(options = {}) {
|
|
|
42
61
|
};
|
|
43
62
|
});
|
|
44
63
|
|
|
64
|
+
server.setRequestHandler(ListResourcesRequestSchema, async (request) =>
|
|
65
|
+
listRegistryResources(request.params || {}, options),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () =>
|
|
69
|
+
listRegistryResourceTemplates(),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) =>
|
|
73
|
+
readRegistryResource(request.params || {}, options),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () =>
|
|
77
|
+
listRegistryPrompts(),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) =>
|
|
81
|
+
getRegistryPrompt(request.params || {}),
|
|
82
|
+
);
|
|
83
|
+
|
|
45
84
|
return server;
|
|
46
85
|
}
|
|
47
86
|
|
package/src/submissions.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export const SUBMISSION_SITE_URL: string;
|
|
2
|
-
export const GITHUB_NEW_ISSUE_URL: string;
|
|
3
2
|
|
|
4
3
|
export function slugify(value: string): string;
|
|
5
4
|
export function normalizeSubmissionFields(
|
|
6
5
|
fields?: Record<string, unknown>,
|
|
7
6
|
): Record<string, string>;
|
|
8
|
-
export function
|
|
7
|
+
export function buildPrDraftFromSpec(
|
|
9
8
|
spec: Record<string, unknown>,
|
|
10
9
|
fields?: Record<string, unknown>,
|
|
11
10
|
): Record<string, unknown>;
|
|
@@ -21,6 +20,19 @@ export function validateSubmissionDraftFromSpec(
|
|
|
21
20
|
spec: Record<string, unknown>,
|
|
22
21
|
args?: Record<string, unknown>,
|
|
23
22
|
): Record<string, unknown>;
|
|
23
|
+
export function prepareSubmissionDraftFromSpec(
|
|
24
|
+
spec: Record<string, unknown>,
|
|
25
|
+
args?: Record<string, unknown>,
|
|
26
|
+
): Record<string, unknown>;
|
|
27
|
+
export function getSubmissionExamplesFromSpec(
|
|
28
|
+
spec: Record<string, unknown>,
|
|
29
|
+
args?: Record<string, unknown>,
|
|
30
|
+
): Record<string, unknown>;
|
|
31
|
+
export function reviewSubmissionDraftFromSpec(
|
|
32
|
+
spec: Record<string, unknown>,
|
|
33
|
+
args?: Record<string, unknown>,
|
|
34
|
+
entries?: Array<Record<string, unknown>>,
|
|
35
|
+
): Record<string, unknown>;
|
|
24
36
|
export function searchDuplicateEntries(
|
|
25
37
|
entries?: Array<Record<string, unknown>>,
|
|
26
38
|
args?: Record<string, unknown>,
|