Skip to content

Commit 74d5be3

Browse files
authored
Merge pull request #39 from metatool-ai/oauth-remote-hosting
OAuth & Remote Hosting
2 parents 8420087 + ea9700b commit 74d5be3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+7718
-322
lines changed

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
FROM node:20-alpine AS base
22

3+
RUN npm i -g corepack@latest
4+
35
# Install pnpm
46
RUN corepack enable && corepack prepare [email protected] --activate
57

@@ -11,6 +13,14 @@ WORKDIR /app
1113
COPY package.json pnpm-lock.yaml* ./
1214
RUN pnpm install --frozen-lockfile
1315

16+
# Build remote-hosting
17+
FROM base AS remote-hosting-builder
18+
WORKDIR /app/remote-hosting
19+
COPY remote-hosting/package.json remote-hosting/pnpm-lock.yaml* ./
20+
RUN pnpm install --frozen-lockfile
21+
COPY remote-hosting ./
22+
RUN pnpm build
23+
1424
# Rebuild the source code only when needed
1525
FROM base AS builder
1626
WORKDIR /app

README.md

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,29 @@ Then open http://localhost:12005 in your browser to open MetaMCP App.
4444
It is recommended to have npx (node.js based mcp) and uvx (python based mcp) installed globally.
4545
To install uv check: https://docs.astral.sh/uv/getting-started/installation/
4646

