Skip to main content
Glama

Server Details

Backend for AI build SAAS applications - auth, dynamo db, functions, file storage, etc

Ownership verified
Status
Healthy
Uptime
100.0% over the last 24 hours
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
ChatGPT
–
Claude
AALY

TDQS

A3.8/5.0

Scored across 47 tools

Disambiguation4/5

Most tools target a distinct resource+action, and descriptions carefully draw boundaries (e.g. create_field vs create_fields bulk, set_notification_channel vs set_notification_template, list_secrets vs list_variables, get_request_trace vs list_logs). A few relationships (endpoint vs function attachment, update_field/update_function/update_endpoint all-or-nothing rules) are subtle enough that an agent could occasionally pick wrong, but the docs mostly disambiguate.

Naming Consistency4/5

Strong, predictable verb_noun pattern throughout: list_*, get_*, create_*, update_*, delete_*, set_*, plus file_feature_request/file_support_ticket used consistently for the 'file a report' concept. The lone outlier is whoami (no verb_noun), and 'file' as a verb is unconventional, but overall very consistent.

Tool Count2/5

47 tools is well above the 25+ threshold and a heavy surface for an agent to navigate in one server, spanning projects, entities, fields, endpoints, functions, deployments, secrets, variables, notifications, logs, files, support and feature requests. The breadth is genuine, but many granular operations inflate the count well beyond a well-scoped set.

Completeness5/5

Near-complete lifecycle coverage across every sub-domain: CRUD for projects, entities, fields, endpoints and functions, plus deploy/list deployments, secrets, variables, notification channels/templates, tickets with comments, feature requests with voting, file upload, and logs/traces. Dead ends are handled (get via list, soft-delete semantics), leaving no obvious operational gaps.

Available Tools

47 tools
add_commentAInspect

Add a reply to the comment thread of a support ticket or feature request you can already see (get_support_ticket / list_feature_requests). Use it to answer a question from the AALY team, add detail they asked for, or report that a fix did or did not work. It only ever appends a comment; it cannot change status or any other field.

The comment is attributed to the signed-in user and labelled as coming from an agent (pass client_name, e.g. 'Claude Code', to say which). Read the thread first with get_support_ticket so you don't repeat what's already there. A closed ticket takes no more comments - if it's still a problem, file a new ticket and mention the old id. A ticket or request with status 'on_hold' is parked on purpose; its holdReason says why - you can still comment.

Inputs: text (required), record_id (required), record_type (required), client_name.

create_endpointAInspect

Write-only schema tool: creates one route DEFINITION record in the project's schema. It does NOT call any API, send any HTTP request, or read or write application data — method below configures which verb the route being defined will answer, it is not a verb this tool performs. Use list_endpoints to read routes back.

What it defines: a custom, non-CRUD REST route attached to an entity, e.g. POST /orders/summary. This record IS the route's identity — its action word, HTTP method, auth mode and execution mode. It runs no code by itself: attach one or more Functions to it via create_function(entity_id=<this endpoint's returned id>, trigger_point='endpoint') — an endpoint's own id, not the entity's, is what a Function's entity_id must reference for that trigger point. Read the aaly://platform/functions resource before your first one.

auth: 'required' (default) behaves exactly like ordinary CRUD — callers need a valid token. 'public' accepts requests with NO Authorization header at all — there is no caller identity for its Functions to act as, so they typically call back into the project's own REST API using an API key stored via set_secret rather than an inherited token. There is no per-endpoint permission scoping yet: a public route is exactly as powerful as whatever key its Functions use, so treat a stored key backing a public route as a full-privilege service account and validate its input defensively (create_field with entity_id set to this endpoint's id, location 'body'/'query', turns on real request validation instead of accepting free-form JSON).

No nested paths: the URL is always /{entity}/{action}, exactly one path segment after the entity.

Inputs: action (required), method (required), entity_id (required), auth, +4 more.

create_entityAInspect

Define a new data entity under a project. CRUD endpoints at {base}/{customer_slug}/{project_slug}/{entity_name} activate immediately. The key must be a unique 3-character UPPERCASE string (e.g. 'ORD' for orders). Pass fields to create its fields in the same call (one bulk request) instead of a create_field per field.

