Bosphorus

← Knowledge base

Personal toolkit: your time zone and your own signing key

Set your time zone, locale and a personal HMAC key once on My variables, then ask the chat for your local time or to sign and verify text.

ToolsMy variablesSigningChecked against the product on

Animated diagram: a request carrying one person's own variable through the gateway to a tool serverMehmetengineeringAyşeengineeringZeynepoperationsaimochat + agentsGateway/api/mcp/githubkeyteamgrantvarsno per-person valueread for this request onlyMCP servergithubGitHub APIsees one identityVAULTOpenBao or sealed · per person, serverno values storedAUDIT LOG
  1. Step 01

    Before: one key for everyone

    • The gateway added the single credential an administrator stored on the server to every call.
    • Ayşe, Mehmet and Zeynep all arrived at the far end as the same identity.
    • Rate limits, permissions and audit trails over there could not tell your people apart.
  2. Step 02

    An administrator declares what the server accepts

    • On the console's /mcp page, Variables tab: a name, whether it is secret, whether it is required, and how it travels.
    • Names only. An administrator never types anyone's value here.
    • A name that was not declared is never stored and never sent. The fields follow the environment-variable shape of the MCP Registry's server.json.
    On the wireGITHUB_API_KEY secret · required header Authorization: Bearer ${value}
  3. Step 03

    Ayşe asks. The gateway stops.

    • Key, team scope and her grant all pass. Then the required variable turns out to be missing.
    • No request leaves for the tool server. Nothing reaches GitHub.
    • The tool reply links to her personal page, and a client that supports MCP link prompts shows it as a prompt. The value is never asked for in chat: the MCP specification forbids collecting secrets that way.
    On the wireisError: true "This tool needs your own GITHUB_API_KEY … Set it once at /vault?server=github"
  4. Step 04

    Ayşe sets it once, on her own page

    • My variables (/vault), behind the same sign-in as the console. She sees only her own rows.
    • Where the installation runs OpenBao, it goes into her own folder, kv/users/<her email>/mcp/github, which she can open there herself. Otherwise it is stored as ciphertext bound to (person, server, name), so a row cannot be moved to another person.
    • Never shown here again. The page shows a short fingerprint instead; administrators and the model never see the value. Only Ayşe can read it back, and only in her own OpenBao folder.
    On the wirekv/users/ayse.demir@corp.example/mcp/github GITHUB_API_KEY = ••••••••
  5. Step 05

    Now the call is hers

    • The gateway reads her value for this one request only, from her OpenBao folder or by decrypting her sealed row, and renders the administrator's template into a header.
    • Never cached and never placed in the model's context.
    • The audit row records the variable's name. If the tool echoes the value, the stored copy of the response is masked.
    On the wirerequestContext.userVars = { injected: ["GITHUB_API_KEY"] }
  6. Step 06

    Everyone on their own key

    • Ayşe and Mehmet reach GitHub as themselves. Zeynep has set nothing, so she gets the link to her page instead.
    • An administrator sees how many people hold a value. Never which value.
    • Offboarding is one delete on the Variables tab. An administrator can delete a person's values but never read them.
    On the wiregithub · 2 of 3 people have set GITHUB_API_KEY
  7. Step 07

    Three ways in, one vault

    • Header template, live: for third-party servers you do not own. Nothing changes on their side.
    • Sealed bundle, live: for servers you run yourself. One encrypted header, bound to that server's name and valid for 60 seconds.
    • Environment bridge, live: for tools that only read environment variables. One child process per person, its environment filled from the vault.
  8. Step 08

    What it protects, and what it does not

    • What the vault protects today, and where the remaining trust sits.

    Never sees a value

    The chat, the model's context, the audit log, the log stream, metrics, a console administrator, another person, and any tool server the variable was not declared for.

    Could still read a value

    The platform itself: it reads values unattended, so a scheduled 03:00 agent run still works. With OpenBao it signs in as its own service account, holds no stored credential and may read only people's mcp/ folders, while OpenBao's own administrators can reach every folder. Without it, whoever holds both the vault key and the database. Backup archives carry the vault, so guard them like it.

