Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
149935 stories
·
33 followers

Securing Production Debugging in Kubernetes

1 Share

During production debugging, the fastest route is often broad access such as cluster-admin (a ClusterRole that grants administrator-level access), shared bastions/jump boxes, or long-lived SSH keys. It works in the moment, but it comes with two common problems: auditing becomes difficult, and temporary exceptions have a way of becoming routine.

This post offers my recommendations for good practices applicable to existing Kubernetes environments with minimal tooling changes:

  • Least privilege with RBAC
  • Short-lived, identity-bound credentials
  • An SSH-style handshake model for cloud native debugging

A good architecture for securing production debugging workflows is to use a just-in-time secure shell gateway (often deployed as an on demand pod in the cluster). It acts as an SSH-style “front door” that makes temporary access actually temporary. You can authenticate with short-lived, identity-bound credentials, establish a session to the gateway, and the gateway uses the Kubernetes API and RBAC to control what they can do, such as pods/log, pods/exec, and pods/portforward. Sessions expire automatically, and both the gateway logs and Kubernetes audit logs capture who accessed what and when without shared bastion accounts or long-lived keys.

1) Using an access broker on top of Kubernetes RBAC

RBAC controls who can do what in Kubernetes. Many Kubernetes environments rely primarily on RBAC for authorization, although Kubernetes also supports other authorization modes such as Webhook authorization. You can enforce access directly with Kubernetes RBAC, or put an access broker in front of the cluster that still relies on Kubernetes permissions under the hood. In either model, Kubernetes RBAC remains the source of truth for what the Kubernetes API allows and at what scope.

An access broker adds controls that RBAC does not cover well. For example, it can decide whether a request is auto-approved or requires manual approval, whether a user can run a command, and which commands are allowed in a session. It can also manage group membership so that you grant permissions to groups instead of individual users. Kubernetes RBAC can allow actions such as pods/exec, but it cannot restrict which commands run inside an exec session.

With that model, Kubernetes RBAC defines the allowed actions for a user or group (for example, an on-call team in a single namespace). I recommend you only define access rules that grant rights to groups or to ServiceAccounts - never to individual users. The broker or identity provider then adds or removes users from that group as needed.

The broker can also enforce extra policy on top, like which commands are permitted in an interactive session and which requests can be auto-approved versus require manual approval. That policy can live in a JSON or XML file and be maintained through code review, so updates go through a formal pull request and are reviewed like any other production change.

Example: a namespaced on-call debug Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: oncall-debug
 namespace: <namespace>
rules:
 # Discover what’s running
 - apiGroups: [""]
 resources: ["pods", "events"]
 verbs: ["get", "list", "watch"]

 # Read logs
 - apiGroups: [""]
 resources: ["pods/log"]
 verbs: ["get"]

 # Interactive debugging actions
 - apiGroups: [""]
 resources: ["pods/exec", "pods/portforward"]
 verbs: ["create"]

 # Understand rollout/controller state
 - apiGroups: ["apps"]
 resources: ["deployments", "replicasets"]
 verbs: ["get", "list", "watch"]

 # Optional: allow kubectl debug ephemeral containers
 - apiGroups: [""]
 resources: ["pods/ephemeralcontainers"]
 verbs: ["update"]

Bind the Role to a group (rather than individual users) so membership can be managed through your identity provider:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: oncall-debug
 namespace: <namespace>
subjects:
 - kind: Group
 name: oncall-<team-name>
 apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: Role
 name: oncall-debug
 apiGroup: rbac.authorization.k8s.io

2) Short-lived, identity-bound credentials

The goal is to use short-lived, identity-bound credentials that clearly tie a session to a real person and expire quickly. These credentials can include the user’s identity and the scope of what they’re allowed to do. They’re typically signed using a private key that stays with the engineer, such as a hardware-backed key (for example, a YubiKey), so they can not be forged without access to that key.