47-
You also need a MCP Client to connect to `@metamcp/mcp-server-metamcp`. For example if you are using [Claude Desktop](https://modelcontextprotocol.io/quickstart/user), the config json may look like this:
47+
### Default Remote Mode SSE endpoint for MetaMCP
48+
49+
The recommended way to connect to MetaMCP is via the SSE endpoint:
50+
51+
```
52+
http://localhost:12007/sse with Authorization: Bearer <your-api-key>
53+
```
54+
55+
Alternatively, if you cannot set headers, you can use this URL-based endpoint:
56+
57+
```
58+
http://localhost:12007/api-key/<your-api-key>/sse
59+
```
60+
61+
You can get the API key from the MetaMCP App's API Keys page.
62+
63+
### For Local Access
64+
65+
You can still use these methods even if your workspace is in Default Remote Mode.
66+
67+
#### Claude Desktop Configuration
68+
69+
For Claude Desktop, the config json should look like this:
4870

4971
```json
5072
{
@@ -61,13 +83,91 @@ You also need a MCP Client to connect to `@metamcp/mcp-server-metamcp`. For exam
6183
}
6284
```
6385

64-
For Cursor, env vars aren't easy to get typed in so you may use args instead
86+
#### Cursor Configuration
87+
88+
For Cursor, env vars aren't easy to get typed in so you may use args instead:
89+
90+
```bash
91+
npx -y @metamcp/mcp-server-metamcp@latest --metamcp-api-key <your-api-key> --metamcp-api-base-url http://localhost:12005
92+
```
93+
94+
#### Windows Configuration
95+
96+
For Windows, you can use the following command for Cursor:
97+
98+
```bash
99+
cmd /c npx -y @metamcp/mcp-server-metamcp@latest --metamcp-api-key <your-api-key> --metamcp-api-base-url http://localhost:12005
100+
```
101+
102+
Or configure it using json:
103+
104+
```json
105+
{
106+
"mcpServers": {
107+
"MetaMCP": {
108+
"command": "cmd",
109+
"args": [
110+
"/c",
111+
"npx",
112+
"-y",
113+
"@metamcp/mcp-server-metamcp@latest"
114+
],
115+
"env": {
116+
"METAMCP_API_KEY": "<your api key>",
117+
"METAMCP_API_BASE_URL": "http://localhost:12005"
118+
}
119+
}
120+
}
121+
}
122+
```
123+
124+
#### Standalone SSE Server
125+
126+
You can also use the following command to start a standalone SSE server:
127+
128+
```bash
129+
mcp-server-metamcp --metamcp-api-key <your-api-key> --transport sse --port 12006
130+
```
131+
132+
Then use following json configuration:
133+
134+
```json
135+
{
136+
"mcpServers": {
137+
"MetaMCP": {
138+
"url": "http://localhost:12006"
139+
}
140+
}
141+
}
142+
```
143+
144+
#### Smithery Windows Configuration
145+
146+
You can also use Smithery to run MCPs in docker on cloud for max compatibility:
65147

66148
```bash
67-
npx -y @metamcp/mcp-server-metamcp@latest --metamcp-api-key <your-api-key> --metamcp-api-base-url <base-url>
149+
smithery run @metatool-ai/mcp-server-metamcp --config '{"metamcpApiKey":"<your api key>"}'
150+
```
151+
152+
Or configure it in your Claude Desktop configuration file:
153+
154+
```json
155+
{
156+
"mcpServers": {
157+
"MetaMCP": {
158+
"command": "smithery",
159+
"args": [
160+
"run",
161+
"@metatool-ai/mcp-server-metamcp",
162+
"--config",
163+
"{\"metamcpApiKey\":\"<your api key>\"}"
164+
]
165+
}
166+
}
167+
}
68168
```
69169

70-
You can get the API key from the MetaMCP App's API Keys page (self hosted available).
170+
You can get the API key from the MetaMCP App's API Keys page.
71171

72172
## Architecture Overview
73173

@@ -103,5 +203,5 @@ sequenceDiagram
103203
GNU AGPL v3
104204

105205
## Credits
106-
206+
- Used some oauth codes in https://github.com/modelcontextprotocol/inspector
107207
- (Deprecated) Demo video uses MCP Client [5ire](https://5ire.app/)

app/(sidebar-layout)/(container)/inspector-guide/page.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,77 @@ export default function InspectorGuidePage() {
1818

1919
const inspectorCommand = `npx -y @modelcontextprotocol/inspector npx -y @metamcp/mcp-server-metamcp@latest -e METAMCP_API_KEY=${apiKey?.api_key || '<YOUR_API_KEY>'} -e METAMCP_API_BASE_URL=http://localhost:12005`;
2020

21+
const sseEndpoint = `http://localhost:12007/sse with Authorization: Bearer ${apiKey?.api_key || '<YOUR_API_KEY>'}`;
22+
const urlBasedSseEndpoint = `http://localhost:12007/api-key/${apiKey?.api_key || '<YOUR_API_KEY>'}/sse`;
23+
2124
return (
2225
<div className='container mx-auto py-6 flex flex-col items-start justify-center gap-6'>
26+
<h1 className='text-2xl font-semibold'>Remote SSE Mode Inspector Guide</h1>
27+
28+
<Card className="w-full">
29+
<CardHeader>
30+
<CardTitle className='flex items-center gap-2'>
31+
<Terminal className='h-5 w-5' />
32+
UI SSE Mode in Inspector
33+
</CardTitle>
34+
</CardHeader>
35+
<CardContent>
36+
<p className="mb-4">
37+
You can use the SSE mode to trigger the inspector directly from your UI. This method allows for a more integrated experience when inspecting tools.
38+
</p>
39+
40+
<div className="space-y-4">
41+
<div>
42+
<h3 className="font-medium mb-2">Using Authorization Header:</h3>
43+
<div className='relative'>
44+
<button
45+
onClick={() => {
46+
navigator.clipboard.writeText(sseEndpoint);
47+
toast({
48+
title: 'Copied to clipboard',
49+
description: 'The SSE endpoint has been copied to your clipboard.',
50+
});
51+
}}
52+
className='absolute top-2 right-2 p-2 text-gray-400 hover:text-white rounded-md hover:bg-gray-700 transition-colors'
53+
title='Copy to clipboard'>
54+
<Copy className='w-5 h-5' />
55+
</button>
56+
<pre className='bg-[#f6f8fa] text-[#24292f] p-4 rounded-md overflow-x-auto'>
57+
{sseEndpoint}
58+
</pre>
59+
</div>
60+
</div>
61+
62+
<div>
63+
<h3 className="font-medium mb-2">Using URL-based Authentication:</h3>
64+
<div className='relative'>
65+
<button
66+
onClick={() => {
67+
navigator.clipboard.writeText(urlBasedSseEndpoint);
68+
toast({
69+
title: 'Copied to clipboard',
70+
description: 'The URL-based SSE endpoint has been copied to your clipboard.',
71+
});
72+
}}
73+
className='absolute top-2 right-2 p-2 text-gray-400 hover:text-white rounded-md hover:bg-gray-700 transition-colors'
74+
title='Copy to clipboard'>
75+
<Copy className='w-5 h-5' />
76+
</button>
77+
<pre className='bg-[#f6f8fa] text-[#24292f] p-4 rounded-md overflow-x-auto'>
78+
{urlBasedSseEndpoint}
79+
</pre>
80+
</div>
81+
</div>
82+
83+
<p className="mt-4">
84+
Configure your UI to connect to these endpoints and the inspector will be triggered automatically, providing real-time tool inspection capabilities.
85+
</p>
86+
</div>
87+
</CardContent>
88+
</Card>
89+
90+
91+
<h1 className='text-2xl font-semibold'>Local Proxy Mode Inspector Guide</h1>
2392
<p className='text-lg'>
2493
Because MetaMCP is a local proxy and we currently don&apos;t support any
2594
cloud hosting of your MCPs. You can use MCP&apos;s official inspector to
@@ -29,6 +98,7 @@ export default function InspectorGuidePage() {
2998
better experience for you to check inspection details directly on our
3099
platform.
31100
</p>
101+
32102
<Card>
33103
<CardHeader>
34104
<CardTitle className='flex items-center gap-2'>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Button } from "@/components/ui/button";
2+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
3+
import { ConnectionStatus } from "@/lib/constants";
4+
5+
interface ServerNotificationsProps {
6+
connectionStatus: ConnectionStatus;
7+
notifications: any[];
8+
clearNotifications: () => void;
9+
}
10+
11+
export default function ServerNotifications({
12+
connectionStatus,
13+
notifications,
14+
clearNotifications
15+
}: ServerNotificationsProps) {
16+
if (connectionStatus !== 'connected') {
17+
return null;
18+
}
19+
20+
return (
21+
<Card className="mt-8">
22+
<CardHeader className="pb-2 flex flex-row items-center justify-between">
23+
<div>
24+
<CardTitle className="text-2xl font-bold">Server Notifications</CardTitle>
25+
<CardDescription>
26+
Real-time notifications from the MCP server connection
27+
</CardDescription>
28+
</div>
29+
{notifications.length > 0 && (
30+
<Button variant="outline" size="sm" onClick={clearNotifications}>
31+
Clear All
32+
</Button>
33+
)}
34+
</CardHeader>
35+
<CardContent>
36+
{notifications.length === 0 ? (
37+
<p className="text-muted-foreground">No notifications received yet.</p>
38+
) : (
39+
<div className="h-64 overflow-y-auto border rounded-md p-4">
40+
{notifications.slice().reverse().map((notification, index) => (
41+
<div key={index} className="mb-3 p-2 bg-secondary rounded-md">
42+
<div className="font-semibold">{notification.method}</div>
43+
<pre className="text-xs overflow-x-auto whitespace-pre-wrap break-words mt-1">
44+
{JSON.stringify(notification.params, null, 2)}
45+
</pre>
46+
</div>
47+
))}
48+
</div>
49+
)}
50+
</CardContent>
51+
</Card>
52+
);
53+
}

0 commit comments

Comments
 (0)