Inputs: key (required), name (required), label, fields, +4 more.

create_fieldAInspect

Add a new field to an entity schema. CHOOSING A TYPE — to LINK records (entity-to-entity relationship), use type 'reference' with targets; for an ARRAY of linked records (e.g. participants, tags) use 'reference' with multiple: true — do NOT store related record IDs as 'text' or as a 'list'. Use 'list' only for arrays of primitives (strings/numbers/booleans), with valueType. For enum fields provide values. Decide type, cardinality (multiple), and targets carefully: they're permanent once set (see update_field's description for what's changeable later and what isn't). Also works against the built-in users entity — its base fields (name/email/password/...) are fixed, but you can add your own business fields (e.g. 'role', 'gender', 'department') exactly like on any other entity; get its entity id from list_entities or describe_project. COMPUTED/STORED — for a field whose value is set by server-side logic rather than the client (computed=true, excluded from the create/update request schema) and/or never persisted (stored=false, e.g. a value presigned/derived fresh on every read): both default to the ordinary case (computed=false, stored=true) and are permanent once set. stored=false cannot be combined with search or unique. A stored=false field only gets a real value if something (today: a platform hook) populates it — declaring one on your own entity is schema support for a capability that isn't available to customer-defined logic yet.

Inputs: name (required), type (required), entity_id (required), max, +17 more.

create_fieldsAInspect

Add MANY fields to one entity in a single call — one bulk POST /fields instead of one create_field per field. Each item takes exactly the attributes create_field takes (name, type, label, required, unique, search, targets, values, valueType, multiple, default_value, formula, computed, stored, ...), and the same type/cardinality/immutability guidance applies — read create_field's description first. PARTIAL SUCCESS IS NORMAL: the result carries a summary ({total, succeeded, failed, notAttempted}) and one entry per field in input order, each with _ref (the field name), status (the HTTP status that field's own create returned) and body (the created field record, or the error object with code/message). Fields that failed did not affect the ones that succeeded — read each failed entry's error, fix it, and call create_fields again with ONLY the failed ones. status: null with code NOT_ATTEMPTED means the request deadline hit before that field started; resubmit it as-is. Prefer this over repeated create_field calls whenever you are defining two or more fields on the same entity.

Inputs: fields (required), entity_id (required).

create_functionAInspect

Define a Function: customer Python that runs on an entity's request lifecycle. This creates METADATA ONLY and deploys nothing — the code comes from the project's bundle, uploaded separately and deployed with deploy_functions.

Read the aaly://platform/functions resource before your first one: it has the payload contract, the repo layout handler paths point into, and runnable examples.

Four axes decide behaviour. trigger_point: before-request can rewrite the payload or reject the request outright; after-request sees the response; endpoint IS the response for a custom-endpoint route (see create_endpoint) rather than wrapping a CRUD operation at all. execution_mode: synchronous blocks the request and shares the trigger's whole-chain budget (2s before, 5s after, 25s for a synchronous endpoint, which stays under API Gateway's 29s timeout); asynchronous is fire-and-forget (5 min budget) with failures visible only in CloudWatch. methods: which HTTP verbs trigger it — irrelevant for trigger_point 'endpoint', where the method lives once on the endpoint record itself. order: Functions on the same trigger run lowest-first in ONE invocation, each receiving the previous one's output.

Metadata edits take effect within 30s with no redeploy — only changing the code bundle requires deploy_functions.

Inputs: name (required), entity_id (required), trigger_point (required), label, +9 more.

create_projectAInspect

Create a new project under the platform customer. Returns the new project record with auto-generated id (e.g. 'PRJ3'). The project's DynamoDB data table is provisioned asynchronously by the engine (~30 seconds). Use this id for create_entity calls.

Inputs: name (required), slug, description, multiTenant, +1 more.

delete_endpointA
DestructiveIdempotent
Inspect

Soft-delete a custom endpoint. It stops routing within 30s; its attached Functions are untouched (and become unreachable until reattached to a different endpoint).

Inputs: endpoint_id (required).

delete_entityA
DestructiveIdempotent
Inspect

Soft-delete an entity schema. Existing data records are NOT deleted.

Inputs: entity_id (required).

delete_fieldA
DestructiveIdempotent
Inspect

