Free YouTube Transcribe

Video transcript

Your Insecure MCP Server Won't Survive Production — Tun Shwe, Lenses

AI Engineer · 3,610 words · 17 min read

Want to search this transcript, jump the video from any line, or download it as TXT, SRT, or VTT?

Open in the transcript tool

Full transcript

0:00Hey folks, thank you for joining us for

0:02this session on why your insecure MCP

0:05server won't survive production.

0:08My name is Tin Shway and I lead AI at

0:10Lenses and day-to-day I'm an AI engineer

0:13and you can connect with me here on

0:14LinkedIn.

0:17And I'm Jeremy Fronae. I work on AI

0:19engineering at Lenses.

0:24First, a quick note on where we work.

0:26Lenses is a data operating fabric that

0:28sits between your agents and

0:32Lenses is the de facto streaming data

0:34layer for providing trusted real-time

0:36context to agentic AI.

0:39Companies work with us because we have

0:40governance, security and large scale at

0:43the top of mind.

0:47Here are a selection of our customers

0:48which gives us exposure to lots of

0:50different industry use cases at large

0:53scale.

0:55And we are here today of course because

0:57we have an open source MCP server that

0:59we're applying our learnings to from the

1:01field. So, please give us a star to

1:03follow the project.

1:06And here's what we'll cover in this

1:07session. The takeaways we want you to

1:09have are the ways of thinking about

1:11designing MCP servers and in fact any

1:13interface to make it robust for agentic

1:16AI systems. And since this is a talk

1:18about MCP, we'll ensure you have tips on

1:21how to approach securing your MCP

1:23service for production.

1:24I'll cover the first few sections and in

1:26his sections Jeremy will go over the

1:29OAuth flows.

1:33So, let's go straight into why most MCP

1:36servers aren't great.

1:39I like the way Jeremy Lowin, who is the

1:41creator of Fast MCP, put it. Um he said

1:44that agents deserve their own interface

1:46that is optimized for their use cases.

1:49To approach designing for agents through

1:51a product engineering lens.

1:53I want to take that approach one step

1:55further.

1:56A badly designed MCP server is also a

1:58badly secured one.

2:00Poor design and poor security compound

2:03each other.

2:05Jeremy put forward three dimensions in

2:07how humans and agents differ from one

2:10another and to consider these three

2:11dimensions when you're designing for MCP

2:14or any agentic interface.

2:16The extra layer I wanted to emphasize is

2:18security that each one casts a security

2:21shadow.

2:24First, there's discovery.

2:26When you use the new API, you pull up

2:27the docs, you scan through them once,

2:30you find the three end points that you

2:31need and you never look at those docs

2:33again.

2:34An agent can't do that.

2:36Every time it connects to an MCP server,

2:38it enumerates every single tool and

2:40reads every single description. And

2:42that's expensive in tokens.

2:44But here's the security set shadow.

2:47Every one of those tool descriptions is

2:48a surface for tool poisoning.

2:51Attackers can embed hidden instructions

2:52inside descriptions that are invisible

2:54in the UI, but the model will follow

2:56them without question.

2:58More tools means more surface area for

3:00injection.

3:03Second is iteration. If your script

3:05fails, you run it again. It takes a

3:07second. When an agent retries, it sends

3:11the full conversation history over the

3:12wire.

3:14And here's its security shadow.

3:17An agent iterating over a poorly scoped

3:19MCP server is broadcasting your data

3:21with every retry.

3:23The full conversation history goes over

3:25the wire including any sensitive data

3:27returned by previous tool calls. Each

3:29round trip is a chance for data leakage.

3:34Third, context. You and I have decades

3:37of memories and experiences and

3:39intuition. An agent has roughly 200,000

3:42tokens and that's it.

3:44The security shadow is detailed in

3:47OWASP's MCP top 10 list which I

3:49recommend you all to go and read. And

3:51there it's listed as number 10, context

3:54injection and oversharing.

3:56If your server dumps unfiltered data

3:58into that limited window, you're handing

4:00off PII, credentials, internal system

4:03details to a model that can be tricked

4:05into exfiltrating them.

4:08An agent has to load all the context in

4:11before it can make a decision.

4:13It makes it suitable for finding

4:14specific things, but it comes at the

4:16cost of latency and context bloat. So,

4:19you think of it as finding a needle in a

4:20haystack.

4:22If some of that hay is poisoned, the

4:24agent just won't notice.

4:27So, you should think about curation.