You can implement this with Kubernetes-native authentication (for example, client certificates or an OIDC-based flow), or have the access broker from the previous section issue short-lived credentials on the user’s behalf. In many setups, Kubernetes still uses RBAC to enforce permissions based on the authenticated identity and groups/claims. If you use an access broker, it can also encode additional scope constraints in the credential and enforce them during the session, such as which cluster or namespace the session applies to and which actions (or approved commands) are allowed against pods or nodes. In either case, the credentials should be signed by a certificate authority (CA), and that CA should be rotated on a regular schedule (for example, quarterly) to limit long-term risk.

Option A: short-lived OIDC tokens

A lot of managed Kubernetes clusters already give you short-lived tokens. The main thing is to make sure your kubeconfig refreshes them automatically instead of copying a long-lived token into the file.

For example:

users:
- name: oncall
 user:
 exec:
 apiVersion: client.authentication.k8s.io/v1
 command: cred-helper
 args: ["--cluster=prod", "--ttl=30m"]

Option B: Short-lived client certificates (X.509)

If your API server (or your access broker from the previous section) is set up to trust a client CA, you can use short-lived client certificates for debugging access. The idea is:

  • The private key is created and kept under the engineer’s machine (ideally hardware-backed, like a non-exportable key in a YubiKey/PIV token)
  • A short-lived certificate is issued (often via the CertificateSigningRequest API, or your access broker from the previous section, with a TTL).
  • RBAC maps the authenticated identity to a minimal Role

This is straightforward to operationalize with the Kubernetes CertificateSigningRequest API.

Generate a key and CSR locally:

# Generate a private key.
# This could instead be generated within a hardware token;
# OpenSSL and several similar tools include support for that.
openssl genpkey -algorithm Ed25519 -out oncall.key

openssl req -new -key oncall.key -out oncall.csr \
 -subj "/CN=user/O=oncall-payments"

Create a CertificateSigningRequest with a short expiration:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
 name: oncall-<user>-20260218
spec:
 request: <base64-encoded oncall.csr>
 signerName: kubernetes.io/kube-apiserver-client
 expirationSeconds: 1800 # 30 minutes
 usages:
 - client auth

After the CSR is approved and signed, you extract the issued certificate and use it together with the private key to authenticate, for example via kubectl.

3) Use a just-in-time access gateway to run debugging commands

Once you have short-lived credentials, you can use them to open a secure shell session to a just-in-time access gateway, often exposed over SSH and created on demand. If the gateway is exposed over SSH, a common pattern is to issue the engineer a short-lived OpenSSH user certificate for the session. The gateway trusts your SSH user CA, authenticates the engineer at connection time, and then applies the approved session policy before making Kubernetes API calls on the user’s behalf. OpenSSH certificates are separate from Kubernetes X.509 client certificates, so these are usually treated as distinct layers.

The resulting session should also be scoped so it cannot be reused outside of what was approved. For example, the gateway or broker can limit it to a specific cluster and namespace, and optionally to a narrower target such as a pod or node. That way, even if someone tries to reuse the access, it will not work outside the intended scope. After the session is established, the gateway executes only the allowed actions and records what happened for auditing.

Example: Namespace-scoped role bindings

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: jit-debug
 namespace: <namespace>
 annotations:
 kubernetes.io/description: >
 Colleagues performing semi-privileged debugging, with access provided
 just in time and on demand.
rules:
 - apiGroups: [""]
 resources: ["pods", "pods/log"]
 verbs: ["get", "list", "watch"]
 - apiGroups: [""]
 resources: ["pods/exec"]
 verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: jit-debug
 namespace: <namespace>
subjects:
 - kind: Group
 name: jit:oncall:<namespace>  # mapped from the short-lived credential (cert/OIDC)
 apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: Role
 name: jit-debug
 apiGroup: rbac.authorization.k8s.io

These RBAC objects, and the rules they define, allow debugging only within the specified namespace; attempts to access other namespaces are not allowed.

Example: Cluster-scoped role binding

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
 name: jit-cluster-read
rules:
 - apiGroups: [""]
 resources: ["nodes", "namespaces"]
 verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: jit-cluster-read
subjects:
 - kind: Group
 name: jit:oncall:cluster
 apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: ClusterRole
 name: jit-cluster-read
 apiGroup: rbac.authorization.k8s.io

These RBAC rules grant cluster-wide read access (for example, to nodes and namespaces) and should be used only for workflows that truly require cluster-scoped resources.

