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

Meet Our Newest AWS Heroes – May 2026

1 Share

We’re excited to welcome four outstanding community leaders as our newest AWS Heroes. These individuals embody the spirit of collaboration and knowledge sharing that makes the AWS community thrive. From building AI-powered tools that help fellow builders navigate AWS re:Invent, to leading some of the largest AWS communities in Latin America, to sharing deep cloud architecture expertise across blogs and events. Their dedication to lifting others up through education, mentorship, and community organizing inspires builders around the world.

Damiano Giorgi – Pavia, Italy

Artificial Intelligence Hero Damiano Giorgi is a Cloud Solutions Architect focused on AI and its evolution, who transitioned from on-premises (on-prem) systems engineering to AWS and never looked back. He helps organize AWS User Group Pavia and AWS User Group Milan, and shares content on his personal blog, “Bass and Bytes.” Damiano developed the “Unofficial post:Invent Session Suggester,” powered by Amazon Bedrock and Amazon Nova, to help builders find AWS re:Invent sessions matching their interests. He speaks at conferences across Europe including AWS Summit Milan, AWS Community Day Italy, Adria, Greece, and the Netherlands.

Darryl Ruggles – Ottawa, Canada

Serverless Hero Darryl Ruggles is a Cloud Solutions Architect who spent many years as a software developer before focusing on AWS application and AI/ML architectures. He shares knowledge across serverless, containers, AI/ML, and FinOps through his blog, LinkedIn, and published projects. Darryl is an active member of many online AWS communities including “Believe In Serverless” and loves interacting with the community at events both online and in person.

Ricardo Daniel Ceci – Buenos Aires, Argentina

Artificial Intelligence Hero Ricardo Daniel Ceci leads the AWS User Group Buenos Aires, which is the largest AWS community in Argentina with nearly 2,400 members. He is also the principal organizer of the AWS Community Day Argentina and was recognized as the AWS Community Leader of the Year 2025 for LATAM. Ricardo hosts a podcast featuring conversations with cloud experts, AWS Heroes, and developer advocates across Latin America. He has over fifteen years of experience in cloud and web development, and is passionate about empowering Spanish-speaking builders and lowering the barrier to cloud and AI across LATAM.

Matias Kreder – Buenos Aires, Argentina

Artificial Intelligence Hero Matias Kreder is an AWS Certification Subject Matter Expert (SME) who contributed to multiple AI/ML certifications, including the AWS Certified AI Practitioner exam. His journey began with AWS DeepRacer where he qualified three times as a finalist, which sparked his community work organizing racing events and ML talks across the region. As an AWS User Group Leader for Buenos Aires, he organized the AWS Community Day Argentina 2025 and speaks at community events throughout LATAM.

Learn More

Visit the AWS Heroes webpage if you’d like to learn more about the AWS Heroes program, or to connect with a Hero near you.

Taylor

Read the whole story
alvinashcraft
15 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Building a Custom MCP Server with Node.js

1 Share
Building a Custom MCP Server with Node.js

Ever wished your AI assistant actually knew your stuff? Your files, your schedule, or even a custom data source? That's exactly what the Model Context Protocol (MCP) makes possible.

MCP is an open standard for connecting AI assistants like Claude to external data sources and tools. Think of it like a USB port for AI - a single, standardised connector that works with any compatible device. Build the server once, plug it into any MCP-compatible client.

In this guide, we'll build a custom MCP server from scratch using Node.js. The example is deliberately practical: a bin collection reminder system. Simple enough to grasp quickly. Complex enough to cover every core concept you'll need.

What is the Model Context Protocol?

MCP gives AI assistants a common language for talking to the outside world. Instead of every tool needing its own bespoke integration, MCP provides a shared standard.

Your MCP server exposes "tools" - functions that AI Assistants can call. The server does the work (reading files, querying a database, calling an API), then returns structured data. The AI Assistant handles the rest.

Right now, Claude Desktop, Visual Studio and VS Code (amongst others) support MCP out of the box. The ecosystem is growing fast.

The Problem We're Solving

To build a basic example (and experiment with real data in my life) - I wanted to create an MCP server that gave me the details of my Bin Collections. I wanted to be able to run a simple chat query and get a response. Ideally, this would save me time logging onto my local council's website and entering my information time and time again.