Header delivery, sealed bundles and the environment bridge are live, and each person's values can live in their own OpenBao folder.

Personal toolkit is a small tool server that works with settings only you hold: your time zone, the locale you like dates written in, and a signing key of your own. You set them once on the console’s My variables page. From then on you can ask the chat workspace things like “what time is it for me?” or “sign this text with my key”, and the answer uses your settings, not anybody else’s.

This guide is for everyone, not only administrators. It was checked end to end on the running product on 27 September 2026. A person set all three values, asked the chat for the time and for a signature over hello, and got their own zone and their own signature. The audit trail recorded the three variable names and none of the values.

What you need

How it works, in one paragraph

Your values are stored encrypted and are sent only on your calls to this one tool server. The server starts a separate process for you, with your values and nobody else’s, and stops it after ten minutes without calls. The model sees the tool’s answers (the time, a signature), never your signing key. Administrators can see how many people have set a variable, but never a value.

Step 1: open My variables

Sign in to the console and open My variables (/vault). Find the Personal toolkit section. It lists three variables, all optional:

Variable What it is Example Shown back to you?
MY_TIMEZONE Your time zone, as an IANA name Europe/Istanbul, Europe/Berlin, America/New_York Yes
MY_LOCALE How dates are written tr-TR, en-GB, de-DE Yes
MY_SIGNING_KEY Your personal key for signing text a long random string (see below) Never

Type a value, press Save, and the row switches to set with a short fingerprint. To change a value later, type the new one and press Replace. To delete it, press Remove.

Never paste a key into a chat instead. Anything typed into a chat goes to the model and into the audit trail. Values saved on My variables do neither.

Step 2: set your time zone and locale

  1. In MY_TIMEZONE, enter your zone’s IANA name, the Region/City form used by every operating system, for example Europe/Istanbul. The list of time zone names has them all. A short form like GMT+3 or TRT is not an IANA name and will not work.
  2. In MY_LOCALE, enter a language tag such as tr-TR (Turkish dates) or en-GB (British English). If you leave it empty, dates are written in en-GB.
  3. Press Save on each.

Step 3: turn the tool on in a chat and check it

Open a new chat in the workspace, enable Personal toolkit in the chat’s tools, and ask:

Which of my settings reached the personal toolkit?

The answer comes from the my_settings tool and reads like this:

Your variables on this tool server:
- MY_TIMEZONE: set to "Europe/Istanbul" — the time zone my_time answers in
- MY_LOCALE: set to "tr-TR" — how my_time writes dates
- MY_SIGNING_KEY: set (secret — value not shown) — the key sign_text and verify_signature use

A variable you have not set says not set. One you set to something unusable says so as well: for example, a zone that is not a valid IANA name is reported and replaced by UTC.

Using your time zone

You never have to tell the chat where you are: the tool reads your zone from My variables. Ask, for example:

With MY_TIMEZONE = Europe/Istanbul and MY_LOCALE = tr-TR, the second question comes back as:

1 Ekim 2026 Perşembe 12:00:00 GMT+3 (Europe/Istanbul)
1 Ekim 2026 Perşembe 05:00:00 GMT-4 (America/New_York)

The same instant with MY_LOCALE = en-GB:

Thursday, 1 October 2026 at 12:00:00 GMT+3 (Europe/Istanbul)
Thursday, 1 October 2026 at 05:00:00 GMT-4 (America/New_York)

If you have not set a zone, the tool answers in UTC and says so, for example Thursday, 1 October 2026 at 09:00:00 UTC (UTC) followed by a line pointing you to My variables.

Signing text with your own key

What an HMAC-SHA256 signature is for

An HMAC-SHA256 is a short code computed from a piece of text and a secret key. Anyone who holds the same key can recompute it and check that the text is exactly what was signed, down to the last space. It is how many webhooks and APIs prove that a message came from someone who knows the key and was not changed on the way.

Two things to keep in mind:

1. Create a key on your own computer

Make a long random key. Any of these prints 64 random hexadecimal characters.

macOS and Linux (Terminal):

openssl rand -hex 32