Finer-grained restrictions like “only this pod/node” or “only these commands” are typically enforced by the access gateway/broker during the session, but Kubernetes also offers other options, such as ValidatingAdmissionPolicy for restricting writes and webhook authorization for custom authorization across verbs.

In environments with stricter access controls, you can add an extra, short-lived session mediation layer to separate session establishment from privileged actions. Both layers are ephemeral, use identity-bound expiring credentials, and produce independent audit trails. The mediation layer handles session setup/forwarding, while the execution layer performs only RBAC-authorized Kubernetes actions. This separation can reduce exposure by narrowing responsibilities, scoping credentials per step, and enforcing end-to-end session expiry.

References

Disclaimer: The views expressed in this post are solely those of the author and do not reflect the views of the author’s employer or any other organization.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

The FBI is buying Americans’ location data

1 Share
WASHINGTON, DC - MARCH 18: Federal Bureau of Investigation Director Kash Patel testifies during a Senate Intelligence Committee hearing on worldwide threats in the Hart Senate Office Building on March 18, 2026 in Washington, DC. A closed session immediately followed the hearing. (Photo by Kevin Dietsch/Getty Images) | Getty Images

FBI director Kash Patel admitted that the agency is buying location data that can be used to track people's movements. Unlike information obtained from cell phone providers, this data can be accessed without a warrant - and used to track anyone.

"We do purchase commercially available information that's consistent with the Constitution and the laws under the Electronic Communications Privacy Act, and it has led to some valuable intelligence for us," Patel said at a hearing before the Senate Intelligence Committee on Wednesday.

Patel would not commit to senators' requests that the agency stop buying Americans' location data. "Doing that wi …

Read the full story at The Verge.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Announcing PowerShell 7.6 (LTS) GA Release

1 Share

We’re excited to announce the General Availability of PowerShell 7.6, the next Long Term Support (LTS) release of PowerShell. PowerShell 7.6 is built on .NET 10 (LTS), continuing the alignment between PowerShell and the modern .NET platform.

PowerShell 7.6 includes reliability improvements across the engine, modules, and interactive shell experience. Preview releases focused on improving consistency, fixing long-standing issues, and refining behavior across platforms.

Notable areas of improvement include:

  • Module updates
  • Engine reliability fixes
  • Native command handling improvements
  • Tab completion consistency improvements
  • Dependency updates aligned with .NET 10

As an LTS release, PowerShell 7.6 becomes the recommended version for production automation environments.

Highlights

  • PowerShell 7.6 includes updates to several core modules:
    • PSReadLine
    • Microsoft.PowerShell.PSResourceGet
    • Microsoft.PowerShell.ThreadJob
  • Dozens of tab completion improvements
    • Improved path completion across providers
    • Added value completion for parameters of several cmdlets
    • Enabled completes in more contexts and scopes
    • Added completion of modules by their shortname
  • Added features to existing commands
    • Added -Delimiter parameter to Get-Clipboard
    • Added the parameter Register-ArgumentCompleter -NativeFallback to support registering a cover-all completer for native commands
    • Treat -Target as literal in New-Item
    • Added -ExcludeModule parameter to Get-Command
    • Improved Start-Process -Wait polling efficiency
  • Several engine improvements
    • Added PSForEach() and PSWhere() as aliases for the PowerShell intrinsic methods Where() and Foreach()
    • Make SystemPolicy public APIs visible but no-op on Unix platforms so that they can be included in PowerShellStandard.Library
    • Update DnsNameList for X509Certificate2 to use X509SubjectAlternativeNameExtension.EnumerateDnsNames() method
    • Fixed stderr output of console host to respect the NO_COLOR environment variable
  • The following features have been converted to mainstream features:
    • PSFeedbackProvider
    • PSNativeWindowsTildeExpansion
    • PSRedirectToVariable
    • PSSubsystemPluginModel

Breaking changes

PowerShell 7.6 includes a small number of breaking changes intended to improve long-term consistency.

  • Converted -ChildPath parameter to string[] for Join-Path cmdlet. Allows user to give an array of child paths and avoid the extra usage with -AdditionalChildPath.
  • WildcardPattern.Escape() now correctly escapes lone backticks.
  • Removed the trailing space from the GetHelpCommand trace source name.