Here's the scenario. Garden waste goes out fortnightly on Fridays. Recycling is every Saturday. General refuse is also fortnightly on Fridays - but on different weeks. It's surprisingly easy to get wrong, especially when you factor in that holidays throw the schedule off.

So we'll build an MCP server that Claude can query to answer questions like "when are my bins next due out?" A simple use case that's genuinely useful and it teaches you the full pattern.

Setting Up the Project

Create a new Node.js project:

mkdir bin-collection-mcp
cd bin-collection-mcp
npm init -y

You only need one dependency - the official MCP SDK:

npm install @modelcontextprotocol/sdk

Update your package.json to use ES modules. Add "type": "module":

{
  "name": "bin-collection-mcp",
  "version": "1.0.0",
  "description": "MCP server for local bin collection day lookups",
  "type": "module",
  "main": "index.js",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0"
  }
}

The Data Structure

Before writing any server code, think about your data. We'll use a simple JSON file - bin-days.json - that stores collection dates:

{
  "collections": [
    {
      "date": "2026-05-29",
      "day": "Friday",
      "types": ["garden"],
      "notes": ""
    },
    {
      "date": "2026-05-30",
      "day": "Saturday",
      "types": ["recycling"],
      "notes": ""
    }
  ],
  "binTypes": {
    "general": {
      "colour": "black",
      "description": "General household refuse"
    },
    "garden": {
      "colour": "brown",
      "description": "Garden waste - grass, leaves, small branches"
    },
    "recycling": {
      "colour": "blue",
      "description": "Paper, card, plastics, tins, glass"
    }
  }
}

Each collection has a date, day name, an array of bin types, and optional notes. The binTypes object describes what each bin is for. Keep it readable - you'll be updating this file manually.

Building the MCP Server

Create index.js. We'll build it in steps.

Step 1 - Import Dependencies and Load Data

#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { readFileSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const BIN_DAYS_PATH = resolve(__dirname, "bin-days.json");

function loadBinDays() {
  const raw = readFileSync(BIN_DAYS_PATH, "utf-8");
  return JSON.parse(raw);
}

The shebang at the top makes the file directly executable. We're loading the JSON synchronously each time it's needed. Not the most efficient approach - but simple, and it means changes to your data file are picked up immediately.

Step 2 - Add Helper Functions

Here's the business logic before we wire up the server:

function getUpcomingCollections(data, daysAhead = 30) {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const cutoff = new Date(today);
  cutoff.setDate(cutoff.getDate() + daysAhead);

  return data.collections.filter((c) => {
    const date = new Date(c.date);
    return date >= today && date <= cutoff;
  });
}

function getNextCollection(data, binType) {
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const upcoming = data.collections
    .filter((c) => {
      const date = new Date(c.date);
      if (date < today) return false;
      if (binType) return c.types.includes(binType.toLowerCase());
      return true;
    })
    .sort((a, b) => new Date(a.date) - new Date(b.date));

  return upcoming[0] || null;
}

getUpcomingCollections returns everything within a date window. getNextCollection finds the soonest one, with an optional filter by bin type. Clean, testable functions. Keep your business logic separate from your server wiring.

Step 3 - Initialise the Server

const server = new Server(
  { name: "bin-collection", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

The capabilities object tells clients what your server can do. Here we're saying: this server exposes tools. That's all your AI assistant needs to know upfront.

Step 4 - Define Your Tools

This is where MCP gets interesting. You're essentially writing a contract - here's what I can do, here's what you can ask me:

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "get_upcoming_collections",
      description:
        "Returns all bin collections scheduled in the next N days (default 30).",
      inputSchema: {
        type: "object",
        properties: {
          days_ahead: {
            type: "number",
            description: "How many days ahead to look (default: 30)",
          },
        },
      },
    },
    {
      name: "get_next_collection",
      description:
        "Returns the next upcoming bin collection, optionally filtered by bin type.",
      inputSchema: {
        type: "object",
        properties: {
          bin_type: {
            type: "string",
            description: "Filter by bin type: 'general', 'recycling', or 'garden'",
            enum: ["general", "recycling", "garden"],
          },
        },
      },
    },
    {
      name: "get_bin_types",
      description: "Returns details about each bin type.",
      inputSchema: {
        type: "object",
        properties: {},
      },
    },
  ],
}));

Your inputSchema uses JSON Schema to define parameters. The AI assistant reads this to understand what arguments to pass. Notice the enum on bin_type - that tells the AI assistant exactly which values are valid. Good schemas mean fewer errors.