4:29Curate the MCP tools available to the

4:31agent and aim to expose the smallest

4:34amount of information.

4:36The less you expose, the less can be

4:39attacked. And here, less is more.

4:43Next, I'll go over what I consider five

4:46key rules for secure agentic design. Uh

4:49to think with your product engineering

4:51hat on and to apply it to MCP servers.

4:54The thing I want you to take away from

4:56this section is that good MCP design and

4:58good MCP security are the same

5:00discipline. If you get the design wrong,

5:03no amount of OAuth will save you.

5:05I've got five principles here and they

5:07all give you protection against the

5:08OWASP MCP top 10 before you write even a

5:11single line of OAuth code.

5:14So, number one,

5:16shrink the attack surface by design.

5:18Think in terms of outcomes. The idea

5:20here is to squash all the fine-grained

5:22operations or underlying API calls into

5:24a single coarse-grained operation that

5:26produces a desired outcome.

5:28Every tool you expose is a door.

5:31Don't give the agent access to delete

5:32users when all it needs is to check an

5:34order.

5:35Consolidate related operations behind a

5:37single tool call with a well-defined

5:39outcome. So, you have one permission

5:41check, one audit log entry, one place to

5:44enforce authorization. So, think fewer

5:47doors with fewer locks to manage.

5:51Number two, constrain your inputs at the

5:53schema level.

5:55You've got to accept the top-level

5:56primitives like the enums, that will be

5:58the best approach. Um dictionaries are

6:00also fine as long as they're not nested

6:02and to introduce more strictness, you

6:04could use a typing library like

6:06Pydantic.

6:08The aim is to reject free-form nested

6:10payloads to avoid command injection

6:12flaws where the root cause is almost

6:14always unconstrained string arguments

6:16that get passed downstream to a shell, a

6:19query engine or an API. Constrained

6:21inputs are easier to validate and harder

6:23to exploit.

6:26Number three, treat your documentation

6:28as a defensive layer.

6:30Tool poisoning is number three on the

6:32OWASP MCP guide and it works by

6:34embedding malicious instructions in tool

6:36descriptions that are invisible in the

6:38UI, but executed by the model.

6:41If you don't write clear, complete

6:42instructions, an attacker-controlled

6:45tool description in a neighboring MCP

6:47server can shadow yours.

6:49If your documentation is complete and

6:51unambiguous for every tool, it crowds

6:53out the space that a poisoned

6:55neighboring server would try to fill.

6:58Number four,

7:00return only what the agent needs.

7:02Oversharing data in tool responses is

7:04number 10 in OWASP's MCP guide and it

7:07turns the agent's context window into a

7:09liability.

7:10PII, internal identifiers, credentials,

7:14system details, all sitting in the

7:16context, they're all just one prompt

7:18injection away from exfiltration. So,

7:20strip your payloads to the minimum. If

7:22the agent doesn't need a piece of data

7:24for its immediate task, then don't

7:26return it.

7:29And number five,

7:31minimize the blast radius. Scope

7:33permissions at the tool and resource

7:35level, not the session level. Use the

7:37MCP read-only annotation for

7:39non-destructive tools so that clients

7:41can enforce boundaries or if an MCP tool

7:45is intended to have read-only access,

7:47then consider turning it into an MCP

7:49resource.

7:50Also, remember that every tool you

7:51remove is an attack vector that you

7:53eliminate.

7:59And you're building an interface, not a

8:00tool. So, this is the mindset to go in

8:02with.

8:03An agent will use anything you provide

8:05it with confidence, so you have to

8:07provide that trust layer.

8:11So, now you've designed your server

8:13well. You followed the five principles.

8:15Now you need to actually deploy it and

8:17this is where most teams hit what I call

8:19the security cliff.

8:21If you're running MCP in standard IO

8:23mode, life is pretty comfortable. It's a

8:26local process, a single user, no no

8:29network exposure, no authentication

8:31needed. Your MCP host talks directly to

8:34the server process on your machine. It's

8:36a walled garden and it works beautifully

8:37for single-player developer

8:39productivity.

8:40But production requires something

8:42completely different.

8:44You need the streamable HTTP transport.

8:47Um this enables remote deployment,

8:49multiple clients connecting to the same

8:51server. You can horizontally scale and

8:54you can centralize your governance. And

8:55this is really where MCP becomes

8:57genuinely valuable to an organization

9:00where you go from one developer on one

9:02laptop to a shared capability that an

9:05entire team or entire fleet of agents