Community contributions

PowerShell is built by a global community of users and contributors. The following individuals contributed code to the PowerShell 7.6 release:

  • @AbishekPonmudi, @ArmaanMcleod, @bdeb1337, @cmkb3, @eltociear
  • @fflaten, @fMichaleczek, @GameMicrowave, @iSazonov, @JayBazuzi
  • @jborean93, @JustinGrote, @kasperk81, @kborowinski, @kilasuit
  • @KyZy7, @MartinGC94, @MatejKafka, @mawosoft, @powercode
  • @pressRtowin, @RichardSlater, @rzippo, @sba923, @senerh
  • @Tadas, @TheSpyGod, @ThomasNieto, @VbhvGupta, @xtqqczze

We want to thank everyone who filed issues, tested previews, improved docs, and submitted fixes during the PowerShell 7.6 release cycle.

Call to action

Install PowerShell 7.6 now.

For more information, see the following articles:

Looking ahead

We continue to work on future releases of PowerShell. See Steve Lee’s recent blog post about our future plans for PowerShell 7.7 and beyond.

Preview releases will continue to provide early access to new capabilities and improvements.

PowerShell Team

The post Announcing PowerShell 7.6 (LTS) GA Release appeared first on PowerShell Team.

Read the whole story
alvinashcraft
3 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Top 5 Reasons to Attend the Microsoft 365 Community Conference

1 Share

Between the inspiring keynotes and sessions, connection opportunities, and the chance to deepen your skills there are lots of reasons to attend the Microsoft 365 Community Conference in Orlando on April 21–23, 2026. This gathering of makers and inventors will illuminate the people, stories, and breakthroughs that are propelling our ecosystem forward. To help break down everything that’s happening, we put together our top five reasons to attend.

1. 200+ sessions, workshops, and AMAs

If you’re interested in learning how Microsoft is shaping the future of work—there’s a session for you. Join Microsoft experts, MVPs, and community leaders as you find out about the latest product innovations and AI-powered tools. Discover what’s new with Microsoft 365 Copilot, Teams, SharePoint, OneDrive, Copilot Studio, and much more. Check out the full catalog.

2. Unprecedented access

Ask the questions you’ve always wanted to ask. Find solutions tailored to your needs by working with Microsoft experts. Immerse yourself in the best community in tech as you talk to and learn from the people building the apps and AI capabilities you use every day. Find the full list of speakers here.

3. A jam-packed keynote lineup

Make sure you've got a great seat to watch:

  • Building for the future: Microsoft 365, Agents and AI, what's new and what's next with Jeff Teper, Executive Vice President – Microsoft Collaborative Apps and Platforms
  • Securing AI: Building Trust in the Era of AI with Vasu Jakkal, Corporate Vice President, Microsoft Security and Rohan Kumar, Corporate Vice President, Microsoft Security

  • Future of work fireside keynote with Jaime Teevan Ph.D. | Chief Scientist and Technical Fellow, Microsoft
  • and more!

These keynotes will leave you ready to learn, grow, innovate, and get hands-on with the technology shaping the next era of work. After each keynote, you’ll also hear from some of the brightest minds in tech in our breakout sessions where they’ll share insights, best practices, and strategies that you can use in your workplace.  

4. Deep-dive workshops

Get hands on with AI-powered tech as you elevate your skills in our workshops. Go beyond product demos as you learn how the latest technology works in real-world scenarios. Work with Microsoft experts who can help you find solutions that work for your organization, your team, and you.

5. Exclusive parties and networking events

Perhaps the most important reason to attend the conference is to be a part of the Microsoft 365 community. Where else can you connect with peers and icons in the tech community all in one place? This is an opportunity to meet with hundreds of Microsoft executives, engineers, product leaders, and friends. Ask questions, share feedback, learn from each other, and help shape the roadmap of technologies you rely on.

 

No matter what reason interests you most, we hope you’ll join us in Orlando on April 21–23, 2026. Register now and use SAVE150 for $150 USD off registration.

