Skip to main content
Glama
ferdhika31

Money Lover MCP Server

login

Authenticate to Money Lover personal finance app using account credentials to obtain a JWT token for accessing financial data and managing transactions.

Instructions

Authenticate using Money Lover credentials to retrieve a JWT token.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
emailYesMoney Lover account email
passwordYesMoney Lover account password

Implementation Reference

  • The handler function for the 'login' MCP tool. It authenticates using email/password via MoneyloverClient.getToken, caches the token, updates environment cache if matching, and returns formatted success/error response.
    async ({ email, password }) => {
      try {
        const token = await MoneyloverClient.getToken(email, password);
        try {
          await writeToken(email, token);
        } catch (error) {
          console.warn('Failed to persist Money Lover token:', error);
        }
        const { email: envEmail } = getEnvConfig();
        if (email === envEmail && envEmail) {
          cachedEnvEmail = envEmail;
          cachedEnvToken = token;
          cacheLoaded = true;
          cachedEnvUsesDirectToken = false;
        }
        return formatSuccess({ token });
      } catch (error) {
        return formatError(error instanceof Error ? error : new Error(String(error)));
      }
    }
  • Zod schemas defining input (email, password) and output (token) for the 'login' tool.
    inputSchema: {
      email: z.string().email().describe('Money Lover account email'),
      password: z.string().min(1).describe('Money Lover account password')
    },
    outputSchema: {
      token: z.string()
    }
  • src/server.js:282-315 (registration)
    Registers the 'login' tool on the MCP server with title, description, schemas, and handler.
    server.registerTool(
      'login',
      {
        title: 'Login to Money Lover',
        description: 'Authenticate using Money Lover credentials to retrieve a JWT token.',
        inputSchema: {
          email: z.string().email().describe('Money Lover account email'),
          password: z.string().min(1).describe('Money Lover account password')
        },
        outputSchema: {
          token: z.string()
        }
      },
      async ({ email, password }) => {
        try {
          const token = await MoneyloverClient.getToken(email, password);
          try {
            await writeToken(email, token);
          } catch (error) {
            console.warn('Failed to persist Money Lover token:', error);
          }
          const { email: envEmail } = getEnvConfig();
          if (email === envEmail && envEmail) {
            cachedEnvEmail = envEmail;
            cachedEnvToken = token;
            cacheLoaded = true;
            cachedEnvUsesDirectToken = false;
          }
          return formatSuccess({ token });
        } catch (error) {
          return formatError(error instanceof Error ? error : new Error(String(error)));
        }
      }
    );
  • Core helper method implementing the Money Lover login flow: fetches login initiation URL and request token, parses client param, then POSTs credentials to oauth endpoint to obtain JWT access token.
    static async getToken(email, password) {
      const loginResponse = await fetch(LOGIN_URL, { method: 'POST' });
      if (!loginResponse.ok) {
        throw new Error(`Failed to initiate login: HTTP ${loginResponse.status}`);
      }
    
      const loginPayload = await readJson(loginResponse);
      const requestToken = loginPayload?.data?.request_token;
      const loginUrl = loginPayload?.data?.login_url;
    
      if (!requestToken || !loginUrl) {
        throw new Error('Login response missing request_token or login_url');
      }
    
      let clientParam = '';
      try {
        const parsed = new URL(loginUrl);
        clientParam = parsed.searchParams.get('client') ?? '';
      } catch (error) {
        throw new Error(`Unable to parse login URL: ${error.message}`);
      }
    
      if (!clientParam) {
        throw new Error('Login URL missing client parameter');
      }
    
      const form = new URLSearchParams();
      form.set('email', ensureString(email, 'email'));
      form.set('password', ensureString(password, 'password'));
    
      const tokenResponse = await fetch(TOKEN_URL, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${requestToken}`,
          Client: clientParam,
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: form.toString()
      });
    
      if (!tokenResponse.ok) {
        throw new Error(`Failed to retrieve access token: HTTP ${tokenResponse.status}`);
      }
    
      const tokenPayload = await readJson(tokenResponse);
      const accessToken = tokenPayload?.access_token;
      if (!accessToken) {
        throw new Error('Access token not present in response');
      }
      return accessToken;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ferdhika31/moneylover-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server