9:06can use.

9:08MCP becomes the single interface that

9:10all clients can use without having to

9:12worry about whether they're the latest

9:13version of an API or considering the

9:15resources needed to scale.

9:19The problem is there's no gradual

9:20on-ramp. You go from zero security

9:23surface to a huge list of concerns all

9:25at once. You're suddenly needing OAuth,

9:28token management, CORS configuration,

9:31TLS, rate limiting and more. And you

9:33need it all at once. So, there's no

9:35halfway house because you can't do a

9:37little bit of production. You're either

9:39behind the wall or you're standing out

9:41in the open.

9:44And you can't just stay local and hope

9:46for the best. Stack lock ran low tests

9:48on standard IO transport and the results

9:50were brutal. 20 out of 22 requests

9:52failed with just 20 simultaneous

9:54connections. Standard IO falls over the

9:57moment you add concurrency. So, if you

9:59want to scale out, you have to cross the

10:00chasm.

10:03And how do you start crossing that

10:04chasm? I'm going to hand it over to

10:06Jeremy to continue.

10:10Yes, so implementing an authorization

10:12server for MCP isn't that simple.

10:15Let's look at the list of RFCs to

10:17implement.

10:20With the core flow, the OAuth client

10:23discovery, and the metadata, and the

10:24management of the token life cycle, we

10:27already have more than 10 specifications

10:29to implement.

10:31Now, let's say we read all these RFCs,

10:34and I'm ready to implement an

10:35authorization [clears throat] server for

10:36MCP.

10:38What does the enterprise grade

10:39authorization look like?

10:44So, let's start by reviewing the local

10:46versus remote MCP server setups and

10:48their respective OAuth flows.

10:51Tune talked about the walled garden, the

10:54local MCP server

10:56running over standard IO with an API

10:58key.

10:59Let's look at the flow diagram.

11:01The MCP server runs on my machine.

11:03The client connects via standard IO.

11:06The user must set the key as a parameter

11:09in the MCP client config.

11:11And the parameter will be stored as an

11:13environment variable

11:15passed by the MCP server with its

11:17request to the external service.

11:24That might be good for local setups, but

11:27I need to provision, store, and maintain

11:30the key.

11:32This key is long-lived, is rarely

11:34rotated, and it isn't scoped to the

11:36specific actions that my client perform.

11:40Even worse, these keys are often shared

11:43across systems.

11:45So, the key is stored in a config file,

11:47an environment variable, and it isn't

11:49verified by the MCP server.

11:52Now, let's look at a remote MCP server.

11:56In this case, the MCP server runs on a

11:59remote server.

12:01The client connects via HTTP.

12:03The user must set the key in the HTTP

12:05authorization header. Again, we can see

12:08the MCP client config here on screen.

12:12So, phase one is the generation of the

12:14token and the configuration of a client.

12:19On step two, runtime,

12:21we can see the client performing a

12:22request, attaching this API key in the

12:24authorization header.

12:27This API key is validated or not by the

12:30MCP server itself, and will be passed

12:32through

12:33to the upstream API, where it will be

12:36this time verified. Whether the API key

12:38is validated or not, we'll get a 200

12:41response or 401 response, in which case

12:44the user will need to rotate the token

12:46manually.

12:48That's how a majority of remote MCP

12:50servers are configured today.

12:52The key is long-lived, it isn't scoped

12:54to the specific action of my agent,

12:56either. The key is stored in a config

12:59file, and it isn't always verified by

13:01the MCP server.

13:04Either the key is simply passed through

13:06to the API, creating a confused deputy

13:08vulnerability, where malicious clients

13:10obtain authorization without the proper

13:12user consent,

13:14or sometimes the key might be mapped to

13:16another key and token

13:18for the API access itself.

13:20Now, we have a single shared credential

13:23serving many users. That credential is

13:25even more powerful, harder to revoke per

13:27user, and if leaked, it compromises

13:30everyone.

13:32This approach works for long-lived,

13:34unscoped credential setups. It still

13:36represents more than 50% of the MCP

13:38servers out there.

13:40But what we see the ecosystem moving

13:42towards is short-lived, scoped tokens

13:45via OAuth 2.1.

13:47We even see token exchange for least

13:49privilege access.

13:51Traditional OAuth assumes you know your

13:53clients up front.

13:55You register them in a developer portal,

13:57you get a client ID, and you move on.

14:00This works when you have five to 10 apps

14:03connecting to your service.

14:05But with MCP,

