Skip to main content
Glama

Log a shot

log_shot

Log an espresso or alternative shot/brew attempt. Uses the active context (bean/grinder/machine/program) unless overridden via bean_id/grinder_id/machine_id/program_id — ALWAYS pass bean_id explicitly when the user names a specific coffee, so the shot cannot land on the wrong bag. Backdate with pulled_at when the shot happened earlier. When the user reports taste (bitter, sour, harsh, hollow…), include matching sensory_tags — the diagnosis engine reads tags and metrics, not free-text flavor_notes. When the user tasted the shot and reports it as GOOD/clean (no defects), pass tasted=1 with no sensory_tags — otherwise a tag-less, rating-less shot is filed taste-pending as if never tasted.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tdsNoTotal Dissolved Solids percentage (e.g. 9.1 or 1.35)
bag_idNoWhich bag of the coffee the shot came from; defaults to its current (open) bag. Bag numbers are on list_beans' bags[]
dose_gYes
ratingNo
tastedNo1 = the shot was tasted at log time. The explicit way to record a CLEAN tasting: sensory tags all describe defects, so a good shot has none — without this flag (or a rating) it would be filed taste-pending. Tags or a rating also mark a shot as tasted; 0 (default) = taste later.
time_sYes
bean_idNoOverride: log against this bean instead of the active one (null = active)
verdictNo
yield_gYes
water_idNoOptional references to waters formulation
best_brewNo1 if marked as best brew, 0 otherwise
favouriteNo1 if favourite, 0 otherwise
pulled_atNoWhen the shot was actually pulled (ISO 8601 or "YYYY-MM-DD HH:MM:SS"), for backdated entries. Defaults to now (null = now). When backdating, pass the returned shot_id to diagnose_shot explicitly — the default diagnosis target is the chronologically latest shot.
beverage_gNoYield mass excluding cup/vessel weight in grams
grinder_idNoOverride: grinder used, if not the active one (null = active)
machine_idNoOverride: machine used, if not the active one (null = active)
program_idNoOverride: machine program used, if not the active one (null = active)
temp_tasteNo
vessel_nameNoCup/vessel name
bloom_time_sNoPre-wetting or bloom duration in seconds
drink_intentNo
flavor_notesNo
flow_profileNoOpaque flow profile data (JSON/TEXT)
method_toolsNoJSON representation of method tools used (e.g., paper filters, screen)
observationsNo
sensory_tagsNo
finish_actionYes
temperature_cNoBrew temperature in Celsius
data_confidenceNomeasured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. missed the timer — "~25s")
vessel_weight_gNoCup/vessel weight in grams
machine_settingsNoOnly when this one shot was pulled with a selector somewhere other than the machine's recorded settings: {key: position}. The shot is otherwise stamped with those automatically; a lasting change goes through update_machine.
pressure_profileNoPressure profile description or values
first_drip_time_sNoTime to first drip in seconds

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
statusYes
messageYes
shot_idYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedInput schema / properties / machine_settings
      Added value: +{
      +  "description": "Only when this one shot was pulled with a selector somewhere other than the machine's recorded settings: {key: position}. The shot is otherwise stamped with those automatically; a lasting change goes through update_machine.",
      +  "maxProperties": 16,
      +  "type": "object"
      +}
  2. Changed1 schema field changed
    • addedInput schema / properties / bag_id
      Added value: +{
      +  "description": "Which bag of the coffee the shot came from; defaults to its current (open) bag. Bag numbers are on list_beans' bags[]",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
  3. Changed1 schema field changed
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "additionalProperties": true,
      +  "properties": {
      +    "message": {
      +      "type": "string"
      +    },
      +    "shot_id": {
      +      "type": "integer"
      +    },
      +    "status": {
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "status",
      +    "shot_id",
      +    "message"
      +  ],
      +  "type": "object"
      +}
  4. Changed13 schema fields changed
    • changedInput schema / properties / bean_id / description
      Previous value: -"Override: log against this bean instead of the active one"New value: +"Override: log against this bean instead of the active one (null = active)"
    • changedInput schema / properties / bean_id / type
      Previous value: -"integer"New value: +[
      +  "integer",
      +  "null"
      +]
    • addedInput schema / properties / data_confidence / description
      Added value: +"measured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. missed the timer — \"~25s\")"
    • changedInput schema / properties / data_confidence / enum
      Previous value: -[
      -  "measured",
      -  "recalled"
      -]New value: +[
      +  "measured",
      +  "recalled",
      +  "estimated"
      +]
    • changedInput schema / properties / grinder_id / description
      Previous value: -"Override: grinder used, if not the active one"New value: +"Override: grinder used, if not the active one (null = active)"
    • changedInput schema / properties / grinder_id / type
      Previous value: -"integer"New value: +[
      +  "integer",
      +  "null"
      +]
    • changedInput schema / properties / machine_id / description
      Previous value: -"Override: machine used, if not the active one"New value: +"Override: machine used, if not the active one (null = active)"
    • changedInput schema / properties / machine_id / type
      Previous value: -"integer"New value: +[
      +  "integer",
      +  "null"
      +]
    • changedInput schema / properties / program_id / description
      Previous value: -"Override: machine program used, if not the active one"New value: +"Override: machine program used, if not the active one (null = active)"
    • changedInput schema / properties / program_id / type
      Previous value: -"integer"New value: +[
      +  "integer",
      +  "null"
      +]
    • changedInput schema / properties / pulled_at / description
      Previous value: -"When the shot was actually pulled (ISO 8601 or \"YYYY-MM-DD HH:MM:SS\"), for backdated entries. Defaults to now. When backdating, pass the returned shot_id to diagnose_shot explicitly — the default diagnosis target is the chronologically latest shot."New value: +"When the shot was actually pulled (ISO 8601 or \"YYYY-MM-DD HH:MM:SS\"), for backdated entries. Defaults to now (null = now). When backdating, pass the returned shot_id to diagnose_shot explicitly — the default diagnosis target is the chronologically latest shot."
    • changedInput schema / properties / pulled_at / type
      Previous value: -"string"New value: +[
      +  "string",
      +  "null"
      +]
    • addedInput schema / properties / tasted
      Added value: +{
      +  "description": "1 = the shot was tasted at log time. The explicit way to record a CLEAN tasting: sensory tags all describe defects, so a good shot has none — without this flag (or a rating) it would be filed taste-pending. Tags or a rating also mark a shot as tasted; 0 (default) = taste later.",
      +  "enum": [
      +    0,
      +    1
      +  ],
      +  "type": "integer"
      +}
  5. Changed5 schema fields changed
    • addedInput schema / properties / bean_id
      Added value: +{
      +  "description": "Override: log against this bean instead of the active one",
      +  "type": "integer"
      +}
    • addedInput schema / properties / grinder_id
      Added value: +{
      +  "description": "Override: grinder used, if not the active one",
      +  "type": "integer"
      +}
    • addedInput schema / properties / machine_id
      Added value: +{
      +  "description": "Override: machine used, if not the active one",
      +  "type": "integer"
      +}
    • addedInput schema / properties / program_id
      Added value: +{
      +  "description": "Override: machine program used, if not the active one",
      +  "type": "integer"
      +}
    • addedInput schema / properties / pulled_at
      Added value: +{
      +  "description": "When the shot was actually pulled (ISO 8601 or \"YYYY-MM-DD HH:MM:SS\"), for backdated entries. Defaults to now. When backdating, pass the returned shot_id to diagnose_shot explicitly — the default diagnosis target is the chronologically latest shot.",
      +  "type": "string"
      +}
  6. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare it is a non-idempotent, non-destructive write. The description adds real behavioral context beyond that: a tag-less, rating-less shot is filed 'taste-pending', the diagnosis engine reads tags/metrics not flavor_notes, and backdating changes the default diagnose_shot target. This is exactly the kind of hidden behavior an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then each sentence carries a distinct usage rule with no filler. The sentences are dense and long, but each earns its place rather than padding.

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?

For a 33-parameter mutation tool with an output schema and safety annotations, the description covers the decisive behaviors (override semantics, backdating, taste recording) completely. Return values are handled by the output schema, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is moderate (67%) over 33 params, and the description adds meaning for the highest-risk ones (bean_id override rule, pulled_at backdating consequence, sensory_tags vs flavor_notes, tasted semantics) and cross-references list_beans' bags[]. It does not cover the many numeric/mechanical params, but compensates where it matters.

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?

States a specific verb (log) and resource (shot/brew attempt), and the scope ('espresso or alternative') distinguishes it from siblings like update_shot and delete_shot. An agent can identify the operation without opening the schema.

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

Usage Guidelines5/5

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

Gives explicit when-to-use rules: ALWAYS pass bean_id when the user names a specific coffee, backdate with pulled_at, include sensory_tags when taste is reported, and pass tasted=1 for clean shots. These conditionals directly route correct invocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources