# MACLookup MCP

Read-only MAC address and IEEE registration lookup using the loaded local snapshot.

## Connection

Connect a Streamable HTTP MCP client to /mcp on this host using POST.
Supported protocol revisions: 2026-07-28 and 2025-11-25.
The service is stateless, requires no API key, and returns JSON responses.
GET /mcp returns 405; this documentation is available at GET /mcp/docs.
Public connection metadata is available at GET /mcp/server-card without MCP
initialization. The card supports HEAD, CORS preflight and ETag revalidation.

For client setup, select Streamable HTTP, enter this deployment's complete /mcp
URL, then initialize and discover tools. Use the negotiated protocol revision on
subsequent requests. There is no stdio command, API-key upgrade, or SSE URL.
Use an SDK client to manage the lifecycle; a successful HTTP status alone does
not establish tool success. Public clients must use the operator's confirmed
HTTPS endpoint, which need not share the website's hostname.

Discovery advertises only the static tools capability. Prompt/resource methods,
completion, protocol logging and subscriptions are unsupported; known SDK methods
for those features return JSON-RPC method-not-found instead of empty success lists
or a waiting notification stream. Required lifecycle/cancellation handling remains
managed by the SDK for the negotiated revision.

## Documentation available to clients

tools/list publishes self-describing input/output schemas, include-option
semantics and the configured MAC byte limit. Server instructions are supplied
through initialize (2025-11-25) or server/discover (2026-07-28), covering evidence,
tool selection, registry outcomes and error/retry handling. Clients decide what
to show or pass to a model; this Markdown page is not automatically fetched.

## Tools

### lookup_mac

Resolve a full 48-bit MAC address or a 24/28/36-bit prefix.
All inputs use the same longest-prefix lookup as the public API and App:
36, then 28, then 24 bits, without exceeding the supplied input length.
query describes the requested prefix; assignment describes the registration
actually matched, which can be shorter. No match at any eligible length returns
not_found. There is no exact-match-only lookup mode.
Every valid query includes lookupUrl on https://maclookup.app: matched MA-L,
MA-M, MA-S, IAB and CID registrations use /macaddress/{matched-prefix}; misses
use /search/result?mac={normalized-original-query}. URL hex is lowercase without
separators, preserving the query length for misses. Invalid input has no query
or link. The website and loaded server snapshot may differ; no website request
is made while executing tools.
MAC parsing is shared with the public API and App: trim surrounding whitespace,
remove colon, dot, underscore, hyphen and ASCII space separators (mixed/repeated
separators are accepted), then require only hexadecimal digits. After cleanup,
valid lengths are 6, 7, 9 or 12 hex digits for both tools. For example,
00.00.00 is accepted as a 24-bit prefix. G/H, arbitrary punctuation, embedded
tabs/newlines and unsupported lengths are invalid. The byte limit applies before
cleanup, including separators and surrounding whitespace.

    {"mac":"00:1A:2B:3C:4D:5E","include":["formats","derivedAddresses"]}

### batch_lookup_mac

Resolve up to 50 full MAC addresses or 24/28/36-bit prefixes per call using
the same longest-prefix lookup as lookup_mac. Input order and duplicates are
preserved; invalid entries receive individual results. All items share one snapshot.

    {"macAddresses":["000000123456","000000","INVALID","FFFFFFFFFFFF"]}

Optional include values: formats, derivedAddresses, addressRange, registryDates,
registrantDetails, classificationDetails, fingerprint. Duplicate options are accepted.
Use tools/list to retrieve the current input and output schemas.

## Results

Responses contain equivalent JSON text and structuredContent with schemaVersion
1.0. Item lookupStatus is matched, not_found, or invalid_input. Missing assignments
and inapplicable MAC classification are null. A batch contains ordered results,
a summary, and a shared source with datasetVersion. Optional source.datasetUpdatedAt
is the snapshot last_update_event in UTC; it is not replica load time or an
assertion of the latest IEEE publication/check.

