@mcpjam/inspector 0.3.9 → 0.8.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/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +89 -0
- package/.next/app-path-routes-manifest.json +13 -0
- package/.next/build-manifest.json +33 -0
- package/.next/cache/.previewinfo +1 -0
- package/.next/cache/.rscinfo +1 -0
- package/.next/cache/.tsbuildinfo +1 -0
- package/.next/cache/eslint/.cache_1pr0xfn +1 -0
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +57 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +41 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +318 -0
- package/.next/routes-manifest.json +65 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/chat/route.js +45 -0
- package/.next/server/app/api/mcp/chat/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/chat/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/connect/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/get/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/read/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/tools/route.js +21 -0
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -0
- package/.next/server/app/favicon.ico/route.js +1 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/oauth/callback/page.js +2 -0
- package/.next/server/app/oauth/callback/page.js.nft.json +1 -0
- package/.next/server/app/oauth/callback/page_client-reference-manifest.js +1 -0
- package/.next/server/app/page.js +16 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +13 -0
- package/.next/server/chunks/175.js +8 -0
- package/.next/server/chunks/260.js +82 -0
- package/.next/server/chunks/546.js +1 -0
- package/.next/server/chunks/548.js +6 -0
- package/.next/server/chunks/55.js +1 -0
- package/.next/server/chunks/985.js +22 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +19 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +5 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/Pq27RIJUfrYOGSjOrYx4E/_buildManifest.js +1 -0
- package/.next/static/Pq27RIJUfrYOGSjOrYx4E/_ssgManifest.js +1 -0
- package/.next/static/chunks/14-ae3a01e72ea53777.js +1 -0
- package/.next/static/chunks/214-cc4c35d88f2695ed.js +1 -0
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +1 -0
- package/.next/static/chunks/866-04c19dda4c52f2bf.js +1 -0
- package/.next/static/chunks/964-eda38e26c0391a47.js +1 -0
- package/.next/static/chunks/app/_not-found/page-8601c49989b0be94.js +1 -0
- package/.next/static/chunks/app/api/mcp/chat/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/connect/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/get/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/read/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/tools/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/layout-9e8115d4bf656fa0.js +1 -0
- package/.next/static/chunks/app/oauth/callback/page-cf6cb1ac31175f40.js +1 -0
- package/.next/static/chunks/app/page-fdd433623879220d.js +1 -0
- package/.next/static/chunks/framework-7c95b8e5103c9e90.js +1 -0
- package/.next/static/chunks/main-app-4e9e28316818cdde.js +1 -0
- package/.next/static/chunks/main-bbdafee21a7bd1d6.js +1 -0
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +1 -0
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-cdfccaf38062dd25.js +1 -0
- package/.next/static/css/1e852d83e9c1d0c6.css +1 -0
- package/.next/static/css/f30152c0704fba31.css +1 -0
- package/.next/static/css/fe751fdbe975e9ca.css +1 -0
- package/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/static/media/ollama_dark.9af45ac0.png +0 -0
- package/.next/static/media/ollama_logo.9f08a95b.svg +7 -0
- package/.next/static/media/openai_logo.3f83154a.png +0 -0
- package/.next/trace +35 -0
- package/.next/types/app/api/mcp/chat/route.ts +347 -0
- package/.next/types/app/api/mcp/connect/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/get/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/read/route.ts +347 -0
- package/.next/types/app/api/mcp/tools/route.ts +347 -0
- package/.next/types/app/layout.ts +84 -0
- package/.next/types/app/oauth/callback/page.ts +84 -0
- package/.next/types/app/page.ts +84 -0
- package/.next/types/cache-life.d.ts +141 -0
- package/.next/types/package.json +1 -0
- package/README.md +76 -161
- package/bin/start.js +504 -0
- package/next.config.ts +7 -0
- package/package.json +71 -54
- package/public/claude_logo.png +0 -0
- package/public/demo_1.png +0 -0
- package/public/demo_2.png +0 -0
- package/public/demo_3.png +0 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/mcp.svg +1 -0
- package/public/next.svg +1 -0
- package/public/ollama_dark.png +0 -0
- package/public/ollama_logo.svg +7 -0
- package/public/openai_logo.png +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/LICENSE +0 -200
- package/cli/build/cli.js +0 -251
- package/cli/build/client/connection.js +0 -33
- package/cli/build/client/index.js +0 -6
- package/cli/build/client/prompts.js +0 -23
- package/cli/build/client/resources.js +0 -30
- package/cli/build/client/tools.js +0 -64
- package/cli/build/client/types.js +0 -1
- package/cli/build/error-handler.js +0 -18
- package/cli/build/index.js +0 -166
- package/cli/build/transport.js +0 -47
- package/client/bin/client.js +0 -71
- package/client/bin/start.js +0 -143
- package/client/dist/assets/OAuthCallback-BSOXmPlE.js +0 -56
- package/client/dist/assets/OAuthDebugCallback-DyzqkofK.js +0 -44
- package/client/dist/assets/index-BT03cD-1.js +0 -63301
- package/client/dist/assets/index-Bwd_BFIj.css +0 -4164
- package/client/dist/index.html +0 -14
- package/client/dist/ollama_logo.png +0 -0
- package/client/dist/openai_logo.png +0 -0
- package/server/build/database/DatabaseManager.js +0 -108
- package/server/build/database/index.js +0 -8
- package/server/build/database/routes.js +0 -86
- package/server/build/database/types.js +0 -27
- package/server/build/database/utils.js +0 -86
- package/server/build/index.js +0 -331
- package/server/build/mcpProxy.js +0 -54
- package/server/build/shared/MCPProxyService.js +0 -221
- package/server/build/shared/TransportFactory.js +0 -130
- package/server/build/shared/index.js +0 -4
- package/server/build/shared/types.js +0 -1
- package/server/build/shared/utils.js +0 -27
- package/server/build/test-server.js +0 -145
- package/server/build/testing/HealthCheck.js +0 -42
- package/server/build/testing/TestExecutor.js +0 -240
- package/server/build/testing/TestRunner.js +0 -198
- package/server/build/testing/TestServer.js +0 -440
- package/server/build/testing/types.js +0 -1
- /package/{client/dist/claude_logo.png → .next/static/media/claude_logo.d33b25b0.png} +0 -0
- /package/{client/dist → public}/mcp_jam.svg +0 -0
- /package/{client/dist → public}/mcp_jam_dark.png +0 -0
- /package/{client/dist → public}/mcp_jam_light.png +0 -0
package/bin/start.js
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { resolve, dirname } from "path";
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { createServer } from "net";
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
const MCP_BANNER = `
|
|
12
|
+
███╗ ███╗ ██████╗██████╗ ██╗ █████╗ ███╗ ███╗
|
|
13
|
+
████╗ ████║██╔════╝██╔══██╗ ██║██╔══██╗████╗ ████║
|
|
14
|
+
██╔████╔██║██║ ██████╔╝ ██║███████║██╔████╔██║
|
|
15
|
+
██║╚██╔╝██║██║ ██╔═══╝██ ██║██╔══██║██║╚██╔╝██║
|
|
16
|
+
██║ ╚═╝ ██║╚██████╗██║ ╚█████╔╝██║ ██║██║ ╚═╝ ██║
|
|
17
|
+
╚═╝ ╚═╝ ╚═════╝╚═╝ ╚════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
// ANSI color codes
|
|
21
|
+
const colors = {
|
|
22
|
+
reset: "\x1b[0m",
|
|
23
|
+
bright: "\x1b[1m",
|
|
24
|
+
dim: "\x1b[2m",
|
|
25
|
+
red: "\x1b[31m",
|
|
26
|
+
green: "\x1b[32m",
|
|
27
|
+
yellow: "\x1b[33m",
|
|
28
|
+
blue: "\x1b[34m",
|
|
29
|
+
magenta: "\x1b[35m",
|
|
30
|
+
cyan: "\x1b[36m",
|
|
31
|
+
white: "\x1b[37m",
|
|
32
|
+
bgRed: "\x1b[41m",
|
|
33
|
+
bgGreen: "\x1b[42m",
|
|
34
|
+
bgYellow: "\x1b[43m",
|
|
35
|
+
bgBlue: "\x1b[44m",
|
|
36
|
+
bgMagenta: "\x1b[45m",
|
|
37
|
+
bgCyan: "\x1b[46m",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Utility functions for beautiful output
|
|
41
|
+
function log(message, color = colors.reset) {
|
|
42
|
+
console.log(`${color}${message}${colors.reset}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function logSuccess(message) {
|
|
46
|
+
log(`✅ ${message}`, colors.green);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function logInfo(message) {
|
|
50
|
+
log(`ℹ️ ${message}`, colors.blue);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function logWarning(message) {
|
|
54
|
+
log(`⚠️ ${message}`, colors.yellow);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function logError(message) {
|
|
58
|
+
log(`❌ ${message}`, colors.red);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function logStep(step, message) {
|
|
62
|
+
log(
|
|
63
|
+
`\n${colors.cyan}${colors.bright}[${step}]${colors.reset} ${message}`,
|
|
64
|
+
colors.white,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function logProgress(message) {
|
|
69
|
+
log(`⏳ ${message}`, colors.magenta);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function logDivider() {
|
|
73
|
+
log("─".repeat(80), colors.dim);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function logBox(content, title = null) {
|
|
77
|
+
const lines = content.split("\n");
|
|
78
|
+
const maxLength = Math.max(...lines.map((line) => line.length));
|
|
79
|
+
const width = maxLength + 4;
|
|
80
|
+
|
|
81
|
+
log("┌" + "─".repeat(width) + "┐", colors.cyan);
|
|
82
|
+
if (title) {
|
|
83
|
+
const titlePadding = Math.floor((width - title.length - 2) / 2);
|
|
84
|
+
log(
|
|
85
|
+
"│" +
|
|
86
|
+
" ".repeat(titlePadding) +
|
|
87
|
+
title +
|
|
88
|
+
" ".repeat(width - title.length - titlePadding) +
|
|
89
|
+
"│",
|
|
90
|
+
colors.cyan,
|
|
91
|
+
);
|
|
92
|
+
log("├" + "─".repeat(width) + "┤", colors.cyan);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
lines.forEach((line) => {
|
|
96
|
+
const padding = width - line.length - 2;
|
|
97
|
+
log("│ " + line + " ".repeat(padding) + " │", colors.cyan);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
log("└" + "─".repeat(width) + "┘", colors.cyan);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function delay(ms) {
|
|
104
|
+
return new Promise((resolve) => setTimeout(resolve, ms, true));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isPortAvailable(port) {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
const server = createServer();
|
|
110
|
+
|
|
111
|
+
server.listen(port, () => {
|
|
112
|
+
server.once("close", () => {
|
|
113
|
+
resolve(true);
|
|
114
|
+
});
|
|
115
|
+
server.close();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
server.on("error", () => {
|
|
119
|
+
resolve(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function findAvailablePort(startPort = 3000, maxPort = 3100) {
|
|
125
|
+
for (let port = startPort; port <= maxPort; port++) {
|
|
126
|
+
if (await isPortAvailable(port)) {
|
|
127
|
+
return port;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
throw new Error(
|
|
131
|
+
`No available ports found between ${startPort} and ${maxPort}`,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function spawnPromise(command, args, options) {
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
const child = spawn(command, args, {
|
|
138
|
+
stdio: options.echoOutput ? "inherit" : "pipe",
|
|
139
|
+
...options,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (options.signal) {
|
|
143
|
+
options.signal.addEventListener("abort", () => {
|
|
144
|
+
child.kill("SIGTERM");
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
child.on("close", (code) => {
|
|
149
|
+
if (code === 0) {
|
|
150
|
+
resolve(code);
|
|
151
|
+
} else {
|
|
152
|
+
reject(new Error(`Process exited with code ${code}`));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
child.on("error", reject);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function showWelcomeMessage() {
|
|
161
|
+
console.clear();
|
|
162
|
+
log(MCP_BANNER, colors.cyan);
|
|
163
|
+
|
|
164
|
+
logDivider();
|
|
165
|
+
|
|
166
|
+
const welcomeText = `Welcome to the MCP Inspector!
|
|
167
|
+
This tool helps you explore and interact with Model Context Protocol servers.
|
|
168
|
+
Get ready to discover the power of MCP integration.`;
|
|
169
|
+
|
|
170
|
+
logBox(welcomeText, "🎯 Getting Started");
|
|
171
|
+
|
|
172
|
+
logDivider();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function showServerInfo(port) {
|
|
176
|
+
const serverInfo = `Server URL: http://localhost:${port}
|
|
177
|
+
Environment: Production
|
|
178
|
+
Framework: Next.js
|
|
179
|
+
Status: Starting up...`;
|
|
180
|
+
|
|
181
|
+
logBox(serverInfo, "🌐 Server Configuration");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function showSuccessMessage(port) {
|
|
185
|
+
logDivider();
|
|
186
|
+
|
|
187
|
+
const successText = `🎉 MCP Inspector is now running successfully!
|
|
188
|
+
|
|
189
|
+
📱 Access your application at: ${colors.bright}${colors.green}http://localhost:${port}${colors.reset}
|
|
190
|
+
🔧 Server is ready to handle MCP connections
|
|
191
|
+
📊 Monitor your MCP tools and resources
|
|
192
|
+
💬 Start chatting with your MCP-enabled AI
|
|
193
|
+
|
|
194
|
+
${colors.dim}Press Ctrl+C to stop the server${colors.reset}`;
|
|
195
|
+
|
|
196
|
+
logBox(successText, "🚀 Ready to Go!");
|
|
197
|
+
|
|
198
|
+
logDivider();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function checkOllamaInstalled() {
|
|
202
|
+
try {
|
|
203
|
+
await spawnPromise("ollama", ["--version"], { echoOutput: false });
|
|
204
|
+
return true;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getTerminalCommand() {
|
|
211
|
+
const platform = process.platform;
|
|
212
|
+
|
|
213
|
+
if (platform === "darwin") {
|
|
214
|
+
// macOS
|
|
215
|
+
return ["open", "-a", "Terminal"];
|
|
216
|
+
} else if (platform === "win32") {
|
|
217
|
+
// Windows
|
|
218
|
+
return ["cmd", "/c", "start", "cmd", "/k"];
|
|
219
|
+
} else {
|
|
220
|
+
// Linux and other Unix-like systems
|
|
221
|
+
// Try common terminal emulators in order of preference
|
|
222
|
+
const terminals = [
|
|
223
|
+
"gnome-terminal",
|
|
224
|
+
"konsole",
|
|
225
|
+
"xterm",
|
|
226
|
+
"x-terminal-emulator",
|
|
227
|
+
];
|
|
228
|
+
for (const terminal of terminals) {
|
|
229
|
+
try {
|
|
230
|
+
execSync(`which ${terminal}`, {
|
|
231
|
+
stdio: "ignore",
|
|
232
|
+
});
|
|
233
|
+
if (terminal === "gnome-terminal") {
|
|
234
|
+
return ["gnome-terminal", "--"];
|
|
235
|
+
} else if (terminal === "konsole") {
|
|
236
|
+
return ["konsole", "-e"];
|
|
237
|
+
} else {
|
|
238
|
+
return [terminal, "-e"];
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
// Terminal not found, try next
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Fallback
|
|
245
|
+
return ["xterm", "-e"];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function openTerminalWithMultipleCommands(commands, title) {
|
|
250
|
+
const platform = process.platform;
|
|
251
|
+
const terminalCmd = getTerminalCommand();
|
|
252
|
+
|
|
253
|
+
if (platform === "darwin") {
|
|
254
|
+
// macOS: Chain commands with && separator
|
|
255
|
+
const chainedCommand = commands.join(" && ");
|
|
256
|
+
const script = `tell application "Terminal"
|
|
257
|
+
activate
|
|
258
|
+
do script "${chainedCommand}"
|
|
259
|
+
end tell`;
|
|
260
|
+
|
|
261
|
+
await spawnPromise("osascript", ["-e", script], { echoOutput: false });
|
|
262
|
+
} else if (platform === "win32") {
|
|
263
|
+
// Windows: Chain commands with && separator
|
|
264
|
+
const chainedCommand = commands.join(" && ");
|
|
265
|
+
const fullCommand = `${chainedCommand} && pause`;
|
|
266
|
+
await spawnPromise("cmd", ["/c", "start", "cmd", "/k", fullCommand], {
|
|
267
|
+
echoOutput: false,
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
// Linux and other Unix-like systems: Chain commands with && separator
|
|
271
|
+
const chainedCommand = commands.join(" && ");
|
|
272
|
+
const fullCommand = `${chainedCommand}; read -p "Press Enter to close..."`;
|
|
273
|
+
await spawnPromise(
|
|
274
|
+
terminalCmd[0],
|
|
275
|
+
[...terminalCmd.slice(1), "bash", "-c", fullCommand],
|
|
276
|
+
{ echoOutput: false },
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function setupOllamaInSingleTerminal(model) {
|
|
282
|
+
logStep("Ollama", `Opening terminal to pull model ${model} and start server`);
|
|
283
|
+
logInfo("Both pull and serve commands will run in the same terminal window");
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const commands = [`ollama pull ${model}`, `ollama serve`];
|
|
287
|
+
|
|
288
|
+
await openTerminalWithMultipleCommands(
|
|
289
|
+
commands,
|
|
290
|
+
`Ollama: Pull ${model} & Serve`,
|
|
291
|
+
);
|
|
292
|
+
logSuccess("Ollama pull and serve started in same terminal");
|
|
293
|
+
logProgress(
|
|
294
|
+
"Waiting for model download to complete and server to start...",
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Wait a bit for the model pull to start
|
|
298
|
+
await delay(3000);
|
|
299
|
+
|
|
300
|
+
// Check if model was pulled successfully and server is ready
|
|
301
|
+
let setupReady = false;
|
|
302
|
+
for (let i = 0; i < 60; i++) {
|
|
303
|
+
// Wait up to 10 minutes for pull + server start
|
|
304
|
+
try {
|
|
305
|
+
// First check if server is responding
|
|
306
|
+
await spawnPromise("ollama", ["list"], { echoOutput: false });
|
|
307
|
+
|
|
308
|
+
// Then check if our model is available
|
|
309
|
+
try {
|
|
310
|
+
await spawnPromise("ollama", ["show", model], { echoOutput: false });
|
|
311
|
+
setupReady = true;
|
|
312
|
+
break;
|
|
313
|
+
} catch (e) {
|
|
314
|
+
// Model not ready yet, but server is responding
|
|
315
|
+
}
|
|
316
|
+
} catch (e) {
|
|
317
|
+
// Server not ready yet
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await delay(10000); // Wait 10 seconds between checks
|
|
321
|
+
if (i % 3 === 0) {
|
|
322
|
+
logProgress(
|
|
323
|
+
`Still waiting for model ${model} to be ready and server to start...`,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (setupReady) {
|
|
329
|
+
logSuccess(`Model ${model} is ready and Ollama server is running`);
|
|
330
|
+
} else {
|
|
331
|
+
logWarning(
|
|
332
|
+
`Setup may still be in progress. Please check the terminal window.`,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logError(`Failed to setup Ollama: ${error.message}`);
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function main() {
|
|
342
|
+
await showWelcomeMessage();
|
|
343
|
+
|
|
344
|
+
// Parse command line arguments
|
|
345
|
+
const args = process.argv.slice(2);
|
|
346
|
+
const envVars = {};
|
|
347
|
+
let parsingFlags = true;
|
|
348
|
+
let ollamaModel = null;
|
|
349
|
+
|
|
350
|
+
for (let i = 0; i < args.length; i++) {
|
|
351
|
+
const arg = args[i];
|
|
352
|
+
|
|
353
|
+
if (parsingFlags && arg === "--") {
|
|
354
|
+
parsingFlags = false;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (parsingFlags && arg === "--ollama" && i + 1 < args.length) {
|
|
359
|
+
ollamaModel = args[++i];
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (parsingFlags && arg === "--port" && i + 1 < args.length) {
|
|
364
|
+
const port = args[++i];
|
|
365
|
+
envVars.PORT = port;
|
|
366
|
+
envVars.NEXT_PUBLIC_BASE_URL = `http://localhost:${port}`;
|
|
367
|
+
envVars.BASE_URL = `http://localhost:${port}`;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (parsingFlags && arg === "-e" && i + 1 < args.length) {
|
|
372
|
+
const envVar = args[++i];
|
|
373
|
+
const equalsIndex = envVar.indexOf("=");
|
|
374
|
+
|
|
375
|
+
if (equalsIndex !== -1) {
|
|
376
|
+
const key = envVar.substring(0, equalsIndex);
|
|
377
|
+
const value = envVar.substring(equalsIndex + 1);
|
|
378
|
+
envVars[key] = value;
|
|
379
|
+
} else {
|
|
380
|
+
envVars[envVar] = "";
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Handle Ollama setup if requested
|
|
386
|
+
if (ollamaModel) {
|
|
387
|
+
logStep("Setup", "Configuring Ollama integration");
|
|
388
|
+
|
|
389
|
+
const isOllamaInstalled = await checkOllamaInstalled();
|
|
390
|
+
if (!isOllamaInstalled) {
|
|
391
|
+
logError("Ollama is not installed. Please install Ollama first:");
|
|
392
|
+
logInfo(
|
|
393
|
+
"Visit https://ollama.ai/download to download and install Ollama",
|
|
394
|
+
);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
logSuccess("Ollama is installed");
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
await setupOllamaInSingleTerminal(ollamaModel);
|
|
402
|
+
|
|
403
|
+
logDivider();
|
|
404
|
+
logSuccess(`Ollama setup complete with model: ${ollamaModel}`);
|
|
405
|
+
logInfo("Ollama server is running and ready for MCP connections");
|
|
406
|
+
logDivider();
|
|
407
|
+
} catch (error) {
|
|
408
|
+
logError("Failed to setup Ollama");
|
|
409
|
+
process.exit(1);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const projectRoot = resolve(__dirname, "..");
|
|
414
|
+
|
|
415
|
+
// Apply parsed environment variables to process.env first
|
|
416
|
+
Object.assign(process.env, envVars);
|
|
417
|
+
|
|
418
|
+
// Get requested port and find available port
|
|
419
|
+
const requestedPort = parseInt(process.env.PORT ?? "3000", 10);
|
|
420
|
+
let PORT;
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
logStep("0", "Checking port availability...");
|
|
424
|
+
|
|
425
|
+
if (await isPortAvailable(requestedPort)) {
|
|
426
|
+
PORT = requestedPort.toString();
|
|
427
|
+
logSuccess(`Port ${requestedPort} is available`);
|
|
428
|
+
} else {
|
|
429
|
+
logWarning(`Port ${requestedPort} is in use, finding alternative...`);
|
|
430
|
+
const availablePort = await findAvailablePort(requestedPort + 1);
|
|
431
|
+
PORT = availablePort.toString();
|
|
432
|
+
logSuccess(`Using available port ${availablePort}`);
|
|
433
|
+
|
|
434
|
+
// Update environment variables with the new port
|
|
435
|
+
envVars.PORT = PORT;
|
|
436
|
+
envVars.NEXT_PUBLIC_BASE_URL = `http://localhost:${PORT}`;
|
|
437
|
+
envVars.BASE_URL = `http://localhost:${PORT}`;
|
|
438
|
+
Object.assign(process.env, envVars);
|
|
439
|
+
}
|
|
440
|
+
} catch (error) {
|
|
441
|
+
logError(`Failed to find available port: ${error.message}`);
|
|
442
|
+
throw error;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
await showServerInfo(PORT);
|
|
446
|
+
|
|
447
|
+
const abort = new AbortController();
|
|
448
|
+
|
|
449
|
+
let cancelled = false;
|
|
450
|
+
process.on("SIGINT", () => {
|
|
451
|
+
cancelled = true;
|
|
452
|
+
abort.abort();
|
|
453
|
+
logDivider();
|
|
454
|
+
logWarning("Shutdown signal received...");
|
|
455
|
+
logProgress("Stopping MCP Inspector server");
|
|
456
|
+
logInfo("Cleaning up resources...");
|
|
457
|
+
logSuccess("Server stopped gracefully");
|
|
458
|
+
logDivider();
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
logStep("1", "Initializing Next.js production server");
|
|
463
|
+
await delay(1000);
|
|
464
|
+
|
|
465
|
+
logStep("2", "Building application for production");
|
|
466
|
+
logProgress("This may take a few moments...");
|
|
467
|
+
await delay(500);
|
|
468
|
+
|
|
469
|
+
logStep("3", "Starting server on port " + PORT);
|
|
470
|
+
|
|
471
|
+
await spawnPromise("npm", ["run", "start"], {
|
|
472
|
+
env: {
|
|
473
|
+
...process.env,
|
|
474
|
+
...envVars,
|
|
475
|
+
PORT: PORT,
|
|
476
|
+
},
|
|
477
|
+
cwd: projectRoot,
|
|
478
|
+
signal: abort.signal,
|
|
479
|
+
echoOutput: true,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
if (!cancelled) {
|
|
483
|
+
await showSuccessMessage(PORT);
|
|
484
|
+
}
|
|
485
|
+
} catch (e) {
|
|
486
|
+
if (!cancelled || process.env.DEBUG) {
|
|
487
|
+
logDivider();
|
|
488
|
+
logError("Failed to start MCP Inspector");
|
|
489
|
+
logError(`Error: ${e.message}`);
|
|
490
|
+
logDivider();
|
|
491
|
+
throw e;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return 0;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
main()
|
|
499
|
+
.then((_) => process.exit(0))
|
|
500
|
+
.catch((e) => {
|
|
501
|
+
logError("Fatal error occurred");
|
|
502
|
+
logError(e.stack || e.message);
|
|
503
|
+
process.exit(1);
|
|
504
|
+
});
|
package/next.config.ts
ADDED
package/package.json
CHANGED
|
@@ -1,72 +1,89 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpjam/inspector",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "MCPJam Inspector",
|
|
5
6
|
"license": "Apache-2.0",
|
|
6
7
|
"author": "MCPJam (https://mcpjam.com)",
|
|
7
8
|
"homepage": "https://mcpjam.com",
|
|
8
9
|
"bugs": "https://github.com/mcpjam/inspector/issues",
|
|
9
|
-
"type": "module",
|
|
10
10
|
"bin": {
|
|
11
|
-
"
|
|
11
|
+
"inspector-v1": "bin/start.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"workspaces": [
|
|
20
|
-
"client",
|
|
21
|
-
"server",
|
|
22
|
-
"cli"
|
|
14
|
+
"bin",
|
|
15
|
+
"public",
|
|
16
|
+
".next",
|
|
17
|
+
"next.config.ts",
|
|
18
|
+
"package.json"
|
|
23
19
|
],
|
|
24
20
|
"scripts": {
|
|
25
|
-
"
|
|
26
|
-
"build
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"start": "node client/bin/start.js",
|
|
33
|
-
"ollama": "ollama serve",
|
|
34
|
-
"start-server": "cd server && npm run start",
|
|
35
|
-
"start-client": "cd client && npm run preview",
|
|
36
|
-
"test": "npm run prettier-check && cd client && npm test",
|
|
37
|
-
"test-cli": "cd cli && npm run test",
|
|
38
|
-
"run-package": "node cli/build/cli.js",
|
|
39
|
-
"prettier-fix": "prettier --write .",
|
|
40
|
-
"prettier-check": "prettier --check .",
|
|
41
|
-
"prepare": "npm run build",
|
|
42
|
-
"publish-all": "npm publish --workspaces --access public && npm publish --access public"
|
|
21
|
+
"dev": "next dev --turbopack",
|
|
22
|
+
"build": "next build",
|
|
23
|
+
"start": "next start",
|
|
24
|
+
"lint": "next lint",
|
|
25
|
+
"publish": "npm publish --access public",
|
|
26
|
+
"publish-all": "npm publish --workspaces --access public && npm publish --access public",
|
|
27
|
+
"prettier-fix": "prettier --write ."
|
|
43
28
|
},
|
|
44
29
|
"dependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"@
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
30
|
+
"@ai-sdk/anthropic": "^1.2.12",
|
|
31
|
+
"@ai-sdk/openai": "^1.3.23",
|
|
32
|
+
"@dnd-kit/core": "^6.3.1",
|
|
33
|
+
"@dnd-kit/modifiers": "^9.0.0",
|
|
34
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
35
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
36
|
+
"@hookform/resolvers": "^3.10.0",
|
|
37
|
+
"@mastra/core": "^0.10.6",
|
|
38
|
+
"@mastra/mcp": "^0.10.6",
|
|
39
|
+
"@mcpjam/inspector-v1": "^0.2.0",
|
|
40
|
+
"@tanstack/react-query": "^5.83.0",
|
|
41
|
+
"@tanstack/react-table": "^8.21.3",
|
|
42
|
+
"@uiw/react-json-view": "^2.0.0-alpha.33",
|
|
43
|
+
"ai": "^4.3.19",
|
|
44
|
+
"class-variance-authority": "^0.7.1",
|
|
45
|
+
"classnames": "^2.5.1",
|
|
46
|
+
"clsx": "^2.1.1",
|
|
47
|
+
"cmdk": "^1.1.1",
|
|
48
|
+
"date-fns": "^3.6.0",
|
|
49
|
+
"embla-carousel-react": "^8.6.0",
|
|
50
|
+
"fast-deep-equal": "^3.1.3",
|
|
51
|
+
"framer-motion": "^12.23.6",
|
|
52
|
+
"input-otp": "^1.4.2",
|
|
55
53
|
"lucide-react": "^0.525.0",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
54
|
+
"next": "15.4.1",
|
|
55
|
+
"next-themes": "^0.4.6",
|
|
56
|
+
"ollama-ai-provider": "^1.2.0",
|
|
57
|
+
"ollama-ai-provider-v2": "^0.0.9",
|
|
58
|
+
"postcss": "^8.5.6",
|
|
59
|
+
"radix-ui": "^1.4.2",
|
|
60
|
+
"react": "19.1.0",
|
|
61
|
+
"react-day-picker": "^9.8.0",
|
|
62
|
+
"react-dom": "19.1.0",
|
|
63
|
+
"react-hook-form": "^7.60.0",
|
|
64
|
+
"react-markdown": "^10.1.0",
|
|
65
|
+
"react-resizable-panels": "^3.0.3",
|
|
66
|
+
"react18-json-view": "^0.2.9",
|
|
67
|
+
"recharts": "^2.15.4",
|
|
68
|
+
"remark-gfm": "^4.0.1",
|
|
69
|
+
"simple-icons": "^15.6.0",
|
|
70
|
+
"sonner": "^2.0.6",
|
|
71
|
+
"tailwind-merge": "^3.3.1",
|
|
72
|
+
"vaul": "^1.1.2",
|
|
73
|
+
"zod": "^3.25.76",
|
|
74
|
+
"zod-to-json-schema": "^3.24.6",
|
|
75
|
+
"zustand": "^5.0.6"
|
|
62
76
|
},
|
|
63
77
|
"devDependencies": {
|
|
64
|
-
"@
|
|
65
|
-
"@
|
|
66
|
-
"@types/
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
78
|
+
"@eslint/eslintrc": "^3",
|
|
79
|
+
"@tailwindcss/postcss": "^4.1.11",
|
|
80
|
+
"@types/node": "^20",
|
|
81
|
+
"@types/react": "^19",
|
|
82
|
+
"@types/react-dom": "^19",
|
|
83
|
+
"eslint": "^9",
|
|
84
|
+
"eslint-config-next": "15.4.1",
|
|
85
|
+
"tailwindcss": "^4.1.11",
|
|
86
|
+
"tw-animate-css": "^1.3.5",
|
|
87
|
+
"typescript": "^5"
|
|
71
88
|
}
|
|
72
89
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/public/file.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
package/public/globe.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
package/public/mcp.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>ModelContextProtocol</title><path d="M15.688 2.343a2.588 2.588 0 00-3.61 0l-9.626 9.44a.863.863 0 01-1.203 0 .823.823 0 010-1.18l9.626-9.44a4.313 4.313 0 016.016 0 4.116 4.116 0 011.204 3.54 4.3 4.3 0 013.609 1.18l.05.05a4.115 4.115 0 010 5.9l-8.706 8.537a.274.274 0 000 .393l1.788 1.754a.823.823 0 010 1.18.863.863 0 01-1.203 0l-1.788-1.753a1.92 1.92 0 010-2.754l8.706-8.538a2.47 2.47 0 000-3.54l-.05-.049a2.588 2.588 0 00-3.607-.003l-7.172 7.034-.002.002-.098.097a.863.863 0 01-1.204 0 .823.823 0 010-1.18l7.273-7.133a2.47 2.47 0 00-.003-3.537z"></path><path d="M14.485 4.703a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a4.115 4.115 0 000 5.9 4.314 4.314 0 006.016 0l7.12-6.982a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a2.588 2.588 0 01-3.61 0 2.47 2.47 0 010-3.54l7.12-6.982z"></path></svg>
|
package/public/next.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
|
Binary file
|