@modelcontextprotocol/inspector 0.16.5 → 0.16.7
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 +39 -1
- package/cli/build/cli.js +34 -3
- package/cli/build/client/prompts.js +16 -1
- package/cli/build/client/tools.js +12 -2
- package/cli/build/index.js +32 -4
- package/cli/build/transport.js +16 -2
- package/cli/build/utils/awaitable-log.js +7 -0
- package/client/dist/assets/{OAuthCallback-BxZPCak0.js → OAuthCallback-aXDAN43J.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-CwfxQhTF.js → OAuthDebugCallback-BanjyQ_V.js} +9 -1
- package/client/dist/assets/{index-BWZfLo5E.css → index-DZ1A0VH0.css} +37 -10
- package/client/dist/assets/{index-BIvDs4Sc.js → index-Dg7mXHRE.js} +230 -110
- package/client/dist/index.html +2 -2
- package/package.json +13 -6
- package/server/build/index.js +242 -126
package/README.md
CHANGED
|
@@ -29,6 +29,14 @@ npx @modelcontextprotocol/inspector
|
|
|
29
29
|
|
|
30
30
|
The server will start up and the UI will be accessible at `http://localhost:6274`.
|
|
31
31
|
|
|
32
|
+
### Docker Container
|
|
33
|
+
|
|
34
|
+
You can also start it in a Docker container with the following command:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
docker run --rm --network host -p 6274:6274 -p 6277:6277 ghcr.io/modelcontextprotocol/inspector:latest
|
|
38
|
+
```
|
|
39
|
+
|
|
32
40
|
### From an MCP server repository
|
|
33
41
|
|
|
34
42
|
To inspect an MCP server implementation, there's no need to clone this repo. Instead, use `npx`. For example, if your server is built at `build/index.js`:
|
|
@@ -90,6 +98,16 @@ The MCP Inspector provides convenient buttons to export server launch configurat
|
|
|
90
98
|
}
|
|
91
99
|
```
|
|
92
100
|
|
|
101
|
+
**Streamable HTTP transport example:**
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"type": "streamable-http",
|
|
106
|
+
"url": "http://localhost:3000/mcp",
|
|
107
|
+
"note": "For Streamable HTTP connections, add this URL directly in your MCP Client"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
93
111
|
- **Servers File** - Copies a complete MCP configuration file structure to your clipboard, with your current server configuration added as `default-server`. This can be saved directly as `mcp.json`.
|
|
94
112
|
|
|
95
113
|
**STDIO transport example:**
|
|
@@ -123,9 +141,23 @@ The MCP Inspector provides convenient buttons to export server launch configurat
|
|
|
123
141
|
}
|
|
124
142
|
```
|
|
125
143
|
|
|
144
|
+
**Streamable HTTP transport example:**
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mcpServers": {
|
|
149
|
+
"default-server": {
|
|
150
|
+
"type": "streamable-http",
|
|
151
|
+
"url": "http://localhost:3000/mcp",
|
|
152
|
+
"note": "For Streamable HTTP connections, add this URL directly in your MCP Client"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
126
158
|
These buttons appear in the Inspector UI after you've configured your server settings, making it easy to save and reuse your configurations.
|
|
127
159
|
|
|
128
|
-
For SSE transport connections, the Inspector provides similar functionality for both buttons. The "Server Entry" button copies the
|
|
160
|
+
For SSE and Streamable HTTP transport connections, the Inspector provides similar functionality for both buttons. The "Server Entry" button copies the configuration that can be added to your existing configuration file, while the "Servers File" button creates a complete configuration file containing the URL for direct use in clients.
|
|
129
161
|
|
|
130
162
|
You can paste the Server Entry into your existing `mcp.json` file under your chosen server name, or use the complete Servers File payload to create a new configuration file.
|
|
131
163
|
|
|
@@ -387,6 +419,9 @@ npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/lis
|
|
|
387
419
|
# Call a specific tool
|
|
388
420
|
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/call --tool-name mytool --tool-arg key=value --tool-arg another=value2
|
|
389
421
|
|
|
422
|
+
# Call a tool with JSON arguments
|
|
423
|
+
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/call --tool-name mytool --tool-arg 'options={"format": "json", "max_tokens": 100}'
|
|
424
|
+
|
|
390
425
|
# List available resources
|
|
391
426
|
npx @modelcontextprotocol/inspector --cli node build/index.js --method resources/list
|
|
392
427
|
|
|
@@ -399,6 +434,9 @@ npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com
|
|
|
399
434
|
# Connect to a remote MCP server (with Streamable HTTP transport)
|
|
400
435
|
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --transport http --method tools/list
|
|
401
436
|
|
|
437
|
+
# Connect to a remote MCP server (with custom headers)
|
|
438
|
+
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --transport http --method tools/list --header "X-API-Key: your-api-key"
|
|
439
|
+
|
|
402
440
|
# Call a tool on a remote server
|
|
403
441
|
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --method tools/call --tool-name remotetool --tool-arg param=value
|
|
404
442
|
|
package/cli/build/cli.js
CHANGED
|
@@ -54,6 +54,10 @@ async function runWebClient(args) {
|
|
|
54
54
|
await spawnPromise("node", [inspectorClientPath, ...startArgs], {
|
|
55
55
|
signal: abort.signal,
|
|
56
56
|
echoOutput: true,
|
|
57
|
+
// pipe the stdout through here, prevents issues with buffering and
|
|
58
|
+
// dropping the end of console.out after 8192 chars due to node
|
|
59
|
+
// closing the stdout pipe before the output has finished flushing
|
|
60
|
+
stdio: "inherit",
|
|
57
61
|
});
|
|
58
62
|
}
|
|
59
63
|
catch (e) {
|
|
@@ -73,18 +77,28 @@ async function runCli(args) {
|
|
|
73
77
|
try {
|
|
74
78
|
// Build CLI arguments
|
|
75
79
|
const cliArgs = [cliPath];
|
|
80
|
+
// Add target URL/command first
|
|
81
|
+
cliArgs.push(args.command, ...args.args);
|
|
76
82
|
// Add transport flag if specified
|
|
77
83
|
if (args.transport && args.transport !== "stdio") {
|
|
78
84
|
// Convert streamable-http back to http for CLI mode
|
|
79
85
|
const cliTransport = args.transport === "streamable-http" ? "http" : args.transport;
|
|
80
86
|
cliArgs.push("--transport", cliTransport);
|
|
81
87
|
}
|
|
82
|
-
// Add
|
|
83
|
-
|
|
88
|
+
// Add headers if specified
|
|
89
|
+
if (args.headers) {
|
|
90
|
+
for (const [key, value] of Object.entries(args.headers)) {
|
|
91
|
+
cliArgs.push("--header", `${key}: ${value}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
84
94
|
await spawnPromise("node", cliArgs, {
|
|
85
95
|
env: { ...process.env, ...args.envArgs },
|
|
86
96
|
signal: abort.signal,
|
|
87
97
|
echoOutput: true,
|
|
98
|
+
// pipe the stdout through here, prevents issues with buffering and
|
|
99
|
+
// dropping the end of console.out after 8192 chars due to node
|
|
100
|
+
// closing the stdout pipe before the output has finished flushing
|
|
101
|
+
stdio: "inherit",
|
|
88
102
|
});
|
|
89
103
|
}
|
|
90
104
|
catch (e) {
|
|
@@ -126,6 +140,18 @@ function parseKeyValuePair(value, previous = {}) {
|
|
|
126
140
|
}
|
|
127
141
|
return { ...previous, [key]: val };
|
|
128
142
|
}
|
|
143
|
+
function parseHeaderPair(value, previous = {}) {
|
|
144
|
+
const colonIndex = value.indexOf(":");
|
|
145
|
+
if (colonIndex === -1) {
|
|
146
|
+
throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
|
|
147
|
+
}
|
|
148
|
+
const key = value.slice(0, colonIndex).trim();
|
|
149
|
+
const val = value.slice(colonIndex + 1).trim();
|
|
150
|
+
if (key === "" || val === "") {
|
|
151
|
+
throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
|
|
152
|
+
}
|
|
153
|
+
return { ...previous, [key]: val };
|
|
154
|
+
}
|
|
129
155
|
function parseArgs() {
|
|
130
156
|
const program = new Command();
|
|
131
157
|
const argSeparatorIndex = process.argv.indexOf("--");
|
|
@@ -144,7 +170,8 @@ function parseArgs() {
|
|
|
144
170
|
.option("--server <n>", "server name from config file")
|
|
145
171
|
.option("--cli", "enable CLI mode")
|
|
146
172
|
.option("--transport <type>", "transport type (stdio, sse, http)")
|
|
147
|
-
.option("--server-url <url>", "server URL for SSE/HTTP transport")
|
|
173
|
+
.option("--server-url <url>", "server URL for SSE/HTTP transport")
|
|
174
|
+
.option("--header <headers...>", 'HTTP headers as "HeaderName: Value" pairs (for HTTP/SSE transports)', parseHeaderPair, {});
|
|
148
175
|
// Parse only the arguments before --
|
|
149
176
|
program.parse(preArgs);
|
|
150
177
|
const options = program.opts();
|
|
@@ -186,6 +213,7 @@ function parseArgs() {
|
|
|
186
213
|
envArgs: { ...(config.env || {}), ...(options.e || {}) },
|
|
187
214
|
cli: options.cli || false,
|
|
188
215
|
transport: "stdio",
|
|
216
|
+
headers: options.header,
|
|
189
217
|
};
|
|
190
218
|
}
|
|
191
219
|
else if (config.type === "sse" || config.type === "streamable-http") {
|
|
@@ -196,6 +224,7 @@ function parseArgs() {
|
|
|
196
224
|
cli: options.cli || false,
|
|
197
225
|
transport: config.type,
|
|
198
226
|
serverUrl: config.url,
|
|
227
|
+
headers: options.header,
|
|
199
228
|
};
|
|
200
229
|
}
|
|
201
230
|
else {
|
|
@@ -206,6 +235,7 @@ function parseArgs() {
|
|
|
206
235
|
envArgs: { ...(config.env || {}), ...(options.e || {}) },
|
|
207
236
|
cli: options.cli || false,
|
|
208
237
|
transport: "stdio",
|
|
238
|
+
headers: options.header,
|
|
209
239
|
};
|
|
210
240
|
}
|
|
211
241
|
}
|
|
@@ -224,6 +254,7 @@ function parseArgs() {
|
|
|
224
254
|
cli: options.cli || false,
|
|
225
255
|
transport: transport,
|
|
226
256
|
serverUrl: options.serverUrl,
|
|
257
|
+
headers: options.header,
|
|
227
258
|
};
|
|
228
259
|
}
|
|
229
260
|
async function main() {
|
|
@@ -11,9 +11,24 @@ export async function listPrompts(client) {
|
|
|
11
11
|
// Get a prompt
|
|
12
12
|
export async function getPrompt(client, name, args) {
|
|
13
13
|
try {
|
|
14
|
+
// Convert all arguments to strings for prompt arguments
|
|
15
|
+
const stringArgs = {};
|
|
16
|
+
if (args) {
|
|
17
|
+
for (const [key, value] of Object.entries(args)) {
|
|
18
|
+
if (typeof value === "string") {
|
|
19
|
+
stringArgs[key] = value;
|
|
20
|
+
}
|
|
21
|
+
else if (value === null || value === undefined) {
|
|
22
|
+
stringArgs[key] = String(value);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
stringArgs[key] = JSON.stringify(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
14
29
|
const response = await client.getPrompt({
|
|
15
30
|
name,
|
|
16
|
-
arguments:
|
|
31
|
+
arguments: stringArgs,
|
|
17
32
|
});
|
|
18
33
|
return response;
|
|
19
34
|
}
|
|
@@ -49,8 +49,18 @@ export async function callTool(client, name, args) {
|
|
|
49
49
|
const tool = tools.find((t) => t.name === name);
|
|
50
50
|
let convertedArgs = args;
|
|
51
51
|
if (tool) {
|
|
52
|
-
// Convert parameters based on the tool's schema
|
|
53
|
-
|
|
52
|
+
// Convert parameters based on the tool's schema, but only for string values
|
|
53
|
+
// since we now accept pre-parsed values from the CLI
|
|
54
|
+
const stringArgs = {};
|
|
55
|
+
for (const [key, value] of Object.entries(args)) {
|
|
56
|
+
if (typeof value === "string") {
|
|
57
|
+
stringArgs[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (Object.keys(stringArgs).length > 0) {
|
|
61
|
+
const convertedStringArgs = convertParameters(tool, stringArgs);
|
|
62
|
+
convertedArgs = { ...args, ...convertedStringArgs };
|
|
63
|
+
}
|
|
54
64
|
}
|
|
55
65
|
const response = await client.callTool({
|
|
56
66
|
name: name,
|
package/cli/build/index.js
CHANGED
|
@@ -4,7 +4,8 @@ import { Command } from "commander";
|
|
|
4
4
|
import { callTool, connect, disconnect, getPrompt, listPrompts, listResources, listResourceTemplates, listTools, readResource, setLoggingLevel, validLogLevels, } from "./client/index.js";
|
|
5
5
|
import { handleError } from "./error-handler.js";
|
|
6
6
|
import { createTransport } from "./transport.js";
|
|
7
|
-
|
|
7
|
+
import { awaitableLog } from "./utils/awaitable-log.js";
|
|
8
|
+
function createTransportOptions(target, transport, headers) {
|
|
8
9
|
if (target.length === 0) {
|
|
9
10
|
throw new Error("Target is required. Specify a URL or a command to execute.");
|
|
10
11
|
}
|
|
@@ -46,10 +47,11 @@ function createTransportOptions(target, transport) {
|
|
|
46
47
|
command: isUrl ? undefined : command,
|
|
47
48
|
args: isUrl ? undefined : commandArgs,
|
|
48
49
|
url: isUrl ? command : undefined,
|
|
50
|
+
headers,
|
|
49
51
|
};
|
|
50
52
|
}
|
|
51
53
|
async function callMethod(args) {
|
|
52
|
-
const transportOptions = createTransportOptions(args.target, args.transport);
|
|
54
|
+
const transportOptions = createTransportOptions(args.target, args.transport, args.headers);
|
|
53
55
|
const transport = createTransport(transportOptions);
|
|
54
56
|
const client = new Client({
|
|
55
57
|
name: "inspector-cli",
|
|
@@ -101,7 +103,7 @@ async function callMethod(args) {
|
|
|
101
103
|
else {
|
|
102
104
|
throw new Error(`Unsupported method: ${args.method}. Supported methods include: tools/list, tools/call, resources/list, resources/read, resources/templates/list, prompts/list, prompts/get, logging/setLevel`);
|
|
103
105
|
}
|
|
104
|
-
|
|
106
|
+
await awaitableLog(JSON.stringify(result, null, 2));
|
|
105
107
|
}
|
|
106
108
|
finally {
|
|
107
109
|
try {
|
|
@@ -119,6 +121,27 @@ function parseKeyValuePair(value, previous = {}) {
|
|
|
119
121
|
if (val === undefined || val === "") {
|
|
120
122
|
throw new Error(`Invalid parameter format: ${value}. Use key=value format.`);
|
|
121
123
|
}
|
|
124
|
+
// Try to parse as JSON first
|
|
125
|
+
let parsedValue;
|
|
126
|
+
try {
|
|
127
|
+
parsedValue = JSON.parse(val);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// If JSON parsing fails, keep as string
|
|
131
|
+
parsedValue = val;
|
|
132
|
+
}
|
|
133
|
+
return { ...previous, [key]: parsedValue };
|
|
134
|
+
}
|
|
135
|
+
function parseHeaderPair(value, previous = {}) {
|
|
136
|
+
const colonIndex = value.indexOf(":");
|
|
137
|
+
if (colonIndex === -1) {
|
|
138
|
+
throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
|
|
139
|
+
}
|
|
140
|
+
const key = value.slice(0, colonIndex).trim();
|
|
141
|
+
const val = value.slice(colonIndex + 1).trim();
|
|
142
|
+
if (key === "" || val === "") {
|
|
143
|
+
throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
|
|
144
|
+
}
|
|
122
145
|
return { ...previous, [key]: val };
|
|
123
146
|
}
|
|
124
147
|
function parseArgs() {
|
|
@@ -171,7 +194,11 @@ function parseArgs() {
|
|
|
171
194
|
throw new Error(`Invalid transport type: ${value}. Valid types are: ${validTransports.join(", ")}`);
|
|
172
195
|
}
|
|
173
196
|
return value;
|
|
174
|
-
})
|
|
197
|
+
})
|
|
198
|
+
//
|
|
199
|
+
// HTTP headers
|
|
200
|
+
//
|
|
201
|
+
.option("--header <headers...>", 'HTTP headers as "HeaderName: Value" pairs (for HTTP/SSE transports)', parseHeaderPair, {});
|
|
175
202
|
// Parse only the arguments before --
|
|
176
203
|
program.parse(preArgs);
|
|
177
204
|
const options = program.opts();
|
|
@@ -184,6 +211,7 @@ function parseArgs() {
|
|
|
184
211
|
return {
|
|
185
212
|
target: finalArgs,
|
|
186
213
|
...options,
|
|
214
|
+
headers: options.header, // commander.js uses 'header' field, map to 'headers'
|
|
187
215
|
};
|
|
188
216
|
}
|
|
189
217
|
async function main() {
|
package/cli/build/transport.js
CHANGED
|
@@ -38,10 +38,24 @@ export function createTransport(options) {
|
|
|
38
38
|
}
|
|
39
39
|
const url = new URL(options.url);
|
|
40
40
|
if (transportType === "sse") {
|
|
41
|
-
|
|
41
|
+
const transportOptions = options.headers
|
|
42
|
+
? {
|
|
43
|
+
requestInit: {
|
|
44
|
+
headers: options.headers,
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
: undefined;
|
|
48
|
+
return new SSEClientTransport(url, transportOptions);
|
|
42
49
|
}
|
|
43
50
|
if (transportType === "http") {
|
|
44
|
-
|
|
51
|
+
const transportOptions = options.headers
|
|
52
|
+
? {
|
|
53
|
+
requestInit: {
|
|
54
|
+
headers: options.headers,
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
: undefined;
|
|
58
|
+
return new StreamableHTTPClientTransport(url, transportOptions);
|
|
45
59
|
}
|
|
46
60
|
throw new Error(`Unsupported transport type: ${transportType}`);
|
|
47
61
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-
|
|
1
|
+
import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-Dg7mXHRE.js";
|
|
2
2
|
const OAuthCallback = ({ onConnect }) => {
|
|
3
3
|
const { toast } = useToast();
|
|
4
4
|
const hasProcessedRef = reactExports.useRef(false);
|
package/client/dist/assets/{OAuthDebugCallback-CwfxQhTF.js → OAuthDebugCallback-BanjyQ_V.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-
|
|
1
|
+
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-Dg7mXHRE.js";
|
|
2
2
|
const OAuthDebugCallback = ({ onConnect }) => {
|
|
3
3
|
reactExports.useEffect(() => {
|
|
4
4
|
let isProcessed = false;
|
|
@@ -21,6 +21,14 @@ const OAuthDebugCallback = ({ onConnect }) => {
|
|
|
21
21
|
if (storedState) {
|
|
22
22
|
try {
|
|
23
23
|
restoredState = JSON.parse(storedState);
|
|
24
|
+
if (restoredState && typeof restoredState.resource === "string") {
|
|
25
|
+
restoredState.resource = new URL(restoredState.resource);
|
|
26
|
+
}
|
|
27
|
+
if (restoredState && typeof restoredState.authorizationUrl === "string") {
|
|
28
|
+
restoredState.authorizationUrl = new URL(
|
|
29
|
+
restoredState.authorizationUrl
|
|
30
|
+
);
|
|
31
|
+
}
|
|
24
32
|
sessionStorage.removeItem(SESSION_KEYS.AUTH_DEBUGGER_STATE);
|
|
25
33
|
} catch (e) {
|
|
26
34
|
console.error("Failed to parse stored auth state:", e);
|
|
@@ -735,6 +735,39 @@ video {
|
|
|
735
735
|
background-color: hsl(var(--background));
|
|
736
736
|
color: hsl(var(--foreground));
|
|
737
737
|
}
|
|
738
|
+
.container {
|
|
739
|
+
width: 100%;
|
|
740
|
+
}
|
|
741
|
+
@media (min-width: 640px) {
|
|
742
|
+
|
|
743
|
+
.container {
|
|
744
|
+
max-width: 640px;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
@media (min-width: 768px) {
|
|
748
|
+
|
|
749
|
+
.container {
|
|
750
|
+
max-width: 768px;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
@media (min-width: 1024px) {
|
|
754
|
+
|
|
755
|
+
.container {
|
|
756
|
+
max-width: 1024px;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
@media (min-width: 1280px) {
|
|
760
|
+
|
|
761
|
+
.container {
|
|
762
|
+
max-width: 1280px;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
@media (min-width: 1536px) {
|
|
766
|
+
|
|
767
|
+
.container {
|
|
768
|
+
max-width: 1536px;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
738
771
|
.sr-only {
|
|
739
772
|
position: absolute;
|
|
740
773
|
width: 1px;
|
|
@@ -944,9 +977,6 @@ video {
|
|
|
944
977
|
.h-screen {
|
|
945
978
|
height: 100vh;
|
|
946
979
|
}
|
|
947
|
-
.max-h-80 {
|
|
948
|
-
max-height: 20rem;
|
|
949
|
-
}
|
|
950
980
|
.max-h-96 {
|
|
951
981
|
max-height: 24rem;
|
|
952
982
|
}
|
|
@@ -1407,9 +1437,6 @@ video {
|
|
|
1407
1437
|
.pr-8 {
|
|
1408
1438
|
padding-right: 2rem;
|
|
1409
1439
|
}
|
|
1410
|
-
.pt-4 {
|
|
1411
|
-
padding-top: 1rem;
|
|
1412
|
-
}
|
|
1413
1440
|
.text-left {
|
|
1414
1441
|
text-align: left;
|
|
1415
1442
|
}
|
|
@@ -1625,6 +1652,10 @@ video {
|
|
|
1625
1652
|
.ring-offset-background {
|
|
1626
1653
|
--tw-ring-offset-color: hsl(var(--background));
|
|
1627
1654
|
}
|
|
1655
|
+
.blur {
|
|
1656
|
+
--tw-blur: blur(8px);
|
|
1657
|
+
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
1658
|
+
}
|
|
1628
1659
|
.filter {
|
|
1629
1660
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
1630
1661
|
}
|
|
@@ -1768,10 +1799,6 @@ h1 {
|
|
|
1768
1799
|
color: hsl(var(--muted-foreground));
|
|
1769
1800
|
}
|
|
1770
1801
|
|
|
1771
|
-
.last\:border-b-0:last-child {
|
|
1772
|
-
border-bottom-width: 0px;
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
1802
|
.hover\:border-\[\#646cff\]:hover {
|
|
1776
1803
|
--tw-border-opacity: 1;
|
|
1777
1804
|
border-color: rgb(100 108 255 / var(--tw-border-opacity, 1));
|