Skip to main content
Glama
AaroYazilim

AARO ERP MCP Server

by AaroYazilim

erp_token_manuel_ekle

Manually parse and cache token information from HTML-formatted text for AARO ERP system integration, enabling authentication data processing.

Instructions

Manuel olarak token bilgilerini parse edip cache'e ekler. Token metni HTML formatında olabilir.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tokenTextYesToken metni (HTML formatında olabilir, kullanıcı, token, tarihler ve grup bilgilerini içermeli)

Implementation Reference

  • The core handler function for the 'erp_token_manuel_ekle' tool. Parses the provided tokenText, extracts token info using parseTokenInfo, caches it using saveTokenCacheWithInfo, and returns success/error response.
    private async addManualToken(args: any) {
      try {
        const { tokenText } = args;
        
        if (!tokenText || typeof tokenText !== 'string') {
          throw new Error('tokenText parametresi gerekli ve string olmalı');
        }
    
        this.log('Manuel token ekleme işlemi başlıyor', 'info', { 
          tokenTextLength: tokenText.length 
        });
    
        // Token bilgilerini parse et
        const tokenInfo = this.parseTokenInfo(tokenText);
        
        if (!tokenInfo.token) {
          throw new Error('Token parse edilemedi');
        }
    
        // Token'i cache'e kaydet
        this.saveTokenCacheWithInfo(tokenInfo);
    
        this.log('Manuel token başarıyla eklendi', 'info', {
          user: tokenInfo.user,
          validFrom: tokenInfo.validFrom,
          validTo: tokenInfo.validTo,
          group: tokenInfo.group,
          tokenLength: tokenInfo.token.length
        });
    
        return {
          content: [
            {
              type: 'text',
              text: `Manuel token başarıyla cache'e eklendi!\n\nKullanıcı: ${tokenInfo.user || 'Bulunamadı'}\nGeçerlilik Başlangıç: ${tokenInfo.validFrom || 'Bulunamadı'}\nGeçerlilik Bitiş: ${tokenInfo.validTo || 'Bulunamadı'}\nGrup: ${tokenInfo.group || 'Bulunamadı'}\nToken Uzunluğu: ${tokenInfo.token.length} karakter\n\nToken artık API çağrılarında kullanılabilir.`,
            },
          ],
        };
      } catch (error) {
        this.log('Manuel token ekleme hatası', 'error', error);
        return {
          content: [
            {
              type: 'text',
              text: `Manuel token ekleme hatası: ${error instanceof Error ? error.message : 'Bilinmeyen hata'}`,
            },
          ],
          isError: true,
        };
      }
  • Helper method used by addManualToken to save the parsed token information to the cache file.
    private saveTokenCacheWithInfo(tokenInfo: TokenCache): void {
      try {
        fs.writeFileSync(this.tokenCacheFile, JSON.stringify(tokenInfo, null, 2));
        
        const remainingMinutes = Math.floor((tokenInfo.expiresAt - Date.now()) / (60 * 1000));
        this.log(`Token cache'e kaydedildi`, 'info', {
          user: tokenInfo.user,
          validFrom: tokenInfo.validFrom,
          validTo: tokenInfo.validTo,
          group: tokenInfo.group,
          remainingMinutes
        });
      } catch (error) {
        this.log('Token cache kaydetme hatası', 'error', error);
      }
    }
  • Helper method used by addManualToken to parse raw token text into structured TokenCache object using regex patterns.
    private parseTokenInfo(tokenText: string): TokenCache {
      try {
        this.log('Token parse işlemi başlıyor', 'info', { tokenTextLength: tokenText.length });
        
        // HTML tag'lerini temizle ve <br> tag'lerini \n ile değiştir
        let cleanText = tokenText
          .replace(/<br\s*\/?>/gi, '\n')  // <br> tag'lerini \n ile değiştir
          .replace(/<[^>]*>/g, '')        // Diğer HTML tag'lerini kaldır
          .replace(/ /g, ' ')        //   karakterlerini boşluk ile değiştir
          .trim();
        
        this.log('HTML temizlendi', 'info', { cleanTextLength: cleanText.length, cleanText: cleanText.substring(0, 200) + '...' });
        
        // Regex ile direkt parse et (satır bazlı değil, tüm metin üzerinde)
        let user = '';
        let token = '';
        let validFrom = '';
        let validTo = '';
        let group = '';
        
        // Kullanıcı bilgisini bul
        const userMatch = cleanText.match(/Kullanıcı\s*:\s*([^\s]+@[^\s]+)/);
        if (userMatch) {
          user = userMatch[1];
          this.log('Kullanıcı bulundu', 'info', { user });
        }
        
        // Token'ı bul - "Geçici Erişim Anahtarı : " dan sonra boşluk öncesine kadar
        const tokenMatch = cleanText.match(/Geçici Erişim Anahtarı\s*:\s*([A-Za-z0-9_\-]+)/);
        if (tokenMatch) {
          token = tokenMatch[1];
          this.log('Token bulundu', 'info', { tokenLength: token.length, tokenPreview: token.substring(0, 20) + '...' });
        }
        
        // Geçerlilik başlangıç tarihini bul
        const validFromMatch = cleanText.match(/Geçerlilik Başlangıç\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})/);
        if (validFromMatch) {
          validFrom = validFromMatch[1];
          this.log('Başlangıç tarihi bulundu', 'info', { validFrom });
        }
        
        // Geçerlilik bitiş tarihini bul
        const validToMatch = cleanText.match(/Geçerlilik Bitiş\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})/);
        if (validToMatch) {
          validTo = validToMatch[1];
          this.log('Bitiş tarihi bulundu', 'info', { validTo });
        }
        
        // Grup bilgisini bul
        const groupMatch = cleanText.match(/Grup\s*:\s*(\d+)/);
        if (groupMatch) {
          group = groupMatch[1];
          this.log('Grup bulundu', 'info', { group });
        }
        
        // Token bulunamadıysa fallback
        if (!token || token.length < 10) {
          this.log('Token regex ile bulunamadı, fallback deneniyor...', 'warn');
          
          // Fallback: En uzun alfanumerik+özel karakter dizisini bul
          const tokenFallbackMatch = cleanText.match(/([A-Za-z0-9_\-]{100,})/);
          if (tokenFallbackMatch) {
            token = tokenFallbackMatch[1];
            this.log('Fallback token bulundu', 'info', { 
              tokenLength: token.length,
              tokenPreview: token.substring(0, 20) + '...'
            });
          } else {
            throw new Error(`Token bulunamadı. Metin: ${cleanText.substring(0, 200)}...`);
          }
        }
        
        // Geçerlilik bitiş tarihini parse et ve expiresAt hesapla
        let expiresAt = Date.now() + (this.settings.erp.tokenCacheMinutes * 60 * 1000); // Varsayılan
        
        if (validTo) {
          try {
            // "2025-07-25 22:43" formatını parse et
            const [datePart, timePart] = validTo.split(' ');
            const [year, month, day] = datePart.split('-').map(Number);
            const [hour, minute] = timePart.split(':').map(Number);
            
            const expireDate = new Date(year, month - 1, day, hour, minute);
            expiresAt = expireDate.getTime();
            
            this.log(`Token geçerlilik bitiş tarihi parse edildi: ${expireDate.toISOString()}`);
          } catch (parseError) {
            this.log('Token geçerlilik tarihi parse edilemedi, varsayılan süre kullanılıyor', 'warn', parseError);
          }
        }
        
        const result = {
          token,
          expiresAt,
          createdAt: Date.now(),
          user,
          validFrom,
          validTo,
          group,
          rawText: tokenText
        };
        
        this.log('Token parse işlemi tamamlandı', 'info', {
          hasToken: !!result.token,
          tokenLength: result.token.length,
          hasUser: !!result.user,
          hasValidTo: !!result.validTo,
          user: result.user,
          validFrom: result.validFrom,
          validTo: result.validTo,
          group: result.group
        });
        
        return result;
        
      } catch (error) {
        this.log('Token parse hatası', 'error', { 
          error: error instanceof Error ? error.message : 'Bilinmeyen hata',
          tokenText: tokenText.substring(0, 200) + '...'
        });
        throw new Error(`Token bilgileri parse edilemedi: ${error instanceof Error ? error.message : 'Bilinmeyen hata'}`);
      }
  • src/index.ts:232-261 (registration)
    Dispatch case in callSpecialHandler that routes calls to the addManualToken handler. The tool name 'erp_token_manuel_ekle' maps to this handler via external config/tools.json.
      case 'addManualToken':
        return await this.addManualToken(args);
    
      case 'createStok':
        return await this.createStok(args);
    
      case 'createCari':
        return await this.createCari(args);
    
      case 'createDekont':
        return await this.createDekont(args);
    
      case 'addDekontKalem':
        return await this.addDekontKalem(args);
    
      case 'updateDekont':
        return await this.updateDekont(args);
    
      case 'testWebhook':
        return await this.testWebhook(args);
    
      case 'callErpApi':
        if (!isValidErpApiArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Geçersiz API çağrı parametreleri');
        }
        return await this.callErpApi(args.endpoint!, args.method || 'GET', args);
    
      default:
        throw new McpError(ErrorCode.MethodNotFound, `Bilinmeyen handler: ${handlerName}`);
    }
  • src/index.ts:176-215 (registration)
    Dynamic tool registration handler that dispatches to special handlers like 'addManualToken' based on toolsConfig from config/tools.json.
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      try {
        const toolConfig = this.toolsConfig[name];
        if (!toolConfig) {
          throw new McpError(ErrorCode.MethodNotFound, `Bilinmeyen araç: ${name}`);
        }
    
        // Request bilgilerini logla
        this.log(`Tool çağrısı: ${name}`, 'info', { 
          tool: name, 
          params: args 
        });
    
        // Özel handler varsa onu kullan
        if (toolConfig.handler) {
          return await this.callSpecialHandler(toolConfig.handler, args);
        }
    
        // Normal API çağrısı
        if (toolConfig.endpoint && toolConfig.method) {
          return await this.callErpApi(toolConfig.endpoint, toolConfig.method as 'GET' | 'POST', args);
        }
    
        throw new McpError(ErrorCode.InternalError, `Tool konfigürasyonu eksik: ${name}`);
    
      } catch (error) {
        this.log(`Tool hatası: ${name}`, 'error', error);
        return {
          content: [
            {
              type: 'text',
              text: `Hata: ${error instanceof Error ? error.message : 'Bilinmeyen hata'}`,
            },
          ],
          isError: true,
        };
      }
    });
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It mentions parsing HTML-formatted token text and caching, but doesn't disclose critical behavioral traits: whether this is a read/write operation, potential side effects (e.g., overwriting existing cache), authentication needs, error handling, or rate limits. For a tool with no annotation coverage, this is insufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded: two sentences that directly state the tool's function and a key constraint (HTML format). Every sentence earns its place with no wasted words, making it efficient for an agent to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (a parsing and caching operation), lack of annotations, and no output schema, the description is incomplete. It doesn't explain what the tool returns, how errors are handled, or the implications of caching—leaving significant gaps for the agent to operate effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the 'tokenText' parameter thoroughly. The description adds minimal value by noting that the token text may be in HTML format and should contain user, token, dates, and group information—hinting at expected content but not providing additional syntax or format details beyond the schema. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Manuel olarak token bilgilerini parse edip cache'e ekler' (Manually parses token information and adds it to cache). It specifies the verb (parse and add), resource (token information), and destination (cache). However, it doesn't explicitly differentiate from sibling tools like 'erp_token_al' or 'erp_token_sil', which would require a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention scenarios where manual parsing is needed over automated methods (e.g., 'erp_token_al'), prerequisites, or exclusions. Without such context, the agent lacks clear usage direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/AaroYazilim/aaro-erp-mcp-server'

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