14:07this flow breaks completely.

14:09Think about what MCP's architecture

14:11actually looks like.

14:13Any client, Cloud Desktop, Cursor, VS

14:16Code, a CLI tool, a random agent,

14:19can discover and connect to any MCP

14:21server at runtime.

14:25Pre-registration requires too much

14:27effort in a highly viable setting.

14:30It's an unbounded number of clients

14:32connected to an unbounded number of

14:34servers.

14:35You can't ask every developer to

14:37manually register their app with every

14:39MCP server they might ever want to talk

14:41to.

14:42So, that's where the dynamic client

14:44registration comes in.

14:47In this case, we still have an MCP

14:49server running on a remote server,

14:52but now it's protected by an OAuth

14:54authorization server.

14:57The client can self-register itself

14:59against the authorization server,

15:01and will get a new client ID on every

15:04registration.

15:06So, on phase one, the discovery,

15:09our MCP client, in this case Cursor,

15:12will perform a request on {slash} MCP

15:14against the MCP server.

15:16We can see the MCP server returning a

15:18401 response because we do not have a

15:20token to pass yet,

15:22but it also passes a WWW-Authenticate

15:25header containing the resource metadata

15:28that can be used by our client in order

15:31to discover the MCP server and its

15:33metadata.

15:36The document itself looks a bit like

15:38this.

15:39It describes the resource we're trying

15:41to access and the authorization server

15:43protecting it.

15:45This lets our client point at the

15:47authorization server itself and

15:48discover, this time, the metadata

15:51exposed by the authorization server

15:52itself.

15:55Now that our client knows how to

15:57authorize itself for an MCP server

15:59access, it needs to register itself

16:01against the authorization server.

16:04That is done via a request, a post

16:06request on {slash} register.

16:10As we mentioned earlier, the

16:11authorization server will generate and

16:13persist on disk a new client ID and

16:16return it to the client.

16:18Now, we know who we're talking to.

16:20Next, it's time to authorize our client

16:24against the authorization server.

16:26And for that, the MCP spec is mandating

16:29to use the PKCE, the proof key for code

16:32exchange protocol. So, our MCP client is

16:34first generating a code verifier and a

16:37code challenge

16:38that it does pass through a request to

16:41{slash} authorize

16:43in order to obtain

16:45an authorization code.

16:47Our authorization server will validate

16:50this request and the code challenge.

16:53And since we don't have a running

16:54session yet for this user, it will

16:56redirect the user to its identity

16:58provider, so that's your single sign-on

17:01form, in order for the user to log in.

17:04Upon successful log in, the user will be

17:06redirected to a consent page where they

17:08can grant different scopes

17:10to their client.

17:14Now that we issued a valid authorization

17:17code for client, it's time to use it in

17:20order to get a token, an access token.

17:23Does that by sending a request on

17:26{slash} token and passing the

17:28authorization code and the code verifier

17:30that we generated for the PKCE protocol

17:32earlier.

17:33Authorization server will validate

17:35the PKCE challenge and the authorization

17:38code,

17:40and it will then mint a brand new token.

17:42In this case, we're using JSON web

17:44tokens

17:45in order to return an access token for

17:48client to now use the MCP server.

17:52The final step is actually to

17:55use the MCP server.

17:58This is when your MCP client is going to

18:00perform a tool call, for example.

18:02We can see it will pass the access token

18:05we just issued

18:07in the authorization as the bearer

18:09value.

18:11Our MCP server will validate this token,

18:14check the valid scopes,

18:16and it will now

18:18perform the token exchange flow in order

18:20to change this delegation token

18:23for a session token.

18:25This means our MCP server now is

18:27actually a OAuth client

18:29for a new resource server,

18:32our API,

18:33but it's using the exact same

18:34authorization server in order to get a

18:36token.

18:38So, that is the token exchange flow that

18:39is defined in RFC 8693.

18:43And as we complete the flow,

18:45our MCP server can use this new session

18:47token in order to perform an API call,

18:50bypassing

18:51the token in the authorization header.

18:55So, DCR solves the self-registration,

18:58the dynamic registration of the client,

19:01so that our user doesn't have to go and

19:02pre-register, pre-generate uh static

19:05credentials, and set it on the client,

19:07but it does have its own problems.

19:09First, every time a user connects a

19:12client to an MCP server,

19:14a new registration is created.

19:17Registrations are not portable, so using

19:19Cloud on Windows and then on macOS

19:22creates two distinct client

