Connect the MCP server
By the end of this page, you will know what the SealTrust MCP server allows an assistant to do, how to connect it to your client, which identifier to pass it, and what each of its seven tools returns.
On this page
- 1. The scope, before anything else
- 2. Connect the server
- Declare the server in a client
- The two available settings
- 3. Know which identifier you have
- 4. The seven tools
- verify_product
- get_passport
- get_passport_proof
- get_product_history
- get_certificate
- resolve_gs1
- verify_credential
- 5. Reading responses and errors
- 6. The call limits
- What can stop you
The MCP server is a small program that you run on your own machine. It gives a conversational assistant the right to query the SealTrust public API, read only. MCP, for Model Context Protocol, is the standardized protocol through which an assistant calls external tools. By the end of this page, you will know how to install the server, declare it in your client, choose the identifier to pass it and call its seven tools.
The path has four steps: check that the scope matches your need, connect the server to your client, learn which identifier you have at hand, call the tools.
#1. The scope, before anything else
The server issues only GET requests, to public endpoints of
https://api.sealtrust.io. It sends no API key and accepts none. None of its
tools creates, modifies or deletes anything.
Direct consequence: the server sees exactly what an anonymous visitor sees when
opening a passport in their browser. The ESPR regulation distinguishes several
audiences: the public, consumers, value chain professionals and market
surveillance authorities. SealTrust applies that distinction with six access
levels: public, end_user, repairer, recycler, upstream and
authority. These values are SealTrust's own. The regulation, for its part,
names audiences. The MCP server reads the public level and that level only.
Fields reserved for professionals or authorities cannot be reached through this
path.
What the server announces to your client when the connection opens: its name,
sealtrust, its version, and a sentence of instructions reminding the assistant
that all data is public and that no tool modifies anything.
#2. Connect the server
You need Node.js version 18 or later. The package is called
@sealtrust-io/mcp-server and the latest published version is 0.4.0.
You can launch it directly, which serves to check that it starts.
npx @sealtrust-io/mcp-serverThe server communicates through its standard input and output. A startup line goes to the error output and indicates the version as well as the API address in use. Standard output is reserved for the dialogue with the client, so nothing else is written there.
#Declare the server in a client
An MCP client is configured with a command and its arguments. The block below is the form expected by desktop clients, to be placed in their configuration file.
{
"mcpServers": {
"sealtrust": {
"command": "npx",
"args": ["-y", "@sealtrust-io/mcp-server"]
}
}
}On the command line with Claude Code, the same declaration is written as follows.
claude mcp add sealtrust -- npx -y @sealtrust-io/mcp-serverRestart the client after modifying its configuration. The seven tools then appear in its list of available tools.
#The two available settings
Two environment variables, and only two, change the behavior of the server.
| Variable | Default value | Effect |
|---|---|---|
SEALTRUST_API_URL | https://api.sealtrust.io | The address of the API being queried. Trailing slashes are stripped. |
SEALTRUST_TIMEOUT_MS | 15000 | The maximum duration of a call, in milliseconds. A value that is not a strictly positive number is ignored, and the default value applies. |
The timeout covers the full round trip, headers and response body included. Going over it returns an explicit network error, never a silent hang.
These two variables go in your client's configuration, under the env key. The
block below is complete and can be copied as is. It carries a 30 second timeout.
{
"mcpServers": {
"sealtrust": {
"command": "npx",
"args": ["-y", "@sealtrust-io/mcp-server"],
"env": {
"SEALTRUST_TIMEOUT_MS": "30000"
}
}
}
}#3. Know which identifier you have
Six tools out of seven take a product identifier. Four forms exist, and they are not accepted everywhere.
| Form | What it looks like | Where you find it |
|---|---|---|
| Serial number | 12 characters, digits and uppercase letters, for example EXEMP1E00000 | This is the only identifier readable on a product. The printed QR carries it. Someone who has scanned or copied a label has that one. |
Identifier hash (uid_hash) | 0x followed by 64 hexadecimal characters | Returned by our own responses. This is the product's internal identifier. It comes from the NFC chip when the product carries one. SealTrust draws it at random when the product is identified by QR alone. |
| Token identifier | A string of digits | The identifier of the on-chain token, returned under the name token_id. |
| Certificate number | Starts with ST-CERT- | On the certificate of authenticity. Accepted by verify_product and get_certificate only. |
The serial number alphabet excludes the letters I, L, O and U, so that a person
copying a label does not mistake a letter for a digit. The MCP server passes the
number along exactly as it is given, without rewriting a single character. It is
the API that puts the number back in uppercase and that brings ambiguous
characters back to their canonical form: I and L are worth 1, O is worth
0.
Two tools also take a GTIN, the article code with 8, 12, 13 or 14 digits. A GTIN designates a model. It designates no particular item.
#4. The seven tools
#verify_product
Answers the question "is this product genuine". The tool chains two calls: resolving the identifier, then reading the certificate.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | yes | Serial number, identifier hash, token identifier or certificate number. |
The response carries a status field that takes five values.
| Value | What it means |
|---|---|
authentic | An active certificate of authenticity is registered. |
revoked | The certificate has been revoked. The product is to be treated as suspect. |
expired | The certificate has passed its end date. |
found_no_certificate | The product exists in the registry and no active certificate is attached to it. |
unknown | No trace of this identifier. |
Coming with them: a plain text message field, a product block carrying the
product name, the brand name, the category, the token identifier, the identifier
hash, the contract address, the mint transaction and the creation date, a
certificate block or the null value, a has_published_passport boolean, and an
anchored_on_base boolean.
anchored_on_base is true when an anchor exists, whichever one it is: the one
for the product batch, or the one for the passport content. The two are
independent. A passport can be anchored while its batch has not been, and the
other way around. To find out which of the two, and with which transaction, call
get_passport_proof.
Expect this boolean to be false most of the time. Anchoring is an operation that
SealTrust triggers by hand. An anchoring request coming from a brand account is
refused. Minting a product does not anchor it, and publishing a passport does not
anchor it either. Most products are never anchored. So an anchored_on_base set
to false says nothing against the product, and your assistant must never present
it as a suspicion.
#get_passport
Returns the published digital passport, at the public access level.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | yes | Serial number, identifier hash or token identifier. A certificate number is not accepted here. |
format | string | no | json by default, or jsonld for a representation in Schema.org and GS1 vocabulary. Any other value is refused before the network call. |
The response in the default format carries the passport version, the published
content under the data field, the SHA-256 hash of that content under
data_hash, the name of the product and of the brand, the GTIN and the product's
GS1 Digital Link.
The two fields that point to the IPFS copy always hold the null value on this
path. They are reserved for authenticated access levels. The link to the
immutable copy, when it is published, appears in the response of
get_passport_proof.
#get_passport_proof
Returns the public proofs that make it possible to verify a passport without trusting us.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | no | The item you want the proof for. |
gtin | string | no | The model you want the proof for, at reference level. |
You must supply exactly one of the two. Neither of them, or both at once, gives an immediate refusal with a message that explains the difference. The two parameters do not designate the same thing: the proof of an item dates the object, the proof of a reference dates the document.
The response contains the content hash, the link to the IPFS copy when it is
published, a seal block that says whether the version is sealed and whether its
content still matches what was sealed, the issuance state of the verifiable
credential, and the number of successful physical verifications. A missing proof
is absent from the response, with no empty field.
A reference level passport, the one obtained with gtin, legitimately carries
neither an anchor block nor a verification count. It is tied to no physical
item. Its proof is the anchoring of its own content, which dates the document.
The response then carries level: "model" and the normalized GTIN.
#get_product_history
Returns the history of a product: ownership movements and authentication scans,
gathered into a single timeline, from the most recent to the oldest. The first
element of timeline is the most recent event.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | yes | Serial number, identifier hash or token identifier. |
Each entry carries a type field that is verify for a scan or transfer for
an ownership movement, a timestamp, the token identifier and the identifier hash.
The rest depends on the type. A verify entry carries a validity indicator and
no party label. A transfer entry carries two display ready labels, for the
party giving up and the party receiving, and no validity indicator.
For an anonymous caller, and the MCP server is one, identities are masked: email addresses are anonymized and raw wallet addresses are not returned.
#get_certificate
Returns the public certificate of authenticity of a product.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | yes | Serial number, identifier hash, token identifier or certificate number. |
The response carries the certificate number, its state, its issuance date, its end date when there is one, the name of the issuer, the name of the product and that of the brand, as well as the custom fields recorded at issuance, returned as is. Everything written there is public.
#resolve_gs1
Starts from a GS1 Digital Link and returns the passport it designates.
| Parameter | Type | Required | Description |
|---|---|---|---|
gtin | string | yes | The article code of the model. |
serial | string | no | The serial number printed on the item. Omit it to target the model. |
The presence of the serial number changes what the link designates. With it, the
link /01/{gtin}/21/{serial} designates a precise item and the response carries
level: "item". Without it, the link /01/{gtin} designates the article class
and returns the reference level passport, the one shared by every item of the
model, with level: "model". It is that second level that is used by goods sold
by the meter, by the box or by the pallet. An empty string in serial is read as
an absence.
The response also carries the reconstructed link, the address the resolution redirects to, the identifier retained, and the public passport when there is one.
Without a published reference passport, /01/{gtin} answers 404 and the tool
returns found: false with the message "Unknown GS1 Digital Link". The result
resolved: true accompanied by a null passport only happens when you supply a
serial and that item has no published passport.
The serial number expected here is indeed the one printed on the product. The on-chain token identifier is not suitable in this place.
#verify_credential
Verifies the signature of the passport's verifiable credential, in SD-JWT-VC
format, against the key published by the issuing brand in the form did:web.
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | yes | Serial number, identifier hash or token identifier. |
The response carries verified, the issuer's decentralized identifier, the type
of the credential, the version of the signing key, the access level applied, an
error field holding verification_failed in case of failure, and the content
of the credential when the signature is valid.
#5. Reading responses and errors
The server separates three situations, and that separation matters for an assistant reasoning on the result.
| Situation | What the server returns | What to conclude from it |
|---|---|---|
| Product, passport or credential untraceable | A normal result carrying found: false and the API message, or status: "unknown" for verify_product | The question got an answer. Nothing broke. |
| API error response other than a 404 | A tool error whose message reads SealTrust API error (, the HTTP code, ): , then the detail returned by the API. There is no space before the colon. | The API answered and refused. The code says why. |
| API unreachable, timeout exceeded, DNS, connection refused | A tool error starting with Network error | No information about the product. Conclude nothing about its authenticity. |
A malformed argument is refused before any network call: an empty identifier, a
format that is neither json nor jsonld, or the absence of a choice between
identifier and gtin on the proof.
#6. The call limits
Public endpoints are capped per calling IP address, over a 60 second window. The path families that have a limit of their own each keep their own counter. The others fall under a general counter, shared by all routes without a dedicated limit.
| Tool | Path called | Limit |
|---|---|---|
verify_product | resolution, then certificate | 60 per minute on each of the two |
get_passport, get_passport_proof, verify_credential | passport | 60 per minute |
get_certificate | certificate | 60 per minute |
get_product_history | timeline | 30 per minute |
resolve_gs1 | GS1 resolution, then passport | general counter on the GS1 resolution, shared with the other paths without a limit of their own, then 60 per minute on the passport |
Two tools consume two calls instead of one. verify_product queries the
resolution then the certificate. resolve_gs1 reads the resolver's redirect
without following it, then requests the passport directly. Count them as two.
Going over the limit returns a 429 response, which the server surfaces as a tool
error. One case is an exception. On verify_product, only the first call
surfaces a 429. Going over the limit on the certificate read is logged to the
error output and the tool answers anyway, with the summarized certificate that
the resolution already carries.
#What can stop you
| Symptom | Cause | What to do |
|---|---|---|
| The client shows no tool | The server did not start, or the client was not restarted after its configuration was modified | Run npx @sealtrust-io/mcp-server by hand. The startup line must appear. Then restart the client. |
Network error on every tool | The API is not reachable from the machine, or SEALTRUST_API_URL points elsewhere | Check the variable, then the machine's network egress. |
| A call systematically exceeds the timeout | The 15 second timeout is too short for your link | Raise SEALTRUST_TIMEOUT_MS under the env key of your client's configuration, as in point 2, then restart the client. |
found: false on an identifier you know to be right | The form used is not accepted by this tool | Check the form in the identifier table. A certificate number only goes through on verify_product and get_certificate. |
| The tools contradict each other on an item withdrawn from the market | Each tool handles end of life in its own way | verify_product returns status: "unknown". get_passport_proof and get_certificate return found: false. get_passport returns the passport, together with a lifecycle block indicating that the item is no longer current. |
| The passport comes back without an IPFS link | The public access level does not carry it | Use get_passport_proof, which returns the link to the immutable copy when it is published. |
| A 429 error | A call limit has been reached | Space out the calls. The counter restarts after 60 seconds. |
Was this page helpful?
Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.