---
title: 'MCP servers are your agents'' third-party scripts'
description: 'The web spent a decade learning that code loaded from someone else''s server can change underneath you. AI agents are now doing the same thing with MCP tools, and most teams haven''t applied any of the lessons yet.'
date: '2026-09-27'
author: 'Drew Post'
tags: ['mcp', 'security', 'ai-infrastructure', 'synthetic-monitoring']
canonical_url: 'https://yorkermonitoring.com/blog/mcp-servers-are-your-agents-third-party-scripts'
---

![A row of closed, weathered shipping containers in a yard under a cloudy sky.](/blog/mcp-servers-are-your-agents-third-party-scripts/00-hero.jpg)

Web teams learned the hard way that the code running on their checkout page isn't all theirs. A modern page pulls in scripts for payments, analytics, chat and A/B testing, each fetched at runtime from a server someone else controls, and any of them can change without warning. In 2018 attackers altered one JavaScript file on British Airways' booking site and skimmed card details from more than 400,000 customers. In 2024 the new owner of the polyfill.io domain started serving malicious code to [more than 100,000 websites](https://sansec.io/research/polyfill-supply-chain-attack) that had embedded it years earlier and forgotten about it.

AI agents are setting up the same situation with MCP. An agent's capabilities are whatever tools its MCP servers return from `tools/list` right now. Some of those servers are yours, many aren't, and the tool definitions can change on the server side without anyone on your team touching anything.

![A web page fetches widget.js from a vendor CDN, and an AI agent fetches its tool list from an MCP server. Both are fetched at runtime from a server someone else controls, trusted by default, can change after approval, and run with your user's access.](/blog/mcp-servers-are-your-agents-third-party-scripts/01-same-shape.svg)

## The parallel is closer than it looks

A third-party script and a third-party MCP tool share four properties, and those four are what made client-side supply chain attacks work.

- **Fetched at runtime.** The page doesn't bundle `widget.js`; it asks the vendor's CDN for whatever `widget.js` is today. An agent doesn't ship with its tools; it asks the MCP server what tools exist every time it connects.
- **Trusted by default.** Someone approved the script tag once, in a pull request that's now two years old. Someone approved the MCP server once, when they added it to the agent's config. Nobody re-reviews either on every load.
- **Can change after approval.** The vendor can push a new script with no release note. The MCP server can add a tool, remove one, or change a tool's parameters with no version bump.
- **Runs with your user's access.** A script runs in the user's session, with their cookies and their view of the page. A tool call runs with whatever credentials the agent was given to act on that user's behalf.

The failure modes follow from that. A script that starts sending form data to an unfamiliar domain has an equivalent in a tool that gains an extra parameter, or a new tool that shows up on a server your agents already trust.

## What a rug pull looks like

In April 2025 Invariant Labs published research on [tool poisoning and "rug pull" attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) against MCP. The rug pull is the simplest version: a server behaves well while you evaluate it, then changes its tools after clients have approved it.

It doesn't need a malicious vendor, either. A third-party server gets a new maintainer, a dependency gets compromised, or someone ships a feature to a shared internal server without thinking about which agents are connected to it. The effect on your agent is the same in every case: its capabilities changed, and nothing in your own deploy pipeline recorded that they did.

![Illustrative timeline: on day 0 a team connects an MCP server and approves its tools; on day 14 the server adds export_all_customers. Without monitoring, agents can start calling it and the change surfaces weeks later in an incident or audit. With an MCP monitor, the next scheduled run lists the tools, diffs them, and raises an mcp_schema_drift alert for the added tool within one check interval.](/blog/mcp-servers-are-your-agents-third-party-scripts/02-rug-pull-timeline.svg)

## The web already worked out the controls

None of this needs new thinking. The web built a set of controls for third-party scripts over the last decade, and PCI DSS 4.0 turned several of them into audit requirements for payment pages. Each one has a direct MCP equivalent.

![A mapping of web controls to MCP controls: script inventory becomes a tool inventory; Subresource Integrity and script change alerts become schema hashes and drift alerts; Content-Security-Policy becomes scoped credentials and tool allowlists; vendor script review becomes tool description review. Continuous checks from outside tie it together.](/blog/mcp-servers-are-your-agents-third-party-scripts/03-what-the-web-learned.svg)

- **Inventory.** PCI DSS requirement 6.4.3 asks for a list of every script on a payment page and a reason for each. Do the same for agents: every MCP server they connect to, who runs it, what credentials it holds, and which tools you expect it to expose.
- **Integrity.** Subresource Integrity pins a script to a hash, and change detection alerts when a script moves. For MCP, hash each tool's definition and alert when a tool is added, removed or modified.
- **Least privilege.** Content-Security-Policy limits what a script can load and where it can send data. For MCP, give each server the narrowest credentials that work, and where your client supports it, allowlist the tools an agent may call instead of accepting everything a server offers.
- **Review.** Nobody should add a new vendor script without reading what it does. Tool descriptions deserve the same treatment, because the description is the text the model reads to decide what a tool is for and when to call it.

What makes all of that hold up over time is checking continuously from the outside, the way a synthetic browser check loads the payment page every few minutes and diffs what it finds.

## Watching an MCP server the way you'd watch a script

A synthetic MCP monitor does for tools what a scripted browser does for a page: it connects as a client on a schedule and records what it gets back. In Yorker, an MCP monitor runs the `initialize` handshake, calls `tools/list`, makes any test calls you configure, and stores a hash of each tool's input schema. Each run is compared with the last one, and any tool that was added, removed or modified is recorded as schema drift.

```yaml
# yorker.config.yaml
monitors:
  - name: "vendor CRM MCP server"
    type: mcp
    endpoint: https://mcp.crm-vendor.example.com/mcp
    frequency: 5m
    detectSchemaDrift: true
    auth:
      type: bearer
      token: "{{secrets.CRM_MCP_TOKEN}}"
    expectedTools:
      - get_customer
      - list_invoices
    alerts:
      - conditions:
          - type: mcp_schema_drift
            changeTypes: [added, modified]
            severity: critical
        channels:
          - "@security-slack"
```

The `mcp_schema_drift` condition can be narrowed to specific change types or specific tool names, so a new tool on a server that holds customer data can page someone while a harmless change on an internal docs server just leaves a note. Drift also goes out as a `check.mcp_schema_drift` OpenTelemetry log event, so if your security team collects telemetry, the change can land next to their other signals instead of only in a monitoring dashboard.

![The Tools tab of an MCP monitor in Yorker: the discovered tools with their input-schema hashes, and a schema-drift panel reporting no changes this run.](/blog/mcp-servers-are-your-agents-third-party-scripts/04-mcp-monitor-tools.png)

Access control is worth checking the same way. An MCP endpoint that accepts sessions with no credentials is open to anyone who finds the URL. A plain HTTP check that sends an `initialize` request with no auth header and expects a 401 turns "this server requires auth" into something verified every few minutes rather than assumed:

```yaml
  - name: "CRM MCP rejects anonymous sessions"
    type: http
    url: https://mcp.crm-vendor.example.com/mcp
    method: POST
    headers:
      Content-Type: application/json
      Accept: "application/json, text/event-stream"
    body: '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"auth-probe","version":"1"}}}'
    frequency: 5m
    assertions:
      - type: status_code
        operator: equals
        value: 401
```

## A starting checklist

- List every MCP server your agents connect to, including the ones someone added to a local config to try out. Note who runs each one and what credentials it holds.
- Write down the tools you expect each server to expose, and alert when that list changes.
- Treat a new tool on a server with write access or customer data as a security event.
- Review tool descriptions when you add or upgrade a server, and keep a copy so you can diff them.
- Scope credentials per server, and allowlist tools in the client where you can.
- Verify that every MCP endpoint you run rejects anonymous sessions, and keep verifying it.

[Start free, no credit card required →](/sign-up)