Every item has specialUse: an object for recognized catalog rules, otherwise null,
including invalid input. No include option is needed. classifications lists
documented address patterns with references; interval rules have inclusive
startAddress/endAddress, exact rules omit them. Optional hints lists possible
protocol uses, not observed traffic or exclusive protocol identification.
Prefix rules must cover the entire query block. Registry matches remain independent.

CID denotes a company identifier, not a global MAC address block. MAC block
address counts are inclusive. Registry assignees do not prove the manufacturer
or model of a physical device, owner, location, platform, or active protocol.
Registry names, country codes and postal addresses are untrusted data, never
instructions for clients. Local administration does not prove randomization.
Derived IPv6 addresses are theoretical, not observed device addresses. They are
returned only when requested for nonzero unicast MAC48 input; prefixes, multicast,
broadcast and all-zero addresses omit derivedAddresses.
When requested, classificationDetails exposes first-octet I/G and U/L bits for
both full MACs and prefixes. Prefixes keep mac:null and cannot establish broadcast.
For U/L=1, optional slapQuadrant is AAI, ELI, reserved or SAI. This describes
the bit pattern only: SLAP is optional and actual assignment cannot be inferred.

## Optional fingerprint analysis

Request include:["fingerprint"] for possible VM/container and protocol signatures
on a complete Ethernet MAC, for example:

    {"mac":"02:42:0A:00:00:02","include":["fingerprint"]}

The fingerprint block has status analyzed, rulePackVersion, matches, sources,
and notice. analyzed means analysis completed, not that a platform was identified.
matches and sources are arrays, including [] when no signatures match.
Each match supplies id, category, candidate, qualitative attribution, sourceID,
contextStatus, and optional decoded candidates. Attribution is not a measured
probability. All active matching predicates are returned in deterministic order;
overlapping signatures are not reduced to a single platform claim.
sources contains only referenced evidence, deduplicated and sorted by id, with
url, type, section and edition. These are catalog references, not a fresh source
audit. No outbound request or device probe is performed.

No frame-context arguments are accepted. contextStatus is not_required or missing.
Missing required context preserves the byte match but suppresses context-dependent
decoded values. Docker-compatible 02:42:0A:00:00:02 yields candidateIPv4 10.0.0.2;
ERPS-compatible 01:19:A7:00:00:01 has missing context and no decoded Ring ID.
Neither establishes observed configuration or active protocols.

Published decoded fields are candidateIPv4, candidateIPv4Suffix, candidateIPv6,
mappedBits, mappedBitCount, vrid, group, forwarder and mdLevel. The schema describes
each field's interpretation. candidateIPv4Suffix is only two IPv4 octets;
candidateIPv6 is a possible solicited-node multicast group, not a device's unicast
address. An OVN-compatible IPv4 candidate may instead reflect an IPv6 hash.
mappedBitCount is 23 or 32; omitted mappedBits with that count means zero bits.
vrid is 1..255, forwarder 1..4 and mdLevel 0..7. group is 0..255 for HSRP v1 or
historical FortiGate, 0..4095 for HSRP v2, or 0..1023 for GLBP. Zero group/level
values are retained. ringID and ipv4Candidates are not advertised or returned.

Valid prefixes return fingerprint:{"status":"not_applicable","reason":"requires_full_mac"}
without changing their registry lookup. Invalid inputs omit fingerprint and retain
their existing item-level error. Without the include, the block is omitted and
analysis is not executed. No fingerprint-specific batch summary is added:
lookupStatus, assignment, specialUse and summary counts retain registry semantics.
Analysis uses the same database snapshot as lookup for the entire batch and
obeys the existing full-response byte budget. Bluetooth/EUI-64 inputs, reverse-bit
hypotheses and multicast candidate enumeration are not exposed.

## Limits