Step 5 - Handle Tool Calls

When the AI assistant actually calls one of your tools, this handler runs:

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  const data = loadBinDays();

  if (name === "get_upcoming_collections") {
    const daysAhead = args?.days_ahead ?? 30;
    const collections = getUpcomingCollections(data, daysAhead);

    if (collections.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: `No bin collections found in the next ${daysAhead} days.`,
          },
        ],
      };
    }

    const formatted = collections
      .map((c) => {
        const types = c.types.join(", ");
        const note = c.notes ? ` (${c.notes})` : "";
        return `• ${c.date} (${c.day}): ${types}${note}`;
      })
      .join("\n");

    return {
      content: [
        {
          type: "text",
          text: `Upcoming bin collections (next ${daysAhead} days):\n\n${formatted}`,
        },
      ],
    };
  }

  if (name === "get_next_collection") {
    const binType = args?.bin_type || null;
    const next = getNextCollection(data, binType);

    if (!next) {
      const label = binType ? `${binType} bin` : "any bin";
      return {
        content: [{ type: "text", text: `No upcoming collections found for ${label}.` }],
      };
    }

    const types = next.types.join(", ");
    const note = next.notes ? `\nNote: ${next.notes}` : "";
    const label = binType ? `Next ${binType} collection` : "Next collection";

    return {
      content: [
        {
          type: "text",
          text: `${label}: ${next.date} (${next.day})\nBins out: ${types}${note}`,
        },
      ],
    };
  }

  if (name === "get_bin_types") {
    const lines = Object.entries(data.binTypes)
      .map(([key, val]) => `• ${key} (${val.colour} bin): ${val.description}`)
      .join("\n");

    return {
      content: [{ type: "text", text: `Bin types:\n\n${lines}` }],
    };
  }

  throw new Error(`Unknown tool: ${name}`);
});

Each tool returns a content array with text. You can return images or embedded resources too - but text handles most cases just fine.

Step 6 - Start the Server

const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Bin collection MCP server running");

We're using stdio transport - the server talks via standard input/output. That's why logging goes to console.error. Stdout is reserved for MCP messages.

Testing It

Make the file executable, then run it:

chmod +x index.js
node index.js

You should see "Bin collection MCP server running" in the console. The server is now waiting for requests on stdin. You can also write unit tests against your helper functions directly - they're just plain JavaScript functions.

Connecting to Visual Studio Code

VS Code supports MCP servers through its settings. Open your settings.json (Cmd+Shift+P → "Open User Settings JSON") and add the following:

{
  "mcp": {
    "servers": {
      "bin-collection": {
        "type": "stdio",
        "command": "node",
        "args": ["/absolute/path/to/bin-collection-mcp/index.js"]
      }
    }
  }
}

Reload VS Code and your server should be picked up automatically. Then try asking Copilot Chat in agent mode:

  • "When are my bins next due out?"
  • "Show me all collections in the next 7 days"
  • "When is the next recycling collection?"

VS Code calls your tools automatically and gives you a natural language answer. It feels like magic the first time. ✨

The Pattern to Remember

MCP servers always follow the same structure. List your tools. Handle tool calls. Return content. That's it. Once you've got this pattern in your head, you can build servers for anything - your local filesystem, an internal API, a Raspberry Pi sensor, whatever you like.

I took this a step further and deployed this code to an Azure App Service and this made it available from anywhere. The full code for this project is on GitHub. Give it a try - and if you build something interesting with it, I'd love to hear about it.

Read the whole story
alvinashcraft
21 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Accessibility question: is nesting interactive elements bad?

1 Share

I am currently writing a gallery script for myself and ran into an interesting accessibility question. I have a list of galleries with links to each of them. I also wanted to provide a checkbox to allow users to select several galleries and merge or download them. The HTML I use is the following. An unordered list with labels and checkboxes and links inside the label.


Given the right CSS and some breathing space this works well with a mouse and keyboard. You can click next to the link to check the checkbox and on the link to navigate to the gallery. It also works using a keyboard. You can tab through the list and check/uncheck using the space bar. The following screencast shows what that looks like.

Screen recording showing the interaction with the nested link inside the label using mouse and keyboard

