diff --git a/src/createJwt.ts b/src/createJwt.ts new file mode 100644 index 0000000..9fd9d57 --- /dev/null +++ b/src/createJwt.ts @@ -0,0 +1,65 @@ +import { execFile, ExecFileException } from 'child_process'; + +interface CreateJwtOptions { + name?: string; + issuer?: string; + audiences?: string[]; + roles?: string[]; + scopes?: string[]; + claims?: string[]; + validFor?: number; + signingKey?: string; +} + +export const createJwt = async (options: CreateJwtOptions): Promise => { + const args: string[] = ['jwt', 'create']; + + if (options.name) { + args.push('--name', options.name); + } + if (options.issuer) { + args.push('--issuer', options.issuer); + } + if (options.audiences) { + for (const audience of options.audiences) { + args.push('--audiences', audience); + } + } + if (options.roles) { + for (const role of options.roles) { + args.push('--roles', role); + } + } + if (options.scopes) { + for (const scope of options.scopes) { + args.push('--scopes', scope); + } + } + if (options.claims) { + for (const claim of options.claims) { + args.push('--claims', claim); + } + } + if (options.validFor !== undefined) { + args.push('--valid-for', options.validFor.toString()); + } + if (options.signingKey) { + args.push('--signing-key', options.signingKey); + } + + return new Promise((resolve, reject) => { + execFile('devproxy', args, (error: ExecFileException | null, stdout: string, stderr: string) => { + if (error) { + reject(`Error creating JWT: ${error.message}`); + return; + } + + if (stderr) { + reject(`Error creating JWT: ${stderr}`); + return; + } + + resolve(stdout.trim()); + }); + }); +}; diff --git a/src/index.ts b/src/index.ts index a5c2ba8..2785e9c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { createRequire } from 'module'; import { z } from 'zod'; +import { createJwt } from './createJwt.js'; import { findDocs } from './findDocs.js'; import { getVersion } from './getVersion.js'; import { getBestPractices } from './getBestPractices.js'; @@ -47,5 +48,24 @@ server.tool('GetVersion', 'Gets the currently installed Dev Proxy version', }) ); +server.tool('CreateJwt', 'Creates a JSON Web Token (JWT) using the Dev Proxy jwt create command. Returns the generated token.', + { + name: z.string().optional().describe('The name of the user to create the token for'), + issuer: z.string().optional().describe('The token issuer'), + audiences: z.array(z.string()).optional().describe('The audiences for the token'), + roles: z.array(z.string()).optional().describe('The roles to include in the token'), + scopes: z.array(z.string()).optional().describe('The scopes to include in the token'), + claims: z.array(z.string()).optional().describe('Custom claims to include in the token in the format name:value'), + validFor: z.number().optional().describe('The token validity in minutes'), + signingKey: z.string().optional().describe('The signing key for the token. Must be at least 32 characters'), + }, + { + title: 'Create JWT', + }, + async ({ name, issuer, audiences, roles, scopes, claims, validFor, signingKey }) => ({ + content: [{ type: 'text', text: await createJwt({ name, issuer, audiences, roles, scopes, claims, validFor, signingKey }) }] + }) +); + const transport = new StdioServerTransport(); await server.connect(transport); \ No newline at end of file