@microlink/mcp 1.0.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/LICENSE.md +21 -0
- package/README.md +435 -0
- package/bin/microlink-mcp.js +8 -0
- package/package.json +104 -0
- package/scripts/postinstall.js +49 -0
- package/src/index.js +65 -0
- package/src/microlink-client.js +239 -0
- package/src/schemas.js +271 -0
- package/src/tools/audio.js +17 -0
- package/src/tools/extract.js +20 -0
- package/src/tools/index.js +23 -0
- package/src/tools/insights.js +21 -0
- package/src/tools/markdown.js +16 -0
- package/src/tools/meta.js +17 -0
- package/src/tools/palette.js +17 -0
- package/src/tools/pdf.js +23 -0
- package/src/tools/register.js +110 -0
- package/src/tools/screenshot.js +23 -0
- package/src/tools/text.js +16 -0
- package/src/tools/video.js +17 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { asToolResult, callMicrolink } from '../microlink-client.js'
|
|
2
|
+
|
|
3
|
+
function getHeaderValueCaseInsensitive (headers, headerName) {
|
|
4
|
+
if (!headers || typeof headers !== 'object') {
|
|
5
|
+
return undefined
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const lookup = headerName.toLowerCase()
|
|
9
|
+
|
|
10
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
11
|
+
if (key.toLowerCase() === lookup) {
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value[0]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getApiKeyFromRequestHeaders (headers) {
|
|
24
|
+
const authorization = getHeaderValueCaseInsensitive(headers, 'authorization')
|
|
25
|
+
|
|
26
|
+
if (typeof authorization === 'string') {
|
|
27
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorization.trim())
|
|
28
|
+
const bearerToken = match?.[1]?.trim()
|
|
29
|
+
|
|
30
|
+
if (bearerToken) {
|
|
31
|
+
return bearerToken
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const xApiKey = getHeaderValueCaseInsensitive(headers, 'x-api-key')
|
|
36
|
+
if (typeof xApiKey === 'string') {
|
|
37
|
+
const token = xApiKey.trim()
|
|
38
|
+
if (token) {
|
|
39
|
+
return token
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function register (server, name, description, inputSchema, forcedFlags) {
|
|
47
|
+
server.registerTool(
|
|
48
|
+
name,
|
|
49
|
+
{
|
|
50
|
+
description,
|
|
51
|
+
inputSchema
|
|
52
|
+
},
|
|
53
|
+
async (args, extra) => {
|
|
54
|
+
const parsedArgs = inputSchema.safeParse(args)
|
|
55
|
+
if (!parsedArgs.success) {
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: JSON.stringify(
|
|
62
|
+
{
|
|
63
|
+
message: 'Input validation failed.',
|
|
64
|
+
issues: parsedArgs.error.issues
|
|
65
|
+
},
|
|
66
|
+
null,
|
|
67
|
+
2
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const headerApiKey = getApiKeyFromRequestHeaders(extra?.requestInfo?.headers)
|
|
76
|
+
const params =
|
|
77
|
+
parsedArgs.data.apiKey || !headerApiKey
|
|
78
|
+
? parsedArgs.data
|
|
79
|
+
: {
|
|
80
|
+
...parsedArgs.data,
|
|
81
|
+
apiKey: headerApiKey
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const result = await callMicrolink({
|
|
85
|
+
params,
|
|
86
|
+
forcedFlags
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return asToolResult(result)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
isError: true,
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: 'text',
|
|
96
|
+
text: JSON.stringify(
|
|
97
|
+
{
|
|
98
|
+
message: 'Microlink request failed before receiving an API response.',
|
|
99
|
+
error: error instanceof Error ? error.message : String(error)
|
|
100
|
+
},
|
|
101
|
+
null,
|
|
102
|
+
2
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { screenshotInputSchema } from '../schemas.js'
|
|
2
|
+
import { register } from './register.js'
|
|
3
|
+
|
|
4
|
+
export function screenshot (server) {
|
|
5
|
+
register(
|
|
6
|
+
server,
|
|
7
|
+
'microlink_screenshot',
|
|
8
|
+
[
|
|
9
|
+
'Capture a screenshot of any public URL via Microlink and return a permanent CDN asset URL.',
|
|
10
|
+
'The screenshot URL is in `data.screenshot.url`.',
|
|
11
|
+
'Pass `screenshot: true` for defaults or `screenshot: { ... }` for options; `screenshot: {}` is treated as `true`.',
|
|
12
|
+
'Use `screenshot.fullPage` to capture the entire scrollable page.',
|
|
13
|
+
'Use `screenshot.element` (CSS selector) to capture a specific DOM element.',
|
|
14
|
+
'Use `screenshot.type` to choose output format: "jpeg" (default "png").',
|
|
15
|
+
'Use `screenshot.omitBackground` to remove the white background (useful with transparent PNGs).',
|
|
16
|
+
'Use `screenshot.overlay` to add a browser chrome overlay with `browser` ("light"|"dark") and `background` (CSS color or gradient).',
|
|
17
|
+
'Use `screenshot.codeScheme` to set the syntax-highlighting theme for code pages (e.g. "dracula", "atom-dark").',
|
|
18
|
+
'Combine with `device`, `viewport`, `click`, `scroll`, `styles`, `scripts`, `modules`, `waitForSelector`, `waitForTimeout`, `waitUntil`, `colorScheme`, and `mediaType` for full browser control.'
|
|
19
|
+
].join(' '),
|
|
20
|
+
screenshotInputSchema,
|
|
21
|
+
{ screenshot: true, meta: false }
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { textInputSchema } from '../schemas.js'
|
|
2
|
+
import { register } from './register.js'
|
|
3
|
+
|
|
4
|
+
export function text (server) {
|
|
5
|
+
register(
|
|
6
|
+
server,
|
|
7
|
+
'microlink_text',
|
|
8
|
+
[
|
|
9
|
+
'Extract plain text from any public URL via Microlink.',
|
|
10
|
+
'Returns JSON output with plain text content under `data.text`.',
|
|
11
|
+
'Useful for getting raw text content from web pages.'
|
|
12
|
+
].join(' '),
|
|
13
|
+
textInputSchema,
|
|
14
|
+
{ data: { text: { attr: 'text' } }, meta: false }
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { videoInputSchema } from '../schemas.js'
|
|
2
|
+
import { register } from './register.js'
|
|
3
|
+
|
|
4
|
+
export function video (server) {
|
|
5
|
+
register(
|
|
6
|
+
server,
|
|
7
|
+
'microlink_video',
|
|
8
|
+
[
|
|
9
|
+
'Detect and extract playable video sources from any URL via Microlink.',
|
|
10
|
+
'Works with YouTube, Vimeo, Twitter/X, TikTok, Instagram, Dailymotion, and hundreds of other platforms.',
|
|
11
|
+
'The video URL is in `data.video.url`. Also returns `type`, `duration`, `size`, `width`, `height`, `duration_pretty`, and `size_pretty`.',
|
|
12
|
+
'Combine with `proxy` for sites that require it, or with `meta` to suppress metadata extraction.'
|
|
13
|
+
].join(' '),
|
|
14
|
+
videoInputSchema,
|
|
15
|
+
{ video: true, meta: false }
|
|
16
|
+
)
|
|
17
|
+
}
|