19:23registration.

19:26DCR is vulnerable to phishing attacks

19:29because it doesn't provide a reliable

19:31way to verify client identities.

19:34Anyone can post to that endpoint, the

19:36{slash} register endpoint, including

19:38attackers.

19:40Finally, the server is just trusting

19:42whatever metadata the client

19:44self-asserts.

19:45It means a malicious client can claim to

19:47be Cloud,

19:49and the server has no way to know

19:50otherwise.

19:54So, the MCP community had to come up

19:56with a better way to let clients

19:58self-register.

20:00And that is CIMD, the client ID metadata

20:03document.

20:05Here in this case, we still have an

20:07authorization server in front of our MCP

20:10server,

20:11but the client owner exposes the client

20:13ID on a public URL.

20:16This will let our MCP server fetching

20:18the client ID during the authorization.

20:21Let's have a look at the diagram.

20:24So, phase one is still the discovery.

20:26Our client hits the MCP server without a

20:29token,

20:30gets a 401 response, and uh the resource

20:33metadata URL. It can follow this URL,

20:36discover the MCP server, and it will get

20:40to discover the authorization server.

20:42But this time, the authorization server

20:45isn't mentioning it needs a slash

20:47register request.

20:50It means the client, the MCP client, can

20:52go straight to the authorization phase.

20:56We generate again the PKCE code

20:57verifier, and we perform a slash

21:00authorize request. But this time, our

21:02client passes its unique ID, and we can

21:05see it here. It's actually a valid URL

21:08where the metadata for the client is

21:11being exposed.

21:14This lets our authorization server fetch

21:16this metadata,

21:18and register a new client with a unique

21:20ID

21:21that is a URL that is exposed by the

21:24client owner.

21:27And we can move to the authentication

21:29phase.

21:32Again, the authorization server will

21:33redirect to the identity provider, wait

21:36for a valid login on our user's side,

21:38present a consent screen

21:40uh for the user to grant some scopes,

21:43and

21:44we are ready to issue

21:46the delegation token and the session

21:48token

21:49for a token use by the MCP server.

21:53So here, CIMD has no growing database of

21:57client registration to maintain.

22:00Proving that you control

22:02https://cloud.ai

22:04is meaningful,

22:05unlike proving that you can post on the

22:07registration endpoint.

22:10The redirect URIs that are explicitly

22:12bound to the client in its metadata

22:14document are making it harder for

22:16attackers to sneak in malicious

22:17callbacks.

22:20And the authorization server can

22:21selectively allow or deny clients.

22:26So, in summary, DCR is a good start, but

22:29it does create problems.

22:32CIMD is a leap forward, and it is the

22:35preferred approach since November 2025.

22:40But becoming enterprise grade

22:42requires adding other layers of security

22:44and confidence.

22:46For permissions,

22:47OAuth scopes gets you part of the way

22:49there,

22:50but it's scoped to the session.

22:53True enterprise grade role-based access

22:54control means scoping permissions at the

22:57individual tool and resource level, not

22:59just the session.

23:03Data masking is how you deal with the

23:05PII fields such as email,

23:07phone, and national insurance numbers.

23:10They may need to be masked before the

23:12agent sees them, because agents should

23:14never be exposed to data that they have

23:17no business handling.

23:22You will need to log what's happening in

23:24each interaction.

23:25Which agent called which tool, with what

23:28parameters, and what data was returned.

23:31For compliance with regulations such as

23:33the EU AI Act, regulators will expect

23:36this level of transparency and detail

23:38for autonomous AI systems.

23:43Finally, you'll need to be able to

23:45observe the full request.

23:47This means the client request validation

23:50through the execution,

23:51data retrieval, and the generated

23:53response.

23:55If you cannot trace what an agent did

23:57end to end, you cannot govern it.

24:00Tracing for agent AI follows the same

24:03principles as distributed system

24:05observability, but applied to autonomous

24:07decision-making.

24:11Thanks very much, Jeremy, and thank you

24:13all for tuning in to this session. We'd

24:16love to know how your journey with

24:18productionizing MCP services is going,

24:20so please leave us a comment or send us

24:22a message. You know where to find us.

24:24And please do check out our MCP server

24:26and give us a star. So, hopefully we'll

24:28see you again soon. Thanks, and bye.

24:31Thank you.

This transcript was generated from the captions YouTube publishes for this video. Get the transcript of any YouTube video atfreeyoutubetranscribe.com: free, unlimited, no sign-up.