Soft-delete a field. Existing records keep the stored values, but the field is excluded from validation and responses (and no longer accepted on writes). Refused with FIELD_IN_USE (409) while another field's formula reads it: a formula cannot be edited, so delete the formula field first, or keep the source and hide it with update_field(hidden=true). The name can be created again later only with the same definition it had (type, unique, search, multiple, targets, valueType, precision, computed, stored, formula); a different one is refused with FIELD_SHAPE_CONFLICT (409) because the old values are still stored under that name — use a new name and migrate the data (migrate-field prompt).

Inputs: field_id (required).

delete_functionA
DestructiveIdempotent
Inspect

Soft-delete a Function. It stops running within 30s; the deployed code bundle is untouched.

Inputs: function_id (required).

delete_notification_channelA
DestructiveIdempotent
Inspect

Delete a notification channel. Sends on that channel then fall back to the platform default for email, and stop delivering for slack and whatsapp. The secret it named is not touched — delete that separately with delete_secret if it is no longer needed.

Inputs: channel_id (required).

delete_notification_templateA
DestructiveIdempotent
Inspect

Delete a notification template. Sends naming it fall back to the platform's shipped default if one exists for that key, and otherwise fail with TEMPLATE_NOT_FOUND rather than sending an empty message.

Inputs: template_id (required).

delete_secretA
DestructiveIdempotent
Inspect

Delete a secret. This is a genuine, immediate deletion rather than the platform's usual soft delete — a revoked credential must not outlive its revocation.

Inputs: secret_id (required).

delete_variableB
DestructiveIdempotent
Inspect

Delete a non-secret Function variable.

Inputs: variable_id (required).

deploy_functionsA
Destructive
Inspect

Deploy a project's Function code bundle. Project-level, not per-Function — one zip holds every handler for the project, so the name is plural.

Upload the zip first with upload_file, then pass the file id here. The zip's own layout is preserved verbatim, so handler dotted paths point into it directly: a handler of 'orders.before.validate' needs orders/before.py in the zip. Dependencies must be vendored into the zip (pip install -r requirements.txt -t .) — the platform does not run pip on customer input.

Returns immediately with status 'deploying'. Poll list_deployments to see it settle to 'ready' or 'failed'. Rolling back is this same call with an earlier file id.

Inputs: code_file_id (required), project_id.

describe_projectA
Read-onlyIdempotent
Inspect

Return a single builder-facing overview of a project's capabilities: its tenant/data-sharing model (and what multiTenant enforces), every entity with its fields, the entity-to-entity relationships (reference fields), and which query parameters actually filter today. Call this to understand a project at a glance before writing app code, instead of piecing it together from list_entities + list_fields. For the full machine-readable REST contract, use generate_openapi_spec.

Inputs: project_id.

file_feature_requestAInspect

Request a capability the AALY platform does not have today. Call list_feature_requests FIRST to check whether the gap has already been filed — if so, prefer vote_feature_request over creating a duplicate.

This is the intended next step whenever aaly://platform/capabilities (or any other guide) tells you something is not implemented and you had to agree a workaround with the user: file the gap here so it shows up as real demand, tagged with what you were building. use_case (WHY you need this, not just what) is the single most useful field for prioritization — fill it in even when brief.

Inputs: title (required), description (required), area, tags, +9 more.

file_support_ticketAInspect

File a bug report, question, incident, or billing/access issue against the AALY platform. Use this instead of guessing around a problem or silently working around it — especially when you (an agent) hit an actual error, not just a documented capability gap (for a missing capability, use file_feature_request instead).

If the problem happened during a specific API call, pass request_id (from the error response or a prior list_logs/get_request_trace call) — it lets a human join straight to that request's full trace instead of reproducing blind. attachment_ids accepts file records from upload_file (screenshots, HAR exports, logs).

Inputs: type (required), title (required), description (required), area, +13 more.

generate_openapi_specA
Idempotent
Inspect

Generate the OpenAPI 3.0 spec for all entities in a project and upload it to S3. Returns a presigned URL. The spec describes the project's REST API (auth + CRUD endpoints) that the generated app code will call directly — this MCP does not proxy data CRUD.

Inputs: project_id.