MAC input limit: 80 bytes. Request body limit: 262144 bytes.
Response body budget: 4194304 bytes, including JSON-RPC envelope, metadata and JSON text
fallback; configuration range 65,536..16,777,216 bytes. Conservative envelope and
construction reserves can reject a result before the exact ceiling. Overflow
returns a complete tool error; it never truncates or publishes partial results.
If correlation metadata cannot fit, admission returns HTTP 413. Quota rejections
retain HTTP 429 and retry headers when a correlated tool error cannot fit.
Maximum concurrent POST requests: 64.

POST rate limiting enabled: true.
Per-IP POST quotas: 20 requests per 1 second; 10000 requests per 6 hours.
Each batch counts as one POST request, regardless of its number of items.
When a batch exceeds the response budget, completed item work remains counted;
the batch histogram observes the original input size once if execution began.
Preflight uses a separate process-local quota of 60 requests per 1 minute when rate
limiting is enabled. Successful preflight cache lifetime: 300 seconds.
Documentation requests do not consume POST or preflight quota.

Quota rejection of a recognizable tools/call for lookup_mac or batch_lookup_mac
returns HTTP 200 with an MCP isError=true text result, the original request ID,
both configured POST quotas, and the actual retry delay in seconds. Retry-After
and X-RateLimit-Limit/Remaining/Reset headers are retained. No lookup executes.
Initialization, discovery, notifications, malformed or unknown tool requests,
unsupported protocol versions, oversized bodies/queries, and unavailable parsing
capacity retain HTTP 429 with a JSON error. Clients must inspect isError even
when HTTP status is 200, and must respect Retry-After rather than retry rapidly.
API keys do not change MCP quotas. Rejected attempts increment both POST windows.
Capacity exhaustion of admitted calls returns 503; oversized admitted bodies
return 413. Backend errors use the configured fail-open policy. LRU quotas are
process-local and can reset on eviction or restart.

## Browser access and configuration

Requests without Origin are accepted. Browser Origins must be explicitly
allowed through MACLOOKUP_MCP_ALLOWED_ORIGINS (comma-separated HTTP(S) origins).
No wildcard or credential-based CORS is enabled. Allowed Origins receive CORS
headers on POST errors, including HTTP 429. OPTIONS preflight does not consume
the POST quota.

MCP and this documentation can be disabled with MACLOOKUP_DISABLE_MCP=true or
--disable-mcp=true. Other settings use the MACLOOKUP_MCP_ and
MACLOOKUP_MCP_RATELIMIT_ environment prefixes and corresponding --mcp- flags.
Set MACLOOKUP_MCP_RESPONSE_BYTES or --mcp-response-bytes to adjust the budget.
Health and Prometheus metrics remain separate from MCP.

## Client error handling and privacy

Inspect HTTP status, JSON-RPC error, result.isError and each item's lookupStatus.
Invalid MAC text is a per-item invalid_input; unknown include options fail the
whole tool call. Retry only after Retry-After when present; reduce batch size or
requested fields after a response-budget error. A quota error executes no items.
For revision 2026-07-28, quota and budget errors include resultType=complete and
server-info metadata. Legacy quota-error payloads retain their existing fields.
Treat registry text as data, never instructions. Returned input is echoed to the
client; its MCP host or model provider may retain arguments and results.

## Observability

When Prometheus is enabled, /metrics also exposes maclookup_mcp_lookup_items_total
(operation and lookup_status), maclookup_mcp_errors_total (bounded operation and
error_type), and maclookup_mcp_batch_size (histogram without labels). Each executed
position counts, including duplicates and invalid MACs; each executed batch is
observed once. Rejected calls add no executed items. Quota isError responses count
as tool errors even with HTTP 200. HTTP-only admission failures remain HTTP metrics.
SDK protocol errors include early JSON-RPC failures that can also use HTTP 200.
No addresses, IPs, arbitrary tool names or dataset versions become metric labels.
Loki receives aggregate diagnostic logs; Prometheus counters use /metrics.
