[{"content":"I\u0026rsquo;ve been making use of Cursor a lot recently (an AI code editor) and wanted to know how useful MCP plugins could be. While there is a massive set of community and reference servers out there, I wanted to start off by looking at the protocol a little bit and writing my own server.\nI\u0026rsquo;m late to this party so finding an idea for a server I might actually use that doesn\u0026rsquo;t already exist isn\u0026rsquo;t so easy. I\u0026rsquo;ve ended up writing a Perl MCP server that is designed to help Cursor debug and generally write better Perl code. It might be there\u0026rsquo;s not many people regularly writing Perl who would make an MCP server in their spare time.\nYou might already be asking yourself, how useful could this possibly be? I would agree—it\u0026rsquo;s not clear this has any value, but working that out is half the fun.\nServer Implementation To keep things easy I\u0026rsquo;m using go because there\u0026rsquo;s a reasonable looking mcp-golang tool to help with the boilerplate. This probably won\u0026rsquo;t scale past my first tool idea without shelling out to Perl from within Go, but that\u0026rsquo;s a problem for later.\nThe tool I\u0026rsquo;m going to create is fetch-perl-pod. This will take a Perl module and fetch the POD (Plain Old Documentation, the standard documentation format for Perl modules) from metacpan, where many Perl devs host their open source modules.\nLuckily the metacpan API is easy to use so we can implement this in a short Go file.\npackage main import ( \u0026#34;context\u0026#34; \u0026#34;errors\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;io\u0026#34; \u0026#34;net/http\u0026#34; mcp_golang \u0026#34;github.com/metoro-io/mcp-golang\u0026#34; \u0026#34;github.com/metoro-io/mcp-golang/transport/stdio\u0026#34; ) const ( TOOL_NAME = \u0026#34;fetch-perl-pod\u0026#34; TOOL_DESCRIPTION = \u0026#34;Given a Perl module name, fetch the POD from metacpan\u0026#34; CPAN_URL = \u0026#34;https://fastapi.metacpan.org/pod/\u0026#34; ) type args struct { Module string `json:\u0026#34;module\u0026#34; jsonschema:\u0026#34;required,description=The module to fetch POD for eg Const::Fast\u0026#34;` } func main() { done := make(chan struct{}) server := mcp_golang.NewServer(stdio.NewStdioServerTransport()) if err := server.RegisterTool(TOOL_NAME, TOOL_DESCRIPTION, handler); err != nil { panic(err) } if err := server.Serve(); err != nil { panic(err) } \u0026lt;-done } func handler(ctx context.Context, arguments *args) (*mcp_golang.ToolResponse, error) { if arguments == nil || arguments.Module == \u0026#34;\u0026#34; { return nil, errors.New(\u0026#34;module is required\u0026#34;) } pod, err := getCpanPod(arguments.Module) if err != nil { return nil, err } return mcp_golang.NewToolResponse( mcp_golang.NewTextContent(pod), ), nil } func getCpanPod(module string) (string, error) { url := fmt.Sprintf(\u0026#34;%s%s\u0026#34;, CPAN_URL, module) resp, err := http.Get(url) if err != nil { return \u0026#34;\u0026#34;, err } defer resp.Body.Close() //nolint:errcheck if resp.StatusCode != http.StatusOK { return \u0026#34;\u0026#34;, fmt.Errorf(\u0026#34;failed to fetch POD from metacpan: %d\u0026#34;, resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { return \u0026#34;\u0026#34;, err } return string(body), nil } Adding to Cursor Build the server with:\ngo build -o mcp-perl main.go Open mcp.json for Cursor and add\n{ \u0026#34;mcpServers\u0026#34;: { \u0026#34;fetch-perl-pod-from-metacpan\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;/path/to/mcp-perl\u0026#34;, \u0026#34;args\u0026#34;: [] } } } Make sure the MCP tool is enabled in the settings and you should be ready to use it.\nYou can ask the model to use the new tool and Cursor will ask for your permission.\nOnce you let it run, the model will have the output in its context—hopefully for more improved debugging and code writing skills.\nHow useful is it This is the part I\u0026rsquo;m most interested in: are all these MCP servers actually useful for day-to-day development, or are they a distraction?\nIt certainly feels like forcing the model to go get some context on a tool you\u0026rsquo;re using can be helpful—especially when it makes bad assumptions. But so far, most of the Perl modules I use, it already has context on.\nI expect this type of tool will be more useful if you expose private documentation which won\u0026rsquo;t be in any LLM training data.\nIn any case, I plan to try this out for a few days and see if it\u0026rsquo;s worth extending in any way.\nThe code here is all available, slightly better formatted, at gitlab.com/danwainwright/mcp-perl\nIf you try this out or have ideas for other useful MCP tools, let me know!\n","permalink":"https://www.danwainwright.com/posts/writing-mcp-server/","summary":"\u003cp\u003eI\u0026rsquo;ve been making use of \u003ca href=\"https://cursor.com\"\u003eCursor\u003c/a\u003e a lot recently (an AI code editor) and wanted\nto know how useful \u003ca href=\"https://modelcontextprotocol.io\"\u003eMCP\u003c/a\u003e plugins could be.\nWhile there is a massive set of community and \u003ca href=\"https://modelcontextprotocol.io/examples\"\u003ereference servers\u003c/a\u003e\nout there, I wanted to start off by\nlooking at the protocol a little bit and writing my own server.\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m late to this party so finding an idea for a server I might actually use that doesn\u0026rsquo;t already exist isn\u0026rsquo;t so easy. I\u0026rsquo;ve ended up writing a Perl\nMCP server that is designed to help Cursor debug and generally write better Perl code. It might be there\u0026rsquo;s not many people regularly writing Perl\nwho would make an MCP server in their spare time.\u003c/p\u003e","title":"Writing an MCP Server"},{"content":"Now that my blog is live, it seems like a good time to talk about how I consume blogs/news from other sources.\nI like to use RSS to get updates on content I really care about rather than letting algorithms decide what is best to show me.\nFreshRSS This is the feed aggregator of choice. There are local-only clients which I\u0026rsquo;ll talk about later, but it\u0026rsquo;s nice to have some state synced between devices. For this, I use a self-hosted option FreshRSS.\nIn an attempt to run this on a budget, I\u0026rsquo;m running this on the cheapest Hetzner VPS available.\nWhile this is configured with the below Terraform, Hetzner doesn\u0026rsquo;t provide an ArchLinux image, so we mount the ISO and manually do the install.\nresource \u0026#34;hcloud_server\u0026#34; \u0026#34;polaris\u0026#34; { name = \u0026#34;polaris\u0026#34; server_type = \u0026#34;cx22\u0026#34; location = \u0026#34;nbg1\u0026#34; ssh_keys = [] backups = true # image is a placeholder as we will manually install arch anyway image = \u0026#34;debian-12\u0026#34; iso = \u0026#34;archlinux-2025.02.01-x86_64.iso\u0026#34; # Define firewall rules through Hetzner Cloud Firewall firewall_ids = [hcloud_firewall.polaris.id] public_net { ipv4_enabled = true ipv6_enabled = true } } resource \u0026#34;hcloud_firewall\u0026#34; \u0026#34;polaris\u0026#34; { name = \u0026#34;firewall\u0026#34; # Allow SSH from anywhere rule { direction = \u0026#34;in\u0026#34; protocol = \u0026#34;tcp\u0026#34; port = \u0026#34;22\u0026#34; source_ips = [\u0026#34;0.0.0.0/0\u0026#34;, \u0026#34;::/0\u0026#34;] } # Allow HTTP from anywhere rule { direction = \u0026#34;in\u0026#34; protocol = \u0026#34;tcp\u0026#34; port = \u0026#34;80\u0026#34; source_ips = [\u0026#34;0.0.0.0/0\u0026#34;, \u0026#34;::/0\u0026#34;] } # Allow HTTPS from anywhere rule { direction = \u0026#34;in\u0026#34; protocol = \u0026#34;tcp\u0026#34; port = \u0026#34;443\u0026#34; source_ips = [\u0026#34;0.0.0.0/0\u0026#34;, \u0026#34;::/0\u0026#34;] } # Allow ICMP (ping) from anywhere rule { direction = \u0026#34;in\u0026#34; protocol = \u0026#34;icmp\u0026#34; source_ips = [\u0026#34;0.0.0.0/0\u0026#34;, \u0026#34;::/0\u0026#34;] } } We also do some DNS setup so I can access this with a nice hostname\nresource \u0026#34;aws_route53_record\u0026#34; \u0026#34;fresh-rss\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;fresh-rss\u0026#34; type = \u0026#34;CNAME\u0026#34; ttl = 30 records = [\u0026#34;polaris.${aws_route53_zone.primary.name}\u0026#34;] } resource \u0026#34;aws_route53_record\u0026#34; \u0026#34;polaris_AAAA\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;polaris\u0026#34; type = \u0026#34;AAAA\u0026#34; ttl = 30 records = [hcloud_server.polaris.ipv6_address] } resource \u0026#34;aws_route53_record\u0026#34; \u0026#34;polaris_A\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;polaris\u0026#34; type = \u0026#34;A\u0026#34; ttl = 30 records = [hcloud_server.polaris.ipv4_address] } Once that is all done, we actually need to install and set up FreshRSS. I manage this machine with Puppet. The setup is quite simple; we just use Podman to run the official FreshRSS docker image and use an nginx reverse proxy to do TLS termination.\nclass fresh_rss ( String $base_url = \u0026#39;https://fresh-rss.danwainwright.com\u0026#39;, ) { require podman include nginx include nginx::ssl::certbot include rss_bridge # Will talk about this later file { \u0026#39;/opt/fresh-rss\u0026#39;: ensure =\u0026gt; directory, } -\u0026gt; file { \u0026#39;/opt/fresh-rss/data\u0026#39;: ensure =\u0026gt; directory, group =\u0026gt; \u0026#39;http\u0026#39;, mode =\u0026gt; \u0026#39;0775\u0026#39;, } -\u0026gt; file { \u0026#39;/opt/fresh-rss/extensions\u0026#39;: ensure =\u0026gt; directory, group =\u0026gt; \u0026#39;http\u0026#39;, } file { \u0026#39;/opt/fresh-rss/data/config.php\u0026#39;: ensure =\u0026gt; file, content =\u0026gt; epp(\u0026#39;fresh_rss/config.php.epp\u0026#39;, { base_url =\u0026gt; $base_url }), require =\u0026gt; File[\u0026#39;/opt/fresh-rss/data\u0026#39;], group =\u0026gt; \u0026#39;http\u0026#39;, mode =\u0026gt; \u0026#39;0664\u0026#39;, } podman::image { \u0026#39;fresh-rss\u0026#39;: image =\u0026gt; \u0026#39;docker.io/freshrss/freshrss:latest\u0026#39;, } -\u0026gt; podman::container { \u0026#39;fresh-rss\u0026#39;: image =\u0026gt; \u0026#39;docker.io/freshrss/freshrss:latest\u0026#39;, flags =\u0026gt; { mount =\u0026gt; [ \u0026#39;type=bind,source=/opt/fresh-rss/data,destination=/var/www/FreshRSS/data\u0026#39;, \u0026#39;type=bind,source=/opt/fresh-rss/extensions,destination=/var/www/FreshRSS/extensions\u0026#39;, ], publish =\u0026gt; [ \u0026#39;4000:80\u0026#39;, ], env =\u0026gt; [ \u0026#39;TZ=Europe/Paris\u0026#39;, \u0026#39;CRON_MIN=13,43\u0026#39;, ], }, } } The nginx config looks like\nserver { listen 80; server_name fresh-rss.danwainwright.com; return 301 https://$server_name$request_uri; } server { server_name fresh-rss.danwainwright.com; listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/fresh-rss.danwainwright.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/fresh-rss.danwainwright.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot location / { proxy_pass http://localhost:4000; } } Some manual CertBot commands were needed to generate the initial Let\u0026rsquo;s Encrypt certificate, which I\u0026rsquo;ll skip over here.\nRSS Bridge So that\u0026rsquo;s the core RSS client done, which should be usable. Now on to a useful addition: RSS-Bridge. This is a tool that can scrape a standard website or API and generate an RSS feed from that.\nFor example, I use the Reddit bridge to get notifications for posts with enough upvotes on subreddits I care about. You can quite easily write new bridges, such as the BazarakiBridge I wrote to get notifications for motorbikes for sale matching my filter.\nThis is also managed by Puppet.\nclass rss_bridge { require podman file { \u0026#39;/opt/rss-bridge\u0026#39;: ensure =\u0026gt; directory, } -\u0026gt; file { \u0026#39;/opt/rss-bridge/config\u0026#39;: ensure =\u0026gt; directory, } # Mount in some custom bridges file { \u0026#39;/opt/rss-bridge/BazarakiBridge.php\u0026#39;: ensure =\u0026gt; file, source =\u0026gt; \u0026#39;puppet:///modules/rss_bridge/BazarakiBridge.php\u0026#39;, } file { \u0026#39;/opt/rss-bridge/CyprusMailBridge.php\u0026#39;: ensure =\u0026gt; file, source =\u0026gt; \u0026#39;puppet:///modules/rss_bridge/CyprusMailBridge.php\u0026#39;, } file { \u0026#39;/opt/rss-bridge/BuySellCyprusBridge.php\u0026#39;: ensure =\u0026gt; file, source =\u0026gt; \u0026#39;puppet:///modules/rss_bridge/BuySellCyprusBridge.php\u0026#39;, } podman::image { \u0026#39;rss-bridge\u0026#39;: image =\u0026gt; \u0026#39;docker.io/rssbridge/rss-bridge:latest\u0026#39;, } -\u0026gt; podman::container { \u0026#39;rss-bridge\u0026#39;: image =\u0026gt; \u0026#39;docker.io/rssbridge/rss-bridge:latest\u0026#39;, flags =\u0026gt; { mount =\u0026gt; [ \u0026#39;type=bind,source=/opt/rss-bridge/config,destination=/config\u0026#39;, \u0026#39;type=bind,source=/opt/rss-bridge/BazarakiBridge.php,destination=/app/bridges/BazarakiBridge.php\u0026#39;, \u0026#39;type=bind,source=/opt/rss-bridge/CyprusMailBridge.php,destination=/app/bridges/CyprusMailBridge.php\u0026#39;, \u0026#39;type=bind,source=/opt/rss-bridge/BuySellCyprusBridge.php,destination=/app/bridges/BuySellCyprusBridge.php\u0026#39;, ], publish =\u0026gt; [ \u0026#39;3000:80\u0026#39;, ], }, } } Issues Bot blocking is becoming a more common thing around the internet, with many sites using CloudFlare services for this. That\u0026rsquo;s not something RSS-Bridge attempts to solve and is slowly breaking my custom bridges.\nLocal Clients Now all of this runs a self-hosted webpage. I like to use NetNewsWire to connect to FreshRSS, providing a nice interface across iOS and macOS.\nConclusion It\u0026rsquo;s really not that hard to set up an RSS client, and once you have it, it makes managing incoming content a lot easier.\nIf you\u0026rsquo;re producing content in any form, please consider adding RSS support for users like myself.\nThis blog has an RSS feed at https://www.danwainwright.com/index.xml\n","permalink":"https://www.danwainwright.com/posts/rss/","summary":"\u003cp\u003eNow that my blog is live, it seems like a good time to talk about how I consume blogs/news from other sources.\u003c/p\u003e\n\u003cp\u003eI like to use \u003ca href=\"https://en.wikipedia.org/wiki/RSS\"\u003eRSS\u003c/a\u003e to get updates on content I really care about rather\nthan letting algorithms decide what is best to show me.\u003c/p\u003e\n\u003ch2 id=\"freshrss\"\u003eFreshRSS\u003c/h2\u003e\n\u003cp\u003eThis is the feed aggregator of choice. There are local-only clients which I\u0026rsquo;ll talk about later, but it\u0026rsquo;s nice\nto have some state synced between devices. For this, I use a self-hosted option \u003ca href=\"https://www.freshrss.org/\"\u003eFreshRSS\u003c/a\u003e.\u003c/p\u003e","title":"Rss"},{"content":"I\u0026rsquo;ve been reading more blog posts recently and decided I should join in. In this post, I\u0026rsquo;ll walk you through setting up a personal blog using Hugo and Cloudflare Pages. This is designed to get me up and running quickly. This isn\u0026rsquo;t meant to be a guide but just a log of what I\u0026rsquo;ve done.\nHugo setup Do the base init as per the quick start.\nbrew install hugo hugo new site . git init git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod echo \u0026#34;theme = \u0026#39;PaperMod\u0026#39;\u0026#34; \u0026gt; hugo.toml Trying out Cursor, next ask to do some admin\ncreate .gitignore add robots.txt add RSS (just a hugo.toml setting) create a blank content/about.md We\u0026rsquo;re now basically ready to go, we just need to customise the about page and config with details specific to my site.\nHosting So arguably that\u0026rsquo;s the easy bit, now how do we do the hosting which always feels painful.\nAs I said earlier I\u0026rsquo;m using Cloudflare Pages building directly from GitLab.\nWe can do most of this in Terraform.\nFirst we need to manually link the Cloudflare and GitLab accounts. To do that you need to manually start creating a new Cloudflare page from GitLab, accept the auth link and cancel the cloudflare page creation.\n# Some admin which should probably be a variable locals { cloudflare_account_id = \u0026#34;\u0026lt;REDACTED\u0026gt;\u0026#34; hugo_version = \u0026#34;0.147.1\u0026#34; } # Create the gitlab project with the default options I like to use resource \u0026#34;gitlab_project\u0026#34; \u0026#34;blog\u0026#34; { name = \u0026#34;blog\u0026#34; description = \u0026#34;Personal blog for danwainwright.com\u0026#34; visibility_level = \u0026#34;private\u0026#34; default_branch = \u0026#34;main\u0026#34; wiki_enabled = false auto_devops_enabled = false container_registry_access_level = \u0026#34;disabled\u0026#34; packages_enabled = true snippets_enabled = false security_and_compliance_access_level = \u0026#34;disabled\u0026#34; builds_access_level = \u0026#34;private\u0026#34; environments_access_level = \u0026#34;disabled\u0026#34; feature_flags_access_level = \u0026#34;disabled\u0026#34; forking_access_level = \u0026#34;disabled\u0026#34; infrastructure_access_level = \u0026#34;disabled\u0026#34; model_experiments_access_level = \u0026#34;disabled\u0026#34; model_registry_access_level = \u0026#34;disabled\u0026#34; monitor_access_level = \u0026#34;disabled\u0026#34; pages_access_level = \u0026#34;disabled\u0026#34; releases_access_level = \u0026#34;disabled\u0026#34; requirements_access_level = \u0026#34;disabled\u0026#34; snippets_access_level = \u0026#34;disabled\u0026#34; analytics_access_level = \u0026#34;disabled\u0026#34; } # The pages project itself linked to the gitlab repo # This manages the full build process resource \u0026#34;cloudflare_pages_project\u0026#34; \u0026#34;blog\u0026#34; { account_id = local.cloudflare_account_id name = \u0026#34;blog\u0026#34; production_branch = gitlab_project.blog.default_branch source { type = \u0026#34;gitlab\u0026#34; config { owner = data.gitlab_current_user.user.username repo_name = gitlab_project.blog.name production_branch = gitlab_project.blog.default_branch } } build_config { build_command = \u0026#34;hugo -b $CF_PAGES_URL\u0026#34; destination_dir = \u0026#34;public\u0026#34; root_dir = \u0026#34;\u0026#34; } deployment_configs { preview { environment_variables = { HUGO_VERSION = local.hugo_version } } production { environment_variables = { HUGO_VERSION = local.hugo_version } } } } # Link the page to the domain using some route53 setup I already have resource \u0026#34;cloudflare_pages_domain\u0026#34; \u0026#34;blog\u0026#34; { account_id = local.cloudflare_account_id project_name = cloudflare_pages_project.blog.name domain = \u0026#34;www.${aws_route53_zone.primary.name}\u0026#34; } # Route53 CNAME to the cloudflare domain resource \u0026#34;aws_route53_record\u0026#34; \u0026#34;blog\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;www\u0026#34; type = \u0026#34;CNAME\u0026#34; ttl = 60 records = [ cloudflare_pages_project.blog.subdomain ] } And like that we\u0026rsquo;re up and running.\nTesting curl -I https://www.danwainwright.com | head -n 1 HTTP/2 200 RSS as it\u0026rsquo;s the best way to consume a blog.\ncurl -I https://www.danwainwright.com/index.xml | head -n 1 HTTP/2 200 Issues The Cloudflare Terraform provider is broken for creating pages from GitLab accounts currently, so we\u0026rsquo;ve pinned against version 4 (issues/18970).\nI\u0026rsquo;ve been unable to get the root of the domain to redirect to www.\nRRSet of type CNAME with DNS name X. is not permitted at apex in zone Y. It sounds like this is part of the RFC so you\u0026rsquo;re meant to use a AWS Route53 Alias to solve but I can\u0026rsquo;t do that as cloudflare requires a CNAME. The fix might be to move away from Route53. For now this is not solved.\nEDIT: I\u0026rsquo;ve now solved this with\nresource \u0026#34;aws_s3_bucket\u0026#34; \u0026#34;root\u0026#34; { bucket = aws_route53_zone.primary.name } resource \u0026#34;aws_s3_bucket_website_configuration\u0026#34; \u0026#34;root\u0026#34; { bucket = aws_s3_bucket.root.id redirect_all_requests_to { host_name = \u0026#34;www.${aws_route53_zone.primary.name}\u0026#34; protocol = \u0026#34;https\u0026#34; } } resource \u0026#34;aws_s3_bucket_public_access_block\u0026#34; \u0026#34;root\u0026#34; { bucket = aws_s3_bucket.root.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } resource \u0026#34;aws_route53_record\u0026#34; \u0026#34;root\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;\u0026#34; type = \u0026#34;A\u0026#34; alias { name = aws_s3_bucket_website_configuration.root.website_domain zone_id = aws_s3_bucket.root.hosted_zone_id evaluate_target_health = false } } resource \u0026#34;aws_route53_record\u0026#34; \u0026#34;root_aaaa\u0026#34; { zone_id = aws_route53_zone.primary.zone_id name = \u0026#34;\u0026#34; type = \u0026#34;AAAA\u0026#34; alias { name = aws_s3_bucket_website_configuration.root.website_domain zone_id = aws_s3_bucket.root.hosted_zone_id evaluate_target_health = false } } Add Content Now the hardest part, what to write about. We\u0026rsquo;re starting with an about the blog because why not.\nhugo new posts/the-blog.md That gives us an empty file to write away in.\nWhat\u0026rsquo;s next Now I have the blog and a first post let\u0026rsquo;s see what\u0026rsquo;s next. I\u0026rsquo;m not expecting to have lots to blog about but hopefully just having the site up and running gives me the push to write something from time to time.\n","permalink":"https://www.danwainwright.com/posts/the-blog/","summary":"\u003cp\u003eI\u0026rsquo;ve been reading more blog posts recently and decided I should join in.\nIn this post, I\u0026rsquo;ll walk you through setting up a personal blog using \u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e\nand \u003ca href=\"https://pages.cloudflare.com/\"\u003eCloudflare Pages\u003c/a\u003e. This is designed to get me\nup and running quickly. This isn\u0026rsquo;t meant to be a guide but just a log of what I\u0026rsquo;ve done.\u003c/p\u003e\n\u003ch2 id=\"hugo-setup\"\u003eHugo setup\u003c/h2\u003e\n\u003cp\u003eDo the base init as per the \u003ca href=\"https://gohugo.io/getting-started/quick-start/\"\u003equick start\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew install hugo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehugo new site .\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit init\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;theme = \u0026#39;PaperMod\u0026#39;\u0026#34;\u003c/span\u003e \u0026gt; hugo.toml\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTrying out \u003ca href=\"https://cursor.com/\"\u003eCursor\u003c/a\u003e, next ask to do some admin\u003c/p\u003e","title":"The Blog"}]