Skip to main content
Glama
itunified-io

mcp-opnsense

by itunified-io

opnsense_nat_source_add

Create a source NAT rule to translate outbound traffic from a specified source network to a target IP or WAN address. Requires explicit confirmation before the rule is added.

Instructions

Add a new Source NAT (outbound) rule. After adding, call opnsense_nat_apply to activate. DESTRUCTIVE: requires explicit confirmation.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
enabledNoRule enabled (default: true)
interfaceYesInterface name (e.g. 'wan', 'lan', 'opt1')
ipprotocolNoIP version
protocolNoProtocol: any/TCP/UDP/TCP/UDP/ICMP/...
source_netNoSource network (any/CIDR/alias). Default: any
source_notNoInvert source match
source_portNoSource port/range
destination_netNoDestination network. Default: any
destination_notNoInvert destination match
destination_portNoDestination port/range
targetNoTranslation target: 'wanip' (default), specific IP, or alias
target_portNoTranslation target port
staticnatportNoUse static source port
nonatNoIf true, exclude this traffic from NAT (no-NAT rule)
logNoLog packets matching this rule
sequenceNoRule order (default: 100)
taggedNoMatch a packet tag set by another rule
descriptionNoHuman-readable description
confirmYesMust be true to confirm

Implementation Reference

  • The handler function for the 'opnsense_nat_source_add' tool. Parses input via SourceNatAddSchema, constructs a rule object, converts booleans to '1'/'0' via the flag() helper, and POSTs to /firewall/source_nat/add_rule.
    case "opnsense_nat_source_add": {
      const p = SourceNatAddSchema.parse(args);
      const rule: Record<string, unknown> = {
        enabled: flag(p.enabled),
        interface: p.interface,
        ipprotocol: p.ipprotocol,
        protocol: p.protocol ?? "",
        source_net: p.source_net,
        source_not: flag(p.source_not),
        source_port: p.source_port ?? "",
        destination_net: p.destination_net,
        destination_not: flag(p.destination_not),
        destination_port: p.destination_port ?? "",
        target: p.target ?? "",
        target_port: p.target_port ?? "",
        staticnatport: flag(p.staticnatport),
        nonat: flag(p.nonat),
        log: flag(p.log),
        sequence: String(p.sequence),
        tagged: p.tagged ?? "",
        description: p.description ?? "",
      };
      const result = await client.post("/firewall/source_nat/add_rule", { rule });
      return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
    }
  • The Zod schema (SourceNatAddSchema) that validates and coerces input parameters for opnsense_nat_source_add. Defines fields like enabled, interface, ipprotocol, protocol, source_net, source_not, source_port, destination_net, destination_not, destination_port, target, target_port, staticnatport, nonat, log, sequence, tagged, description, and a confirm flag.
    const SourceNatAddSchema = z.object({
      enabled: CoerceBoolean.optional().default(true),
      interface: z.string().min(1, "interface is required (e.g. 'wan')"),
      ipprotocol: z.enum(["inet", "inet6"]).optional().default("inet"),
      protocol: z.string().optional(), // any | TCP | UDP | TCP/UDP | ...
      source_net: z.string().optional().default("any"),
      source_not: CoerceBoolean.optional().default(false),
      source_port: z.string().optional(),
      destination_net: z.string().optional().default("any"),
      destination_not: CoerceBoolean.optional().default(false),
      destination_port: z.string().optional(),
      target: z.string().optional().default("wanip"), // wanip | <ip> | host alias
      target_port: z.string().optional(),
      staticnatport: CoerceBoolean.optional().default(false),
      nonat: CoerceBoolean.optional().default(false),
      log: CoerceBoolean.optional().default(false),
      sequence: z.coerce.number().int().min(1).max(99999).optional().default(100),
      tagged: z.string().optional(),
      description: z.string().optional(),
      confirm: ConfirmTrue("confirm must be true to add a source NAT rule"),
    });
  • The tool registration definition (name, description, inputSchema) for 'opnsense_nat_source_add', exported as part of the natToolDefinitions array.
    {
      name: "opnsense_nat_source_add",
      description:
        "Add a new Source NAT (outbound) rule. After adding, call opnsense_nat_apply to activate. DESTRUCTIVE: requires explicit confirmation.",
      inputSchema: {
        type: "object" as const,
        properties: {
          enabled: { type: "boolean", description: "Rule enabled (default: true)" },
          interface: { type: "string", description: "Interface name (e.g. 'wan', 'lan', 'opt1')" },
          ipprotocol: { type: "string", enum: ["inet", "inet6"], description: "IP version" },
          protocol: { type: "string", description: "Protocol: any/TCP/UDP/TCP/UDP/ICMP/..." },
          source_net: { type: "string", description: "Source network (any/CIDR/alias). Default: any" },
          source_not: { type: "boolean", description: "Invert source match" },
          source_port: { type: "string", description: "Source port/range" },
          destination_net: { type: "string", description: "Destination network. Default: any" },
          destination_not: { type: "boolean", description: "Invert destination match" },
          destination_port: { type: "string", description: "Destination port/range" },
          target: { type: "string", description: "Translation target: 'wanip' (default), specific IP, or alias" },
          target_port: { type: "string", description: "Translation target port" },
          staticnatport: { type: "boolean", description: "Use static source port" },
          nonat: { type: "boolean", description: "If true, exclude this traffic from NAT (no-NAT rule)" },
          log: { type: "boolean", description: "Log packets matching this rule" },
          sequence: { type: "number", description: "Rule order (default: 100)" },
          tagged: { type: "string", description: "Match a packet tag set by another rule" },
          description: { type: "string", description: "Human-readable description" },
          confirm: { type: "boolean", description: "Must be true to confirm", enum: [true] },
        },
        required: ["interface", "confirm"],
      },
    },
  • src/index.ts:70-70 (registration)
    Registration of the handler: all NAT tool definitions (including opnsense_nat_source_add) are mapped to handleNatTool in the toolHandlers map.
    for (const def of natToolDefinitions) toolHandlers.set(def.name, handleNatTool);
  • Helper function flag() converts a boolean to '1'/'0' string for the OPNsense API, used when building the rule payload.
    function flag(b: boolean | undefined): string | undefined {
      if (b === undefined) return undefined;
      return b ? "1" : "0";
    }
Behavior4/5

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

With no annotations, the description carries the burden and declares 'DESTRUCTIVE: requires explicit confirmation'. It also indicates the rule is not active until apply is called. This provides adequate transparency, though more detail on what 'destructive' entails would be beneficial.

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 consists of three concise sentences, each serving a distinct purpose: stating the action, indicating the necessary follow-up, and warning about destructiveness. No extraneous information is present.

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

Completeness5/5

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

Given the extensive schema coverage, the description completes the context by explaining the activation requirement and destructive nature. The tool is complex with 19 parameters, but the description is sufficient for an agent to select and invoke it correctly.

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 all parameters are documented in the schema. The description does not add further parameter-specific meaning, but the schema alone is sufficient for understanding parameter semantics.

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

Purpose5/5

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

Description clearly states 'Add a new Source NAT (outbound) rule', providing a specific verb and resource. It distinguishes from siblings like opnsense_nat_source_update, opnsense_nat_source_delete, etc., by specifying 'new' and 'outbound'.

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

Usage Guidelines4/5

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

Description instructs to call opnsense_nat_apply after adding, and highlights the need for explicit confirmation. It does not explicitly state when not to use it, but the context of siblings makes the intended use clear.

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/itunified-io/mcp-opnsense'

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