Read the whole story
alvinashcraft
3 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Tool Annotations as Risk Vocabulary: What Hints Can and Can't Do

1 Share

MCP tool annotations were introduced nearly a year ago as a way for servers to describe the behavior of their tools — whether they’re read-only, destructive, idempotent, or reach outside their local environment. Since then, the community has filed five independent Specification Enhancement Proposals (SEPs) proposing new annotations, driven in part by a sharper collective understanding of where risk actually lives in agentic workflows. This post recaps where tool annotations are today, what they can and can’t realistically do, and offers a framework for evaluating new proposals.

What Tool Annotations Are

Tool annotations shipped in the 2025-03-26 spec revision. The current ToolAnnotations interface looks like this:

interface ToolAnnotations {
  title?: string;
  readOnlyHint?: boolean; // default: false
  destructiveHint?: boolean; // default: true
  idempotentHint?: boolean; // default: false
  openWorldHint?: boolean; // default: true
}

Every property is a hint. The spec is explicit about this: annotations are not guaranteed to faithfully describe tool behavior, and clients must treat them as untrusted unless they come from a trusted server.

These four boolean hints give clients a basic risk vocabulary:

  • readOnlyHint: Does the tool modify its environment?
  • destructiveHint: If it does modify things, is the change destructive (as opposed to additive)?
  • idempotentHint: Can you safely call it again with the same arguments?
  • openWorldHint: Does the tool interact with an open world of external entities, or is its domain closed?

The first three hints mostly answer a preflight question: should the client ask for confirmation before calling this tool? openWorldHint is different. It’s about where the tool reaches and what its output might carry back, which matters after the call as much as before. It’s also the hint most sensitive to deployment context. “External” might mean anything outside a corporate network or anything beyond the local machine, depending on where the server runs. The safest posture is to treat anything a tool considers external as a potential source of untrusted content.

The defaults are deliberately cautious: a tool with no annotations is assumed to be non-read-only, potentially destructive, non-idempotent, and open-world. The spec assumes the worst until told otherwise. Making annotations optional kept the barrier to entry low for server authors, but it also means coverage is uneven. Many servers ship without them, and clients vary in how strictly they honor the pessimistic defaults. Closing that gap is part of what the current wave of SEPs is trying to do.

How We Got Here

The original proposal discussion surfaced a question that still shapes every annotation proposal today: what value do hints provide when they can’t be trusted? MCP co-creator Justin Spahr-Summers raised it directly during review:

I think the information itself, if it could be trusted, would be very useful, but I wonder how a client makes use of this flag knowing that it’s not trustable.

Basil Hosmer pushed the point further, arguing that clients should ignore annotations from untrusted servers entirely:

“Clients should ignore annotations from untrusted servers” applies to all annotations, even title — but especially the ones that describe operational properties.

The spec landed on a compromise: call everything a hint, require clients to treat hints as untrusted by default, and leave it to each client to decide how much weight to give them based on what it knows about the server.

The interface has stayed small since then, and that’s been intentional. title went in because it’s just a display name with no trust implications. taskHint was proposed as an annotation but landed as Tool.execution instead, on the grounds that execution metadata isn’t really a behavioral hint. Earlier takes on stateless, streaming, and async annotations and security annotations are worth knowing about too, since the same concerns show up again in the SEPs open today.

What’s Open Now

Five SEPs currently propose new annotations or closely related capabilities:

SEP Proposal Status
#1913 Trust and Sensitivity Annotations Draft
#1984 Comprehensive Tool Annotations for Governance/UX Draft
#1561 unsafeOutputHint Proposal
#1560 secretHint Proposal
#1487 trustedHint Proposal

The trust and sensitivity work is co-authored by GitHub and OpenAI based on gaps they hit running MCP in production. A Tool Annotations Interest Group is forming to work through these alongside related proposals like tool resolution and preflight checks. Reviewing each one in isolation makes it easy to miss how a given annotation interacts with others, and it’s those interactions that determine how risky a tool actually is in a given session.

The Lethal Trifecta: Why Combinations Matter

