@soulbatical/tetra-core 0.1.24 → 0.1.26
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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/mcp/index.d.ts +48 -0
- package/dist/shared/mcp/index.d.ts.map +1 -0
- package/dist/shared/mcp/index.js +49 -0
- package/dist/shared/mcp/index.js.map +1 -0
- package/dist/shared/mcp/mcp-auth-routes.d.ts +26 -0
- package/dist/shared/mcp/mcp-auth-routes.d.ts.map +1 -0
- package/dist/shared/mcp/mcp-auth-routes.js +138 -0
- package/dist/shared/mcp/mcp-auth-routes.js.map +1 -0
- package/dist/shared/mcp/mcp-routes.d.ts +29 -0
- package/dist/shared/mcp/mcp-routes.d.ts.map +1 -0
- package/dist/shared/mcp/mcp-routes.js +168 -0
- package/dist/shared/mcp/mcp-routes.js.map +1 -0
- package/dist/shared/mcp/mcp-tokens-routes.d.ts +21 -0
- package/dist/shared/mcp/mcp-tokens-routes.d.ts.map +1 -0
- package/dist/shared/mcp/mcp-tokens-routes.js +82 -0
- package/dist/shared/mcp/mcp-tokens-routes.js.map +1 -0
- package/dist/shared/mcp/mcp-usage-routes.d.ts +17 -0
- package/dist/shared/mcp/mcp-usage-routes.d.ts.map +1 -0
- package/dist/shared/mcp/mcp-usage-routes.js +78 -0
- package/dist/shared/mcp/mcp-usage-routes.js.map +1 -0
- package/dist/shared/mcp/tenant-context.d.ts +44 -0
- package/dist/shared/mcp/tenant-context.d.ts.map +1 -0
- package/dist/shared/mcp/tenant-context.js +117 -0
- package/dist/shared/mcp/tenant-context.js.map +1 -0
- package/dist/shared/mcp/types.d.ts +58 -0
- package/dist/shared/mcp/types.d.ts.map +1 -0
- package/dist/shared/mcp/types.js +7 -0
- package/dist/shared/mcp/types.js.map +1 -0
- package/package.json +8 -2
- package/src/shared/mcp/migrations/001_mcp_api_tokens.sql +21 -0
- package/src/shared/mcp/migrations/002_mcp_audit_log.sql +16 -0
package/dist/index.d.ts
CHANGED
|
@@ -96,6 +96,8 @@ export { RPCGenerator, DetailRPCGenerator, validateConfig as validateRPCConfig,
|
|
|
96
96
|
export type { GeneratedSQL, FilterDefinition, RPCGeneratorOptions, DetailRPCGeneratorOptions, ValidationResult as RPCValidationResult, ValidationError as RPCValidationError, AccessLevel, CreatorVisibilityConfig as RPCCreatorVisibilityConfig } from './generators/rpc/index.js';
|
|
97
97
|
export { EmailService, sendMailgunEmail, escapeHtml } from './shared/email/index.js';
|
|
98
98
|
export type { EmailConfig, SendEmailOpts, EmailTemplate, EmailLogEntry, MailgunResponse } from './shared/email/index.js';
|
|
99
|
+
export { addMcpRoutes, addMcpAuthRoutes, addMcpTokenRoutes, addMcpUsageRoutes, getMcpOrganizationId, getMcpTenantContext, runWithMcpTenant, validateMcpApiToken, generateMcpApiToken } from './shared/mcp/index.js';
|
|
100
|
+
export type { McpRoutesConfig, McpAuthRoutesConfig, McpToolDefinition, McpToolResult, McpToolHandler, TenantContext as McpTenantContext } from './shared/mcp/index.js';
|
|
99
101
|
export { createApp } from './core/createApp.js';
|
|
100
102
|
export type { CreateAppConfig } from './core/createApp.js';
|
|
101
103
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,8 @@ export { generateExecSQL, checkExecSQLExists } from './generators/rls-exec-sql.j
|
|
|
90
90
|
export { RPCGenerator, DetailRPCGenerator, validateConfig as validateRPCConfig, generateAuthCheck, generateAuthWhereClause, generateAuthDeclarations, generateTimestamp, getTableAlias, escapeIdentifier } from './generators/rpc/index.js';
|
|
91
91
|
// ─── Email Module ───────────────────────────────────────────
|
|
92
92
|
export { EmailService, sendMailgunEmail, escapeHtml } from './shared/email/index.js';
|
|
93
|
+
// ─── MCP Online Module ──────────────────────────────────────
|
|
94
|
+
export { addMcpRoutes, addMcpAuthRoutes, addMcpTokenRoutes, addMcpUsageRoutes, getMcpOrganizationId, getMcpTenantContext, runWithMcpTenant, validateMcpApiToken, generateMcpApiToken } from './shared/mcp/index.js';
|
|
93
95
|
// ─── App Bootstrap ──────────────────────────────────────────
|
|
94
96
|
export { createApp } from './core/createApp.js';
|
|
95
97
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Online Module
|
|
3
|
+
*
|
|
4
|
+
* Provides everything needed to expose MCP tools over HTTP:
|
|
5
|
+
* - StreamableHTTP transport with Bearer token auth
|
|
6
|
+
* - Browser-based login flow for token acquisition
|
|
7
|
+
* - Token CRUD management
|
|
8
|
+
* - Usage stats / audit logging
|
|
9
|
+
* - Tenant isolation via AsyncLocalStorage
|
|
10
|
+
*
|
|
11
|
+
* Quick start:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { addMcpRoutes, addMcpAuthRoutes, addMcpTokenRoutes, addMcpUsageRoutes } from '@soulbatical/tetra-core';
|
|
14
|
+
* import { Router } from 'express';
|
|
15
|
+
*
|
|
16
|
+
* const tokenPrefix = 'myapp_';
|
|
17
|
+
*
|
|
18
|
+
* // MCP endpoint (Bearer API token auth)
|
|
19
|
+
* const mcpRouter = Router();
|
|
20
|
+
* addMcpRoutes(mcpRouter, { tools, handlers, tokenPrefix });
|
|
21
|
+
* app.use('/api/mcp', mcpRouter);
|
|
22
|
+
*
|
|
23
|
+
* // Browser auth flow (public + JWT)
|
|
24
|
+
* const mcpAuthRouter = Router();
|
|
25
|
+
* addMcpAuthRoutes(mcpAuthRouter, { tokenPrefix });
|
|
26
|
+
* app.use('/api/mcp-auth', mcpAuthRouter);
|
|
27
|
+
*
|
|
28
|
+
* // Token management (JWT auth)
|
|
29
|
+
* const mcpTokensRouter = Router();
|
|
30
|
+
* addMcpTokenRoutes(mcpTokensRouter, { tokenPrefix });
|
|
31
|
+
* app.use('/api/mcp-tokens', mcpTokensRouter);
|
|
32
|
+
*
|
|
33
|
+
* // Usage stats (JWT auth)
|
|
34
|
+
* const mcpUsageRouter = Router();
|
|
35
|
+
* addMcpUsageRoutes(mcpUsageRouter);
|
|
36
|
+
* app.use('/api/mcp-usage', mcpUsageRouter);
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Database: requires `mcp_api_tokens` and `mcp_audit_log` tables.
|
|
40
|
+
* See migrations/ directory for SQL.
|
|
41
|
+
*/
|
|
42
|
+
export { addMcpRoutes } from './mcp-routes.js';
|
|
43
|
+
export { addMcpAuthRoutes } from './mcp-auth-routes.js';
|
|
44
|
+
export { addMcpTokenRoutes } from './mcp-tokens-routes.js';
|
|
45
|
+
export { addMcpUsageRoutes } from './mcp-usage-routes.js';
|
|
46
|
+
export { getMcpOrganizationId, getMcpTenantContext, runWithMcpTenant, validateMcpApiToken, generateMcpApiToken } from './tenant-context.js';
|
|
47
|
+
export type { McpRoutesConfig, McpAuthRoutesConfig, McpToolDefinition, McpToolResult, McpToolHandler, TenantContext } from './types.js';
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG5I,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Online Module
|
|
3
|
+
*
|
|
4
|
+
* Provides everything needed to expose MCP tools over HTTP:
|
|
5
|
+
* - StreamableHTTP transport with Bearer token auth
|
|
6
|
+
* - Browser-based login flow for token acquisition
|
|
7
|
+
* - Token CRUD management
|
|
8
|
+
* - Usage stats / audit logging
|
|
9
|
+
* - Tenant isolation via AsyncLocalStorage
|
|
10
|
+
*
|
|
11
|
+
* Quick start:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { addMcpRoutes, addMcpAuthRoutes, addMcpTokenRoutes, addMcpUsageRoutes } from '@soulbatical/tetra-core';
|
|
14
|
+
* import { Router } from 'express';
|
|
15
|
+
*
|
|
16
|
+
* const tokenPrefix = 'myapp_';
|
|
17
|
+
*
|
|
18
|
+
* // MCP endpoint (Bearer API token auth)
|
|
19
|
+
* const mcpRouter = Router();
|
|
20
|
+
* addMcpRoutes(mcpRouter, { tools, handlers, tokenPrefix });
|
|
21
|
+
* app.use('/api/mcp', mcpRouter);
|
|
22
|
+
*
|
|
23
|
+
* // Browser auth flow (public + JWT)
|
|
24
|
+
* const mcpAuthRouter = Router();
|
|
25
|
+
* addMcpAuthRoutes(mcpAuthRouter, { tokenPrefix });
|
|
26
|
+
* app.use('/api/mcp-auth', mcpAuthRouter);
|
|
27
|
+
*
|
|
28
|
+
* // Token management (JWT auth)
|
|
29
|
+
* const mcpTokensRouter = Router();
|
|
30
|
+
* addMcpTokenRoutes(mcpTokensRouter, { tokenPrefix });
|
|
31
|
+
* app.use('/api/mcp-tokens', mcpTokensRouter);
|
|
32
|
+
*
|
|
33
|
+
* // Usage stats (JWT auth)
|
|
34
|
+
* const mcpUsageRouter = Router();
|
|
35
|
+
* addMcpUsageRoutes(mcpUsageRouter);
|
|
36
|
+
* app.use('/api/mcp-usage', mcpUsageRouter);
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Database: requires `mcp_api_tokens` and `mcp_audit_log` tables.
|
|
40
|
+
* See migrations/ directory for SQL.
|
|
41
|
+
*/
|
|
42
|
+
// Routes
|
|
43
|
+
export { addMcpRoutes } from './mcp-routes.js';
|
|
44
|
+
export { addMcpAuthRoutes } from './mcp-auth-routes.js';
|
|
45
|
+
export { addMcpTokenRoutes } from './mcp-tokens-routes.js';
|
|
46
|
+
export { addMcpUsageRoutes } from './mcp-usage-routes.js';
|
|
47
|
+
// Tenant context
|
|
48
|
+
export { getMcpOrganizationId, getMcpTenantContext, runWithMcpTenant, validateMcpApiToken, generateMcpApiToken } from './tenant-context.js';
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,iBAAiB;AACjB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Auth Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Browser-based login flow for MCP token acquisition.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. MCP client POST /request → gets request_id + login URL
|
|
8
|
+
* 2. User opens browser, logs in
|
|
9
|
+
* 3. Frontend calls POST /approve/:requestId (authenticated)
|
|
10
|
+
* 4. MCP client polls GET /poll/:requestId → receives API token
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { addMcpAuthRoutes } from '@soulbatical/tetra-core';
|
|
15
|
+
*
|
|
16
|
+
* const mcpAuthRouter = Router();
|
|
17
|
+
* addMcpAuthRoutes(mcpAuthRouter, {
|
|
18
|
+
* tokenPrefix: 'vincifox_',
|
|
19
|
+
* });
|
|
20
|
+
* app.use('/api/mcp-auth', mcpAuthRouter);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import type { Router } from 'express';
|
|
24
|
+
import type { McpAuthRoutesConfig } from './types.js';
|
|
25
|
+
export declare function addMcpAuthRoutes(router: Router, config: McpAuthRoutesConfig): void;
|
|
26
|
+
//# sourceMappingURL=mcp-auth-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-auth-routes.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-auth-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAKzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAiCtD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAwHlF"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Auth Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Browser-based login flow for MCP token acquisition.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. MCP client POST /request → gets request_id + login URL
|
|
8
|
+
* 2. User opens browser, logs in
|
|
9
|
+
* 3. Frontend calls POST /approve/:requestId (authenticated)
|
|
10
|
+
* 4. MCP client polls GET /poll/:requestId → receives API token
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { addMcpAuthRoutes } from '@soulbatical/tetra-core';
|
|
15
|
+
*
|
|
16
|
+
* const mcpAuthRouter = Router();
|
|
17
|
+
* addMcpAuthRoutes(mcpAuthRouter, {
|
|
18
|
+
* tokenPrefix: 'vincifox_',
|
|
19
|
+
* });
|
|
20
|
+
* app.use('/api/mcp-auth', mcpAuthRouter);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { randomUUID } from 'node:crypto';
|
|
24
|
+
import { authenticateToken } from '../../middleware/authMiddleware.js';
|
|
25
|
+
import { systemDB } from '../../core/systemDb.js';
|
|
26
|
+
import { generateMcpApiToken } from './tenant-context.js';
|
|
27
|
+
// In-memory store (short-lived, <5min)
|
|
28
|
+
const pendingRequests = new Map();
|
|
29
|
+
// Cleanup expired every 30s
|
|
30
|
+
setInterval(() => {
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
for (const [id, req] of pendingRequests) {
|
|
33
|
+
if (now - req.createdAt > 600_000) { // 10min hard limit
|
|
34
|
+
pendingRequests.delete(id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, 30_000).unref();
|
|
38
|
+
function getOrgId(req) {
|
|
39
|
+
const user = req.user;
|
|
40
|
+
return user?.activeOrganizationId || user?.active_organization_id || user?.organizationId || null;
|
|
41
|
+
}
|
|
42
|
+
function paramStr(value) {
|
|
43
|
+
return Array.isArray(value) ? value[0] : value || '';
|
|
44
|
+
}
|
|
45
|
+
export function addMcpAuthRoutes(router, config) {
|
|
46
|
+
const { tokenPrefix, frontendApprovalPath = '/app/settings/api-tokens', defaultDeviceName = 'Claude Code', expirySeconds = 300, } = config;
|
|
47
|
+
const frontendUrl = config.frontendUrl || process.env.FRONTEND_URL || 'http://localhost:3000';
|
|
48
|
+
const db = systemDB('mcp-auth');
|
|
49
|
+
// POST /request — Create pending auth request
|
|
50
|
+
router.post('/request', (req, res) => {
|
|
51
|
+
const { device_name } = req.body || {};
|
|
52
|
+
const requestId = randomUUID();
|
|
53
|
+
pendingRequests.set(requestId, {
|
|
54
|
+
requestId,
|
|
55
|
+
deviceName: device_name || defaultDeviceName,
|
|
56
|
+
createdAt: Date.now(),
|
|
57
|
+
});
|
|
58
|
+
res.json({
|
|
59
|
+
request_id: requestId,
|
|
60
|
+
login_url: `${frontendUrl}${frontendApprovalPath}?mcp_auth=${requestId}`,
|
|
61
|
+
expires_in: expirySeconds,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
// GET /status/:requestId — Check if request is valid (for frontend)
|
|
65
|
+
router.get('/status/:requestId', (req, res) => {
|
|
66
|
+
const requestId = paramStr(req.params.requestId);
|
|
67
|
+
const pending = pendingRequests.get(requestId);
|
|
68
|
+
if (!pending) {
|
|
69
|
+
res.status(404).json({ error: 'Auth request not found or expired' });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const expiryMs = expirySeconds * 1000;
|
|
73
|
+
res.json({
|
|
74
|
+
status: pending.approved ? 'approved' : 'pending',
|
|
75
|
+
device_name: pending.deviceName,
|
|
76
|
+
expires_in: Math.max(0, Math.ceil((pending.createdAt + expiryMs - Date.now()) / 1000)),
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
// POST /approve/:requestId — Approve and generate token (requires JWT)
|
|
80
|
+
router.post('/approve/:requestId', authenticateToken, async (req, res) => {
|
|
81
|
+
try {
|
|
82
|
+
const requestId = paramStr(req.params.requestId);
|
|
83
|
+
const user = req.user;
|
|
84
|
+
const pending = pendingRequests.get(requestId);
|
|
85
|
+
if (!pending) {
|
|
86
|
+
res.status(404).json({ error: 'Auth request not found or expired' });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (pending.approved) {
|
|
90
|
+
res.status(409).json({ error: 'Already approved' });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const organizationId = getOrgId(req);
|
|
94
|
+
if (!organizationId) {
|
|
95
|
+
res.status(400).json({ error: 'No active organization' });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Generate API token
|
|
99
|
+
const tokenName = `${pending.deviceName} (${new Date().toISOString().slice(0, 10)})`;
|
|
100
|
+
const token = await generateMcpApiToken(organizationId, tokenName, tokenPrefix, user.id);
|
|
101
|
+
// Get org name for display
|
|
102
|
+
const { data: org } = await db
|
|
103
|
+
.from('organizations')
|
|
104
|
+
.select('name')
|
|
105
|
+
.eq('id', organizationId)
|
|
106
|
+
.single();
|
|
107
|
+
pending.apiToken = token;
|
|
108
|
+
pending.organizationName = org?.name || 'Unknown';
|
|
109
|
+
pending.approved = true;
|
|
110
|
+
res.json({ success: true, organization: org?.name });
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// GET /poll/:requestId — Poll for token (MCP client side)
|
|
117
|
+
router.get('/poll/:requestId', (req, res) => {
|
|
118
|
+
const requestId = paramStr(req.params.requestId);
|
|
119
|
+
const pending = pendingRequests.get(requestId);
|
|
120
|
+
if (!pending) {
|
|
121
|
+
res.status(404).json({ error: 'Auth request not found or expired' });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!pending.approved) {
|
|
125
|
+
res.json({ status: 'pending' });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// Return token and clean up (one-time retrieval)
|
|
129
|
+
const result = {
|
|
130
|
+
status: 'approved',
|
|
131
|
+
api_token: pending.apiToken,
|
|
132
|
+
organization: pending.organizationName,
|
|
133
|
+
};
|
|
134
|
+
pendingRequests.delete(requestId);
|
|
135
|
+
res.json(result);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=mcp-auth-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-auth-routes.js","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-auth-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP StreamableHTTP Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates an Express router that exposes MCP tools over HTTP
|
|
5
|
+
* with Bearer token authentication, rate limiting, and audit logging.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { addMcpRoutes } from '@soulbatical/tetra-core';
|
|
10
|
+
*
|
|
11
|
+
* const mcpRouter = Router();
|
|
12
|
+
* addMcpRoutes(mcpRouter, {
|
|
13
|
+
* tools: myToolDefinitions,
|
|
14
|
+
* handlers: myToolHandlers,
|
|
15
|
+
* tokenPrefix: 'vincifox_',
|
|
16
|
+
* });
|
|
17
|
+
* app.use('/api/mcp', mcpRouter);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import type { Router } from 'express';
|
|
21
|
+
import type { McpRoutesConfig } from './types.js';
|
|
22
|
+
/**
|
|
23
|
+
* Add MCP StreamableHTTP routes to a router.
|
|
24
|
+
*
|
|
25
|
+
* The router handles POST (JSON-RPC requests), GET (SSE), and DELETE (cleanup).
|
|
26
|
+
* Authentication is via Bearer token in the Authorization header.
|
|
27
|
+
*/
|
|
28
|
+
export declare function addMcpRoutes(router: Router, config: McpRoutesConfig): void;
|
|
29
|
+
//# sourceMappingURL=mcp-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-routes.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAIzD,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AA8CjE;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAuI1E"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP StreamableHTTP Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates an Express router that exposes MCP tools over HTTP
|
|
5
|
+
* with Bearer token authentication, rate limiting, and audit logging.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { addMcpRoutes } from '@soulbatical/tetra-core';
|
|
10
|
+
*
|
|
11
|
+
* const mcpRouter = Router();
|
|
12
|
+
* addMcpRoutes(mcpRouter, {
|
|
13
|
+
* tools: myToolDefinitions,
|
|
14
|
+
* handlers: myToolHandlers,
|
|
15
|
+
* tokenPrefix: 'vincifox_',
|
|
16
|
+
* });
|
|
17
|
+
* app.use('/api/mcp', mcpRouter);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { createLogger } from '../../utils/logger.js';
|
|
21
|
+
import { systemDB } from '../../core/systemDb.js';
|
|
22
|
+
import { validateMcpApiToken, runWithMcpTenant } from './tenant-context.js';
|
|
23
|
+
const logger = createLogger('mcp:routes');
|
|
24
|
+
const rateBuckets = new Map();
|
|
25
|
+
// Clean up expired buckets every 5 min
|
|
26
|
+
setInterval(() => {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
for (const [key, bucket] of rateBuckets) {
|
|
29
|
+
if (now > bucket.resetAt) {
|
|
30
|
+
rateBuckets.delete(key);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, 5 * 60 * 1000).unref();
|
|
34
|
+
function checkRateLimit(tokenId, max, windowMs) {
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
let bucket = rateBuckets.get(tokenId);
|
|
37
|
+
if (!bucket || now > bucket.resetAt) {
|
|
38
|
+
bucket = { count: 0, resetAt: now + windowMs };
|
|
39
|
+
rateBuckets.set(tokenId, bucket);
|
|
40
|
+
}
|
|
41
|
+
bucket.count++;
|
|
42
|
+
const remaining = Math.max(0, max - bucket.count);
|
|
43
|
+
return {
|
|
44
|
+
allowed: bucket.count <= max,
|
|
45
|
+
remaining,
|
|
46
|
+
resetAt: bucket.resetAt,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Add MCP StreamableHTTP routes to a router.
|
|
51
|
+
*
|
|
52
|
+
* The router handles POST (JSON-RPC requests), GET (SSE), and DELETE (cleanup).
|
|
53
|
+
* Authentication is via Bearer token in the Authorization header.
|
|
54
|
+
*/
|
|
55
|
+
export function addMcpRoutes(router, config) {
|
|
56
|
+
const { tools, handlers, tokenPrefix, rateLimitMax = 100, rateLimitWindowMs = 15 * 60 * 1000, enableAuditLog = true, } = config;
|
|
57
|
+
const db = enableAuditLog ? systemDB('mcp-audit') : null;
|
|
58
|
+
// Audit logging (fire-and-forget)
|
|
59
|
+
function logToolCall(tokenId, organizationId, toolName) {
|
|
60
|
+
if (!db)
|
|
61
|
+
return;
|
|
62
|
+
db.from('mcp_audit_log')
|
|
63
|
+
.insert({ token_id: tokenId, organization_id: organizationId, tool_name: toolName })
|
|
64
|
+
.then(() => { });
|
|
65
|
+
}
|
|
66
|
+
// Auth helper
|
|
67
|
+
async function authenticateRequest(req, res) {
|
|
68
|
+
const authHeader = req.headers.authorization;
|
|
69
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
70
|
+
res.status(401).json({ error: 'Missing or invalid Authorization header' });
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const token = authHeader.substring(7);
|
|
74
|
+
try {
|
|
75
|
+
return await validateMcpApiToken(token, tokenPrefix);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : 'Authentication failed';
|
|
79
|
+
res.status(401).json({ error: message });
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Lazy import MCP SDK (peer dependency)
|
|
84
|
+
let mcpSdkLoaded = false;
|
|
85
|
+
let Server;
|
|
86
|
+
let StreamableHTTPServerTransport;
|
|
87
|
+
let CallToolRequestSchema;
|
|
88
|
+
let ListToolsRequestSchema;
|
|
89
|
+
async function ensureMcpSdk() {
|
|
90
|
+
if (mcpSdkLoaded)
|
|
91
|
+
return;
|
|
92
|
+
const serverMod = await import('@modelcontextprotocol/sdk/server/index.js');
|
|
93
|
+
const transportMod = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
94
|
+
const typesMod = await import('@modelcontextprotocol/sdk/types.js');
|
|
95
|
+
Server = serverMod.Server;
|
|
96
|
+
StreamableHTTPServerTransport = transportMod.StreamableHTTPServerTransport;
|
|
97
|
+
CallToolRequestSchema = typesMod.CallToolRequestSchema;
|
|
98
|
+
ListToolsRequestSchema = typesMod.ListToolsRequestSchema;
|
|
99
|
+
mcpSdkLoaded = true;
|
|
100
|
+
}
|
|
101
|
+
// Create MCP server instance
|
|
102
|
+
function createMcpServer(tenant) {
|
|
103
|
+
const server = new Server({ name: 'tetra-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
104
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
105
|
+
tools,
|
|
106
|
+
}));
|
|
107
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
108
|
+
const { name, arguments: args = {} } = request.params;
|
|
109
|
+
const handler = handlers[name];
|
|
110
|
+
if (!handler) {
|
|
111
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
112
|
+
}
|
|
113
|
+
logToolCall(tenant.tokenId, tenant.organizationId, name);
|
|
114
|
+
return handler(args);
|
|
115
|
+
});
|
|
116
|
+
return server;
|
|
117
|
+
}
|
|
118
|
+
// Main endpoint
|
|
119
|
+
router.all('/', async (req, res) => {
|
|
120
|
+
const tenant = await authenticateRequest(req, res);
|
|
121
|
+
if (!tenant)
|
|
122
|
+
return;
|
|
123
|
+
// Rate limit
|
|
124
|
+
const rateResult = checkRateLimit(tenant.tokenId, rateLimitMax, rateLimitWindowMs);
|
|
125
|
+
res.setHeader('X-RateLimit-Limit', rateLimitMax);
|
|
126
|
+
res.setHeader('X-RateLimit-Remaining', rateResult.remaining);
|
|
127
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(rateResult.resetAt / 1000));
|
|
128
|
+
if (!rateResult.allowed) {
|
|
129
|
+
res.status(429).json({
|
|
130
|
+
error: 'Rate limit exceeded',
|
|
131
|
+
retry_after: Math.ceil((rateResult.resetAt - Date.now()) / 1000),
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Lazy-load MCP SDK
|
|
136
|
+
try {
|
|
137
|
+
await ensureMcpSdk();
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
logger.error({ err }, 'Failed to load @modelcontextprotocol/sdk — is it installed?');
|
|
141
|
+
res.status(500).json({ error: 'MCP SDK not available' });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const transport = new StreamableHTTPServerTransport({
|
|
145
|
+
sessionIdGenerator: undefined,
|
|
146
|
+
});
|
|
147
|
+
const server = createMcpServer(tenant);
|
|
148
|
+
try {
|
|
149
|
+
await server.connect(transport);
|
|
150
|
+
await runWithMcpTenant(tenant, async () => {
|
|
151
|
+
await transport.handleRequest(req, res, req.body);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (!res.headersSent) {
|
|
156
|
+
res.status(500).json({
|
|
157
|
+
error: 'MCP request failed',
|
|
158
|
+
details: error instanceof Error ? error.message : 'Unknown error',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await transport.close().catch(() => { });
|
|
164
|
+
await server.close().catch(() => { });
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=mcp-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-routes.js","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Token Management Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* CRUD for API tokens. All endpoints require authenticated user (Supabase JWT).
|
|
5
|
+
* Tokens are scoped to the user's active organization.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { addMcpTokenRoutes } from '@soulbatical/tetra-core';
|
|
10
|
+
*
|
|
11
|
+
* const mcpTokensRouter = Router();
|
|
12
|
+
* addMcpTokenRoutes(mcpTokensRouter, { tokenPrefix: 'vincifox_' });
|
|
13
|
+
* app.use('/api/mcp-tokens', mcpTokensRouter);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import type { Router } from 'express';
|
|
17
|
+
export interface McpTokenRoutesConfig {
|
|
18
|
+
tokenPrefix: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function addMcpTokenRoutes(router: Router, config: McpTokenRoutesConfig): void;
|
|
21
|
+
//# sourceMappingURL=mcp-tokens-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tokens-routes.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-tokens-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAKzD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAqEpF"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Token Management Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* CRUD for API tokens. All endpoints require authenticated user (Supabase JWT).
|
|
5
|
+
* Tokens are scoped to the user's active organization.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { addMcpTokenRoutes } from '@soulbatical/tetra-core';
|
|
10
|
+
*
|
|
11
|
+
* const mcpTokensRouter = Router();
|
|
12
|
+
* addMcpTokenRoutes(mcpTokensRouter, { tokenPrefix: 'vincifox_' });
|
|
13
|
+
* app.use('/api/mcp-tokens', mcpTokensRouter);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import { authenticateToken } from '../../middleware/authMiddleware.js';
|
|
17
|
+
import { systemDB } from '../../core/systemDb.js';
|
|
18
|
+
import { generateMcpApiToken } from './tenant-context.js';
|
|
19
|
+
function getOrgId(req) {
|
|
20
|
+
const user = req.user;
|
|
21
|
+
return user?.activeOrganizationId || user?.active_organization_id || user?.organizationId || null;
|
|
22
|
+
}
|
|
23
|
+
export function addMcpTokenRoutes(router, config) {
|
|
24
|
+
const { tokenPrefix } = config;
|
|
25
|
+
const db = systemDB('mcp-tokens');
|
|
26
|
+
// GET / — List all tokens for the active organization
|
|
27
|
+
router.get('/', authenticateToken, async (req, res) => {
|
|
28
|
+
const orgId = getOrgId(req);
|
|
29
|
+
if (!orgId) {
|
|
30
|
+
res.status(400).json({ error: 'No active organization' });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const { data, error } = await db
|
|
34
|
+
.from('mcp_api_tokens')
|
|
35
|
+
.select('id, name, is_active, last_used_at, created_at, revoked_at, created_by')
|
|
36
|
+
.eq('organization_id', orgId)
|
|
37
|
+
.order('created_at', { ascending: false });
|
|
38
|
+
if (error) {
|
|
39
|
+
res.status(500).json({ error: 'Failed to list tokens' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
res.json({ tokens: data || [] });
|
|
43
|
+
});
|
|
44
|
+
// POST / — Generate a new API token
|
|
45
|
+
router.post('/', authenticateToken, async (req, res) => {
|
|
46
|
+
const orgId = getOrgId(req);
|
|
47
|
+
const user = req.user;
|
|
48
|
+
if (!orgId) {
|
|
49
|
+
res.status(400).json({ error: 'No active organization' });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const { name } = req.body || {};
|
|
53
|
+
const tokenName = name || `API Token (${new Date().toISOString().slice(0, 10)})`;
|
|
54
|
+
try {
|
|
55
|
+
const token = await generateMcpApiToken(orgId, tokenName, tokenPrefix, user.id);
|
|
56
|
+
res.json({ token, name: tokenName });
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
res.status(500).json({ error: 'Failed to generate token' });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// DELETE /:tokenId — Revoke a token
|
|
63
|
+
router.delete('/:tokenId', authenticateToken, async (req, res) => {
|
|
64
|
+
const orgId = getOrgId(req);
|
|
65
|
+
if (!orgId) {
|
|
66
|
+
res.status(400).json({ error: 'No active organization' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const tokenId = Array.isArray(req.params.tokenId) ? req.params.tokenId[0] : req.params.tokenId;
|
|
70
|
+
const { error } = await db
|
|
71
|
+
.from('mcp_api_tokens')
|
|
72
|
+
.update({ is_active: false, revoked_at: new Date().toISOString() })
|
|
73
|
+
.eq('id', tokenId)
|
|
74
|
+
.eq('organization_id', orgId);
|
|
75
|
+
if (error) {
|
|
76
|
+
res.status(500).json({ error: 'Failed to revoke token' });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
res.json({ success: true });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=mcp-tokens-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tokens-routes.js","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-tokens-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Usage Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Returns audit log stats for the active organization.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { addMcpUsageRoutes } from '@soulbatical/tetra-core';
|
|
9
|
+
*
|
|
10
|
+
* const mcpUsageRouter = Router();
|
|
11
|
+
* addMcpUsageRoutes(mcpUsageRouter);
|
|
12
|
+
* app.use('/api/mcp-usage', mcpUsageRouter);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import type { Router } from 'express';
|
|
16
|
+
export declare function addMcpUsageRoutes(router: Router): void;
|
|
17
|
+
//# sourceMappingURL=mcp-usage-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-usage-routes.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-usage-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AASzD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA8DtD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Usage Routes — Factory
|
|
3
|
+
*
|
|
4
|
+
* Returns audit log stats for the active organization.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { addMcpUsageRoutes } from '@soulbatical/tetra-core';
|
|
9
|
+
*
|
|
10
|
+
* const mcpUsageRouter = Router();
|
|
11
|
+
* addMcpUsageRoutes(mcpUsageRouter);
|
|
12
|
+
* app.use('/api/mcp-usage', mcpUsageRouter);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { authenticateToken } from '../../middleware/authMiddleware.js';
|
|
16
|
+
import { systemDB } from '../../core/systemDb.js';
|
|
17
|
+
function getOrgId(req) {
|
|
18
|
+
const user = req.user;
|
|
19
|
+
return user?.activeOrganizationId || user?.active_organization_id || user?.organizationId || null;
|
|
20
|
+
}
|
|
21
|
+
export function addMcpUsageRoutes(router) {
|
|
22
|
+
const db = systemDB('mcp-usage');
|
|
23
|
+
// GET / — Usage stats (total calls, by tool, daily trend)
|
|
24
|
+
// Query: ?period=7d|30d|90d
|
|
25
|
+
router.get('/', authenticateToken, async (req, res) => {
|
|
26
|
+
const orgId = getOrgId(req);
|
|
27
|
+
if (!orgId) {
|
|
28
|
+
res.status(400).json({ error: 'No active organization' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const period = req.query.period || '30d';
|
|
32
|
+
const days = period === '7d' ? 7 : period === '90d' ? 90 : 30;
|
|
33
|
+
const since = new Date();
|
|
34
|
+
since.setDate(since.getDate() - days);
|
|
35
|
+
try {
|
|
36
|
+
const { count: totalCalls } = await db
|
|
37
|
+
.from('mcp_audit_log')
|
|
38
|
+
.select('id', { count: 'exact', head: true })
|
|
39
|
+
.eq('organization_id', orgId)
|
|
40
|
+
.gte('created_at', since.toISOString());
|
|
41
|
+
const { data: logs } = await db
|
|
42
|
+
.from('mcp_audit_log')
|
|
43
|
+
.select('tool_name, created_at')
|
|
44
|
+
.eq('organization_id', orgId)
|
|
45
|
+
.gte('created_at', since.toISOString())
|
|
46
|
+
.order('created_at', { ascending: true });
|
|
47
|
+
// Aggregate
|
|
48
|
+
const byTool = {};
|
|
49
|
+
const byDay = {};
|
|
50
|
+
for (const log of logs || []) {
|
|
51
|
+
byTool[log.tool_name] = (byTool[log.tool_name] || 0) + 1;
|
|
52
|
+
const day = log.created_at.slice(0, 10);
|
|
53
|
+
byDay[day] = (byDay[day] || 0) + 1;
|
|
54
|
+
}
|
|
55
|
+
// Fill day gaps
|
|
56
|
+
const trend = [];
|
|
57
|
+
const current = new Date(since);
|
|
58
|
+
const now = new Date();
|
|
59
|
+
while (current <= now) {
|
|
60
|
+
const day = current.toISOString().slice(0, 10);
|
|
61
|
+
trend.push({ date: day, count: byDay[day] || 0 });
|
|
62
|
+
current.setDate(current.getDate() + 1);
|
|
63
|
+
}
|
|
64
|
+
res.json({
|
|
65
|
+
period,
|
|
66
|
+
total_calls: totalCalls || 0,
|
|
67
|
+
by_tool: Object.entries(byTool)
|
|
68
|
+
.map(([tool, count]) => ({ tool, count }))
|
|
69
|
+
.sort((a, b) => b.count - a.count),
|
|
70
|
+
trend,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
res.status(500).json({ error: 'Failed to load usage stats' });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=mcp-usage-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-usage-routes.js","sourceRoot":"","sources":["../../../src/shared/mcp/mcp-usage-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tenant Context
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Token validation (Bearer token → organization_id)
|
|
6
|
+
* - Request-scoped tenant context via AsyncLocalStorage
|
|
7
|
+
* - Token generation for admin use
|
|
8
|
+
*
|
|
9
|
+
* Works with any project that has the mcp_api_tokens table.
|
|
10
|
+
*/
|
|
11
|
+
import type { TenantContext } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Get the current tenant's organization_id.
|
|
14
|
+
* Returns undefined when running in local stdio mode (no tenant context).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getMcpOrganizationId(): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Get the full tenant context (org + token).
|
|
19
|
+
*/
|
|
20
|
+
export declare function getMcpTenantContext(): TenantContext | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Run a function within a tenant context.
|
|
23
|
+
* The context is propagated through async calls via AsyncLocalStorage.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runWithMcpTenant<T>(ctx: TenantContext, fn: () => T): T;
|
|
26
|
+
/**
|
|
27
|
+
* Validate a Bearer token and return the tenant context.
|
|
28
|
+
* Throws if token is invalid, revoked, or inactive.
|
|
29
|
+
*
|
|
30
|
+
* @param token - The raw API token (e.g. "vincifox_abc123...")
|
|
31
|
+
* @param expectedPrefix - Expected token prefix (e.g. "vincifox_")
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateMcpApiToken(token: string, expectedPrefix: string): Promise<TenantContext>;
|
|
34
|
+
/**
|
|
35
|
+
* Generate a new API token for an organization.
|
|
36
|
+
* Returns the plaintext token (only shown once — stored as SHA-256 hash).
|
|
37
|
+
*
|
|
38
|
+
* @param organizationId - The organization UUID
|
|
39
|
+
* @param name - Human-readable token name
|
|
40
|
+
* @param prefix - Token prefix (e.g. "vincifox_")
|
|
41
|
+
* @param createdBy - Optional user UUID who created the token
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateMcpApiToken(organizationId: string, name: string, prefix: string, createdBy?: string): Promise<string>;
|
|
44
|
+
//# sourceMappingURL=tenant-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-context.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/tenant-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMhD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAEzD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,GAAG,SAAS,CAE/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEtE;AA4BD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,CAiCxB;AAID;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tenant Context
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Token validation (Bearer token → organization_id)
|
|
6
|
+
* - Request-scoped tenant context via AsyncLocalStorage
|
|
7
|
+
* - Token generation for admin use
|
|
8
|
+
*
|
|
9
|
+
* Works with any project that has the mcp_api_tokens table.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
12
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
13
|
+
import { createClient } from '@supabase/supabase-js';
|
|
14
|
+
// ── AsyncLocalStorage for request-scoped context ──
|
|
15
|
+
const tenantStorage = new AsyncLocalStorage();
|
|
16
|
+
/**
|
|
17
|
+
* Get the current tenant's organization_id.
|
|
18
|
+
* Returns undefined when running in local stdio mode (no tenant context).
|
|
19
|
+
*/
|
|
20
|
+
export function getMcpOrganizationId() {
|
|
21
|
+
return tenantStorage.getStore()?.organizationId;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the full tenant context (org + token).
|
|
25
|
+
*/
|
|
26
|
+
export function getMcpTenantContext() {
|
|
27
|
+
return tenantStorage.getStore();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run a function within a tenant context.
|
|
31
|
+
* The context is propagated through async calls via AsyncLocalStorage.
|
|
32
|
+
*/
|
|
33
|
+
export function runWithMcpTenant(ctx, fn) {
|
|
34
|
+
return tenantStorage.run(ctx, fn);
|
|
35
|
+
}
|
|
36
|
+
// ── DB client ──
|
|
37
|
+
let db = null;
|
|
38
|
+
function getDb() {
|
|
39
|
+
if (!db) {
|
|
40
|
+
const url = process.env.SUPABASE_URL;
|
|
41
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
42
|
+
if (!url || !key) {
|
|
43
|
+
throw new Error('SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY required for MCP tenant auth');
|
|
44
|
+
}
|
|
45
|
+
db = createClient(url, key, {
|
|
46
|
+
auth: { autoRefreshToken: false, persistSession: false },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return db;
|
|
50
|
+
}
|
|
51
|
+
// ── Token hashing ──
|
|
52
|
+
function hashToken(token) {
|
|
53
|
+
return createHash('sha256').update(token).digest('hex');
|
|
54
|
+
}
|
|
55
|
+
// ── Token validation ──
|
|
56
|
+
/**
|
|
57
|
+
* Validate a Bearer token and return the tenant context.
|
|
58
|
+
* Throws if token is invalid, revoked, or inactive.
|
|
59
|
+
*
|
|
60
|
+
* @param token - The raw API token (e.g. "vincifox_abc123...")
|
|
61
|
+
* @param expectedPrefix - Expected token prefix (e.g. "vincifox_")
|
|
62
|
+
*/
|
|
63
|
+
export async function validateMcpApiToken(token, expectedPrefix) {
|
|
64
|
+
if (!token.startsWith(expectedPrefix)) {
|
|
65
|
+
throw new Error('Invalid token format');
|
|
66
|
+
}
|
|
67
|
+
const hash = hashToken(token);
|
|
68
|
+
const supabase = getDb();
|
|
69
|
+
const { data, error } = await supabase
|
|
70
|
+
.from('mcp_api_tokens')
|
|
71
|
+
.select('id, organization_id, is_active, revoked_at')
|
|
72
|
+
.eq('token_hash', hash)
|
|
73
|
+
.single();
|
|
74
|
+
if (error || !data) {
|
|
75
|
+
throw new Error('Invalid API token');
|
|
76
|
+
}
|
|
77
|
+
if (!data.is_active || data.revoked_at) {
|
|
78
|
+
throw new Error('Token has been revoked');
|
|
79
|
+
}
|
|
80
|
+
// Update last_used_at (fire and forget)
|
|
81
|
+
supabase
|
|
82
|
+
.from('mcp_api_tokens')
|
|
83
|
+
.update({ last_used_at: new Date().toISOString() })
|
|
84
|
+
.eq('id', data.id)
|
|
85
|
+
.then(() => { });
|
|
86
|
+
return {
|
|
87
|
+
organizationId: data.organization_id,
|
|
88
|
+
tokenId: data.id,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ── Token generation ──
|
|
92
|
+
/**
|
|
93
|
+
* Generate a new API token for an organization.
|
|
94
|
+
* Returns the plaintext token (only shown once — stored as SHA-256 hash).
|
|
95
|
+
*
|
|
96
|
+
* @param organizationId - The organization UUID
|
|
97
|
+
* @param name - Human-readable token name
|
|
98
|
+
* @param prefix - Token prefix (e.g. "vincifox_")
|
|
99
|
+
* @param createdBy - Optional user UUID who created the token
|
|
100
|
+
*/
|
|
101
|
+
export async function generateMcpApiToken(organizationId, name, prefix, createdBy) {
|
|
102
|
+
const hex = randomBytes(32).toString('hex');
|
|
103
|
+
const token = `${prefix}${hex}`;
|
|
104
|
+
const hash = hashToken(token);
|
|
105
|
+
const supabase = getDb();
|
|
106
|
+
const { error } = await supabase.from('mcp_api_tokens').insert({
|
|
107
|
+
organization_id: organizationId,
|
|
108
|
+
token_hash: hash,
|
|
109
|
+
name,
|
|
110
|
+
created_by: createdBy || null,
|
|
111
|
+
});
|
|
112
|
+
if (error) {
|
|
113
|
+
throw new Error(`Failed to create token: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
return token;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=tenant-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-context.js","sourceRoot":"","sources":["../../../src/shared/mcp/tenant-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Online Module — Types
|
|
3
|
+
*
|
|
4
|
+
* Shared types for MCP StreamableHTTP endpoints.
|
|
5
|
+
*/
|
|
6
|
+
export interface McpToolDefinition {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object';
|
|
11
|
+
properties?: Record<string, unknown>;
|
|
12
|
+
required?: string[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface McpToolResult {
|
|
16
|
+
content: Array<{
|
|
17
|
+
type: 'text';
|
|
18
|
+
text: string;
|
|
19
|
+
}>;
|
|
20
|
+
isError?: boolean;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
export type McpToolHandler = (args: Record<string, unknown>) => Promise<McpToolResult>;
|
|
24
|
+
export interface TenantContext {
|
|
25
|
+
organizationId: string;
|
|
26
|
+
tokenId: string;
|
|
27
|
+
}
|
|
28
|
+
export interface McpRoutesConfig {
|
|
29
|
+
/** Tool definitions to expose via the MCP endpoint */
|
|
30
|
+
tools: McpToolDefinition[];
|
|
31
|
+
/** Map of tool name → handler function */
|
|
32
|
+
handlers: Record<string, McpToolHandler>;
|
|
33
|
+
/** Token prefix for validation, e.g. "vincifox_" or "snelstart_" */
|
|
34
|
+
tokenPrefix: string;
|
|
35
|
+
/** Rate limit: max requests per window (default: 100) */
|
|
36
|
+
rateLimitMax?: number;
|
|
37
|
+
/** Rate limit: window in ms (default: 15 minutes) */
|
|
38
|
+
rateLimitWindowMs?: number;
|
|
39
|
+
/** Enable audit logging to mcp_audit_log table (default: true) */
|
|
40
|
+
enableAuditLog?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface McpAuthRoutesConfig {
|
|
43
|
+
/** Token prefix for generated tokens, e.g. "vincifox_" */
|
|
44
|
+
tokenPrefix: string;
|
|
45
|
+
/** Frontend URL for login redirect (falls back to FRONTEND_URL env or localhost:3000) */
|
|
46
|
+
frontendUrl?: string;
|
|
47
|
+
/** Path on the frontend where the approval page lives (default: "/app/settings/api-tokens") */
|
|
48
|
+
frontendApprovalPath?: string;
|
|
49
|
+
/** Default device name when not provided (default: "Claude Code") */
|
|
50
|
+
defaultDeviceName?: string;
|
|
51
|
+
/** Request expiry in seconds (default: 300 = 5 minutes) */
|
|
52
|
+
expirySeconds?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface McpTokenRoutesConfig {
|
|
55
|
+
}
|
|
56
|
+
export interface McpUsageRoutesConfig {
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/shared/mcp/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAIvF,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACzC,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;CAEpC;AAED,MAAM,WAAW,oBAAoB;CAEpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/shared/mcp/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulbatical/tetra-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "restricted"
|
|
6
6
|
},
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"scripts",
|
|
31
31
|
"src/shared/auth/migrations",
|
|
32
32
|
"src/shared/affiliate/migrations",
|
|
33
|
-
"src/shared/email/migrations"
|
|
33
|
+
"src/shared/email/migrations",
|
|
34
|
+
"src/shared/mcp/migrations"
|
|
34
35
|
],
|
|
35
36
|
"scripts": {
|
|
36
37
|
"build": "tsc",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"zod": "^3.22.4"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49
51
|
"@supabase/supabase-js": "2.93.3",
|
|
50
52
|
"@tanstack/react-table": "^8.0.0",
|
|
51
53
|
"express": "^5.0.0",
|
|
@@ -61,9 +63,13 @@
|
|
|
61
63
|
},
|
|
62
64
|
"@tanstack/react-table": {
|
|
63
65
|
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@modelcontextprotocol/sdk": {
|
|
68
|
+
"optional": true
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
"devDependencies": {
|
|
72
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
67
73
|
"@supabase/supabase-js": "2.93.3",
|
|
68
74
|
"@tanstack/react-table": "^8.21.3",
|
|
69
75
|
"@types/express": "^5.0.0",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- MCP API tokens for online MCP access
|
|
2
|
+
-- Each token is linked to an organization for multi-tenant isolation
|
|
3
|
+
-- Token is stored as SHA-256 hash, never plaintext
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS public.mcp_api_tokens (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
organization_id UUID NOT NULL REFERENCES organizations(id),
|
|
8
|
+
token_hash TEXT NOT NULL UNIQUE,
|
|
9
|
+
name TEXT NOT NULL DEFAULT 'Default',
|
|
10
|
+
created_by UUID REFERENCES auth.users(id),
|
|
11
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
12
|
+
last_used_at TIMESTAMPTZ,
|
|
13
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
14
|
+
revoked_at TIMESTAMPTZ
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
ALTER TABLE public.mcp_api_tokens ENABLE ROW LEVEL SECURITY;
|
|
18
|
+
CREATE POLICY "Service role full access" ON public.mcp_api_tokens
|
|
19
|
+
FOR ALL TO service_role USING (true) WITH CHECK (true);
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_api_tokens_hash ON public.mcp_api_tokens(token_hash);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_api_tokens_org ON public.mcp_api_tokens(organization_id);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- MCP audit log for tracking tool usage per token/organization
|
|
2
|
+
|
|
3
|
+
CREATE TABLE IF NOT EXISTS public.mcp_audit_log (
|
|
4
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
5
|
+
token_id UUID REFERENCES mcp_api_tokens(id),
|
|
6
|
+
organization_id UUID NOT NULL REFERENCES organizations(id),
|
|
7
|
+
tool_name TEXT NOT NULL,
|
|
8
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
ALTER TABLE public.mcp_audit_log ENABLE ROW LEVEL SECURITY;
|
|
12
|
+
CREATE POLICY "Service role full access" ON public.mcp_audit_log
|
|
13
|
+
FOR ALL TO service_role USING (true) WITH CHECK (true);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_audit_log_org ON public.mcp_audit_log(organization_id);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_audit_log_token ON public.mcp_audit_log(token_id);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_audit_log_created ON public.mcp_audit_log(created_at DESC);
|