get_request_traceA
Read-onlyIdempotent
Inspect

Everything about ONE request in a single call: its own status/latency/payload, plus every Function invocation it triggered, in order, with each one's status, error text, and captured print() output. This is the tool for 'a request failed, was it my code' — pass the requestId you already have (from a client error, a support ticket, or list_logs) and get the whole story back at once.

request is the client's own top-level request. When a Function calls the project's API during it, those internal calls share the requestId and are listed in subRequests (oldest first, each with internal: true and parentRequestId), never as request.

Inputs: request_id (required), project_id.

get_support_ticketA
Read-onlyIdempotent
Inspect

Fetch one support ticket by id, including its full comment thread and attachments.

Inputs: ticket_id (required).

list_deploymentsA
Read-onlyIdempotent
Inspect

Deployment history for a project, newest first — status, failure message, bundle version, and who deployed it when. This is the 'did my deploy work' tool.

isLive: true marks the deployment the project is serving now — the newest one that reached 'ready'; at most one per project. A failed deployment does not disturb the previously-ready one, so the project keeps running its last good bundle and that one stays live. Rolling back is a new deployment, which becomes the live one once it is ready.

Inputs: limit, status, project_id.

list_endpointsA
Read-onlyIdempotent
Inspect

List custom, non-CRUD endpoint routes. Optionally filter by project_id or entity_id.

Inputs: limit, offset, entity_id, project_id.

list_entitiesA
Read-onlyIdempotent
Inspect

List entity schemas. Optionally filter by project_id to see only entities under a specific project.

Inputs: limit, offset, search, project_id.

list_feature_requestsA
Read-onlyIdempotent
Inspect

List feature requests, filtered by status/priority/area/project. Call this before file_feature_request to check for an existing match — vote for it instead of filing a duplicate.

Inputs: area, limit, status, blocking, +2 more.

list_fieldsA
Read-onlyIdempotent
Inspect

List field definitions for a specific entity. Returns field names, types, and validation rules (required, unique, search, min, max, enum values, reference targets).

Inputs: entity_id (required), limit, offset.

list_functionsA
Read-onlyIdempotent
Inspect

List Functions, optionally filtered by project, entity, trigger point or enabled state.

Inputs: limit, offset, enabled, entity_id, +2 more.

list_logsA
Read-onlyIdempotent
Inspect

Browse request and Function execution logs for a project — 'was it my engine or my Function code' debugging, with rich filtering.

log_type='requests' returns one row per API request (status, latency split into engine vs. Function time, redacted payload). log_type='function_logs' returns one row per Function invocation within a request's chain (status, duration, its own error text in full, and its captured print() output). The two share a requestId — use get_request_trace to fetch both sides of one request in a single call.

Filters: tenant_id, entity, http_method, and (function_logs only) function_id are exact-match and fast. At least one of those, an exact request_id, or a bounded created_after/created_before time range is required — an unfiltered, unbounded query is rejected, since requests rows never expire.

Inputs: log_type (required), limit, entity, status, +7 more.

list_notification_channelsB
Read-onlyIdempotent
Inspect

List a project's notification channels. Returns each channel's config and the NAME of the secret it uses — never a credential value, because a channel does not store one.

Inputs: limit, project_id.

list_notification_templatesA
Read-onlyIdempotent
Inspect

List a project's notification templates, including their rendered-from Mustache source. Does not include the platform's own shipped defaults, which apply whenever no template here matches.

Inputs: limit, project_id, channel_type.

list_projectsB
Read-onlyIdempotent
Inspect

List all projects under the platform customer. Returns project id, slug, name, multiTenant/publicSignup flags, provisionStatus, and _createdAt.

Inputs: limit, offset, search.

list_secretsA
Read-onlyIdempotent
Inspect

List a project's secrets. VALUES ARE NEVER RETURNED — each shows a masked preview and a fingerprint, which is enough to confirm whether a secret still matches what was set without exposing it.

Inputs: limit, project_id.

list_support_ticketsB
Read-onlyIdempotent
Inspect

List support tickets, filtered by status/priority/area/type/project. Scoped to your own customer automatically.

Inputs: area, type, limit, status, +2 more.

list_variablesA
Read-onlyIdempotent
Inspect

List a project's non-secret Function variables, including their values — they are not secrets, so there is nothing to mask. Use list_secrets for credentials.

Inputs: limit, project_id.

set_notification_channelA
Idempotent
Inspect

Configure how a project delivers notifications on one channel — the transport and sender identity, never the message text (that is set_notification_template).

To send from the project's OWN domain use provider 'smtp', not 'ses': 'ses' sends through AALY's role, which may only send as aaly.io, so any other address fails at send time. For smtp, config.username is the LOGIN name and defaults to from_address - set it explicitly for SendGrid ('apikey'), Postmark (server token), Mailgun or Amazon SES SMTP.

NO CREDENTIAL IS ACCEPTED HERE. credential_key is the NAME of a secret, so a live token never passes through this tool. To configure Slack: call set_secret to have a human enter the bot token, then name that key here.

One channel per channel_type: calling this again updates the existing one rather than failing, so it is safe to re-run.

Email is the only channel with a platform fallback — a project that configures nothing can still send email through AALY's own verified sender. Slack and WhatsApp send through accounts only you can own, so they do not deliver at all until configured here.

This sets the project DEFAULT. A tenant can override it for itself via the project's own REST API; those overrides are not reachable from here.

Inputs: provider (required), channel_type (required), config, enabled, +4 more.

set_notification_templateA
Idempotent
Inspect

Set the message a notification sends, rendered with Mustache against the data passed on each send: 'Hi {{name}}' with data {"name": "Ada"} becomes 'Hi Ada'. {{value}} is HTML-escaped; use {{{value}}} only where raw markup is intended.

Templates are per (key, channel_type), so one key can carry a full HTML email and a one-line Slack message. Calling this again updates the existing template rather than failing.

What each channel needs: email — subject and body_text (body_html optional); slack and in_app — body_text; whatsapp — provider_config with templateName, because Meta only accepts templates it has already approved for a message a business initiates, and will refuse a body we compose.

The platform ships defaults for auth.verify_email and auth.password_reset, so those work before you set anything; a template you set here overrides them.

Inputs: key (required), channel_type (required), enabled, subject, +5 more.

set_secretA
Read-onlyIdempotent
Inspect

Register a credential a project's Functions read at runtime, as req.secrets['KEY'].

NO VALUE IS ACCEPTED HERE. This returns instructions for a human to enter the value in the AALY app, along with the exact key name to use — a live credential must not pass through an agent's context, this MCP's transport, or a conversation transcript. Call this to declare which secrets a Function needs, then hand the operator that list.

A secret may hold a single string (an API key) or a whole structured token set — an OAuth access token, refresh token and expiry together, so they rotate atomically in one write rather than tearing across separate records. The web app decides which when the value is entered.

This sets the project DEFAULT; a tenant overrides its own via the project's REST API.

Inputs: key (required), project_id, description.

set_variableAInspect

Set a NON-SECRET configuration value a project's Functions read at runtime, as req.env['KEY'].

Variables are stored and returned in plain text — that is the point of them not being secrets. Anything that must not be readable (an API key, an OAuth token) belongs in set_secret instead.

This sets the project DEFAULT. A tenant can override any key for itself by calling the project's own REST API; those overrides are not reachable from here, because this MCP is scoped to the platform project.

Inputs: key (required), value (required), project_id, description.

update_endpointA
Idempotent
Inspect

Update a custom endpoint's auth mode, execution mode, enabled state, or metadata. entity_id, action and method are immutable — together they ARE the route's identity, so passing any rejects the whole call atomically, nothing applied — same all-or-nothing rule as update_field/update_function. To actually change one of those: create_endpoint with the shape you want, repoint its Functions (update_function's entity_id is also immutable, so this means create_function against the new endpoint's id and delete_function the old attachment), then delete_endpoint the old route.

Inputs: endpoint_id (required), auth, label, action, +5 more.

update_entityA
Idempotent
Inspect

Update an entity's metadata (label, description, allowed methods). Does not affect field definitions.

Inputs: entity_id (required), label, methods, description, +1 more.

update_fieldA
Idempotent
Inspect

