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

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, because 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. "~25s" after missing the timer)
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

NameRequiredDescriptionDefault
statusYes
messageYes
shot_idYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • changedInput schema / properties / data_confidence / description
      Previous value: -"measured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. missed the timer — \"~25s\")"New value: +"measured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. \"~25s\" after missing the timer)"
    • 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 (null = 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, because the default diagnosis target is the chronologically latest shot."
    • changedInput schema / properties / tasted / description
      Previous value: -"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."New value: +"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."
  2. 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"
      +}
  3. 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"
      +  ]
      +}
  4. 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"
      +}
  5. 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"
      +}
  6. 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"
      +}
  7. First observed

TDQS

A4.4/5.0
Behavior4/5

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

Beyond annotations (write, non-idempotent, non-destructive) it discloses two non-obvious behaviors: shots with no tags/rating are filed as taste-pending, and the diagnosis engine reads sensory_tags rather than flavor_notes. It does not mention the backdating interaction with diagnose_shot's default target (that hint lives in the schema), so a small gap remains.

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 and active-context semantics, then ordered by decision importance (bean override → backdating → tasting). Dense but nearly every clause carries an actionable rule; the closing sentence is long and could be split, but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/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, the description covers the risky/ambiguous decisions well, but the four required fields (dose_g, yield_g, time_s, finish_action) have no description in either schema or text, and the many optional fields get no framing. Adequate but not complete for this surface area.

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 67%, so the description must add meaning for high-stakes params – it does for bean_id (wrong-bag risk), pulled_at (backdating semantics) and the sensory_tags/tasted/flavor_notes relationship (tags are defect-oriented, so a clean shot has none). Many optional params (verdict, drink_intent, observations, the metric fields) are left to the schema alone.

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?

"Log an espresso or alternative shot/brew attempt" states a specific verb and resource, and the body makes the scope concrete (active-context stamping, overrides, tasting state). It is clearly distinguishable from siblings like update_shot (edits an existing shot), diagnose_shot (analysis) and log_recommendation.

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?

Explicit conditional rules are given for the three decisions that matter: pass bean_id when the user names a coffee, use pulled_at for backdating, and pass tasted=1 with no tags for a clean shot. It also names the alternative handling (rating or tags) and the consequence of doing neither.

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