@microlink/mcp 2.4.0 → 2.4.1

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@microlink/mcp",
3
3
  "description": "MCP server for Microlink API",
4
4
  "homepage": "https://github.com/microlinkhq/microlink",
5
- "version": "2.4.0",
5
+ "version": "2.4.1",
6
6
  "main": "./src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js"
@@ -66,5 +66,5 @@
66
66
  "access": "public"
67
67
  },
68
68
  "type": "module",
69
- "gitHead": "de05659e0fe9d49ba25643efbcb9914d5332ca91"
69
+ "gitHead": "f2d20e6f64995a7084ed097d5441d0f0f4950c76"
70
70
  }
@@ -32,19 +32,22 @@ export function resolveApiKey (inputApiKey, headerApiKey) {
32
32
  )
33
33
  }
34
34
 
35
- // Every tool returns the library's direct result (a string, array, or object).
36
- // MCP `structuredContent` must be an object, so wrap the value under `data`.
37
- export function asToolResult (value) {
38
- const data = value ?? null
35
+ const isPlainObject = value =>
36
+ value !== null && typeof value === 'object' && !Array.isArray(value)
37
+
38
+ function toToolResponse (isError, field, value) {
39
39
  return {
40
- isError: false,
41
- structuredContent: { data },
42
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }]
40
+ isError,
41
+ structuredContent: { [field]: value },
42
+ content: [{ type: 'text', text: JSON.stringify(value, null, 2) }]
43
43
  }
44
44
  }
45
45
 
46
- const isPlainObject = value =>
47
- value !== null && typeof value === 'object' && !Array.isArray(value)
46
+ // Every tool returns the library's direct result (a string, array, or object).
47
+ // MCP `structuredContent` must be an object, so wrap the value under `data`.
48
+ export function asToolResult (value) {
49
+ return toToolResponse(false, 'data', value ?? null)
50
+ }
48
51
 
49
52
  // The API wraps some failures in a generic top-level message ("The request
50
53
  // has been not processed…"), while the specific cause travels in `data`
@@ -53,7 +56,7 @@ const isPlainObject = value =>
53
56
  // auxiliary strings in `data`.
54
57
  const GENERIC_API_MESSAGE = 'The request has been not processed.'
55
58
 
56
- export function asErrorResult (error) {
59
+ function toErrorPayload (error) {
57
60
  const isMql = error instanceof MicrolinkError
58
61
  const statusCode = isMql ? error.statusCode : undefined
59
62
  const description = isMql ? error.description : undefined
@@ -99,9 +102,16 @@ export function asErrorResult (error) {
99
102
  payload.hint = FREE_QUOTA_EXCEEDED_HINT
100
103
  }
101
104
 
102
- return {
103
- isError: true,
104
- structuredContent: { error: payload },
105
- content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }]
106
- }
105
+ return payload
106
+ }
107
+
108
+ export function asErrorResult (error) {
109
+ const payload =
110
+ isPlainObject(error) &&
111
+ !(error instanceof Error) &&
112
+ typeof error.message === 'string'
113
+ ? error
114
+ : toErrorPayload(error)
115
+
116
+ return toToolResponse(true, 'error', payload)
107
117
  }
package/src/schemas.js CHANGED
@@ -214,6 +214,9 @@ export const metaConfigSchema = objectLikeSchema(
214
214
  .strict()
215
215
  )
216
216
 
217
+ const optionalApiKey = description =>
218
+ z.string().min(1).optional().describe(description)
219
+
217
220
  const baseSchema = z.object({
218
221
  url: z
219
222
  .string()
@@ -221,13 +224,9 @@ const baseSchema = z.object({
221
224
  .describe(
222
225
  'Public URL of the page to process. Include the protocol, for example https://example.com.'
223
226
  ),
224
- apiKey: z
225
- .string()
226
- .min(1)
227
- .optional()
228
- .describe(
229
- 'Microlink PRO API key. Omit it unless you have one: requests then use the MICROLINK_API_KEY environment variable or the free endpoint.'
230
- )
227
+ apiKey: optionalApiKey(
228
+ 'Microlink PRO API key. Omit it unless you have one: requests then use the MICROLINK_API_KEY environment variable or the free endpoint.'
229
+ )
231
230
  })
232
231
 
233
232
  const fullShape = {
@@ -426,13 +425,9 @@ export const searchInputSchema = z
426
425
  .describe(
427
426
  'Google search query. Operators like site:, filetype: or quotes work as-is.'
428
427
  ),
429
- apiKey: z
430
- .string()
431
- .min(1)
432
- .optional()
433
- .describe(
434
- 'Microlink API key. Required for this tool: Google search runs on the PRO endpoint.'
435
- ),
428
+ apiKey: optionalApiKey(
429
+ 'Microlink API key. Required for this tool: Google search runs on the PRO endpoint.'
430
+ ),
436
431
  type: z
437
432
  .enum([
438
433
  'search',
@@ -94,15 +94,10 @@ export function register (
94
94
  const parsed = inputSchema.safeParse(args)
95
95
 
96
96
  if (!parsed.success) {
97
- const payload = {
97
+ return asErrorResult({
98
98
  message: 'Input validation failed.',
99
99
  issues: parsed.error.issues
100
- }
101
- return {
102
- isError: true,
103
- structuredContent: { error: payload },
104
- content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }]
105
- }
100
+ })
106
101
  }
107
102
 
108
103
  try {