Windows (PowerShell, both Windows PowerShell 5.1 and PowerShell 7):

$bytes = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
-join ($bytes | ForEach-Object { $_.ToString('x2') })

Copy the output. Keep a copy wherever the other side, the system that will check your signatures, needs it, for example your password manager.

2. Save it as MY_SIGNING_KEY

On My variables, paste it into MY_SIGNING_KEY under Personal toolkit and press Save. The value is never shown again, not even to you; the fingerprint tells you that a key is set.

3. Sign “hello” in the chat

Ask the chat:

Sign the text “hello” with my key.

The sign_text tool answers with the signature and nothing else:

HMAC-SHA256 (hex): <64 hexadecimal characters>
Signed 5 bytes with your MY_SIGNING_KEY.

5 bytes is the length of hello. If the model added a space or a line break, the byte count shows it. Ask for base64 instead of hex if the receiving system expects that.

4. Check the signature on your own computer

Recompute the same signature locally with your key. If the two match, the chat signed exactly hello with exactly your key.

macOS and Linux:

KEY='paste-your-key-here'
printf '%s' 'hello' | openssl dgst -sha256 -hmac "$KEY" | awk '{print $NF}'

Windows (PowerShell):

$key  = 'paste-your-key-here'
$text = 'hello'
$hmac = New-Object System.Security.Cryptography.HMACSHA256 (,[System.Text.Encoding]::UTF8.GetBytes($key))
-join ($hmac.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($text)) | ForEach-Object { $_.ToString('x2') })

Any system with Python 3:

python3 -c 'import hmac,hashlib,sys; print(hmac.new(sys.argv[1].encode(), b"hello", hashlib.sha256).hexdigest())' 'paste-your-key-here'

For base64 on macOS or Linux, add -binary and pipe it through base64: printf '%s' 'hello' | openssl dgst -sha256 -hmac "$KEY" -binary | base64. In PowerShell, use [Convert]::ToBase64String(...) on the computed hash.

Try your command on a known answer first. Before using your real key, run the command with this example key, which is for testing only:

Key Text HMAC-SHA256 (hex)
example-key-replace-me-7f3a91c2 hello 2c7dc87df6dc4ecc10a47c8410264630283876d183f253b1fb95aa1f569d6820

The same example in base64:

LH3IffbcTswQpHyEECZGMCg4dtGD8lOx+5WqH1adaCA=

All three commands above produce exactly these values: they were run on macOS (OpenSSL 3 and the built-in LibreSSL), with Python 3, and in PowerShell 7, and each matched the toolkit’s own result.

The most common mistake is echo. echo hello sends hello followed by a line break, which is six bytes, not five, and gives a completely different signature (d85119b6… for the example key). Use printf '%s' as shown, or echo -n where your shell supports it.

5. Verify a signature in the chat

You can also ask the tool to check a signature for you:

Verify that <signature> is my signature over “hello”.

The verify_signature tool answers Valid: this is your signature over exactly that text. or NOT valid: the signature does not match that text under your key. It accepts hex or base64 and compares in constant time.

Changing or removing a value

When something is not right

Situation What to do
Personal toolkit is not on My variables It is not available to you yet. Ask your administrator to make it available to your team.
The chat does not use the tool Enable Personal toolkit in the chat’s tools, or name it: use the personal toolkit to …
my_time answers in UTC MY_TIMEZONE is not set, or is not an IANA Region/City name. Ask which of my settings reached the personal toolkit? to see which.
Dates are in English although you set tr-TR Check the spelling (tr-TR, with a hyphen). An unsupported locale is reported and replaced by en-GB.
sign_text says MY_SIGNING_KEY is not set Save a key on My variables, then ask again.
Your local signature differs from the chat’s In order: you used echo (extra line break); the text differs by a space or quote mark (check the byte count); you pasted a different key than the one saved; you compared hex with base64.
You changed a value but the old one is still used Ask again: the change applies from the next call. If it persists after a few minutes, tell your administrator.

What stays private

The walkthrough at the top of this page shows how a value travels from My variables to a tool, and the GitHub article shows the same vault used with a third-party service.