Now, it feels wrong though. I am mixing two interaction modes here, navigation and selection, one being link based and the other form based. I am wondering if that creates any issues for screenreader users. The other thing I am wondering about is if there is an issue with nesting all in the label as some older assistive technology didn’t like that. I can work around that using `for` and `ids`:


The question though is if that is still an accessibility issue and if it doesn’t make more sense to show the navigation as links and create a toggle to switch to the selection use case? What do you think?

You can try out the demo page for yourself here.

Read the whole story
alvinashcraft
29 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Budget Bytes is about building apps for under $25, what’s the biggest myth about doing that?

1 Share
From: Microsoft Developer
Duration: 1:16
Views: 51

Think building an app under $25 isn’t realistic? Shireesh Thota breaks down why that’s a myth and how using free tiers, serverless options, and smarter architecture choices can actually make it doable.

Budget Bytes Playlist: https://msft.it/6057vkUD1

#ai #azuresql #cloudcomputing #developers #softwaredevelopment

Read the whole story
alvinashcraft
44 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Predicting the SpaceX, OpenAI, and Anthropic IPOs — With Dick Costolo

1 Share

Dick Costolo is the ex-CEO of Twitter and managing partner at 01 Advisors. Costolo joins Big Technology Podcast to look ahead to the SpaceX, OpenAI, and Anthropic IPOs, looking at whether the offerings will be successful, who should go first, how the companies differ, and where the capital will come from. Tune in for the second half where we discuss the state of Meta, Costolo's Twitter memories, and Silicon Valley's 'Permanent Underclass.' Tune in for a fun, in-depth discussion of the most important pending business event in decades.

Learn more about your ad choices. Visit megaphone.fm/adchoices





Download audio: https://pdst.fm/e/tracking.swap.fm/track/t7yC0rGPUqahTF4et8YD/pscrb.fm/rss/p/traffic.megaphone.fm/AMPP8546634208.mp3
Read the whole story
alvinashcraft
52 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Agent 365 | Security Operations in Defender

1 Share
From: Microsoft Mechanics
Duration: 7:50
Views: 253

Surface every AI agent in your tenant and expose the ones throwing security signals — across both the IT and SOC view. Triage high-severity alerts as IT in the Microsoft 365 admin center, then pivot into the full incident graph as a SOC analyst in Microsoft Defender. Block malicious tool invocations the instant they fire and catch jailbreak attempts on Copilot Studio agents before they take hold.

Trace a compromised user back to suspicious agent activity, then trigger Microsoft Entra conditional access to revoke the session and force a password reset straight from the incident. Hunt overpermissioned agents with pre-built advanced hunting templates — including one that exposes every agent running MCP tools on the maker's standing credentials — and pull risky builds from the Agent Store using the Agent Registry.

Spencer Berg, AI & Security Product Manager, shares how to turn agent risk signals into coordinated remediation across Defender, Entra, and the Microsoft 365 admin center.

► QUICK LINKS:
00:00 - Stay in control with Agent 365
00:40 - Gain visibility with unified control plane
01:48 - Unified IT & SOC agent view
02:54 - Real-time blocking and jailbreak detection
04:08 - Auto-revoke via Entra conditional access
04:32 - Prevent future incidents
05:28 - Advanced hunting for AI agents
06:43 - Block risky agents
07:15 - Wrap up

► Link References

Check out https://aka.ms/Agent365SecOps

► Unfamiliar with Microsoft Mechanics?
As Microsoft's official video series for IT, you can watch and share valuable content and demos of current and upcoming tech from the people who build it at Microsoft.

• Subscribe to our YouTube: https://www.youtube.com/c/MicrosoftMechanicsSeries
• Talk with other IT Pros, join us on the Microsoft Tech Community: https://techcommunity.microsoft.com/t5/microsoft-mechanics-blog/bg-p/MicrosoftMechanicsBlog
• Watch or listen from anywhere, subscribe to our podcast: https://microsoftmechanics.libsyn.com/podcast

► Keep getting this insider knowledge, join us on social:
• Follow us on Twitter: https://twitter.com/MSFTMechanics
• Share knowledge on LinkedIn: https://www.linkedin.com/company/microsoft-mechanics/
• Enjoy us on Instagram: https://www.instagram.com/msftmechanics/
• Loosen up with us on TikTok: https://www.tiktok.com/@msftmechanics

#microsoftdefender #AISecurity #MicrosoftSecurity #AIAgents

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