C# Multiple ASYNC requests single response (Promise like)
Bug
You have a pretty big multithreading issue in your code. When this method can be called from different threads, the MemoryCache doesn't necessarily contain an already created task. Consider the following execution:
Thread 1                     | Thread 2
string cacheKey = ...        |  -
var cachedRequest = ..       |  -
if (cachedRequest != null)   |  -
if (cachedRequest != null)   |  string cacheKey = ...
if (cachedRequest != null)   |  var cachedRequest = ...
TaskCompletionSource tcs =   |  var cachedRequest = ...
TaskCompletionSource tcs =   |  if (cachedRequest != null) 
TaskCompletionSource tcs =   |  TaskCompletionSource tcs = 
...                          |  ...

The result should be pretty obvious: This way two tasks for the same key can be started. Depending on how strict you need that semantic, that's a problem.
Fixing this is not trivial, but should be simple enough with a lock (_lock) block onto a private static const Object _lock = new Object();
How to Task
In general I'd expect a method that returns a Task&lt;bool&gt; to not actually do the work, as is suggested by //do something long here. Instead the code should submit the work as an Action or something along these lines. Something like that:
Task&lt;bool&gt; result = new Task&lt;bool&gt;(() =&gt; 
{
    try
    {
         // do something long here
         return true;
    }
    catch (Exception e) 
    {
         return false;
    }
});

this shows an additional problem. The return value of that Task is basically just a flag for successful completion. But you know what? Task already has that: Task.IsFaulted
This makes for a pretty different return value. Use Task instead of Task&lt;bool&gt;, because it removes redundancy.
Back to the code: We're still not quite there with the lookup and caching mechanics.
CacheItemPolicy cip = new CacheItemPolicy()
...
MemoryCache.Default.Set(cacheKey, result, cip);

This is for the caching, now we just need to clean the cache when we're finished:
result.ContinueWith(() =&gt; MemoryCache.Default.Remove(cacheKey));
result.Start(); // actually start doing work
return result;