Simon Willison’s lethal trifecta names three capabilities that, when combined, create the conditions for data theft: access to private data, exposure to untrusted content, and the ability to externally communicate. The attack is simple: LLMs follow instructions in content, and they can’t reliably tell a user’s instructions apart from ones an attacker embedded in a web page, email, or calendar event. If the agent has all three capabilities, an attacker who controls one piece of untrusted content can trick the model into reading private data and sending it out.

Researchers have demonstrated this using a malicious Google Calendar event description, an MCP calendar server, and a local code execution tool. The code execution tool is the linchpin in that chain — any agent with unrestrained shell access sits one injected instruction away from exfiltration, and that’s true whether the tool arrived via MCP or was built into the host. What MCP adds is the ease of assembling the chain: users routinely combine tools from several servers in one session, so the risk profile is a property of the session, not of any single server.

One commenter on Willison’s newsletter connected this directly to tool annotations:

If the current state is tainted, block (or require explicit human approval for) any action with exfiltration potential… This also makes MCP’s mix-and-match story extra risky unless tools carry metadata like: reads_private_data / sees_untrusted_content / can_exfiltrate — and the runtime enforces ’never allow all three in a single tainted execution path.'

Several of the open SEPs are trying to define that kind of metadata so a client can spot when a session has all three legs of the trifecta available.

What Annotations Can Do

Drive confirmation prompts. A tool marked readOnlyHint: true from a trusted server might be auto-approved, while destructiveHint: true gets a confirmation step. A user asks their agent to clean up old files, the agent reaches for delete_file, and the client shows a dialog listing what’s about to be deleted before anything happens. This is the most common use of annotations today.

Enable graduated trust. An enterprise running its own internal MCP servers behind auth has a very different trust relationship than someone installing a random server off the internet. Annotations from the first can drive policy; from the second they’re informational at best. In practice most clients still treat installation itself as the trust signal and don’t distinguish further, so this is more of a design opportunity than a widely shipped feature.

Improve UX. title is just a display name. Annotations that help users understand what tools do without running them are useful regardless of trust. This is largely unexploited today: no MCP client lets users filter tools by annotation values, and none surface annotations as context in approval prompts. GitHub’s read-only mode is the closest production analog, enabled by about 17% of users.

Feed policy engines. Annotations can be one input among several into a policy engine enforcing rules like “no destructive tools without approval” or “open-world tools are blocked in sessions that have accessed private data.” The hints don’t need to be perfectly trustworthy if the engine cross-references other signals.

Adoption across all of these is uneven, partly because MCP users split into two camps. Developers building autonomous agents treat confirmations as friction and lean on sandboxing instead. Enterprise adopters want more annotations than currently exist. One camp barely notices annotations, the other wants a much richer vocabulary.

What Annotations Can’t Do

They don’t make the model resist prompt injection. Annotations are static metadata on a tool definition; nothing in them tells the model to ignore malicious instructions it reads from a calendar event. What an annotation like seesUntrustedData could do is let the client treat the session as tainted once that tool runs and tighten approvals from then on — a defense at the host layer, not inside the model.

An untrusted server can lie. A server can claim readOnlyHint: true and delete your files anyway. This is why the spec says clients must treat annotations from untrusted servers as untrusted.

They aren’t enforcement. If you need a guarantee that a tool can’t exfiltrate data, that’s a job for network controls or sandboxing, not a boolean hint. We made the same point about server instructions: don’t rely on soft signals for things that need to be hard guarantees.

A tool’s risk depends on what else is in the session. search_emails isn’t safe or dangerous on its own; it depends on what other tools the agent has. Annotations on one tool can’t tell you that.

Questions for Evaluating New Annotations

As a starting point for the Interest Group, we’re putting forward a tentative set of questions to ask of each annotation proposal. These will likely change as the group works through the open SEPs.

1. What client behavior does it enable?

Maintainer Jonathan Hefner put this directly on an early draft of what became the governance/UX annotations proposal:

It’s not clear to me exactly how a client would behave differently when presented with these annotations.

If there’s no concrete client action that changes based on the annotation, it probably doesn’t belong in the protocol. Each of the existing hints maps to at least one decision a client can make:

