Skip to main content
Glama

aegis_proxy_request

Make authenticated API calls through Aegis with automatic credential injection. Provide service name and API path; Aegis handles authentication securely without exposing credentials.

Instructions

Make an authenticated API call through Aegis. Credentials are injected automatically — you never see them. Provide the service name and API path; Aegis handles authentication.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
serviceYesThe service name (must match a registered credential in Aegis)
pathYesThe API path to call (e.g. "/v1/chat/completions")
methodNoHTTP method (default: GET)GET
headersNoAdditional request headers (auth headers are injected automatically)
bodyNoRequest body (for POST/PUT/PATCH)
targetHostNoOverride the target domain (must be in the credential's allowlist). Defaults to the credential's primary domain.

Implementation Reference

  • The `registerProxyRequestTool` method defines the `aegis_proxy_request` MCP tool, handling input schema validation and calling the `proxyRequest` handler logic.
    private registerProxyRequestTool(): void {
      this.server.registerTool(
        'aegis_proxy_request',
        {
          title: 'Aegis Proxy Request',
          description:
            'Make an authenticated API call through Aegis. Credentials are injected automatically — you never see them. Provide the service name and API path; Aegis handles authentication.',
          inputSchema: {
            service: z
              .string()
              .describe('The service name (must match a registered credential in Aegis)'),
            path: z.string().describe('The API path to call (e.g. "/v1/chat/completions")'),
            method: z
              .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])
              .optional()
              .default('GET')
              .describe('HTTP method (default: GET)'),
            headers: z
              .record(z.string(), z.string())
              .optional()
              .describe('Additional request headers (auth headers are injected automatically)'),
            body: z.string().optional().describe('Request body (for POST/PUT/PATCH)'),
            targetHost: z
              .string()
              .optional()
              .describe(
                "Override the target domain (must be in the credential's allowlist). Defaults to the credential's primary domain.",
              ),
          },
        },
        async (args: {
          service: string;
          path: string;
          method?: string;
          headers?: Record<string, string>;
          body?: string;
          targetHost?: string;
        }) => {
          try {
            const result = await this.proxyRequest(args);
            return {
              content: [
                {
                  type: 'text' as const,
                  text: JSON.stringify(
                    {
                      status: result.status,
                      headers: result.headers,
                      body: result.body,
                    },
                    null,
                    2,
                  ),
                },
              ],
            };
          } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            return {
              content: [{ type: 'text' as const, text: `Error: ${message}` }],
              isError: true,
            };
          }
        },
      );
    }
  • The `proxyRequest` method acts as the primary handler, implementing security controls (credential lookup, TTL, scope, policy, rate limiting, domain guard, body inspection) before performing the outbound request.
    private async proxyRequest(params: {
      service: string;
      path: string;
      method?: string;
      headers?: Record<string, string>;
      body?: string;
      targetHost?: string;
    }): Promise<ProxyResult> {
      const method = params.method ?? 'GET';
      const path = params.path.startsWith('/') ? params.path : `/${params.path}`;
      const requestId = generateRequestId();
    
      // 1. Credential lookup
      const credential = this.vault.getByService(params.service);
      if (!credential) {
        this.metrics?.recordBlocked(params.service, 'no_credential', this.authenticatedAgent?.name);
        this.webhooks?.emit('blocked_request', {
          service: params.service,
          reason: 'no_credential',
          method,
          path,
          agent: this.authenticatedAgent?.name,
        });
        this.ledger.logBlocked({
          service: params.service,
          targetDomain: 'unknown',
          method,
          path,
          reason: `No credential found for service: ${params.service}`,
          agentName: this.authenticatedAgent?.name,
          agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
          channel: 'mcp',
        });
        throw new Error(
          `No credential registered for service: ${params.service}. ` +
            `Register one with: aegis vault add --name ${params.service} --service ${params.service} --secret YOUR_KEY --domains api.example.com`,
        );
      }
    
      // 2. TTL enforcement
      if (this.vault.isExpired(credential)) {
        this.metrics?.recordBlocked(
          params.service,
          'credential_expired',
          this.authenticatedAgent?.name,
        );
        this.webhooks?.emit('credential_expiry', {
          service: params.service,
          credential: credential.name,
          expiredAt: credential.expiresAt,
          agent: this.authenticatedAgent?.name,
        });
        this.ledger.logBlocked({
          service: params.service,
          targetDomain: credential.domains[0] ?? 'unknown',
          method,
          path,
          reason: `Credential "${credential.name}" expired at ${credential.expiresAt}`,
          agentName: this.authenticatedAgent?.name,
          agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
          channel: 'mcp',
        });
        throw new Error(
          `Credential "${credential.name}" has expired at ${credential.expiresAt}. ` +
            `Rotate with: aegis vault rotate --name ${credential.name} --secret NEW_SECRET`,
        );
      }
    
      // 3. Agent credential scoping
      if (this.authenticatedAgent && this.agentRegistry) {
        if (!this.agentRegistry.hasAccess(this.authenticatedAgent.id, credential.id)) {
          this.metrics?.recordBlocked(params.service, 'agent_scope', this.authenticatedAgent.name);
          this.webhooks?.emit('blocked_request', {
            service: params.service,
            reason: 'agent_scope',
            agent: this.authenticatedAgent.name,
            credential: credential.name,
            method,
            path,
          });
          this.ledger.logBlocked({
            service: params.service,
            targetDomain: credential.domains[0] ?? 'unknown',
            method,
            path,
            reason: `Agent "${this.authenticatedAgent.name}" not granted access to credential "${credential.name}"`,
            agentName: this.authenticatedAgent.name,
            agentTokenPrefix: this.authenticatedAgent.tokenPrefix,
            channel: 'mcp',
          });
          throw new Error(
            `Agent "${this.authenticatedAgent.name}" is not granted access to credential "${credential.name}". ` +
              `Grant access with: aegis agent grant --agent ${this.authenticatedAgent.name} --credential ${credential.name}`,
          );
        }
      }
    
      // 4. Credential scope enforcement
      if (!methodMatchesScope(method, credential.scopes)) {
        const scopeList = credential.scopes.join(', ');
        this.metrics?.recordBlocked(
          params.service,
          'credential_scope',
          this.authenticatedAgent?.name,
        );
        this.webhooks?.emit('blocked_request', {
          service: params.service,
          reason: 'credential_scope',
          credential: credential.name,
          method,
          scopes: credential.scopes,
          agent: this.authenticatedAgent?.name,
          path,
        });
        this.ledger.logBlocked({
          service: params.service,
          targetDomain: credential.domains[0] ?? 'unknown',
          method,
          path,
          reason: `Method "${method}" not permitted by credential scopes [${scopeList}]`,
          agentName: this.authenticatedAgent?.name,
          agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
          channel: 'mcp',
        });
        throw new Error(
          `Method "${method}" is not permitted by credential scopes [${scopeList}]. ` +
            `Update scopes with: aegis vault update --name ${credential.name} --scopes ${scopeList},${method === 'GET' ? 'read' : 'write'}`,
        );
      }
    
      // 5. Policy evaluation
      if (this.authenticatedAgent && this.policyMap.size > 0) {
        const agentPolicy = this.policyMap.get(this.authenticatedAgent.name);
        if (agentPolicy) {
          const evaluation = evaluatePolicy(agentPolicy, {
            service: params.service,
            method,
            path,
          });
    
          if (!evaluation.allowed) {
            const reason = `Policy violation: ${evaluation.reason}`;
    
            if (this.policyMode === 'enforce') {
              this.metrics?.recordBlocked(
                params.service,
                'policy_violation',
                this.authenticatedAgent.name,
              );
              this.webhooks?.emit('blocked_request', {
                service: params.service,
                reason: 'policy_violation',
                agent: this.authenticatedAgent.name,
                violation: evaluation.violation,
                detail: evaluation.reason,
                method,
                path,
              });
              this.ledger.logBlocked({
                service: params.service,
                targetDomain: credential.domains[0] ?? 'unknown',
                method,
                path,
                reason,
                agentName: this.authenticatedAgent.name,
                agentTokenPrefix: this.authenticatedAgent.tokenPrefix,
                channel: 'mcp',
              });
              throw new Error(
                `Policy violation for agent "${this.authenticatedAgent.name}": ${evaluation.reason}`,
              );
            }
    
            // Dry-run: log but allow
            this.ledger.logBlocked({
              service: params.service,
              targetDomain: credential.domains[0] ?? 'unknown',
              method,
              path,
              reason: `POLICY_DRY_RUN: ${evaluation.reason}`,
              agentName: this.authenticatedAgent.name,
              agentTokenPrefix: this.authenticatedAgent.tokenPrefix,
              channel: 'mcp',
            });
            this.logger.info(
              { agent: this.authenticatedAgent.name, reason: evaluation.reason, requestId },
              'Dry-run: would block',
            );
          }
        }
      }
    
      // 6. Agent rate limiting
      if (this.authenticatedAgent?.rateLimit) {
        try {
          const agentParsedLimit = parseRateLimit(this.authenticatedAgent.rateLimit);
          const agentResult = this.rateLimiter.check(
            `agent:${this.authenticatedAgent.id}`,
            agentParsedLimit,
          );
          if (!agentResult.allowed) {
            this.metrics?.recordBlocked(
              params.service,
              'agent_rate_limit',
              this.authenticatedAgent.name,
            );
            this.webhooks?.emit('rate_limit_exceeded', {
              service: params.service,
              type: 'agent',
              agent: this.authenticatedAgent.name,
              limit: this.authenticatedAgent.rateLimit,
              retryAfter: agentResult.retryAfterSeconds,
            });
            this.ledger.logBlocked({
              service: params.service,
              targetDomain: credential.domains[0] ?? 'unknown',
              method,
              path,
              reason: `Agent rate limit exceeded: ${this.authenticatedAgent.rateLimit} (retry after ${agentResult.retryAfterSeconds}s)`,
              agentName: this.authenticatedAgent.name,
              agentTokenPrefix: this.authenticatedAgent.tokenPrefix,
              channel: 'mcp',
            });
            throw new Error(
              `Agent rate limit exceeded (${this.authenticatedAgent.rateLimit}). Retry after ${agentResult.retryAfterSeconds} seconds.`,
            );
          }
        } catch (err) {
          // Re-throw rate limit errors, ignore parse errors
          if (err instanceof Error && err.message.includes('rate limit')) {
            throw err;
          }
          this.logger.error(
            {
              agent: this.authenticatedAgent.name,
              rateLimit: this.authenticatedAgent.rateLimit,
              requestId,
            },
            'Invalid agent rate limit config',
          );
        }
      }
    
      // 7. Credential rate limiting
      if (credential.rateLimit) {
        try {
          const parsedLimit = parseRateLimit(credential.rateLimit);
          const result = this.rateLimiter.check(credential.id, parsedLimit);
          if (!result.allowed) {
            this.metrics?.recordBlocked(
              params.service,
              'credential_rate_limit',
              this.authenticatedAgent?.name,
            );
            this.webhooks?.emit('rate_limit_exceeded', {
              service: params.service,
              type: 'credential',
              credential: credential.name,
              limit: credential.rateLimit,
              retryAfter: result.retryAfterSeconds,
              agent: this.authenticatedAgent?.name,
            });
            this.ledger.logBlocked({
              service: params.service,
              targetDomain: credential.domains[0] ?? 'unknown',
              method,
              path,
              reason: `Rate limit exceeded: ${credential.rateLimit} (retry after ${result.retryAfterSeconds}s)`,
              agentName: this.authenticatedAgent?.name,
              agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
              channel: 'mcp',
            });
            throw new Error(
              `Rate limit exceeded for "${credential.name}" (${credential.rateLimit}). Retry after ${result.retryAfterSeconds} seconds.`,
            );
          }
        } catch (err) {
          if (err instanceof Error && err.message.includes('Rate limit')) {
            throw err;
          }
          this.logger.error(
            { credential: credential.name, rateLimit: credential.rateLimit, requestId },
            'Invalid credential rate limit config',
          );
        }
      }
    
      // 8. Domain guard
      const targetDomain = params.targetHost ?? credential.domains[0];
      if (!this.vault.domainMatches(targetDomain, credential.domains)) {
        this.metrics?.recordBlocked(params.service, 'domain_guard', this.authenticatedAgent?.name);
        this.webhooks?.emit('blocked_request', {
          service: params.service,
          reason: 'domain_guard',
          targetDomain,
          allowedDomains: credential.domains,
          agent: this.authenticatedAgent?.name,
          method,
          path,
        });
        this.ledger.logBlocked({
          service: params.service,
          targetDomain,
          method,
          path,
          reason: `Domain "${targetDomain}" not in allowlist [${credential.domains.join(', ')}]`,
          agentName: this.authenticatedAgent?.name,
          agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
          channel: 'mcp',
        });
        throw new Error(
          `Domain "${targetDomain}" is not in the credential's allowlist [${credential.domains.join(', ')}].`,
        );
      }
    
      // 9. Body inspection
      if (credential.bodyInspection !== 'off' && params.body && params.body.length > 0) {
        const inspection = this.bodyInspector.inspect(params.body);
        if (inspection.suspicious) {
          const matchSummary = inspection.matches.join('; ');
    
          if (credential.bodyInspection === 'block') {
            this.metrics?.recordBlocked(
              params.service,
              'body_inspection',
              this.authenticatedAgent?.name,
            );
            this.webhooks?.emit('body_inspection', {
              service: params.service,
              credential: credential.name,
              matches: inspection.matches,
              agent: this.authenticatedAgent?.name,
              method,
              path,
            });
            this.ledger.logBlocked({
              service: params.service,
              targetDomain,
              method,
              path,
              reason: `Body inspection: potential credential exfiltration — ${matchSummary}`,
              agentName: this.authenticatedAgent?.name,
              agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
              channel: 'mcp',
            });
            throw new Error(
              `Request body contains credential-like patterns: ${matchSummary}. ` +
                "If this is intentional, set body inspection to 'warn' or 'off' for this credential.",
            );
          }
    
          // Warn mode
          this.logger.warn(
            { credential: credential.name, matches: inspection.matches, requestId },
            'Body inspection: credential-like patterns detected (warn mode)',
          );
        }
      }
    
      // 10. Make the outbound request with credential injection
      const result = await this.makeOutboundRequest(credential, {
        targetDomain,
        path,
        method,
        headers: params.headers,
        body: params.body,
      });
    
      // 11. Audit log
      this.ledger.logAllowed({
        credentialId: credential.id,
        credentialName: credential.name,
        service: params.service,
        targetDomain,
        method,
        path,
        responseCode: result.status,
        agentName: this.authenticatedAgent?.name,
        agentTokenPrefix: this.authenticatedAgent?.tokenPrefix,
        channel: 'mcp',
      });
    
      this.logger.info(
        { service: params.service, method, path, status: result.status, requestId },
        'MCP request proxied',
      );
    
      this.metrics?.recordRequest(
        params.service,
        method,
        result.status,
        this.authenticatedAgent?.name,
      );
    
      return result;
    }

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/getaegis/aegis'

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