The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Viewing files at commit 68c3fd2f8af0Commit detailsView latest

api/mcp.ts 39 lines · 1.7 KB · typescript
1
import descopeSdk from '@descope/node-sdk';
2
import type { AuthInfo } from '@modelcontextprotocol/server';
3
import { createMcpHandler, withMcpAuth } from 'mcp-handler';
4
import { TrustEngine } from '../packages/core/src/index.js';
5
import { registerOpenClaspTools } from '../packages/mcp-server/src/server.js';
6
7
const engine = new TrustEngine();
8
const mcp = createMcpHandler((server) => registerOpenClaspTools(server, engine), {
9
  serverInfo: { name: 'openclasp', version: '0.1.0' },
10
  instructions:
11
    'OpenClasp provides identity, interaction assurance, private clues, receipts, and contextual behavioural history. Never submit raw private conversations.',
12
});
13
14
async function verifyToken(_request: Request, bearerToken?: string): Promise<AuthInfo | undefined> {
15
  const projectId = process.env.DESCOPE_PROJECT_ID ?? process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID;
16
  if (!projectId || !bearerToken) return undefined;
17
  const descope = descopeSdk({ projectId });
18
  const authentication = await descope.validateSession(bearerToken, {
19
    ...(process.env.OPENCLASP_MCP_URL ? { audience: process.env.OPENCLASP_MCP_URL } : {}),
20
  });
21
  if (!authentication.token.exp) return undefined;
22
  return {
23
    token: bearerToken,
24
    clientId: authentication.token.sub ?? 'unknown-client',
25
    scopes: descope.getJwtPermissions(bearerToken),
26
    expiresAt: authentication.token.exp,
27
  };
28
}
29
30
const handler = withMcpAuth(mcp, verifyToken, {
31
  required: true,
32
  requiredScopes: ['profile:read'],
33
  resourceMetadataPath: '/.well-known/oauth-protected-resource',
34
  ...(process.env.OPENCLASP_MCP_URL
35
    ? { resourceUrl: new URL(process.env.OPENCLASP_MCP_URL).origin }
36
    : {}),
37
});
38
39
export { handler as GET, handler as POST };