Hint Example client behavior
readOnlyHint: true Skip the confirmation dialog
destructiveHint: true Show a warning before executing
idempotentHint: true Safe to retry on failure
openWorldHint: true Scrutinize output for untrusted content; flag a trust-boundary cross

2. Does it need trust to be useful?

title is useful even from an untrusted server; worst case you show a bad display name. readOnlyHint from an untrusted server isn’t actionable, because the decision it informs — whether to skip a confirmation — only makes sense if you believe the hint. Proposals should say where they fall on that spectrum, since it determines which clients can actually use them.

3. Could _meta handle it instead?

Tools already have _meta, which accepts namespaced keys like com.example/my-field for exactly this kind of metadata. If an annotation only matters to one deployment style where the same organization runs both the server and the client, _meta is a reasonable home for it. It’s also a good way to prove out an idea before writing a SEP: ship a namespaced field, see how it holds up in production, and come back with a proposal backed by actual usage instead of a design doc. What _meta can’t do is drive behavior in off-the-shelf clients — those won’t read a key they’ve never heard of, so anything aimed at ecosystem-wide UX still needs a real annotation.

4. Does it help reason about combinations?

Annotations that help a client understand what happens when tools are used together are worth more than ones that only describe a tool in isolation. openWorldHint already hints at this: a client could use it to notice that a session mixes closed-world data access tools with open-world communication tools.

5. Is it a hint or a contract?

Hints inform decisions; contracts enforce them. If a proposal’s value depends on the annotation being true, it’s asking for a contract, and the right place for that is the authorization layer, the transport, or the runtime rather than ToolAnnotations. Hints work best when they’re still useful even if some servers get them wrong.

Where This Is Heading

The Tool Annotations Interest Group includes participants from Microsoft, OpenAI, AWS, Cloudflare, and Anthropic, among others. These are companies that build both MCP hosts and MCP servers at scale, so they sit on both sides of the annotation contract: they need annotations expressive enough to surface risk to their users, and they need to author annotations that other clients will actually honor. Among the questions on the group’s agenda are whether annotations belong on tool responses as well as tool definitions, and whether any annotations should be evaluated at runtime rather than declared statically.

In the meantime, the existing annotations are worth using. If you’re writing a server, set readOnlyHint: true on read-only tools, destructiveHint: false on additive operations, and openWorldHint: false on closed-domain tools. If you’re writing a client, treat annotations from untrusted servers as informational and lean on them for UX, but keep your actual safety guarantees in deterministic controls. And if you’re thinking of proposing a new annotation, the questions above are a good place to start shaping it.

Get Involved

The Tool Annotations Interest Group is forming now. If you’re interested in contributing:

  • Review the open SEPs linked above and leave feedback
  • Join the conversation in #tool-annotations-ig on the MCP Contributors Discord

Acknowledgements

This post draws on discussions with the MCP community, particularly the contributors involved in the Tool Annotations Interest Group proposal, including Sam Morrow (GitHub), Robert Reichel (OpenAI), Den Delimarsky (Anthropic), Nick Cooper (OpenAI), Connor Peet (Microsoft), and Luca Chang (AWS).

Read the whole story
alvinashcraft
4 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

How many branches can your CPU predict?

1 Share

Modern processors have the ability to execute many instructions per cycle, on a single core. To be able to execute many instructions per cycle in practice, processors predict branches. I have made the point over the years that modern CPUs have an incredible ability to predict branches.

It makes benchmarking difficult because if you test on small datasets, you can get surprising results that might not work on real data.

My go-to benchmark is a function like so:

while (howmany != 0) {
    val = generate_random_value()
    if(val is odd) write to buffer
    decrement howmany
}

The processor tries to predict the branch (if clause). Because we use random values, the processor should mispredict one time out of two.

However, if we repeat multiple times the benchmark, always using the same random values, the processor learns the branches. How many can processors learn? I test using three recent processors.

  • The AMD Zen 5 processor can predict perfectly 30,000 branches.
  • The Apple M4 processor can predict perfectly 10,000 branches.
  • Intel Emerald Rapids can predict perfectly 5,000 branches.

Once more I am disappointed by Intel. AMD is doing wonderfully well on this benchmark.

My source code is available.

Read the whole story
alvinashcraft
4 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories