I invite you to upgrade to a paid subscription. Paid subscribers have told me they appreciate me creating the programming projects and would like to see more of them in the future. Coding Challenge #139 - Code Context MCP ServerThis challenge is to build your own Code Context MCP server with memory.
Hi, this is John with this week’s Coding Challenge. 🙏 Thank you for being a subscriber, I’m honoured to have you as a reader. 🎉 If there is a Coding Challenge you’d like to see, please let me know by replying to this email📧 Coding Challenge #X139 - Code Context MCP ServerThis challenge is to build your own code context server, a searchable, self-improving brain for your codebases that any AI coding tool can plug into. If you use an AI coding assistant, you have probably noticed that it starts every session knowing nothing. It greps around, opens a few files, makes some guesses at how the project fits together, and then forgets all of it the moment you close or clear the session. Next task, it does the same work again to get the same context. In this challenge you are going to build the missing layer. You will ingest a codebase, or a whole collection of them, into a database, chop it up at function and class boundaries, and turn it into something you can ask questions of in plain English. Then you will serve it over the Model Context Protocol, so Claude Code, Codex, Cursor, or any other MCP client is talking to the same brain. Finally you will make it improve over time: it will write its own notes, remember what it has already worked out about your code, and learn from which answers actually got used. This challenge was created in collaboration with Oracle, inspired by their blog post Build a Self-Improving Second Brain on Oracle AI Database. The Challenge - Building Your Own Code Context MCP ServerYou are going to build a tool that indexes codebases and serves them to AI clients over MCP. Along the way you will get to play with semantic search, hybrid ranking, graph queries, and a few ideas from the world of AI agents that are genuinely useful and not just hype. This Coding Challenge leverages Oracle AI Database 26ai because it supports generating embeddings inside the database, hybrid search that fuses keyword and semantic results, and graph queries over your code, all in the same database engine. That means your source code never leaves the database to be indexed, and you do not need an embedding API key. If you would rather use a different stack, it still works, but you will be assembling three or four separate pieces of infrastructure instead of one. Step ZeroIn this introductory step you’re going to set your environment up ready to begin developing and testing your solution. Choose your programming language. You will need a decent database driver, a code parser, and an MCP server library, so pick something well served on all three counts. Python, TypeScript, Go, Java, and Rust are all great choices. You will need a few things in place before you start:
Spend a little time reading about the two ideas that are core to this challenge. The Model Context Protocol specification explains how tools are described and called. The Oracle AI Vector Search guide covers the Finally, grab some code to index. I would suggest cloning two real projects in different languages, so you exercise multi-repository and multi-language support from the start:
Throughout this challenge I will call the tool Step 1In this step your goal is to get the database running and create somewhere to put the code. Start Oracle AI Database 26ai Free as a local container from Then create your schema. You need somewhere to record repositories, files, and symbols. A symbol is a single indexed chunk of code, and for each one you will want to know which repository and file it came from, its path, its language, its name, what kind of thing it is (a function, a method, a class), and the line range it occupies, along with the source code itself. Finally, give your tool a way to register a codebase. The user should be able to point it at a local directory, give it a short name, and later list everything that has been registered along with how many files and symbols each one holds. Testing: Check the container is up and the database is ready:
You are looking for Then register both repositories and list them:
You should see something like:
Both counts are zero, because we have not indexed anything yet. That is next. Step 2In this step your goal is to ingest a codebase and parse it into meaningful chunks. Walk the working tree of a registered repository and decide what is worth indexing. Respect the repository’s Rather than chopping files into arbitrary blocks of text, cut them at function, method, and class boundaries, so that every chunk is a complete, self-contained piece of code. Support at least three languages. Some files will not parse, either because you have no grammar for that language or because the code is broken, so fall back to 60 line windows with 10 lines of overlap rather than skipping them. The overlap is important, because it stops a chunk boundary from slicing a relevant section of code in half. For every symbol you store, record the commit SHA the repository was sitting at when you indexed it. You are not using it yet, but in Step 5 it becomes the thing that makes re-ingestion cheap, and it means every chunk is traceable back to an exact revision of the code. Round the step off by reporting what happened: how many files you scanned, how many you skipped and why, how many symbols you indexed, and how long it all took. Testing:
You should output a summary along these lines:
Check the chunking is doing something sensible rather than just producing 60 line windows everywhere:
Each row should name a real function or class with a believable line range. Pick one and compare it against the file on disk to confirm the boundaries line up. Now ingest the Go repository too, and confirm your language detection is working:
You should see Python symbols from Step 3In this step your goal is to make the code searchable by meaning rather than by exact text. Load an embedding model into the database itself. Oracle publishes a prebuilt ONNX version of Store the embeddings in a With that in place, add a search command. Given a question in plain English, it should return the 10 closest symbols by cosine distance. Throw away anything below a cosine similarity of 0.3, because a bad match is worse than no match at all when the results are going to be fed to a language model. Testing: First confirm the model is loaded and working:
The first should list Re-ingest so your symbols get embeddings, then try a question that shares no words with the code you expect back:
You should get routing and dispatch code from both repositories, ranked by similarity, even though none of it contains the phrase you typed. That is the whole point: grep could not have found this. Check your similarity floor is doing its job by searching for something completely unrelated to the indexed code:
You should get few results or none at all, rather than ten weak matches presented as if they were useful. Step 4In this step your goal is to combine semantic search with keyword search, so exact names win when exact names matter. Semantic search is excellent at “where do we handle retries” and surprisingly bad at “show me Create a hybrid vector index over your symbol text, so lexical and semantic matching are served from one index rather than two. Query it with Make sure that when someone searches for an identifier that exists in the code, the definition of that identifier comes back above its call sites. There are usually hundreds of call sites and exactly one definition, and the definition is almost always what the reader wanted. Finally, now that you have more than one repository indexed, let the user choose. Search everything by default, and provide a flag to narrow a search to one or more named repositories. Testing: Search for an exact identifier and check what comes first:
The definition of Compare the three modes on the same query to see the fusion working:
Vector mode will return things that are conceptually about URL building. Text mode will return everything containing the string. Hybrid should look better than either. Then check repository scoping:
Every result should come from Step 5In this step your goal is to make re-indexing cheap, so you can keep the brain current. Right now every ingest starts from scratch on a large repository that is slow enough that you will stop doing it. And a stale index is worse than no index because you cannot tell when to trust it. The fix is to only do the work that the changes require. Record the commit SHA of each repository the last time you indexed it. If someone asks you to re-ingest while the working tree is still at that revision, say so and do nothing, unless they insist. When there are changes, work out what they are by comparing the working tree against the last indexed commit, and only re-parse and re-embed the files that were added, changed, or renamed. Everything else is already correct and does not need touching. Deletions need care. When a file is removed or renamed, its old symbols and embeddings have to go too. Orphaned chunks are poison in a search index, because they point at code that is not there anymore and there is nothing in the results to tell the reader that. Lastly, give the user an escape hatch: a full rebuild that throws away a repository’s index and starts over. You will want it the first time you change your chunking rules. Testing: Re-ingest with nothing changed:
It should tell you the repository is already up-to-date and do no work. Now make a change and try again:
The summary should report a handful of changed files rather than the whole repository, and it should be noticeably faster than the first ingest was. Test deletion handling by removing a file, re-ingesting, and confirming its symbols have gone:
No result should point at the deleted file. Restore it with Finally check the full rebuild:
This should re-index everything, with counts matching your original ingest. Step 6In this step your goal is to turn the relationships between bits of code into something you can query. Searching finds code that looks like what you asked for. It cannot tell you what will break if you change a function. For that you need the structure of the code, not just its text. While you are ingesting, extract the relationships you can see: which files import which other files, which symbols call which other symbols, and which file defines which symbol. You will not catch everything, especially anything dynamic, and that is fine. A graph that captures most direct calls is enormously useful even when it is incomplete. Expose those relationships as a SQL property graph with Then answer the two questions every developer asks before changing anything. “What calls this?” and “What does this call?” using a Testing: Pick a function with a decent number of callers and look both ways:
Cross-check the results against Now try the blast radius:
You should get a list of affected symbols with a hop count, and there should be more results at 3 hops than at 1:
Step 7In this step your goal is to hand all of this to an AI client over MCP. Everything so far has been for you at a terminal. Now make it available to the tools you actually code with. Expose the brain as an MCP server over standard input and output. There is no network listener and no authentication to worry about, because the client starts your server as a child process and talks to it over standard io. Provide four tools, described well enough that a model can work out when to reach for each one. Tool descriptions are effectively prompts, so it is worth spending time on them.
Testing: Start with the MCP Inspector, which lets you call tools by hand:
Confirm all four tools appear with their descriptions and parameters, then call Then wire it into a real client and use it for some real coding:
Start a session in an unrelated directory, so the client has no filesystem access to the code and has to use your server, and ask it something like “using ccctx, how does Flask decide which view function handles a request?”. Watch which tools it chooses. If it reaches for the wrong one, your descriptions need work, and that is a genuinely useful thing to learn. Step 8In this step your goal is to have your tool write and maintain its own architecture notes. Search answers narrow questions well. It is much weaker at “what does this module actually do,” because that answer is not written down in any single chunk. So have your tool write it down. Generate a wiki page for each module or directory once it holds at least 10 indexed symbols. A page should cover what the module is for, its key symbols, and which other modules it depends on. You already have everything needed to work that out: the symbols, and the import edges from Step 6. Store each page’s citations as rows pointing at real file and symbol records, not as text in the prose. This is the part that makes the wiki trustworthy. A citation that is just a sentence saying “ That also gives you staleness for free. When the commit SHA of a symbol a page cites changes, mark that page stale, and recompile stale pages on the next re-ingestion. A wiki that quietly goes out of date is worse than no wiki, because people keep believing it. Then make the pages useful: expose a Testing: Build the wiki and read a page:
The page should describe what the module does and name real symbols from it. Check the citations are stored as references rather than prose:
Every citation should resolve to a symbol that exists. Now test staleness by changing a cited function:
The
A wiki page should rank above the individual functions. Step 9In this step your goal is to give your server a memory, so it stops working the same things out over and over. You can draw on the ideas for AI Agent Memory and if you’re working in Python, leverage Oracle’s AI Agent Memory Python package for this step. Every time a client calls one of your tools, record it: the question, which tool was used, what came back, and when. This is your episodic memory, a raw log of everything that has happened. On its own it is not much use, because by next week there will be thousands of rows and no way to find anything in them. So distil it. Turn those raw runs into durable facts about the codebase, each with a subject, the fact itself, a confidence score, and the run IDs it came from so you can always trace it back. Merge duplicates as you go rather than accumulating fifty near-identical variations of the same observation. Run this on demand, and automatically after each re-ingestion, so the memory keeps pace with the code. Then expose it. A Testing: Ask your server several related questions through the MCP Inspector or a real client, then look at what it remembered:
You should see one row per tool call. Now distil them:
You should get a much shorter list of facts than you had runs, each traceable to the runs it came from. Ask two near-identical questions, consolidate again, and confirm you get one merged fact rather than two. Then check recall works end-to-end. Start a fresh client session and ask “what do you already know about this codebase?”. The client should call Step 10In this step your goal is to let your server learn from which results actually turned out to be useful. Start recording when a client uses a result by citing it in an answer or opening it. Mark it as used, so you can tell the difference between a result you returned and a result that helped. Then feed that back into ranking carefully. Boost frequently used symbols on future searches, but cap the boost at 20 percent. Feedback loops in search have a nasty habit of eating themselves: popular results get boosted, so they get shown more, so they get used more, so they get boosted further, until your search only ever returns the same five things. A bounded boost nudges the ordering without ever overruling relevance. Add decay for the same reason. Halve the weight of feedback every 30 days, so what the tool learned during last quarter’s refactor fades out instead of haunting your searches forever. Testing: Build your gold set as a simple file of questions and expected paths, then take a baseline:
Now generate feedback by running sessions and marking useful results, then measure again:
Recall should improve, or at least hold steady. If it drops, your boost is too strong and is pushing correct answers out of the top 10, which is exactly the failure this step is designed to let you catch. Check the cap is real by hammering a single symbol with feedback and confirming it does not take over:
A heavily used but irrelevant symbol should still not appear for an unrelated query. Test decay by backdating some feedback and confirming its influence has halved:
Going FurtherOnce you have the core server working, here are some ideas to take it further:
Share Your Solutions!If you think your solution is an example other developers can learn from please share it, put it on GitHub, GitLab or elsewhere. Then let me know via Bluesky or LinkedIn or just post about it there and tag me. Alternately please add a link to it in the Coding Challenges Shared Solutions Github repo. Request for FeedbackI’m writing these challenges to help you develop your skills as a software engineer based on how I’ve approached my own personal learning and development. What works for me might not be the best way for you - so if you have suggestions for how I can make these challenges more useful to you and others, please get in touch and let me know. All feedback is greatly appreciated. You can reach me on Bluesky, LinkedIn or through SubStack Thanks and happy coding! John You're currently a free subscriber to Coding Challenges. For the full experience, upgrade your subscription.
|
#6636 WWE 2K26 v1.06 + 6 DLCs [Monkey Repack] Genres/Tags: Arcade, Fighting, Sports, 3D Companies: 2K Games, Visual Concepts Languages: ENG/MULTI6 Original Size: 129.2 GB Repack Size: 107.8 GB Download Mirrors (Direct Links) .dlinks {margi… Read on blog or Reader FitGirl Repacks Read on blog or Reader WWE 2K26, v1.06 + 6 DLCs [Monkey Repack] By FitGirl on 28/03/2026 # 66 3 6 WWE 2K2 6 v1.0 6 + 6 DLCs [Monkey ...

Comments
Post a Comment