Gate MCP endpoint behind MCP_ENABLED flag

This commit is contained in:
Mike Cao committed 2026-09-09 15:24:51 -07:00
commit 2b7eb29a0e
5 files changed
+46 -2

No files matched your search

+3
View File
@@ -54,6 +54,9 @@ Optional: set `TWO_FACTOR_ENCRYPTION_KEY` to a 64-character hex string to enable
authentication. Generate one with `openssl rand -hex 32`. Two-factor authentication is unavailable
and cannot be required until this key is set.
MCP is disabled by default. Set `MCP_ENABLED=1` to enable the `/mcp` endpoint, then
authenticate with an API key generated under Settings → API keys.
The connection URL format:
```bash
+1
View File
@@ -38,6 +38,7 @@ x-umami-env: &umami-env
DISABLE_BOT_CHECK: "1"
DISABLE_TELEMETRY: "1"
DISABLE_UPDATES: "1"
MCP_ENABLED: "1"
services:
db:
+1 -1
View File
@@ -60,7 +60,7 @@ Authorization: Bearer umami_<your-api-key>
Use a client that supports bearer tokens or custom authorization headers. The endpoint accepts
self-hosted API keys; browser login tokens are not supported. Tools are read-only and respect
the key owner's existing user/team permissions. Revoke the key in Settings to disconnect access.
Set `MCP_DISABLED=1` to disable the endpoint.
MCP is disabled by default. Set `MCP_ENABLED=1` to enable the endpoint.
## Local / stdio
+40
View File
@@ -0,0 +1,40 @@
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
import { authenticateMcpRequest } from '@/lib/mcp/auth';
import { DELETE, GET, POST } from './route';
vi.mock('@umami/mcp', () => ({
createUmamiMcpHttpHandler: () => ({ fetch: vi.fn() }),
}));
vi.mock('@/lib/mcp/auth', () => ({
authenticateMcpRequest: vi.fn(),
mcpAuthErrorResponse: () => new Response(null, { status: 401 }),
}));
beforeEach(() => {
vi.mocked(authenticateMcpRequest).mockReset();
vi.mocked(authenticateMcpRequest).mockResolvedValue({
ok: false,
status: 401,
error: 'invalid_request',
description: 'Missing bearer API key.',
});
});
afterEach(() => vi.unstubAllEnvs());
test.each([undefined, '', '0', 'true'])('MCP stays disabled for MCP_ENABLED=%s', async value => {
vi.stubEnv('MCP_ENABLED', value);
for (const handler of [GET, POST, DELETE]) {
const response = await handler(new Request('http://localhost/mcp'));
expect(response.status).toBe(404);
}
expect(authenticateMcpRequest).not.toHaveBeenCalled();
});
test('MCP_ENABLED=1 enables API-key authentication', async () => {
vi.stubEnv('MCP_ENABLED', '1');
const request = new Request('http://localhost/mcp');
const response = await POST(request);
expect(response.status).toBe(401);
expect(authenticateMcpRequest).toHaveBeenCalledWith(request);
});
+1 -1
View File
@@ -38,7 +38,7 @@ const handler = createUmamiMcpHttpHandler({
});
async function handle(request: Request) {
if (process.env.MCP_DISABLED === '1') {
if (process.env.MCP_ENABLED !== '1') {
return new Response(null, { status: 404 });
}