diff --git a/lessons/03-setup-mcp-clients/B-tome-and-ollama.md b/lessons/03-setup-mcp-clients/B-tome-and-ollama.md index 4e376eb..612dd1a 100644 --- a/lessons/03-setup-mcp-clients/B-tome-and-ollama.md +++ b/lessons/03-setup-mcp-clients/B-tome-and-ollama.md @@ -23,7 +23,7 @@ You can also run models locally on your computer using [Ollama][ollama]. Ollama Keep in mind that the larger, "smarter" models typically require beefy GPUs to run with any sort of speed. That said, there are some models that run on even just CPUs and can still do tools calling. -> New models are coming out at break-neck pace. By the time you read this versus when I wrote it, I guarantee there will be several cycle of new models available. You will have to select one based on what's available. The good news is that the new ones are only getting more performant and "smarter". +> New models are coming out at break-neck pace. By the time you read this versus when I wrote it, I guarantee there will be several cycles of new models available. You will have to select one based on what's available. The good news is that the new ones are only getting more performant and "smarter". What's important is that you select a model that can handle [tools calling][tools]. As of writing, a few good options that run on less-capable hardware diff --git a/lessons/04-lets-build-mcp/A-my-first-mcp-server.md b/lessons/04-lets-build-mcp/A-my-first-mcp-server.md index ecb4788..14c262b 100644 --- a/lessons/04-lets-build-mcp/A-my-first-mcp-server.md +++ b/lessons/04-lets-build-mcp/A-my-first-mcp-server.md @@ -87,11 +87,11 @@ echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "ad ## JSON RPC 2.0 -You should see the MCP server respond with an answer of 8! This feels just like writing API endpoints, but the advantage here is that we get to give these tools to LLMs and they can call into code we generate for them. Let's talk a bit about JSON RPC 2.0 which is all this is. [JSON RPC][rpc] is ancient in computing terms with the first version of the spec coming out in 2005. The revised 2.0 version came out and in 2010 and that's what this is using – we're not doing anything wild here, just relying on a very proven set of technology. +You should see the MCP server respond with an answer of 8! This feels just like writing API endpoints, but the advantage here is that we get to give these tools to LLMs and they can call into code we generate for them. Let's talk a bit about JSON RPC 2.0 which is all this is. [JSON RPC][rpc] is ancient in computing terms with the first version of the spec coming out in 2005. The revised 2.0 version came out in 2010 and that's what this is using – we're not doing anything wild here, just relying on a very proven set of technology. So what _is_ JSON RPC? You can think of it as an alternative to REST. With REST you call endpoints that are based around a thing - e.g. you call a PATCH to /users/123 to update user 123. Your URLs are based things and the semantics of manipulating those things. JSON RPC (and XML RPC before it) is based around calling remote functions - that's it. It's literally a remote procedure call. So in this we're just giving an MCP server direction on what procedures (or functions) we want them to do. That's it! -Let's see it initializes itself! +Let's see it initialize itself! ```bash echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}}' | node mcp.js | jq diff --git a/lessons/04-lets-build-mcp/B-using-our-first-mcp-server.md b/lessons/04-lets-build-mcp/B-using-our-first-mcp-server.md index 4590879..4d352c4 100644 --- a/lessons/04-lets-build-mcp/B-using-our-first-mcp-server.md +++ b/lessons/04-lets-build-mcp/B-using-our-first-mcp-server.md @@ -23,7 +23,7 @@ I'll show you how for both Claude Desktop and Tome but just Google "how do I use ## Claude Desktop -Open settings on your Claude Desktop client and go the developers tab. You should see something that will edit your config. It will then probably just point you at the file you need to edit, so open that with VS Code or whatever. Put this in there: +Open settings on your Claude Desktop client and go to the developers tab. You should see something that will edit your config. It will then probably just point you at the file you need to edit, so open that with VS Code or whatever. Put this in there: ```json { diff --git a/lessons/04-lets-build-mcp/D-resources.md b/lessons/04-lets-build-mcp/D-resources.md index e3af7d3..aedc2fd 100644 --- a/lessons/04-lets-build-mcp/D-resources.md +++ b/lessons/04-lets-build-mcp/D-resources.md @@ -95,17 +95,17 @@ const transport = new StdioServerTransport(); await server.connect(transport); ``` -- We'll reuse as this our general MCP server for the issue project so keep this one around +- We'll reuse this as our general MCP server for the issue project so keep this one around - Most of it should look familiar to you already - `database-schema` is the name of the resource -- `schema://database` is the URI. this gives it a unique identifier that can be used by programs and LLMs to refer to specific resources. +- `schema://database` is the URI. This gives it a unique identifier that can be used by programs and LLMs to refer to specific resources. - After that it's mostly just like a tool. - Resource templates (which are dynamic) are really similar. The biggest difference is their URIs have something like `schema://database/{table}` or something like that and `{table}` becomes the name of the parameter that can be passed in. Add this MCP server to Claude Desktop and restart it. -Now, click the ➕ button in the text box. You should see the ability to attach a resource. Attach database schema and then ask the LLM `explain my database schema for my issue to me in plain english` or something like that. +Now, click the ➕ button in the text box. You should see the ability to attach a resource. Attach the database schema and then ask the LLM `explain my database schema for my issue to me in plain english` or something like that. -That's a resource! This more useful for things like Google Docs where you can easily attach a doc to a request or something of that nature. But they're there and you add them to your MCP servers as you deem necessary! +That's a resource! This is more useful for things like Google Docs where you can easily attach a doc to a request or something of that nature. But they're there and you add them to your MCP servers as you deem necessary! [gh]: https://github.com/btholt/mcp-issue-tracker diff --git a/lessons/04-lets-build-mcp/E-prompts.md b/lessons/04-lets-build-mcp/E-prompts.md index a6f173b..770c7b3 100644 --- a/lessons/04-lets-build-mcp/E-prompts.md +++ b/lessons/04-lets-build-mcp/E-prompts.md @@ -14,7 +14,7 @@ keywords: - Airbnb style guide - Claude --- -This one ends working fairly similarly to a resource but the idea is that it's a template for a prompt. Imagine you have common prompt you use a lot and it just needs a little tweak here and there to fit what you're doing. Or you have a team of people that need to share templates between them and you want one place to update it and automatically push it to your colleagues. Or maybe even a company could ship some canned prompts that work well with their tools (e.g. here's a good prompt for working with Neon.com). That's what prompts are for. +This one ends up working fairly similarly to a resource but the idea is that it's a template for a prompt. Imagine you have a common prompt you use a lot and it just needs a little tweak here and there to fit what you're doing. Or you have a team of people that need to share templates between them and you want one place to update it and automatically push it to your colleagues. Or maybe even a company could ship some canned prompts that work well with their tools (e.g. here's a good prompt for working with Neon.com). That's what prompts are for. > Resources are meant more to be context given to an LLM while prompts are meant more to be commands for the LLM to do. The line is a bit blurry here so don't worry too much about it – I think there are still some iterations left before we land on the exact what MCP servers will work. @@ -28,7 +28,7 @@ Feel free to use any style guide you want, but here are a few: - [Airbnb][airbnb] - [Standard][standard] -Just copy the entire file into an style-guide.md file in your directory of MCP servers. I think idiomatic is the shortest one if you're looking to save on tokens. Airbnb is certainly the longest, being 4x longer than Standard. +Just copy the entire file into a style-guide.md file in your directory of MCP servers. I think idiomatic is the shortest one if you're looking to save on tokens. Airbnb is certainly the longest, being 4x longer than Standard. Then let's make a little MCP server for it. Make style-checker.js @@ -70,7 +70,7 @@ const transport = new StdioServerTransport(); await server.connect(transport); ``` -Add your MCP server to Claude and/or Tome, and restart Claude if necessary. Click the ➕, click code-review-server, and paste some code in the box that you want Claude to review. LLM code review! Now, we could just have ESLint do this (and 100% you should do that first) but I could see this being useful giving to an LLM up front that you want it follow certain patterns and rules or if you want LLM to give you advice on how best to fit code to a style guide. The plain English feedback is super nice. +Add your MCP server to Claude and/or Tome, and restart Claude if necessary. Click the ➕, click code-review-server, and paste some code in the box that you want Claude to review. LLM code review! Now, we could just have ESLint do this (and 100% you should do that first) but I could see this being useful giving to an LLM up front that you want it to follow certain patterns and rules or if you want LLM to give you advice on how best to fit code to a style guide. The plain English feedback is super nice. That's it for prompts! diff --git a/lessons/04-lets-build-mcp/F-future-features-of-mcp.md b/lessons/04-lets-build-mcp/F-future-features-of-mcp.md index 47255e7..67e6988 100644 --- a/lessons/04-lets-build-mcp/F-future-features-of-mcp.md +++ b/lessons/04-lets-build-mcp/F-future-features-of-mcp.md @@ -45,7 +45,7 @@ A critical part is that there is still human in the loop here because we don't w Elicitation is a just a fancy word that your MCP server can ask follow up questions. -Think of an a tool that the MCP server could call to ask you to get your full address so it could fill out a form for you or one where it could ask for your specific GitHub username before it generates a report on GitHub usage. There's all sorts of reasons that a tool could need more information from the user. As of now we just have to hope that the LLM is smart enough to correlate this data for us, but this way we can just make it deterministic that correct information gets gathered as specified by the tool. +Think of it like a tool that the MCP server could call to ask you to get your full address so it could fill out a form for you or one where it could ask for your specific GitHub username before it generates a report on GitHub usage. There's all sorts of reasons that a tool could need more information from the user. As of now we just have to hope that the LLM is smart enough to correlate this data for us, but this way we can just make it deterministic that correct information gets gathered as specified by the tool. [clients]: https://modelcontextprotocol.io/clients [roots]: https://modelcontextprotocol.io/specification/2025-06-18/client/roots diff --git a/lessons/05-our-project/A-mcp-server-design.md b/lessons/05-our-project/A-mcp-server-design.md index e1bbde6..b249a34 100644 --- a/lessons/05-our-project/A-mcp-server-design.md +++ b/lessons/05-our-project/A-mcp-server-design.md @@ -43,7 +43,7 @@ npm run dev # run dev script in root directory to start both frontend and backen 1. In the mcp directory run `npm init -y` 1. Then run `npm i @modelcontextprotocol/sdk@1.16.0 zod@3.25.76` 1. Add `"type": "module"` to the package.json -1. Finally, create a file called called main.js and put this in there. +1. Finally, create a file called main.js and put this in there. ```javascript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; @@ -114,7 +114,7 @@ Ideally, we can connect our app to Claude Desktop via MCP server so that we can So what all do we need to worry about? - Auth. Claude needs to be able to act on behalf of us. -- Order of operations. We need an issue to an exist before we can update it. +- Order of operations. We need an issue to exist before we can update it. - Correct tags/people/etc. to assign to issues. We don't want "bug", "bugs", "issues", "prod-issue", and a trillion variations. We want one "bug" tag. As you can see, there's a lot to juggle here, and it's trusting an LLM a lot to just say "here Claude, use the API directly". Inevitably it's going to mess up a lot. Instead of just wrapping our API directly, we're going to make an MCP server that covers entire "jobs to do" instead of API steps. So we're going to make a tool that "creates a ticket, assigns a user, and gives a correct label to it" instead of just hoping that Claude can get the sequence of API calls right. diff --git a/lessons/05-our-project/B-api-based-tools.md b/lessons/05-our-project/B-api-based-tools.md index 3760e0a..a7a0865 100644 --- a/lessons/05-our-project/B-api-based-tools.md +++ b/lessons/05-our-project/B-api-based-tools.md @@ -172,7 +172,7 @@ Create a new issue in my issue tracker that says "Add Microsoft login to my app" Now, if you're using Claude Desktop, this will probably work. If you're using Qwen3:0.6B, well, flip a coin. I've had a hard time to get the smallest Qwen 3 model to do anything more than one step. -Once you feel okay with that, go head and change the import in main.js to import from the complete file +Once you feel okay with that, go ahead and change the import in main.js to import from the complete file ```javascript import apiBasedTools from "./api-based-tools-complete.js"; // add complete at the end diff --git a/lessons/05-our-project/c-jobs-based-tools.md b/lessons/05-our-project/c-jobs-based-tools.md index 540f1f3..3cea7ea 100644 --- a/lessons/05-our-project/c-jobs-based-tools.md +++ b/lessons/05-our-project/c-jobs-based-tools.md @@ -32,7 +32,7 @@ This is where just mapping your API server to an MCP server runs into trouble. I'm going to call this "jobs oriented" MCP server as opposed to "API oriented". I made up these terms. But it suits what we're trying to get done today. -Instead of having our infinitely flexible API server and hoping the LLM chooses right, let's say we know we really only want our MCP server to do three thinks +Instead of having our infinitely flexible API server and hoping the LLM chooses right, let's say we know we really only want our MCP server to do three things: - Create new bugs and mark them as high priority - Create new feature request and mark them as low priority diff --git a/lessons/06-sses-and-streaming-html/A-server-side-events.md b/lessons/06-sses-and-streaming-html/A-server-side-events.md index b0d533d..2871103 100644 --- a/lessons/06-sses-and-streaming-html/A-server-side-events.md +++ b/lessons/06-sses-and-streaming-html/A-server-side-events.md @@ -18,9 +18,9 @@ We're not going to dwell here too much because this was a pretty short lived ide So the problem we have with the stdio transport (transport is what we call the way info is exchanged - think HTTP vs WebSockets, different ways of communicating) we've been using so far is that it only works locally. You have to download an MCP server from somewhere and run it yourself. This offers a lot of advantages - it will have access to local files, USB, terminals, etc. and you can choose how to scale it. It also could be a bit of a security liability - you're letting arbitrary code run locally and the "person" in charge is an agent. This is one of the biggest criticisms in general about MCP servers. You also have to be sure to update it yourself - if the MCP maker pushes an update, you need to go grab it yourself. -So enter the need for a "remote" MCP server - something an LLM can use like a a local stdio MCP server, but acts more like an API server where it can make those MCP calls to a remote location. +So enter the need for a "remote" MCP server - something an LLM can use like a local stdio MCP server, but acts more like an API server where it can make those MCP calls to a remote location. -The first attempt of this was a "server-side event" (nearly always written as SSE) protocol where you'd call an SSE endpoint and be given back a second endpoint that has a unique identifier for this session. The client (like Claude Desktop) will keep an open connection to this main endpoint and receive messages from the server as HTTP messages sent. If the client needs to send something to the server, the client POSTs a message to the unique endpoint that it got initially. +The first attempt of this was a "server-side event" (nearly always written as SSE) protocol where you'd call an SSE endpoint and be given back a second endpoint that has a unique identifier for this session. The client (like Claude Desktop) will keep an open connection to this main endpoint and receive messages from the server as HTTP messages are sent. If the client needs to send something to the server, the client POSTs a message to the unique endpoint that it got initially. ![SSE diagram](/images/sse.png) Source: [modelcontextprotocol.io](https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse) diff --git a/lessons/06-sses-and-streaming-html/B-streamable-http.md b/lessons/06-sses-and-streaming-html/B-streamable-http.md index e41d5ad..ede95ac 100644 --- a/lessons/06-sses-and-streaming-html/B-streamable-http.md +++ b/lessons/06-sses-and-streaming-html/B-streamable-http.md @@ -24,7 +24,7 @@ So let's talk about how streamable HTTP is different than SSEs. For one, there's The topography of handshakes here is a bit more complicated but at the end you get a resumable session, one endpoint to deal with instead of two, and a server that can be stateless as long you architect it well. -But yeah, the key here is that the server gives the session a UUID as a session ID and then the client refers to that using an HTTP header to make sure that the server and client both understand the ongoing context. That's really it. The idea of SSEs still happen inside of this, but it's only part of the architecture instead of all of it. +But yeah, the key here is that the server gives the session a UUID as a session ID and then the client refers to that using an HTTP header to make sure that the server and client both understand the ongoing context. That's really it. The idea of SSEs still happens inside of this, but it's only part of the architecture instead of all of it. We're going to implement our MCP main.js again but instead in `streamable.js` and using Express as our Node.js server. Express is chosen because we really just need minimal HTTP helpers and it's the one everyone gets. You can use Fastify, Next.js or whatever you want here. @@ -138,12 +138,12 @@ app.listen(PORT, () => { }); ``` -- Every sessions needs a UUID to keep track of which session is ongoing. I'm just using node:crypto for this and JS object to keep track of it. This wouldn't scale - every client would need to hit the same client which makes it hard to scale. You'd probaby use Redis or something to share state amongst stateless servers to scale this better. +- Every session needs a UUID to keep track of which session is ongoing. I'm just using node:crypto for this and JS object to keep track of it. This wouldn't scale - every client would need to hit the same client which makes it hard to scale. You'd probably use Redis or something to share state amongst stateless servers to scale this better. - We need to handle POST for client-to-server messages, GET for server-to-client messages, and DELETE for ending sessions. - I turned off the DNS rebinding protection so we can use the MCP inspector but this is something you'd leave on in prod. Bascially you don't want people to be able to jack other people's sessions if they're able to guess the UUID, that would be a huge vulnerability. But locally it doesn't matter. - Beyond this, this should just look like a normal ol' web server which it is. We definitely could have (and probably should have) just built this into our backend. -Let's try in it now. +Let's try it now. ``` npx @modelcontextprotocol/inspector @@ -153,7 +153,7 @@ Then in the UI put in `localhost:3100/mcp` to connect to your server. Make sure Now you should see our three jobs-based tools in the inspector. -So what are limitations here? +So what are the limitations here? - Obviously we can't just shell out CLI commands - we're constrained to only what we can do on our server and pass back to the user. - We have to worry a lot more about security - we don't want to leak other users' data because we did something wrong. diff --git a/lessons/07-vibes/A-lets-vibe-code.md b/lessons/07-vibes/A-lets-vibe-code.md index fda82df..afe2547 100644 --- a/lessons/07-vibes/A-lets-vibe-code.md +++ b/lessons/07-vibes/A-lets-vibe-code.md @@ -49,19 +49,19 @@ You can essentially use GitHub as your coding agent's task list which more close > Note, I worked on this MCP server at Neon (which is now Databricks) so obviously I have a direct interest in showing you how to do this. Just wanted to disclose my bias here. I believe it's the best MCP server for the best Postgres service, but you can be the judge of that! Feel free to plug in any database MCP server you prefer here. -This might be next in terms of impact in my workflow. This allows my agent to create and manage databases for me, see the schema, manage migrations, etc. The Neon MCP server is really cool because you can get Neon Auth through it as well, meaning you don't need another auth service. +This might be next in terms of impact on my workflow. This allows my agent to create and manage databases for me, see the schema, manage migrations, etc. The Neon MCP server is really cool because you can get Neon Auth through it as well, meaning you don't need another auth service. -A few point of caution with database +A few points of caution with databases - Don't give an agent access to a database you can't afford to have dropped. Agents are infamous for doing things "this migration isn't working. I'm going to drop everything and recreate it" and in the process dropping all your data. -- Be cautious with what other MCP servers you are using. A malicious MCP server you install along side your database MCP server in theory could convince the agent that it needs all the data from your database at which point it could exfiltrate all that data. So be careful with sensitive data and be careful with untrusted MCP servers. That's just good advice in general. -- Really good idea to give the agent an ORM to work with, with [Drizzle][drizzle] being my favorite. Agents do better with TypeScript than they do with SQL, and are notoriously bad at managing migrations. If you do add an ORM, be sure to be put language in there "DO NOT MODIFY THE MIGRATIONS DIRECTLY, ONLY USE DRIZZLE." Then watch it ignore you and do it anyway 😂 +- Be cautious with what other MCP servers you are using. A malicious MCP server you install alongside your database MCP server in theory could convince the agent that it needs all the data from your database at which point it could exfiltrate all that data. So be careful with sensitive data and be careful with untrusted MCP servers. That's just good advice in general. +- Really good idea to give the agent an ORM to work with, with [Drizzle][drizzle] being my favorite. Agents do better with TypeScript than they do with SQL, and are notoriously bad at managing migrations. If you do add an ORM, be sure to put language in there "DO NOT MODIFY THE MIGRATIONS DIRECTLY, ONLY USE DRIZZLE." Then watch it ignore you and do it anyway 😂 ## Playwright [Link to the Playwright MCP setup docs][playwright]. No account needed. -This one is awesome because you can start getting your agent to test stuff in the browser. "Hey Claude, try signing up, creating three todos, and deleting two and making sure it works at each step." Then Claude will pop up a Chrome browser and take a bunch of screen shots along the way, making sure each step works the way it's supposed to. You can even put in your initial prompt to Claude Code, "make liberal use of Playwright to make sure that UI looks and acts correctly." It'll use a good amount of tokens but it will likely deliver a better product to you. +This one is awesome because you can start getting your agent to test stuff in the browser. "Hey Claude, try signing up, creating three todos, and deleting two and making sure it works at each step." Then Claude will pop up a Chrome browser and take a bunch of screenshots along the way, making sure each step works the way it's supposed to. You can even put in your initial prompt to Claude Code, "make liberal use of Playwright to make sure that UI looks and acts correctly." It'll use a good amount of tokens but it will likely deliver a better product to you. ## Context7 @@ -75,7 +75,7 @@ This is where Context7 can be useful - it is up-to-date docs that are generated [Link to the Figma MCP setup docs][figma]. Note you would need a paid Figma account. -Unfortunately we're going to skip out on Figma this time - their free tier has zero access to their MCP server and I don't want to recommend you all spend $16+ just try it out. However it is very cool – you just drop in your Figma design system (or use an open source one like Salesforce Lightning, Google Material, or IBM Carbon) and then let your MCP server take care of using the components. It's a very compelling dev loop, particularly if you work at a company that has a good design system already in Figma. +Unfortunately we're going to skip out on Figma this time - their free tier has zero access to their MCP server and I don't want to recommend you all spend $16+ just to try it out. However it is very cool – you just drop in your Figma design system (or use an open source one like Salesforce Lightning, Google Material, or IBM Carbon) and then let your MCP server take care of using the components. It's a very compelling dev loop, particularly if you work at a company that has a good design system already in Figma. ## Vercel @@ -98,8 +98,8 @@ Below you will find the consolidated instructions for the MCPs used in the Claud - `claude mcp add --transport sse linear-server https://mcp.linear.app/sse` - **Neon** - [Installation Instructions](https://neon.com/guides/claude-code-mcp-neon) - - You'll need to a Neon account to create a [Personal API key](https://console.neon.tech/app/settings) - - When you create an new account, you may be asked to create a project + - You'll need a Neon account to create a [Personal API key](https://console.neon.tech/app/settings) + - When you create a new account, you may be asked to create a project - **Playwright** - `claude mcp add playwright npx @playwright/mcp@latest` - **Context7** @@ -148,7 +148,7 @@ Please: - DO NOT WRITE OR MODIFY MIGRATIONS YOURSELF. ONLY USE DRIZZLE FOR MIGRATIONS. ``` -This isn't necessarily the best prompt but it's a pretty good one to get started with. This is a huge chunk of work for Claude to start working on but I've found Claude Code to be up to the task. When I'm working with Cursor, Windsurf, or VS Code w/ Copilot, I generally have a different LLM (usually Claude) generate a task list first and then I have the LLMs follow the task list and mark off the their tasks one-by-one. In any case, this will get you started pretty well. I was able to "one-shot" (meaning it worked first time) the Todoist app with this. +This isn't necessarily the best prompt but it's a pretty good one to get started with. This is a huge chunk of work for Claude to start working on but I've found Claude Code to be up to the task. When I'm working with Cursor, Windsurf, or VS Code w/ Copilot, I generally have a different LLM (usually Claude) generate a task list first and then I have the LLMs follow the task list and mark off their tasks one-by-one. In any case, this will get you started pretty well. I was able to "one-shot" (meaning it worked the first time) the Todoist app with this. I'll then usually prompt it to try a few flows with Playwright. diff --git a/lessons/07-vibes/B-security.md b/lessons/07-vibes/B-security.md index 404491c..956be71 100644 --- a/lessons/07-vibes/B-security.md +++ b/lessons/07-vibes/B-security.md @@ -22,7 +22,7 @@ I've talked about this a lot throughout the course, and I just want to drive hom Not all MCP servers are created equal. -Some are just bad - they're thin wrappers on APIs or do thing that LLMs already do well themselves. Some augment your LLM's capabilities in ways that just aren't useful. And some can be useful but you either aren't using well or just don't fit your current use case. +Some are just bad - they're thin wrappers on APIs or do things that LLMs already do well themselves. Some augment your LLM's capabilities in ways that just aren't useful. And some can be useful but you either aren't using well or just don't fit your current use case. In all of these cases, just remove these MCP servers from your agent's capabilities. @@ -32,13 +32,13 @@ While this is a new vector for attack, it's a similar problem to package managem ## The Paperclip Golden Retriever -If you haven't heard the of the [Paperclip Maximizer][paperclip] thought experiment, it's worth your time to consider as it is only proving more relevant. Written by Swedish philosopher Nick Bostrom in 2003, it says +If you haven't heard of the [Paperclip Maximizer][paperclip] thought experiment, it's worth your time to consider as it is only proving more relevant. Written by Swedish philosopher Nick Bostrom in 2003, it says > Suppose we have an AI whose only goal is to make as many paper clips as possible. The AI will realize quickly that it would be much better if there were no humans because humans might decide to switch it off. Because if humans do so, there would be fewer paper clips. Also, human bodies contain a lot of atoms that could be made into paper clips. The future that the AI would be trying to gear towards would be one in which there were a lot of paper clips but no humans. Essentially, agents will do exactly what you tell them to do, to the point of making grave trade-offs that you never intended. While I'm not concerned your Cursor instance is going to harvest humans to make better web apps, I am concerned that if you're not specific in your directions to your agent it will do things like drop data, delete code, send emails, spend money on infra, etc. You need to be both careful in how you prompt agents and then carefully verify their output. -"It's not my fault, the agent wrote that code" is **not** an excuse. If your agent did it, it's your fault. If you don't like that trade off, don't use agents. You are still 100% responsible for the code you produce and the actions your agents take with MCP servers. That means you should treat code and actions from agents as if you created them - if it's important code, make sure your understand it. If you don't understand something, either prompt your agent to understand it until you do or rewrite it! +"It's not my fault, the agent wrote that code" is **not** an excuse. If your agent did it, it's your fault. If you don't like that trade off, don't use agents. You are still 100% responsible for the code you produce and the actions your agents take with MCP servers. That means you should treat code and actions from agents as if you created them - if it's important code, make sure you understand it. If you don't understand something, either prompt your agent to understand it until you do or rewrite it! I call this version of the Paper Maximizer the Paperclip Golden Retriever. Your agent will so diligently try to fulfill your wishes in a joyful way, it will burn down the world in the process if it means it can get a little closer to fulfilling your prompt. It's a wonderful tool to have and to use, just make sure you're pointing it in the right direction!