Catalyst-Plugin-MCP
view release on metacpan or search on metacpan
protocol_versions => ['2025-06-18'], # newest-first
server_info => { name => 'myapp', version => '1.0' },
},
);
```
## Security
**This plugin ships no authentication and no `Origin` validation, and
`mcp_dispatch` does not add any.** A `tools/call` runs your provider's code, so
an endpoint mounted as in the synopsis above executes tools for anyone who can
POST to it. Guarding it is the application's job:
- **Authenticate the endpoint.** The MCP Streamable HTTP transport says servers
SHOULD authenticate connections. Put your own authentication (a Catalyst
authentication plugin, an `auto` action, or middleware) in front of
`mcp_dispatch`. Consider also what a provider is allowed to reach: the engine
does not scope tools or resources to a user.
- **Validate the `Origin` header.** The transport says servers MUST validate
`Origin`, to stop a browser on another site from driving your endpoint via DNS
rebinding. Check it against an allow-list and reject anything else before
dispatching.
Binding to localhost rather than `0.0.0.0` is worth it for a local server, but
it is not a substitute for either of the above. See the `SECURITY` section in
`Catalyst::Plugin::MCP` for detail.
## Author
Mike Whitaker <mike@altrion.org>
lib/Catalyst/Plugin/MCP.pm view on Meta::CPAN
=head1 SYNOPSIS
package MyApp;
use Catalyst qw/
+Catalyst::Plugin::JSONRPC::Server
+Catalyst::Plugin::MCP
/;
__PACKAGE__->setup;
# in a controller action mounted at your MCP endpoint
sub mcp :Path('/mcp') :Args(0) {
my ( $self, $c ) = @_;
$c->mcp_register_provider( $c->model('MCP::Resources') );
$c->mcp_register_provider( $c->model('MCP::Tools') );
$c->mcp_dispatch;
}
=head1 REQUIRED PLUGINS
This plugin builds on L<Catalyst::Plugin::JSONRPC::Server> and calls its
lib/Catalyst/Plugin/MCP.pm view on Meta::CPAN
Advertised at C<initialize>. Defaults to a generic name and this plugin's
version, so set it to your own.
=back
=head1 SECURITY
B<This plugin ships no authentication and no C<Origin> validation, and
C<mcp_dispatch> does not add any.> A C<tools/call> runs your provider's code,
so an endpoint mounted as in the SYNOPSIS executes tools for anyone who can
POST to it. Guarding it is the application's job, and both of these are on you:
=over
=item Authenticate the endpoint
The MCP Streamable HTTP transport says servers SHOULD authenticate connections.
Put your own authentication (a Catalyst authentication plugin, an C<auto>
action, or middleware) in front of C<mcp_dispatch>, and let the request reach it
only once it is authorised. Consider also what a provider is allowed to reach:
the engine does not scope tools or resources to a user.
=item Validate the C<Origin> header
The transport says servers MUST validate C<Origin> on incoming connections, to
stop a browser on another site from driving your endpoint via DNS rebinding.
Check it against an allow-list and reject anything else before dispatching.
=back
Binding to localhost rather than C<0.0.0.0> is worth it for a local server, but
it is not a substitute for either of the above.
=head1 EXAMPLES
A runnable example lives in F<examples/>: a small Catalyst app loading
( run in 0.576 second using v1.01-cache-2.11-cpan-92ad3014f07 )