What we did at our company was to set up a tools repository, and then a project repository. The tools repository is a Subversion repository, organized as follows:
/svn/tools/
vendor1/
too11/
1.0/
1.1/
latest = a copy of vendor1/tool1/1.1
tool2/
1.0/
1.5/
latest = a copy of vendor1/tool2/1.5
vendor2/
foo/
1.0.0/
1.1.0/
1.2.0/
latest = a copy of vendor2/foo/1.2.0
Every time we get a new version of a tool from a vendor, it is added under its vendor, name, and version number, and the 'latest' tag is updated.
[Clarification: this is NOT a typical source respository -- it's intended to store specific versions of 'installed' images. Thus /svn/tools/nunit/nunit2/2.4 would be the top of a directory tree containing the results of installing NUnit 2.4 to a directory and importing it into the tools repository. Source and examples may be present, but the primary focus is on executables and libraries that are necessary to use the tool. If we needed to modify a vendor tool, we'd do that in a separate repository, and release the result to this repository.]
One of the vendors is my company, and has a separate section for each tool, assembly, whatever that we release internally.
The projects repository is a standard Subversion repository, with trunks, tags, and branches as you normally expect. Any given project will look like:
/svn/
branches/
tags/
trunk/
foo/
source/
tools/
publish/
foo-build.xml (for NAnt)
foo.build (for MSBuild)
The tools directory has a Subversion svn:externals property set, that links in the appropriate version (either a specific version or 'latest') of each tool or assembly that is needed by that project. When the 'foo' project is built by CruiseControl.NET, the publish task will populate the 'publish' directory as the 'foo' assembly is intended to be deployed, and then executes the following subversion commands:
svn import publish /svn/tools/vendor2/foo/1.2.3
svn delete /svn/tools/vendor2/foo/latest
svn copy /svn/tools/vendor2/foo/1.2.3 /svn/tools/vendor2/foo/latest
Developers work on their projects as normal, and let the build automation take care of the details. A normal subversion update will pull the latest versions of external tools as well as as project updates.
If you've got a lot of tool interdependency, you can configure CruiseControl.NET (by hand) to trigger builds for subordinate projects when their dependencies change, but we haven't needed to go that far yet.
Note: All of the Subversion repository paths have been shortened for clarity. We actually use Apache+SVN, and two separate servers, but you should adapt this as you see fit.