Server event examples
Code to send an event for each call to your service, from curl, Python, Node or an MCP server.
Each sends one call’s event with the token from the FIVEBAR_TOKEN environment variable, and gives
up after 2 seconds. Send it once your service has answered, never waiting for it. Server
events says how to make the token, what each field holds and what each answer means.
curl
curl https://fiveb.ar/api/events \
-H "Authorization: Bearer $FIVEBAR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"site": "example.com", "name": "/v1/postcodes/:code", "ip": "203.0.113.7"}' \
--max-time 2 -w '%{http_code}\n'Python
With the standard library alone, in a thread of its own:
import json, os, threading, urllib.request
def send_event(name, **caller):
req = urllib.request.Request(
'https://fiveb.ar/api/events',
data=json.dumps({'site': 'example.com', 'name': name, **caller}).encode(),
headers={
'Authorization': 'Bearer ' + os.environ['FIVEBAR_TOKEN'],
'Content-Type': 'application/json',
},
)
def send():
try:
urllib.request.urlopen(req, timeout=2).close()
except OSError:
pass
threading.Thread(target=send).start()
send_event('/v1/postcodes/:code', ip='203.0.113.7')Node
For Node 18 or later. sendEvent() doesn’t wait for fivebar’s answer. With Express,
req.route.path is the route as written, req.ip is the caller’s address only where Express’s
trust proxy setting names the proxies in front of your service, as a proxy’s own address is refused,
bad ip, and lookUp() stands for your own code:
export function sendEvent(name, caller = {}) {
fetch('https://fiveb.ar/api/events', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.FIVEBAR_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({ site: 'example.com', name, ...caller }),
signal: AbortSignal.timeout(2000),
}).catch(() => {});
}
app.get('/v1/postcodes/:code', async (req, res) => {
res.json(await lookUp(req.params.code));
sendEvent(req.route.path, { ip: req.ip, user_agent: req.get('User-Agent') });
});An MCP server
With version 1 of the MCP TypeScript
SDK, @modelcontextprotocol/sdk, and sendEvent() above, each tools/call is
counted once it has its answer: the tool as its name, the session as its caller and the app’s
clientInfo.name as its source, read as What is counted says.
server is the SDK’s Server, and callTool() your own:
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
const answer = await callTool(request.params.name, request.params.arguments);
sendEvent(request.params.name, {
id: extra.sessionId,
client: server.getClientVersion()?.name,
});
return answer;
});A session has an id only on a server that keeps sessions, over Streamable HTTP with a
sessionIdGenerator. A stateless server, or one over stdio, has none, and an event with neither
id nor ip is refused: send another id there, such as the account calling, as
fivebar’s own MCP server does.