Update a field's behavior or metadata. MUTABLE (change any time): label, description, default_value, required, hidden, min, max, pattern, values. IMMUTABLE: type, unique, search, targets, multiple, valueType, computed, stored, formula. Passing ANY of these — even mixed with mutable ones in the same call — rejects the WHOLE call atomically with NOTHING applied; update_field never silently drops or partially applies an immutable attribute, so only pass attributes you actually intend to change (don't echo back a full field record from list_fields). To actually change one: create a differently-named field with the correct shape and migrate data into it per-tenant via direct REST calls — do NOT delete_field + create_field under the same name, that leaves stale data readable under the old shape. Run the migrate-field prompt for the full step-by-step recipe, or see the aaly://platform/capabilities resource, 'Known footguns'. Note: there is no separate 'facet' attribute at all (create_field has no such param) — faceting is automatic whenever search:true is set on an eligible type, so it follows search's own immutability.

Inputs: field_id (required), max, min, label, +6 more.

update_functionA
Idempotent
Inspect

Update a Function's mutable metadata: label, description, methods, execution_mode, handler, order, enabled, error_handling, timeout_ms. Takes effect within 30s with no redeploy.

entity_id, name, trigger_point and language are immutable — passing any of them rejects the whole call, with nothing applied.

Inputs: function_id (required), name, label, order, +10 more.

update_projectA
Idempotent
Inspect

Update project metadata (name, description, multiTenant/publicSignup flags, email verification mode and email branding). logoUrl and brandColor can be removed by passing an empty string or null. Does not affect the project's data table or schema.

Inputs: name, logoUrl, brandColor, project_id, +4 more.

upload_fileAInspect

Upload a file into the platform project's own files entity. Works over any transport (local stdio or the hosted mcp.aaly.io endpoint) — no local filesystem access required. Platform-project only — for uploading into an end-customer's own project, call that project's own REST API (POST /files/presigned-url, then POST /files) directly, the same way the generated app does; this tool does not do that.

Three ways to use it, in order of preference:

  1. Pass content_base64 (the file's bytes, base64-encoded) with filename and mime_type — this tool uploads and registers it in one call. Keep it under 8MB for this mode; base64 in a single tool-call argument gets unreliable well before that.

  2. If you can perform your own HTTP request (e.g. a sandboxed curl/fetch capability) and the file is larger: call with filename, mime_type, and size only (no content_base64, no s3_key) to get back a presigned upload URL — POST the file directly to it yourself (uploadFields as form fields, the file's bytes as the LAST field, named 'file'), then call this tool again with s3_key set to the returned value (plus the same filename/mime_type/size) to register the record.

  3. If neither is possible in your environment, don't force it — tell the user to upload the file directly through the AALY platform app instead.

100MB cap either way (enforced server-side at the presign step).

Inputs: filename (required), size, s3_key, mime_type, +1 more.

vote_feature_requestAInspect

Add one vote to an existing feature request — the 'me too' signal for something already filed, instead of creating a duplicate. Call once per distinct person/session you're voting on behalf of; there is currently no per-voter dedupe, so an agent must not call this repeatedly for the same requester to inflate the count.

Inputs: request_id (required).

whoamiA
Read-onlyIdempotent
Inspect

ALWAYS CALL THIS FIRST in any new conversation. Resolves your identity from the request token (API key when hosted, or the AALY_TOKEN JWT/API key when running locally), fetches the platform user record, and lists all projects under the platform customer. Returns user, projects (id, slug, name), the key's context object, default_project_id (from context.projectId, if the key was minted with one), and a hint telling you what to do next. When default_project_id is set, project_id can be omitted on create_entity/generate_openapi_spec/describe_project/update_project. No parameters.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Remote MCP server that lets AI assistants read tracked competitive intelligence — competitor news, reviews, website changes, social posts and ads — and act on it by managing projects, competitors, battle cards, reports and canvases. Every answer carries a source and a date, and write actions only publish when explicitly shared.
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Enables brand visibility monitoring across major AI platforms like ChatGPT, Claude, Gemini, and Perplexity. It allows users to track visibility scores, analyze competitor data, and receive actionable insights to improve AI-generated brand recommendations.
      16
      9 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Browse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.
      MIT
    Try in Browser

    Glama MCP Gateway

    Add one secure layer between your agents and this server.

    Resources